Compare commits
2764 Commits
STABLE-1_4
...
STABLE-2_0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea2f6fb57c | ||
|
|
b307fea1b9 | ||
|
|
c31bd404e2 | ||
|
|
0381849624 | ||
|
|
19d56b4096 | ||
|
|
66db517a28 | ||
|
|
2452bc9336 | ||
|
|
2848b17e80 | ||
|
|
c71c9882c2 | ||
|
|
40fbd6bc24 | ||
|
|
df7485de1c | ||
|
|
fe6e1bd4af | ||
|
|
168fa1c38a | ||
|
|
f0975b3c59 | ||
|
|
563932b888 | ||
|
|
8849a443a4 | ||
|
|
e318688195 | ||
|
|
fa8b6a92b4 | ||
|
|
2ca39c275a | ||
|
|
4d1d567ab7 | ||
|
|
8927cda2f8 | ||
|
|
bc78251f4a | ||
|
|
0a3e4cd10e | ||
|
|
76efa271e6 | ||
|
|
b3293d903e | ||
|
|
5ef8a3cb60 | ||
|
|
01c2e43c5c | ||
|
|
0b7bef5420 | ||
|
|
3c4aec99a4 | ||
|
|
dc38e21a70 | ||
|
|
d471e5f89e | ||
|
|
99ef13f2be | ||
|
|
bb2b2be454 | ||
|
|
faa7a21a83 | ||
|
|
d6e8e05edd | ||
|
|
0b299f96e9 | ||
|
|
777d54f0e4 | ||
|
|
8c6ac8eb59 | ||
|
|
4fc3770278 | ||
|
|
e53c84654e | ||
|
|
d0b0cf983e | ||
|
|
90d68b41df | ||
|
|
e6756387b0 | ||
|
|
4fe1436904 | ||
|
|
1fdbda9700 | ||
|
|
fed15778dd | ||
|
|
bbe91e356f | ||
|
|
0a73e0ff30 | ||
|
|
7ba2633ef0 | ||
|
|
d860dd7655 | ||
|
|
2694486309 | ||
|
|
cb97e27120 | ||
|
|
890c5982a1 | ||
|
|
4deaebae44 | ||
|
|
5fe195c3d3 | ||
|
|
e5071daf45 | ||
|
|
980b219c28 | ||
|
|
76b4365aaa | ||
|
|
a5a4830b16 | ||
|
|
1a2a9a4e96 | ||
|
|
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 | ||
|
|
216bf89491 | ||
|
|
a68eddbd47 | ||
|
|
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 | ||
|
|
fd096a5769 | ||
|
|
15b75555a6 | ||
|
|
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 | ||
|
|
33955c636d | ||
|
|
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 |
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# These files are text and should be normalized
|
||||
*.txt text
|
||||
*.c text
|
||||
*.h text
|
||||
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
*.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
|
||||
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.
|
||||
|
||||
65
README
65
README
@@ -10,28 +10,41 @@ 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.
|
||||
|
||||
|
||||
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)
|
||||
* 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
|
||||
* 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
|
||||
|
||||
|
||||
APPLICATIONS
|
||||
|
||||
* HTTP server with SSI and CGI
|
||||
* SNMPv2c agent with MIB compiler (Simple Network Management Protocol)
|
||||
* SNTP (Simple network time protocol)
|
||||
* NetBIOS name service responder
|
||||
* MDNS (Multicast DNS) responder
|
||||
* iPerf server implementation
|
||||
|
||||
|
||||
LICENSE
|
||||
|
||||
lwIP is freely available under a BSD license.
|
||||
|
||||
|
||||
DEVELOPMENT
|
||||
|
||||
lwIP has grown into an excellent TCP/IP stack for embedded devices,
|
||||
@@ -40,38 +53,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 +89,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>
|
||||
|
||||
|
||||
93
UPGRADING
93
UPGRADING
@@ -4,10 +4,101 @@ 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.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.
|
||||
|
||||
117
doc/NO_SYS_SampleCode.c
Normal file
117
doc/NO_SYS_SampleCode.c
Normal file
@@ -0,0 +1,117 @@
|
||||
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, sizeof(netif->hwaddr));
|
||||
netif->hwaddr_len = sizeof(netif->hwaddr);
|
||||
|
||||
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_init();
|
||||
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 */
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
2505
doc/doxygen/lwip.Doxyfile
Normal file
2505
doc/doxygen/lwip.Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
132
doc/doxygen/main_page.h
Normal file
132
doc/doxygen/main_page.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* @defgroup lwip lwIP
|
||||
*
|
||||
* @defgroup infrastructure Infrastructure
|
||||
*
|
||||
* @defgroup callbackstyle_api Callback-style APIs
|
||||
* Non thread-safe APIs, callback style for maximum performance and minimum
|
||||
* memory footprint.
|
||||
*
|
||||
* @defgroup sequential_api Sequential-style APIs
|
||||
* Sequential-style APIs, blocking functions. More overhead, but can be called
|
||||
* from any thread except TCPIP thread.
|
||||
*
|
||||
* @defgroup addons Addons
|
||||
*
|
||||
* @defgroup apps Applications
|
||||
*/
|
||||
|
||||
/**
|
||||
* @mainpage Overview
|
||||
* @verbinclude "README"
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page upgrading Upgrading
|
||||
* @verbinclude "UPGRADING"
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page changelog 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).
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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 raw_api lwIP API
|
||||
* @verbinclude "rawapi.txt"
|
||||
*/
|
||||
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>
|
||||
113
doc/mdns.txt
Normal file
113
doc/mdns.txt
Normal file
@@ -0,0 +1,113 @@
|
||||
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 needs a strncasecmp() implementation. If you have one, define
|
||||
LWIP_MDNS_STRNCASECMP 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.
|
||||
|
||||
It is recommended to call this function after an IPv4 address has been set,
|
||||
since there is currently no check if the v4 address is valid.
|
||||
|
||||
Call mdns_resp_netif_settings_changed() every time the IP address
|
||||
on the netif has changed.
|
||||
|
||||
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.
|
||||
|
||||
Removing services is currently not supported. Services are removed when the
|
||||
netif is removed.
|
||||
|
||||
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
|
||||
190
doc/rawapi.txt
190
doc/rawapi.txt
@@ -8,6 +8,12 @@ to use for communication with the TCP/IP code:
|
||||
* higher-level "sequential" API.
|
||||
* BSD-style socket API.
|
||||
|
||||
The raw API (sometimes called native API) is an event-driven API designed
|
||||
to be used without an operating system that implements zero-copy send and
|
||||
receive. This API is also used by the core stack for interaction between
|
||||
the various protocols. It is the only API available when running lwIP
|
||||
without an operating system.
|
||||
|
||||
The sequential API provides a way for ordinary, sequential, programs
|
||||
to use the lwIP stack. It is quite similar to the BSD socket API. The
|
||||
model of execution is based on the blocking open-read-write-close
|
||||
@@ -22,14 +28,17 @@ 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
|
||||
** 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"). 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.
|
||||
(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
|
||||
@@ -38,6 +47,7 @@ communicate with this main thread through message passing.
|
||||
- netbuf.h
|
||||
- netdb.h
|
||||
- netifapi.h
|
||||
- pppapi.h
|
||||
- sockets.h
|
||||
- sys.h
|
||||
|
||||
@@ -46,13 +56,18 @@ communicate with this main thread through message passing.
|
||||
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,
|
||||
Netconn or Socket API functions are thread safe against the
|
||||
core thread but they are not reentrant at the control block
|
||||
granularity level. That is, a UDP or TCP control block must
|
||||
not be shared among multiple threads without proper locking.
|
||||
|
||||
If SYS_LIGHTWEIGHT_PROT is set to 1 and
|
||||
LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1,
|
||||
pbuf_free() may also be called from another thread or
|
||||
an ISR (since only then, mem_free - for PBUF_RAM - may
|
||||
be called from an ISR: otherwise, the HEAP is only
|
||||
protected by semaphores).
|
||||
|
||||
|
||||
|
||||
** The remainder of this document discusses the "raw" API. **
|
||||
|
||||
@@ -71,13 +86,28 @@ 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
|
||||
All APIs can be used simultaneously by different application
|
||||
programs. In fact, the sequential API is implemented as an application
|
||||
program using the raw TCP/IP interface.
|
||||
|
||||
Do not confuse the lwIP raw API with raw Ethernet or IP sockets.
|
||||
The former is a way of interfacing the lwIP network stack (including
|
||||
TCP and UDP), the later refers to processing raw Ethernet or IP data
|
||||
instead of TCP connections or UDP packets.
|
||||
|
||||
Raw API applications may never block since all packet processing
|
||||
(input and output) as well as timer processing (TCP mainly) is done
|
||||
in a single execution context.
|
||||
|
||||
--- Callbacks
|
||||
|
||||
Program execution is driven by callbacks. Each callback is an ordinary
|
||||
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,
|
||||
@@ -107,7 +137,7 @@ incoming connections or be explicitly connected to another host.
|
||||
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,
|
||||
- err_t tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr,
|
||||
u16_t port)
|
||||
|
||||
Binds the pcb to a local IP address and port number. The IP address
|
||||
@@ -141,21 +171,14 @@ incoming connections or be explicitly connected to another host.
|
||||
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,
|
||||
|
||||
- err_t tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr,
|
||||
u16_t port, err_t (* connected)(void *arg,
|
||||
struct tcp_pcb *tpcb,
|
||||
err_t err));
|
||||
@@ -176,7 +199,7 @@ incoming connections or be explicitly connected to another host.
|
||||
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
|
||||
@@ -184,15 +207,19 @@ 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)
|
||||
- err_t tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len,
|
||||
u8_t apiflags)
|
||||
|
||||
Enqueues the data pointed to by the argument dataptr. The length of
|
||||
the data is passed as the len parameter. The 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 data is passed as the len parameter. The apiflags can be one or more of:
|
||||
- TCP_WRITE_FLAG_COPY: indicates whether the new memory should be allocated
|
||||
for the data to be copied into. If this flag is not given, no new memory
|
||||
should be allocated and the data should only be referenced by pointer. This
|
||||
also means that the memory behind dataptr must not change until the data is
|
||||
ACKed by the remote host
|
||||
- TCP_WRITE_FLAG_MORE: indicates that more data follows. If this is omitted,
|
||||
the PSH flag is set in the last segment created by this call to tcp_write.
|
||||
If this flag is given, the PSH flag is not set.
|
||||
|
||||
The tcp_write() function will fail and return ERR_MEM if the length
|
||||
of the data exceeds the current send buffer size or if the length of
|
||||
@@ -238,7 +265,7 @@ window.
|
||||
|
||||
Must be called when the application has received the data. The len
|
||||
argument indicates the length of the received data.
|
||||
|
||||
|
||||
|
||||
--- Application polling
|
||||
|
||||
@@ -253,7 +280,7 @@ 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)
|
||||
u8_t interval)
|
||||
|
||||
Specifies the polling interval and the callback function that should
|
||||
be called to poll the application. The interval is specified in
|
||||
@@ -296,17 +323,6 @@ function to be called is set using the tcp_err() function.
|
||||
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
|
||||
@@ -322,14 +338,14 @@ level of complexity of UDP, the interface is significantly simpler.
|
||||
|
||||
Removes and deallocates the pcb.
|
||||
|
||||
- err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr,
|
||||
- err_t udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr,
|
||||
u16_t port)
|
||||
|
||||
Binds the pcb to a local address. The IP-address argument "ipaddr"
|
||||
can be IP_ADDR_ANY to indicate that it should listen to any local IP
|
||||
address. The function currently always return ERR_OK.
|
||||
|
||||
- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr,
|
||||
- err_t udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr,
|
||||
u16_t port)
|
||||
|
||||
Sets the remote end of the pcb. This function does not generate any
|
||||
@@ -347,7 +363,7 @@ level of complexity of UDP, the interface is significantly simpler.
|
||||
- void udp_recv(struct udp_pcb *pcb,
|
||||
void (* recv)(void *arg, struct udp_pcb *upcb,
|
||||
struct pbuf *p,
|
||||
struct ip_addr *addr,
|
||||
ip_addr_t *addr,
|
||||
u16_t port),
|
||||
void *recv_arg)
|
||||
|
||||
@@ -357,9 +373,9 @@ level of complexity of UDP, the interface is significantly simpler.
|
||||
|
||||
--- 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).
|
||||
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
|
||||
@@ -367,51 +383,13 @@ UDP and TCP transport layers, IPv4 and the DHCP client.
|
||||
|
||||
Call these functions in the order of appearance:
|
||||
|
||||
- stats_init()
|
||||
- lwip_init()
|
||||
|
||||
Clears the structure where runtime statistics are gathered.
|
||||
Initialize the lwIP stack and all of its subsystems.
|
||||
|
||||
- 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))
|
||||
- netif_add(struct netif *netif, const ip4_addr_t *ipaddr,
|
||||
const ip4_addr_t *netmask, const ip4_addr_t *gw,
|
||||
void *state, netif_init_fn init, netif_input_fn input)
|
||||
|
||||
Adds your network interface to the netif_list. Allocate a struct
|
||||
netif and pass a pointer to this structure as the first argument.
|
||||
@@ -419,18 +397,20 @@ Call these functions in the order of appearance:
|
||||
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.
|
||||
your Ethernet netif interface. The following code illustrates its use.
|
||||
|
||||
err_t netif_if_init(struct netif *netif)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
for(i = 0; i < ETHARP_HWADDR_LEN; i++) netif->hwaddr[i] = some_eth_addr[i];
|
||||
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
|
||||
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".
|
||||
|
||||
@@ -438,18 +418,30 @@ Call these functions in the order of appearance:
|
||||
|
||||
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)
|
||||
|
||||
When the netif is fully configured this function must be called.
|
||||
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.
|
||||
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.
|
||||
|
||||
- sys_check_timeouts()
|
||||
|
||||
When the system is running, you have to periodically call
|
||||
sys_check_timeouts() which will handle all timers for all protocols in
|
||||
the stack; add this to your main loop or equivalent.
|
||||
|
||||
|
||||
--- Optimalization hints
|
||||
|
||||
@@ -464,9 +456,11 @@ 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>
|
||||
#define lwip_htons(x) <your_htons>
|
||||
#define lwip_htonl(x) <your_htonl>
|
||||
If you #define them to htons() and htonl(), you should
|
||||
#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from
|
||||
defining hton*/ntoh* compatibility macros.
|
||||
|
||||
Check your network interface driver if it reads at
|
||||
a higher speed than the maximum wire-speed. If the
|
||||
|
||||
131
doc/savannah.txt
131
doc/savannah.txt
@@ -2,37 +2,34 @@ 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 -t dsa
|
||||
|
||||
Under Windows, a recommended SSH client is "PuTTY", freely available with good
|
||||
documentation and a graphic user interface. Use its key generator.
|
||||
@@ -41,95 +38,83 @@ Now paste the id_dsa.pub contents into your Savannah account public key list. Wa
|
||||
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 */
|
||||
141
doc/sys_arch.txt
141
doc/sys_arch.txt
@@ -1,6 +1,7 @@
|
||||
sys_arch interface for lwIP 0.6++
|
||||
sys_arch interface for lwIP
|
||||
|
||||
Author: Adam Dunkels
|
||||
Simon Goldschmidt
|
||||
|
||||
The operating system emulation layer provides a common interface
|
||||
between the lwIP code and the underlying operating system kernel. The
|
||||
@@ -9,12 +10,11 @@ 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
|
||||
The sys_arch provides semaphores, mailboxes and mutexes to lwIP. For the full
|
||||
lwIP functionality, multiple threads support can be implemented in the
|
||||
sys_arch, but this is not required for the basic lwIP
|
||||
functionality. 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.
|
||||
functionality. Timer scheduling is implemented in lwIP, but can be implemented
|
||||
by the sys_arch port (LWIP_TIMERS_CUSTOM==1).
|
||||
|
||||
In addition to the source file providing the functionality of sys_arch,
|
||||
the OS emulation layer must provide several header files defining
|
||||
@@ -22,17 +22,21 @@ 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.
|
||||
kinds. Mailboxes should be implemented as a queue which allows multiple messages
|
||||
to be posted (implementing as a rendez-vous point where only one message can be
|
||||
posted at a time can have a highly negative impact on performance). A message
|
||||
in a mailbox is just a pointer, nothing more.
|
||||
|
||||
Semaphores are represented by the type "sys_sem_t" which is typedef'd
|
||||
in the sys_arch.h file. Mailboxes are equivalently represented by the
|
||||
type "sys_mbox_t". lwIP does not place any restrictions on how
|
||||
sys_sem_t or sys_mbox_t are represented internally.
|
||||
type "sys_mbox_t". Mutexes are represented by the type "sys_mutex_t".
|
||||
lwIP does not place any restrictions on how these types are represented
|
||||
internally.
|
||||
|
||||
Since lwIP 1.4.0, semaphore, mutexes and mailbox functions are prototyped in a way that
|
||||
allows both using pointers or actual OS structures to be used. This way, memory
|
||||
required for such types can be either allocated in place (globally or on the
|
||||
stack) or on the heap (allocated internally in the "*_new()" functions).
|
||||
|
||||
The following functions must be implemented by the sys_arch:
|
||||
|
||||
@@ -40,20 +44,25 @@ The following functions must be implemented by the sys_arch:
|
||||
|
||||
Is called to initialize the sys_arch layer.
|
||||
|
||||
- sys_sem_t sys_sem_new(u8_t count)
|
||||
- err_t sys_sem_new(sys_sem_t *sem, u8_t count)
|
||||
|
||||
Creates and returns a new semaphore. The "count" argument specifies
|
||||
the initial state of the semaphore.
|
||||
Creates a new semaphore. The semaphore is allocated to the memory that 'sem'
|
||||
points to (which can be both a pointer or the actual OS structure).
|
||||
The "count" argument specifies the initial state of the semaphore (which is
|
||||
either 0 or 1).
|
||||
If the semaphore has been created, ERR_OK should be returned. Returning any
|
||||
other error will provide a hint what went wrong, but except for assertions,
|
||||
no real error handling is implemented.
|
||||
|
||||
- void sys_sem_free(sys_sem_t sem)
|
||||
- void sys_sem_free(sys_sem_t *sem)
|
||||
|
||||
Deallocates a semaphore.
|
||||
|
||||
- void sys_sem_signal(sys_sem_t sem)
|
||||
- void sys_sem_signal(sys_sem_t *sem)
|
||||
|
||||
Signals a semaphore.
|
||||
|
||||
- u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
|
||||
- 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
|
||||
@@ -70,30 +79,81 @@ The following functions must be implemented by the sys_arch:
|
||||
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)
|
||||
- int sys_sem_valid(sys_sem_t *sem)
|
||||
|
||||
Returns 1 if the semaphore is valid, 0 if it is not valid.
|
||||
When using pointers, a simple way is to check the pointer for != NULL.
|
||||
When directly using OS structures, implementing this may be more complex.
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
- void sys_sem_set_invalid(sys_sem_t *sem)
|
||||
|
||||
Invalidate a semaphore so that sys_sem_valid() returns 0.
|
||||
ATTENTION: This does NOT mean that the semaphore shall be deallocated:
|
||||
sys_sem_free() is always called before calling this function!
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
- void sys_mutex_new(sys_mutex_t *mutex)
|
||||
|
||||
Creates a new mutex. The mutex is allocated to the memory that 'mutex'
|
||||
points to (which can be both a pointer or the actual OS structure).
|
||||
If the mutex has been created, ERR_OK should be returned. Returning any
|
||||
other error will provide a hint what went wrong, but except for assertions,
|
||||
no real error handling is implemented.
|
||||
|
||||
- void sys_mutex_free(sys_mutex_t *mutex)
|
||||
|
||||
Deallocates a mutex.
|
||||
|
||||
- void sys_mutex_lock(sys_mutex_t *mutex)
|
||||
|
||||
Blocks the thread until the mutex can be grabbed.
|
||||
|
||||
- void sys_mutex_unlock(sys_mutex_t *mutex)
|
||||
|
||||
Releases the mutex previously locked through 'sys_mutex_lock()'.
|
||||
|
||||
- void sys_mutex_valid(sys_mutex_t *mutex)
|
||||
|
||||
Returns 1 if the mutes is valid, 0 if it is not valid.
|
||||
When using pointers, a simple way is to check the pointer for != NULL.
|
||||
When directly using OS structures, implementing this may be more complex.
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
- void sys_mutex_set_invalid(sys_mutex_t *mutex)
|
||||
|
||||
Invalidate a mutex so that sys_mutex_valid() returns 0.
|
||||
ATTENTION: This does NOT mean that the mutex shall be deallocated:
|
||||
sys_mutex_free() is always called before calling this function!
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
- err_t sys_mbox_new(sys_mbox_t *mbox, int size)
|
||||
|
||||
Creates an empty mailbox for maximum "size" elements. Elements stored
|
||||
in mailboxes are pointers. You have to define macros "_MBOX_SIZE"
|
||||
in your lwipopts.h, or ignore this parameter in your implementation
|
||||
and use a default size.
|
||||
If the mailbox has been created, ERR_OK should be returned. Returning any
|
||||
other error will provide a hint what went wrong, but except for assertions,
|
||||
no real error handling is implemented.
|
||||
|
||||
- void sys_mbox_free(sys_mbox_t mbox)
|
||||
- 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)
|
||||
- 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)
|
||||
- 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)
|
||||
- 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
|
||||
@@ -110,7 +170,7 @@ The following functions must be implemented by the sys_arch:
|
||||
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)
|
||||
- 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
|
||||
@@ -122,7 +182,21 @@ The following functions must be implemented by the sys_arch:
|
||||
#define sys_arch_mbox_tryfetch(mbox,msg) \
|
||||
sys_arch_mbox_fetch(mbox,msg,1)
|
||||
although this would introduce unnecessary delays.
|
||||
|
||||
|
||||
- int sys_mbox_valid(sys_mbox_t *mbox)
|
||||
|
||||
Returns 1 if the mailbox is valid, 0 if it is not valid.
|
||||
When using pointers, a simple way is to check the pointer for != NULL.
|
||||
When directly using OS structures, implementing this may be more complex.
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
- void sys_mbox_set_invalid(sys_mbox_t *mbox)
|
||||
|
||||
Invalidate a mailbox so that sys_mbox_valid() returns 0.
|
||||
ATTENTION: This does NOT mean that the mailbox shall be deallocated:
|
||||
sys_mbox_free() is always called before calling this function!
|
||||
This may also be a define, in which case the function is not prototyped.
|
||||
|
||||
If threads are supported by the underlying operating system and if
|
||||
such functionality is needed in lwIP, the following function will have
|
||||
to be implemented as well:
|
||||
@@ -135,6 +209,9 @@ to be implemented as well:
|
||||
the "stacksize" parameter. The id of the new thread is returned. Both the id
|
||||
and the priority are system dependent.
|
||||
|
||||
When lwIP is used from more than one context (e.g. from multiple threads OR from
|
||||
main-loop and from interrupts), the SYS_LIGHTWEIGHT_PROT protection SHOULD be enabled!
|
||||
|
||||
- sys_prot_t sys_arch_protect(void)
|
||||
|
||||
This optional function does a "fast" critical region protection and returns
|
||||
@@ -156,9 +233,19 @@ to be implemented as well:
|
||||
more information. This function is only required if your port is supporting
|
||||
an operating system.
|
||||
|
||||
For some configurations, you also need:
|
||||
|
||||
- u32_t sys_now(void)
|
||||
|
||||
This optional function returns the current time in milliseconds (don't care
|
||||
for wraparound, this is only used for time diffs).
|
||||
Not implementing this function means you cannot use some modules (e.g. TCP
|
||||
timestamps, internal timeouts for NO_SYS==1).
|
||||
|
||||
|
||||
Note:
|
||||
|
||||
Be carefull with using mem_malloc() in sys_arch. When malloc() refers to
|
||||
Be careful with using mem_malloc() in sys_arch. When malloc() refers to
|
||||
mem_malloc() you can run into a circular function call problem. In mem.c
|
||||
mem_init() tries to allcate a semaphore using mem_malloc, which of course
|
||||
can't be performed when sys_arch uses mem_malloc.
|
||||
|
||||
@@ -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.
|
||||
|
||||
181
src/Filelists.mk
Normal file
181
src/Filelists.mk
Normal file
@@ -0,0 +1,181 @@
|
||||
#
|
||||
# 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/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/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/slipif.c
|
||||
|
||||
# SIXLOWPAN: 6LoWPAN
|
||||
SIXLOWPAN=$(LWIPDIR)/netif/lowpan6.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_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 \
|
||||
$(LWIPDIR)/apps/snmp/snmpv3_mbedtls.c \
|
||||
$(LWIPDIR)/apps/snmp/snmpv3_dummy.c
|
||||
|
||||
# HTTPDFILES: HTTP server
|
||||
HTTPDFILES=$(LWIPDIR)/apps/httpd/fs.c \
|
||||
$(LWIPDIR)/apps/httpd/httpd.c
|
||||
|
||||
# LWIPERFFILES: IPERF server
|
||||
LWIPERFFILES=$(LWIPDIR)/apps/lwiperf/lwiperf.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
|
||||
|
||||
# LWIPAPPFILES: All LWIP APPs
|
||||
LWIPAPPFILES=$(SNMPFILES) \
|
||||
$(HTTPDFILES) \
|
||||
$(LWIPERFFILES) \
|
||||
$(SNTPFILES) \
|
||||
$(MDNSFILES) \
|
||||
$(NETBIOSNSFILES) \
|
||||
$(TFTPFILES) \
|
||||
$(MQTTFILES)
|
||||
File diff suppressed because it is too large
Load Diff
1164
src/api/api_msg.c
1164
src/api/api_msg.c
File diff suppressed because it is too large
Load Diff
@@ -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,26 +17,63 @@
|
||||
* 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
|
||||
|
||||
@@ -50,13 +87,14 @@ static const char *err_strerr[] = {
|
||||
"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 */
|
||||
"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 */
|
||||
|
||||
@@ -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
|
||||
@@ -123,6 +118,7 @@ netbuf_alloc(struct netbuf *buf, u16_t size)
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netbuf
|
||||
* Free the packet buffer included in a netbuf
|
||||
*
|
||||
* @param buf pointer to the netbuf which contains the packet buffer to free
|
||||
@@ -138,6 +134,7 @@ netbuf_free(struct netbuf *buf)
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netbuf
|
||||
* Let a netbuf reference existing (non-volatile) data.
|
||||
*
|
||||
* @param buf netbuf which should reference the data
|
||||
@@ -158,13 +155,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 +171,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 +179,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 +204,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 +217,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 +229,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 +239,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;
|
||||
}
|
||||
|
||||
|
||||
177
src/api/netdb.c
177
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;
|
||||
};
|
||||
@@ -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,7 +108,10 @@ 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);
|
||||
@@ -114,22 +120,16 @@ lwip_gethostbyname(const char *name)
|
||||
#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++) {
|
||||
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])));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ipaddr_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx])));
|
||||
}
|
||||
}
|
||||
#endif /* DNS_DEBUG */
|
||||
@@ -180,7 +180,7 @@ 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;
|
||||
@@ -197,10 +197,10 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *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 +209,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,10 +258,12 @@ 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,
|
||||
@@ -269,10 +272,11 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
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,9 +286,25 @@ 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)) {
|
||||
return EAI_SERVICE;
|
||||
@@ -293,19 +313,49 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
|
||||
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(ai_family == AF_INET6, &addr);
|
||||
} else {
|
||||
ip_addr_set_loopback(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! :-) */
|
||||
@@ -313,18 +363,34 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
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);
|
||||
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 +398,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_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,21 +21,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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
@@ -36,59 +43,79 @@
|
||||
#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/netifapi.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/priv/tcpip_priv.h"
|
||||
|
||||
#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 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netifapi_netif
|
||||
* Call netif_add() in a thread-safe way by running that function inside the
|
||||
* tcpip_thread context.
|
||||
*
|
||||
@@ -96,27 +123,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 +168,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
|
||||
@@ -148,13 +206,16 @@ err_t
|
||||
netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,
|
||||
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;
|
||||
}
|
||||
|
||||
#endif /* LWIP_NETIF_API */
|
||||
|
||||
2222
src/api/sockets.c
2222
src/api/sockets.c
File diff suppressed because it is too large
Load Diff
448
src/api/tcpip.c
448
src/api/tcpip.c
@@ -40,14 +40,20 @@
|
||||
|
||||
#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"
|
||||
|
||||
#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;
|
||||
@@ -59,6 +65,13 @@ static sys_mbox_t mbox;
|
||||
sys_mutex_t lock_tcpip_core;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
|
||||
#if LWIP_TIMERS
|
||||
/* wait for a message, timeouts are processed while waiting */
|
||||
#define TCPIP_MBOX_FETCH(mbox, msg) sys_timeouts_mbox_fetch(mbox, msg)
|
||||
#else /* LWIP_TIMERS */
|
||||
/* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */
|
||||
#define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg)
|
||||
#endif /* LWIP_TIMERS */
|
||||
|
||||
/**
|
||||
* The main lwIP thread. This thread has exclusive access to lwIP core functions
|
||||
@@ -85,45 +98,35 @@ tcpip_thread(void *arg)
|
||||
UNLOCK_TCPIP_CORE();
|
||||
LWIP_TCPIP_THREAD_ALIVE();
|
||||
/* wait for a message, timeouts are processed while waiting */
|
||||
sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
|
||||
TCPIP_MBOX_FETCH(&mbox, (void **)&msg);
|
||||
LOCK_TCPIP_CORE();
|
||||
if (msg == NULL) {
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n"));
|
||||
LWIP_ASSERT("tcpip_thread: invalid message", 0);
|
||||
continue;
|
||||
}
|
||||
switch (msg->type) {
|
||||
#if LWIP_NETCONN
|
||||
#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);
|
||||
}
|
||||
msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif);
|
||||
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,7 +137,18 @@ 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));
|
||||
@@ -147,6 +161,48 @@ tcpip_thread(void *arg)
|
||||
/**
|
||||
* 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(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(&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,40 +211,12 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,7 +225,7 @@ tcpip_input(struct pbuf *p, struct netif *inp)
|
||||
* A function called in that way may access lwIP core code
|
||||
* without fearing concurrent access.
|
||||
*
|
||||
* @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
|
||||
@@ -207,33 +235,32 @@ tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
|
||||
{
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
if (sys_mbox_valid(&mbox)) {
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(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 (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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return ERR_VAL;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#if LWIP_TCPIP_TIMEOUT
|
||||
#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 +270,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(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(&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 +297,160 @@ 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(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(&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(mbox));
|
||||
|
||||
TCPIP_MSG_VAR_ALLOC(msg);
|
||||
TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API;
|
||||
TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn;
|
||||
TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg;
|
||||
sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg));
|
||||
sys_arch_sem_wait(sem, 0);
|
||||
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(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(&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 */
|
||||
|
||||
/**
|
||||
* Allocate a structure for a static callback message and initialize it.
|
||||
* This is intended to be used to send "static" messages from interrupt context.
|
||||
*
|
||||
* @param function the function to call
|
||||
* @param ctx parameter passed to function
|
||||
* @return a struct pointer to pass to tcpip_trycallback().
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a callback message allocated by tcpip_callbackmsg_new().
|
||||
*
|
||||
* @param msg the message to free
|
||||
*/
|
||||
void
|
||||
tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg)
|
||||
{
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to post a callback-message to the tcpip_thread mbox
|
||||
* This is intended to be used to send "static" messages from interrupt context.
|
||||
*
|
||||
* @param msg pointer to the message to post
|
||||
* @return sys_mbox_trypost() return code
|
||||
*/
|
||||
err_t
|
||||
tcpip_trycallback(struct tcpip_callback_msg* msg)
|
||||
{
|
||||
LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
|
||||
return sys_mbox_trypost(&mbox, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup lwip_os
|
||||
* Initialize this module:
|
||||
* - initialize all sub modules
|
||||
* - start the tcpip_thread
|
||||
@@ -407,11 +465,11 @@ 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(&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 */
|
||||
|
||||
179
src/apps/httpd/fs.c
Normal file
179
src/apps/httpd/fs.c
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* 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 "fsdata.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#if HTTPD_USE_CUSTOM_FSDATA
|
||||
#include "fsdata_custom.c"
|
||||
#else /* HTTPD_USE_CUSTOM_FSDATA */
|
||||
#include "fsdata.c"
|
||||
#endif /* HTTPD_USE_CUSTOM_FSDATA */
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
#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/httpd/fs/404.html
Normal file
21
src/apps/httpd/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/httpd/fs/img/sics.gif
Normal file
BIN
src/apps/httpd/fs/img/sics.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 724 B |
47
src/apps/httpd/fs/index.html
Normal file
47
src/apps/httpd/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>
|
||||
|
||||
298
src/apps/httpd/fsdata.c
Normal file
298
src/apps/httpd/fsdata.c
Normal file
@@ -0,0 +1,298 @@
|
||||
#include "lwip/apps/fs.h"
|
||||
#include "lwip/def.h"
|
||||
#include "fsdata.h"
|
||||
|
||||
|
||||
#define file_NULL (struct fsdata_file *) NULL
|
||||
|
||||
|
||||
static const unsigned int dummy_align__img_sics_gif = 0;
|
||||
static const unsigned char data__img_sics_gif[] = {
|
||||
/* /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/1.3.1 (http://savannah.nongnu.org/projects/lwip)
|
||||
" (63 bytes) */
|
||||
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33,
|
||||
0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,
|
||||
0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,
|
||||
0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
|
||||
/* "Content-type: image/gif
|
||||
|
||||
" (27 bytes) */
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,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,};
|
||||
|
||||
static const unsigned int dummy_align__404_html = 1;
|
||||
static const unsigned char data__404_html[] = {
|
||||
/* /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/1.3.1 (http://savannah.nongnu.org/projects/lwip)
|
||||
" (63 bytes) */
|
||||
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33,
|
||||
0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,
|
||||
0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,
|
||||
0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
|
||||
/* "Content-type: text/html
|
||||
|
||||
" (27 bytes) */
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,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,};
|
||||
|
||||
static const unsigned int dummy_align__index_html = 2;
|
||||
static const unsigned char data__index_html[] = {
|
||||
/* /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/1.3.1 (http://savannah.nongnu.org/projects/lwip)
|
||||
" (63 bytes) */
|
||||
0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33,
|
||||
0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,
|
||||
0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,
|
||||
0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a,
|
||||
/* "Content-type: text/html
|
||||
|
||||
" (27 bytes) */
|
||||
0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,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,
|
||||
1,
|
||||
}};
|
||||
|
||||
const struct fsdata_file file__404_html[] = { {
|
||||
file__img_sics_gif,
|
||||
data__404_html,
|
||||
data__404_html + 12,
|
||||
sizeof(data__404_html) - 12,
|
||||
1,
|
||||
}};
|
||||
|
||||
const struct fsdata_file file__index_html[] = { {
|
||||
file__404_html,
|
||||
data__index_html,
|
||||
data__index_html + 12,
|
||||
sizeof(data__index_html) - 12,
|
||||
1,
|
||||
}};
|
||||
|
||||
#define FS_ROOT file__index_html
|
||||
#define FS_NUMFILES 3
|
||||
|
||||
@@ -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,22 @@
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef __LWIP_INET_H__
|
||||
#define __LWIP_INET_H__
|
||||
#ifndef LWIP_FSDATA_H
|
||||
#define LWIP_FSDATA_H
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/apps/httpd_opts.h"
|
||||
#include "lwip/apps/fs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#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__ */
|
||||
struct fsdata_file {
|
||||
const struct fsdata_file *next;
|
||||
const unsigned char *name;
|
||||
const unsigned char *data;
|
||||
int len;
|
||||
u8_t flags;
|
||||
#if HTTPD_PRECALCULATED_CHECKSUM
|
||||
u16_t chksum_count;
|
||||
const struct fsdata_chksum *chksum;
|
||||
#endif /* HTTPD_PRECALCULATED_CHECKSUM */
|
||||
};
|
||||
|
||||
#endif /* LWIP_FSDATA_H */
|
||||
2629
src/apps/httpd/httpd.c
Normal file
2629
src/apps/httpd/httpd.c
Normal file
File diff suppressed because it is too large
Load Diff
114
src/apps/httpd/httpd_structs.h
Normal file
114
src/apps/httpd/httpd_structs.h
Normal file
@@ -0,0 +1,114 @@
|
||||
#ifndef LWIP_HTTPD_STRUCTS_H
|
||||
#define LWIP_HTTPD_STRUCTS_H
|
||||
|
||||
#include "lwip/apps/httpd.h"
|
||||
|
||||
#if LWIP_HTTPD_DYNAMIC_HEADERS
|
||||
/** This struct is used for a list of HTTP header strings for various
|
||||
* filename extensions. */
|
||||
typedef struct
|
||||
{
|
||||
const char *extension;
|
||||
const char *content_type;
|
||||
} tHTTPHeader;
|
||||
|
||||
/** A list of strings used in HTTP headers (see RFC 1945 HTTP/1.0 and
|
||||
* RFC 2616 HTTP/1.1 for header field definitions) */
|
||||
static const char * const g_psHTTPHeaderStrings[] =
|
||||
{
|
||||
"HTTP/1.0 200 OK\r\n",
|
||||
"HTTP/1.0 404 File not found\r\n",
|
||||
"HTTP/1.0 400 Bad Request\r\n",
|
||||
"HTTP/1.0 501 Not Implemented\r\n",
|
||||
"HTTP/1.1 200 OK\r\n",
|
||||
"HTTP/1.1 404 File not found\r\n",
|
||||
"HTTP/1.1 400 Bad Request\r\n",
|
||||
"HTTP/1.1 501 Not Implemented\r\n",
|
||||
"Content-Length: ",
|
||||
"Connection: Close\r\n",
|
||||
"Connection: keep-alive\r\n",
|
||||
"Connection: keep-alive\r\nContent-Length: ",
|
||||
"Server: "HTTPD_SERVER_AGENT"\r\n",
|
||||
"\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
|
||||
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
|
||||
,"Connection: keep-alive\r\nContent-Length: 77\r\n\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Indexes into the g_psHTTPHeaderStrings array */
|
||||
#define HTTP_HDR_OK 0 /* 200 OK */
|
||||
#define HTTP_HDR_NOT_FOUND 1 /* 404 File not found */
|
||||
#define HTTP_HDR_BAD_REQUEST 2 /* 400 Bad request */
|
||||
#define HTTP_HDR_NOT_IMPL 3 /* 501 Not Implemented */
|
||||
#define HTTP_HDR_OK_11 4 /* 200 OK */
|
||||
#define HTTP_HDR_NOT_FOUND_11 5 /* 404 File not found */
|
||||
#define HTTP_HDR_BAD_REQUEST_11 6 /* 400 Bad request */
|
||||
#define HTTP_HDR_NOT_IMPL_11 7 /* 501 Not Implemented */
|
||||
#define HTTP_HDR_CONTENT_LENGTH 8 /* Content-Length: (HTTP 1.0)*/
|
||||
#define HTTP_HDR_CONN_CLOSE 9 /* Connection: Close (HTTP 1.1) */
|
||||
#define HTTP_HDR_CONN_KEEPALIVE 10 /* Connection: keep-alive (HTTP 1.1) */
|
||||
#define HTTP_HDR_KEEPALIVE_LEN 11 /* Connection: keep-alive + Content-Length: (HTTP 1.1)*/
|
||||
#define HTTP_HDR_SERVER 12 /* Server: HTTPD_SERVER_AGENT */
|
||||
#define DEFAULT_404_HTML 13 /* default 404 body */
|
||||
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
|
||||
#define DEFAULT_404_HTML_PERSISTENT 14 /* default 404 body, but including Connection: keep-alive */
|
||||
#endif
|
||||
|
||||
|
||||
#define HTTP_HDR_HTML "Content-type: text/html\r\n\r\n"
|
||||
#define HTTP_HDR_SSI "Content-type: text/html\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\nPragma: no-cache\r\n\r\n"
|
||||
#define HTTP_HDR_GIF "Content-type: image/gif\r\n\r\n"
|
||||
#define HTTP_HDR_PNG "Content-type: image/png\r\n\r\n"
|
||||
#define HTTP_HDR_JPG "Content-type: image/jpeg\r\n\r\n"
|
||||
#define HTTP_HDR_BMP "Content-type: image/bmp\r\n\r\n"
|
||||
#define HTTP_HDR_ICO "Content-type: image/x-icon\r\n\r\n"
|
||||
#define HTTP_HDR_APP "Content-type: application/octet-stream\r\n\r\n"
|
||||
#define HTTP_HDR_JS "Content-type: application/javascript\r\n\r\n"
|
||||
#define HTTP_HDR_RA "Content-type: application/javascript\r\n\r\n"
|
||||
#define HTTP_HDR_CSS "Content-type: text/css\r\n\r\n"
|
||||
#define HTTP_HDR_SWF "Content-type: application/x-shockwave-flash\r\n\r\n"
|
||||
#define HTTP_HDR_XML "Content-type: text/xml\r\n\r\n"
|
||||
#define HTTP_HDR_PDF "Content-type: application/pdf\r\n\r\n"
|
||||
#define HTTP_HDR_JSON "Content-type: application/json\r\n\r\n"
|
||||
|
||||
#define HTTP_HDR_DEFAULT_TYPE "Content-type: text/plain\r\n\r\n"
|
||||
|
||||
/** A list of extension-to-HTTP header strings (see outdated RFC 1700 MEDIA TYPES
|
||||
* and http://www.iana.org/assignments/media-types for registered content types
|
||||
* and subtypes) */
|
||||
static const tHTTPHeader g_psHTTPHeaders[] =
|
||||
{
|
||||
{ "html", HTTP_HDR_HTML},
|
||||
{ "htm", HTTP_HDR_HTML},
|
||||
{ "shtml",HTTP_HDR_SSI},
|
||||
{ "shtm", HTTP_HDR_SSI},
|
||||
{ "ssi", HTTP_HDR_SSI},
|
||||
{ "gif", HTTP_HDR_GIF},
|
||||
{ "png", HTTP_HDR_PNG},
|
||||
{ "jpg", HTTP_HDR_JPG},
|
||||
{ "bmp", HTTP_HDR_BMP},
|
||||
{ "ico", HTTP_HDR_ICO},
|
||||
{ "class",HTTP_HDR_APP},
|
||||
{ "cls", HTTP_HDR_APP},
|
||||
{ "js", HTTP_HDR_JS},
|
||||
{ "ram", HTTP_HDR_RA},
|
||||
{ "css", HTTP_HDR_CSS},
|
||||
{ "swf", HTTP_HDR_SWF},
|
||||
{ "xml", HTTP_HDR_XML},
|
||||
{ "xsl", HTTP_HDR_XML},
|
||||
{ "pdf", HTTP_HDR_PDF},
|
||||
{ "json", HTTP_HDR_JSON}
|
||||
};
|
||||
|
||||
#define NUM_HTTP_HEADERS (sizeof(g_psHTTPHeaders) / sizeof(tHTTPHeader))
|
||||
|
||||
#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
|
||||
|
||||
#if LWIP_HTTPD_SSI
|
||||
static const char * const g_pcSSIExtensions[] = {
|
||||
".shtml", ".shtm", ".ssi", ".xml"
|
||||
};
|
||||
#define NUM_SHTML_EXTENSIONS (sizeof(g_pcSSIExtensions) / sizeof(const char *))
|
||||
#endif /* LWIP_HTTPD_SSI */
|
||||
|
||||
#endif /* LWIP_HTTPD_STRUCTS_H */
|
||||
97
src/apps/httpd/makefsdata/makefsdata
Normal file
97
src/apps/httpd/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");
|
||||
1033
src/apps/httpd/makefsdata/makefsdata.c
Normal file
1033
src/apps/httpd/makefsdata/makefsdata.c
Normal file
File diff suppressed because it is too large
Load Diff
13
src/apps/httpd/makefsdata/readme.txt
Normal file
13
src/apps/httpd/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'.
|
||||
661
src/apps/lwiperf/lwiperf.c
Normal file
661
src/apps/lwiperf/lwiperf.c
Normal file
@@ -0,0 +1,661 @@
|
||||
/**
|
||||
* @file
|
||||
* lwIP iPerf server implementation
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup iperf Iperf server
|
||||
* @ingroup apps
|
||||
*
|
||||
* This is a simple performance measuring server to check your bandwith using
|
||||
* iPerf2 on a PC as client.
|
||||
* It is currently a minimal implementation providing an IPv4 TCP server only.
|
||||
*
|
||||
* @todo: implement UDP mode and IPv6
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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-over-IPv4 is implemented (does iperf support IPv6 anyway?) */
|
||||
#if LWIP_IPV4 && 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
|
||||
|
||||
/* 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 {
|
||||
/* 1=tcp, 0=udp */
|
||||
u8_t tcp;
|
||||
/* 1=server, 0=client */
|
||||
u8_t server;
|
||||
lwiperf_state_base_t* next;
|
||||
lwiperf_state_base_t* related_server_state;
|
||||
};
|
||||
|
||||
/** 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;
|
||||
u32_t bytes_transferred;
|
||||
lwiperf_settings_t settings;
|
||||
u8_t have_settings_buf;
|
||||
} 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);
|
||||
|
||||
/** Add an iperf session to the 'active' list */
|
||||
static void
|
||||
lwiperf_list_add(lwiperf_state_base_t* item)
|
||||
{
|
||||
if (lwiperf_all_connections == NULL) {
|
||||
lwiperf_all_connections = item;
|
||||
} else {
|
||||
item = lwiperf_all_connections;
|
||||
}
|
||||
}
|
||||
|
||||
/** 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 = item;
|
||||
}
|
||||
/* @debug: ensure this item is listed only once */
|
||||
for (iter = iter->next; iter != NULL; iter = iter->next) {
|
||||
LWIP_ASSERT("duplicate entry", iter != item);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 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;
|
||||
|
||||
lwip_tcp_conn_report(conn, report_type);
|
||||
lwiperf_list_remove(&conn->base);
|
||||
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 server 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(lwiperf_state_tcp_t* conn)
|
||||
{
|
||||
err_t err;
|
||||
lwiperf_state_tcp_t* client_conn;
|
||||
struct tcp_pcb* newpcb;
|
||||
ip_addr_t remote_addr;
|
||||
u16_t remote_port;
|
||||
|
||||
client_conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t);
|
||||
if (client_conn == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
newpcb = tcp_new();
|
||||
if (newpcb == NULL) {
|
||||
LWIPERF_FREE(lwiperf_state_tcp_t, client_conn);
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
MEMCPY(client_conn, conn, sizeof(lwiperf_state_tcp_t));
|
||||
client_conn->base.server = 0;
|
||||
client_conn->server_pcb = NULL;
|
||||
client_conn->conn_pcb = newpcb;
|
||||
client_conn->time_started = sys_now(); /* @todo: set this again on 'connected' */
|
||||
client_conn->poll_count = 0;
|
||||
client_conn->next_num = 4; /* initial nr is '4' since the header has 24 byte */
|
||||
client_conn->bytes_transferred = 0;
|
||||
client_conn->settings.flags = 0; /* prevent the remote side starting back as client again */
|
||||
|
||||
tcp_arg(newpcb, client_conn);
|
||||
tcp_sent(newpcb, lwiperf_tcp_client_sent);
|
||||
tcp_poll(newpcb, lwiperf_tcp_poll, 2U);
|
||||
tcp_err(newpcb, lwiperf_tcp_err);
|
||||
|
||||
ip_addr_copy(remote_addr, conn->conn_pcb->remote_ip);
|
||||
remote_port = (u16_t)lwip_htonl(client_conn->settings.remote_port);
|
||||
|
||||
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);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/** 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|LWIPERF_FLAGS_ANSWER_NOW)) ==
|
||||
PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) {
|
||||
/* client requested transmission after end of test */
|
||||
lwiperf_tx_start(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_VAL;
|
||||
}
|
||||
if (!conn->have_settings_buf) {
|
||||
if (pbuf_copy_partial(p, &conn->settings, sizeof(lwiperf_settings_t), 0) != sizeof(lwiperf_settings_t)) {
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL);
|
||||
pbuf_free(p);
|
||||
return ERR_VAL;
|
||||
}
|
||||
conn->have_settings_buf = 1;
|
||||
if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) ==
|
||||
PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) {
|
||||
/* client requested parallel transmission test */
|
||||
err_t err2 = lwiperf_tx_start(conn);
|
||||
if (err2 != ERR_OK) {
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_TXERROR);
|
||||
pbuf_free(p);
|
||||
return err2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (pbuf_memcmp(p, 0, &conn->settings, sizeof(lwiperf_settings_t)) != 0) {
|
||||
lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
|
||||
pbuf_free(p);
|
||||
return ERR_VAL;
|
||||
}
|
||||
}
|
||||
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_header(p, -24);
|
||||
LWIP_ASSERT("pbuf_header failed", tmp == 0);
|
||||
}
|
||||
|
||||
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_VAL;
|
||||
}
|
||||
}
|
||||
#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;
|
||||
conn = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t);
|
||||
if (conn == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
memset(conn, 0, sizeof(lwiperf_state_tcp_t));
|
||||
conn->base.tcp = 1;
|
||||
conn->base.server = 1;
|
||||
conn->base.related_server_state = &s->base;
|
||||
conn->server_pcb = s->server_pcb;
|
||||
conn->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);
|
||||
|
||||
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;
|
||||
struct tcp_pcb* pcb;
|
||||
lwiperf_state_tcp_t* s;
|
||||
|
||||
if (local_addr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = (lwiperf_state_tcp_t*)LWIPERF_ALLOC(lwiperf_state_tcp_t);
|
||||
if (s == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset(s, 0, sizeof(lwiperf_state_tcp_t));
|
||||
s->base.tcp = 1;
|
||||
s->base.server = 1;
|
||||
s->report_fn = report_fn;
|
||||
s->report_arg = report_arg;
|
||||
|
||||
pcb = tcp_new();
|
||||
if (pcb != NULL) {
|
||||
err = tcp_bind(pcb, local_addr, local_port);
|
||||
if (err == ERR_OK) {
|
||||
s->server_pcb = tcp_listen_with_backlog(pcb, 1);
|
||||
}
|
||||
}
|
||||
if (s->server_pcb == NULL) {
|
||||
if (pcb != NULL) {
|
||||
tcp_close(pcb);
|
||||
}
|
||||
LWIPERF_FREE(lwiperf_state_tcp_t, s);
|
||||
return NULL;
|
||||
}
|
||||
pcb = NULL;
|
||||
|
||||
tcp_arg(s->server_pcb, s);
|
||||
tcp_accept(s->server_pcb, lwiperf_tcp_accept);
|
||||
|
||||
lwiperf_list_add(&s->base);
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
for (i = lwiperf_all_connections; i != NULL; ) {
|
||||
if ((i == lwiperf_session) || (i->related_server_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_IPV4 && LWIP_TCP && LWIP_CALLBACK_API */
|
||||
2028
src/apps/mdns/mdns.c
Normal file
2028
src/apps/mdns/mdns.c
Normal file
File diff suppressed because it is too large
Load Diff
1341
src/apps/mqtt/mqtt.c
Normal file
1341
src/apps/mqtt/mqtt.c
Normal file
File diff suppressed because it is too large
Load Diff
367
src/apps/netbiosns/netbiosns.c
Normal file
367
src/apps/netbiosns/netbiosns.c
Normal file
@@ -0,0 +1,367 @@
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
*/
|
||||
|
||||
#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/netif.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/** default port number for "NetBIOS Name service */
|
||||
#define NETBIOS_PORT 137
|
||||
|
||||
/** size of a NetBIOS name */
|
||||
#define NETBIOS_NAME_LEN 16
|
||||
|
||||
/** 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 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
|
||||
|
||||
/** 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 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
|
||||
|
||||
#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
|
||||
|
||||
struct udp_pcb *netbiosns_pcb;
|
||||
|
||||
/** Decode a NetBIOS name (from packet to string) */
|
||||
static int
|
||||
netbiosns_name_decode(char *name_enc, char *name_dec, int name_dec_len)
|
||||
{
|
||||
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 (cname < 'A' || cname > 'Z') {
|
||||
/* Not legal. */
|
||||
return -1;
|
||||
}
|
||||
cname -= 'A';
|
||||
cnbname = cname << 4;
|
||||
pname++;
|
||||
|
||||
cname = *pname;
|
||||
if (cname == '\0' || cname == '.') {
|
||||
/* No more characters in the name - but we're in
|
||||
* the middle of a pair. Not legal. */
|
||||
return -1;
|
||||
}
|
||||
if (cname < 'A' || cname > 'Z') {
|
||||
/* 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_name_hdr* netbios_name_hdr = (struct netbios_name_hdr*)(netbios_hdr+1);
|
||||
|
||||
/* 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_name_hdr->encname), netbios_name, sizeof(netbios_name));
|
||||
/* if the packet is for us */
|
||||
if (lwip_strnicmp(netbios_name, NETBIOS_LOCAL_NAME, sizeof(NETBIOS_LOCAL_NAME)) == 0) {
|
||||
struct pbuf *q;
|
||||
struct netbios_resp *resp;
|
||||
|
||||
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_name_hdr->encname, sizeof(netbios_name_hdr->encname));
|
||||
resp->resp_name.nametype = netbios_name_hdr->nametype;
|
||||
resp->resp_name.type = netbios_name_hdr->type;
|
||||
resp->resp_name.cls = netbios_name_hdr->cls;
|
||||
resp->resp_name.ttl = PP_HTONL(NETBIOS_NAME_TTL);
|
||||
resp->resp_name.datalen = PP_HTONS(sizeof(resp->resp_name.flags)+sizeof(resp->resp_name.addr));
|
||||
resp->resp_name.flags = PP_HTONS(NETB_NFLAG_NODETYPE_BNODE);
|
||||
ip4_addr_copy(resp->resp_name.addr, *netif_ip4_addr(netif_default));
|
||||
|
||||
/* send the NetBIOS response */
|
||||
udp_sendto(upcb, q, addr, port);
|
||||
|
||||
/* free the "reference" pbuf */
|
||||
pbuf_free(q);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* free the pbuf */
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netbiosns
|
||||
* Init netbios responder
|
||||
*/
|
||||
void
|
||||
netbiosns_init(void)
|
||||
{
|
||||
#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, NETBIOS_PORT);
|
||||
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!
|
||||
*/
|
||||
void
|
||||
netbiosns_set_name(const char* hostname)
|
||||
{
|
||||
size_t copy_len = strlen(hostname);
|
||||
LWIP_ASSERT("NetBIOS name is too long!", copy_len < NETBIOS_NAME_LEN);
|
||||
if (copy_len >= NETBIOS_NAME_LEN) {
|
||||
copy_len = NETBIOS_NAME_LEN - 1;
|
||||
}
|
||||
MEMCPY(netbiosns_local_name, hostname, copy_len + 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup netbiosns
|
||||
* Stop netbios responder
|
||||
*/
|
||||
void
|
||||
netbiosns_stop(void)
|
||||
{
|
||||
if (netbiosns_pcb != NULL) {
|
||||
udp_remove(netbiosns_pcb);
|
||||
netbiosns_pcb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LWIP_IPV4 && LWIP_UDP */
|
||||
749
src/apps/snmp/snmp_asn1.c
Normal file
749
src/apps/snmp/snmp_asn1.c
Normal file
@@ -0,0 +1,749 @@
|
||||
/**
|
||||
* @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 u64_t (counter64) into a pbuf chained ASN1 msg.
|
||||
*
|
||||
* @param pbuf_stream points to a pbuf stream
|
||||
* @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
|
||||
* @param value is the host order u32_t value to be encoded
|
||||
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) encode
|
||||
*
|
||||
* @see snmp_asn1_enc_u64t_cnt()
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value)
|
||||
{
|
||||
if (octets_needed > 9) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
if (octets_needed == 9) {
|
||||
/* not enough bits in 'value' add leading 0x00 */
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, 0x00));
|
||||
octets_needed--;
|
||||
}
|
||||
|
||||
while (octets_needed > 4) {
|
||||
octets_needed--;
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> ((octets_needed-4) << 3))));
|
||||
}
|
||||
|
||||
/* skip to low u32 */
|
||||
value++;
|
||||
|
||||
while (octets_needed > 1) {
|
||||
octets_needed--;
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value >> (octets_needed << 3))));
|
||||
}
|
||||
|
||||
/* always write at least one octet (also in case of value == 0) */
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_write(pbuf_stream, (u8_t)(*value)));
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes s32_t integer into a pbuf chained ASN1 msg.
|
||||
*
|
||||
* @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 u64_t.
|
||||
*
|
||||
* @param value value to be encoded
|
||||
* @param octets_needed points to the return value
|
||||
*
|
||||
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
|
||||
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
|
||||
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
|
||||
*/
|
||||
void
|
||||
snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed)
|
||||
{
|
||||
/* check if high u32 is 0 */
|
||||
if (*value == 0x00) {
|
||||
/* only low u32 is important */
|
||||
value++;
|
||||
snmp_asn1_enc_u32t_cnt(*value, octets_needed);
|
||||
} else {
|
||||
/* low u32 does not matter for length determination */
|
||||
snmp_asn1_enc_u32t_cnt(*value, octets_needed);
|
||||
*octets_needed = *octets_needed + 4; /* add the 4 bytes of low u32 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns octet count for an s32_t.
|
||||
*
|
||||
* @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;
|
||||
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 large positive integer (counter64) into 2x u32_t.
|
||||
*
|
||||
* @param pbuf_stream points to a pbuf stream
|
||||
* @param len length of the coded integer field
|
||||
* @param value return host order integer
|
||||
* @return ERR_OK if successful, ERR_ARG if we can't (or won't) decode
|
||||
*
|
||||
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
|
||||
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
|
||||
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_dec_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value)
|
||||
{
|
||||
u8_t data;
|
||||
|
||||
if (len <= 4) {
|
||||
/* high u32 is 0 */
|
||||
*value = 0;
|
||||
/* directly skip to low u32 */
|
||||
value++;
|
||||
}
|
||||
|
||||
if ((len > 0) && (len <= 9)) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
|
||||
/* expecting sign bit to be zero, only unsigned please! */
|
||||
if (((len == 9) && (data == 0x00)) || ((len < 9) && ((data & 0x80) == 0))) {
|
||||
*value = data;
|
||||
len--;
|
||||
|
||||
while (len > 0) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
|
||||
if (len == 4) {
|
||||
/* skip to low u32 */
|
||||
value++;
|
||||
*value = 0;
|
||||
} else {
|
||||
*value <<= 8;
|
||||
}
|
||||
|
||||
*value |= data;
|
||||
len--;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes integer into s32_t.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
u8_t *lsb_ptr = (u8_t*)value;
|
||||
#endif
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;
|
||||
#endif
|
||||
u8_t sign;
|
||||
u8_t data;
|
||||
|
||||
if ((len > 0) && (len < 5)) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
len--;
|
||||
|
||||
if (data & 0x80) {
|
||||
/* negative, start from -1 */
|
||||
*value = -1;
|
||||
sign = 1;
|
||||
*lsb_ptr &= data;
|
||||
} else {
|
||||
/* positive, start from 0 */
|
||||
*value = 0;
|
||||
sign = 0;
|
||||
*lsb_ptr |= data;
|
||||
}
|
||||
|
||||
/* OR/AND octets with value */
|
||||
while (len > 0) {
|
||||
PBUF_OP_EXEC(snmp_pbuf_stream_read(pbuf_stream, &data));
|
||||
len--;
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
*value <<= 8;
|
||||
#endif
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
*value >>= 8;
|
||||
#endif
|
||||
|
||||
if (sign) {
|
||||
*lsb_ptr |= 255;
|
||||
*lsb_ptr &= data;
|
||||
} else {
|
||||
*lsb_ptr |= data;
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
108
src/apps/snmp/snmp_asn1.h
Normal file
108
src/apps/snmp/snmp_asn1.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @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) */
|
||||
#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_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_u64t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t *value);
|
||||
err_t snmp_asn1_dec_s32t(struct snmp_pbuf_stream *pbuf_stream, u16_t len, s32_t *value);
|
||||
err_t snmp_asn1_dec_oid(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u32_t* oid, u8_t* oid_len, u8_t oid_max_len);
|
||||
err_t snmp_asn1_dec_raw(struct snmp_pbuf_stream *pbuf_stream, u16_t len, u8_t *buf, u16_t* buf_len, u16_t buf_max_len);
|
||||
|
||||
err_t snmp_ans1_enc_tlv(struct snmp_pbuf_stream* pbuf_stream, struct snmp_asn1_tlv* tlv);
|
||||
|
||||
void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed);
|
||||
void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed);
|
||||
void snmp_asn1_enc_u64t_cnt(const u32_t *value, u16_t *octets_needed);
|
||||
void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);
|
||||
void snmp_asn1_enc_oid_cnt(const u32_t *oid, u16_t oid_len, u16_t *octets_needed);
|
||||
err_t snmp_asn1_enc_oid(struct snmp_pbuf_stream* pbuf_stream, const u32_t *oid, u16_t oid_len);
|
||||
err_t snmp_asn1_enc_s32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, s32_t value);
|
||||
err_t snmp_asn1_enc_u32t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, u32_t value);
|
||||
err_t snmp_asn1_enc_u64t(struct snmp_pbuf_stream* pbuf_stream, u16_t octets_needed, const u32_t* value);
|
||||
err_t snmp_asn1_enc_raw(struct snmp_pbuf_stream* pbuf_stream, const u8_t *raw, u16_t raw_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
|
||||
#endif /* LWIP_HDR_APPS_SNMP_ASN1_H */
|
||||
1349
src/apps/snmp/snmp_core.c
Normal file
1349
src/apps/snmp/snmp_core.c
Normal file
File diff suppressed because it is too large
Load Diff
76
src/apps/snmp/snmp_core_priv.h
Normal file
76
src/apps/snmp/snmp_core_priv.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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_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 */
|
||||
375
src/apps/snmp/snmp_mib2_interfaces.c
Normal file
375
src/apps/snmp/snmp_mib2_interfaces.c
Normal file
@@ -0,0 +1,375 @@
|
||||
/**
|
||||
* @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_list;
|
||||
while (netif != NULL) {
|
||||
num_netifs++;
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
*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 = netif_list;
|
||||
while (netif != NULL) {
|
||||
if (netif_to_num(netif) == ifIndex) {
|
||||
/* store netif pointer for subsequent operations (get/test/set) */
|
||||
cell_instance->reference.ptr = netif;
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
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 = netif_list;
|
||||
while (netif != NULL) {
|
||||
u32_t test_oid[LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)];
|
||||
test_oid[0] = netif_to_num(netif);
|
||||
|
||||
/* check generated OID: is it a candidate for the next one? */
|
||||
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges), netif);
|
||||
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
/* did we find a next one? */
|
||||
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 */
|
||||
743
src/apps/snmp/snmp_mib2_ip.c
Normal file
743
src/apps/snmp/snmp_mib2_ip.c
Normal file
@@ -0,0 +1,743 @@
|
||||
/**
|
||||
* @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 = netif_list;
|
||||
while (netif != NULL) {
|
||||
if (ip4_addr_cmp(&ip, netif_ip4_addr(netif))) {
|
||||
/* fill in object properties */
|
||||
return ip_AddrTable_get_cell_value_core(netif, column, value, value_len);
|
||||
}
|
||||
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
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 = netif_list;
|
||||
while (netif != NULL) {
|
||||
u32_t test_oid[LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges)];
|
||||
snmp_ip4_to_oid(netif_ip4_addr(netif), &test_oid[0]);
|
||||
|
||||
/* check generated OID: is it a candidate for the next one? */
|
||||
snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges), netif);
|
||||
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
/* did we find a next one? */
|
||||
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
|
||||
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
|
||||
/* fill in object properties */
|
||||
return ip_AddrTable_get_cell_value_core((struct netif*)state.reference, column, value, value_len);
|
||||
}
|
||||
|
||||
/* 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 = netif_list;
|
||||
while (netif != NULL) {
|
||||
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);
|
||||
}
|
||||
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
/* 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 = netif_list;
|
||||
while (netif != NULL) {
|
||||
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);
|
||||
}
|
||||
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
/* 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(u8_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;
|
||||
u8_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)
|
||||
{
|
||||
u8_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(u8_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 */
|
||||
377
src/apps/snmp/snmp_mib2_system.c
Normal file
377
src/apps/snmp/snmp_mib2_system.c
Normal file
@@ -0,0 +1,377 @@
|
||||
/**
|
||||
* @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 */
|
||||
594
src/apps/snmp/snmp_mib2_tcp.c
Normal file
594
src/apps/snmp/snmp_mib2_tcp.c
Normal file
@@ -0,0 +1,594 @@
|
||||
/**
|
||||
* @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);
|
||||
case 17: /* tcpHCInSegs */
|
||||
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
|
||||
return 2*sizeof(u32_t);
|
||||
case 18: /* tcpHCOutSegs */
|
||||
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
|
||||
return 2*sizeof(u32_t);
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_value(): unknown id: %"S32_F"\n", instance->node->oid));
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
#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)
|
||||
CREATE_LWIP_SYNC_NODE(17, tcp_HCInSegs)
|
||||
CREATE_LWIP_SYNC_NODE(18, tcp_HCOutSegs)
|
||||
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,
|
||||
&SYNC_NODE_NAME(tcp_HCOutSegs).node.node,
|
||||
&SYNC_NODE_NAME(tcp_ConnectionTable).node.node,
|
||||
&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 */
|
||||
357
src/apps/snmp/snmp_mib2_udp.c
Normal file
357
src/apps/snmp/snmp_mib2_udp.c
Normal file
@@ -0,0 +1,357 @@
|
||||
/**
|
||||
* @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);
|
||||
case 8: /* udpHCInDatagrams */
|
||||
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
|
||||
return 2*sizeof(u32_t);
|
||||
case 9: /* udpHCOutDatagrams */
|
||||
memset(value, 0, 2*sizeof(u32_t)); /* not supported */
|
||||
return 2*sizeof(u32_t);
|
||||
default:
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_value(): unknown id: %"S32_F"\n", instance->node->oid));
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
#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)
|
||||
CREATE_LWIP_SYNC_NODE(8, udp_HCInDatagrams)
|
||||
CREATE_LWIP_SYNC_NODE(9, udp_HCOutDatagrams)
|
||||
|
||||
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,
|
||||
&SYNC_NODE_NAME(udp_HCInDatagrams).node.node,
|
||||
&SYNC_NODE_NAME(udp_HCOutDatagrams).node.node
|
||||
};
|
||||
|
||||
const struct snmp_tree_node snmp_mib2_udp_root = SNMP_CREATE_TREE_NODE(7, udp_nodes);
|
||||
#endif /* LWIP_SNMP && SNMP_LWIP_MIB2 && LWIP_UDP */
|
||||
1668
src/apps/snmp/snmp_msg.c
Normal file
1668
src/apps/snmp/snmp_msg.c
Normal file
File diff suppressed because it is too large
Load Diff
194
src/apps/snmp/snmp_msg.h
Normal file
194
src/apps/snmp/snmp_msg.h
Normal file
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* @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
|
||||
|
||||
/* The listen port of the SNMP agent. Clients have to make their requests to
|
||||
this port. Most standard clients won't work if you change this! */
|
||||
#ifndef SNMP_IN_PORT
|
||||
#define SNMP_IN_PORT 161
|
||||
#endif
|
||||
/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't
|
||||
work if you change this! */
|
||||
#ifndef SNMP_TRAP_PORT
|
||||
#define SNMP_TRAP_PORT 162
|
||||
#endif
|
||||
|
||||
/* version defines used in PDU */
|
||||
#define SNMP_VERSION_1 0
|
||||
#define SNMP_VERSION_2c 1
|
||||
#define SNMP_VERSION_3 3
|
||||
|
||||
struct snmp_varbind_enumerator
|
||||
{
|
||||
struct snmp_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;
|
||||
|
||||
#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_privacy_parameters[SNMP_V3_MAX_PRIV_PARAM_LENGTH];
|
||||
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 */
|
||||
121
src/apps/snmp/snmp_netconn.c
Normal file
121
src/apps/snmp/snmp_netconn.c
Normal file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* @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"
|
||||
|
||||
/** 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, SNMP_IN_PORT);
|
||||
#else /* LWIP_IPV6 */
|
||||
conn = netconn_new(NETCONN_UDP);
|
||||
netconn_bind(conn, IP4_ADDR_ANY, SNMP_IN_PORT);
|
||||
#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)
|
||||
{
|
||||
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 */
|
||||
73
src/apps/snmp/snmp_pbuf_stream.h
Normal file
73
src/apps/snmp/snmp_pbuf_stream.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @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 */
|
||||
100
src/apps/snmp/snmp_raw.c
Normal file
100
src/apps/snmp/snmp_raw.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @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 "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;);
|
||||
|
||||
snmp_traps_handle = snmp_pcb;
|
||||
|
||||
udp_recv(snmp_pcb, snmp_recv, (void *)SNMP_IN_PORT);
|
||||
err = udp_bind(snmp_pcb, IP_ANY_TYPE, SNMP_IN_PORT);
|
||||
LWIP_ERROR("snmp_raw: Unable to bind PCB", (err == ERR_OK), return;);
|
||||
}
|
||||
|
||||
#endif /* LWIP_SNMP && SNMP_USE_RAW */
|
||||
220
src/apps/snmp/snmp_scalar.c
Normal file
220
src/apps/snmp/snmp_scalar.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
|
||||
const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr;
|
||||
|
||||
return array_node->get_value(array_node_def, value);
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
snmp_scalar_array_set_test(struct snmp_node_instance* instance, u16_t value_len, void* value)
|
||||
{
|
||||
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
|
||||
const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr;
|
||||
|
||||
return array_node->set_test(array_node_def, value_len, value);
|
||||
}
|
||||
|
||||
static snmp_err_t
|
||||
snmp_scalar_array_set_value(struct snmp_node_instance* instance, u16_t value_len, void* value)
|
||||
{
|
||||
const struct snmp_scalar_array_node* array_node = (const struct snmp_scalar_array_node*)(const void*)instance->node;
|
||||
const struct snmp_scalar_array_node_def* array_node_def = (const struct snmp_scalar_array_node_def*)instance->reference.const_ptr;
|
||||
|
||||
return array_node->set_value(array_node_def, value_len, value);
|
||||
}
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
343
src/apps/snmp/snmp_table.c
Normal file
343
src/apps/snmp/snmp_table.c
Normal file
@@ -0,0 +1,343 @@
|
||||
/**
|
||||
* @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 */
|
||||
219
src/apps/snmp/snmp_threadsync.c
Normal file
219
src/apps/snmp/snmp_threadsync.c
Normal file
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* @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;
|
||||
|
||||
call_data->retval.s16 = call_data->proxy_instance.get_value(&call_data->proxy_instance, call_data->arg1.value);
|
||||
|
||||
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;
|
||||
|
||||
call_data->retval.err = call_data->proxy_instance.set_test(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value);
|
||||
|
||||
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;
|
||||
|
||||
call_data->retval.err = call_data->proxy_instance.set_value(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value);
|
||||
|
||||
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 */
|
||||
445
src/apps/snmp/snmp_traps.c
Normal file
445
src/apps/snmp/snmp_traps.c
Normal file
@@ -0,0 +1,445 @@
|
||||
/**
|
||||
* @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 "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 void snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream);
|
||||
static void snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds);
|
||||
|
||||
/** 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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 ino 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, SNMP_TRAP_PORT);
|
||||
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 void
|
||||
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);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
|
||||
while (varbind != NULL) {
|
||||
snmp_append_outbound_varbind(pbuf_stream, varbind);
|
||||
|
||||
varbind = varbind->next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes trap header from head to tail.
|
||||
*/
|
||||
static void
|
||||
snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream)
|
||||
{
|
||||
struct snmp_asn1_tlv tlv;
|
||||
|
||||
/* 'Message' sequence */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->seqlen);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
|
||||
/* version */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
|
||||
snmp_asn1_enc_s32t_cnt(trap->snmp_version, &tlv.value_len);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->snmp_version);
|
||||
|
||||
/* community */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, trap->comlen);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)snmp_community_trap, trap->comlen);
|
||||
|
||||
/* 'PDU' sequence */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_TRAP), 0, trap->pdulen);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
|
||||
/* object ID */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, 0, 0);
|
||||
snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &tlv.value_len);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_oid(pbuf_stream, trap->enterprise->id, trap->enterprise->len);
|
||||
|
||||
/* IP addr */
|
||||
if (IP_IS_V6_VAL(trap->sip)) {
|
||||
#if LWIP_IPV6
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip6(&trap->sip)->addr));
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip6(&trap->sip)->addr, sizeof(ip_2_ip6(&trap->sip)->addr));
|
||||
#endif
|
||||
} else {
|
||||
#if LWIP_IPV4
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip4(&trap->sip)->addr));
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip4(&trap->sip)->addr, sizeof(ip_2_ip4(&trap->sip)->addr));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* trap length */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
|
||||
snmp_asn1_enc_s32t_cnt(trap->gen_trap, &tlv.value_len);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->gen_trap);
|
||||
|
||||
/* specific trap */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
|
||||
snmp_asn1_enc_s32t_cnt(trap->spc_trap, &tlv.value_len);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->spc_trap);
|
||||
|
||||
/* timestamp */
|
||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_TIMETICKS, 0, 0);
|
||||
snmp_asn1_enc_s32t_cnt(trap->ts, &tlv.value_len);
|
||||
snmp_ans1_enc_tlv(pbuf_stream, &tlv);
|
||||
snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->ts);
|
||||
}
|
||||
|
||||
#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.
|
||||
*/
|
||||
u32_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.
|
||||
*/
|
||||
u32_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 = LWIP_SNMPV3_GET_ENGINE_BOOTS();
|
||||
SMEMCPY(&priv_param[0], &boots, 4);
|
||||
SMEMCPY(&priv_param[4], &ctr, 4);
|
||||
ctr++;
|
||||
#endif
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* LWIP_SNMP_V3_CRYPTO */
|
||||
|
||||
#endif
|
||||
145
src/apps/snmp/snmpv3_dummy.c
Normal file
145
src/apps/snmp/snmpv3_dummy.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* @file
|
||||
* Dummy SNMPv3 functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 Elias Oenal.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* Author: Elias Oenal <lwip@eliasoenal.com>
|
||||
* Dirk Ziegelmeier <dirk@ziegelmeier.net>
|
||||
*/
|
||||
|
||||
#include "lwip/apps/snmpv3.h"
|
||||
#include "snmpv3_priv.h"
|
||||
#include <string.h>
|
||||
#include "lwip/err.h"
|
||||
|
||||
#if LWIP_SNMP && LWIP_SNMP_V3
|
||||
|
||||
/**
|
||||
* @param username is a pointer to a string.
|
||||
* @param auth_algo is a pointer to u8_t. The implementation has to set this if user was found.
|
||||
* @param auth_key is a pointer to a pointer to a string. Implementation has to set this if user was found.
|
||||
* @param priv_algo is a pointer to u8_t. The implementation has to set this if user was found.
|
||||
* @param priv_key is a pointer to a pointer to a string. Implementation has to set this if user was found.
|
||||
*/
|
||||
err_t
|
||||
snmpv3_get_user(const char* username, u8_t *auth_algo, u8_t *auth_key, u8_t *priv_algo, u8_t *priv_key)
|
||||
{
|
||||
const char* engine_id;
|
||||
u8_t engine_id_len;
|
||||
|
||||
if(strlen(username) == 0) {
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
if(memcmp(username, "lwip", 4) != 0) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
snmpv3_get_engine_id(&engine_id, &engine_id_len);
|
||||
|
||||
if(auth_key != NULL) {
|
||||
snmpv3_password_to_key_sha((const u8_t*)"maplesyrup", 10,
|
||||
(const u8_t*)engine_id, engine_id_len,
|
||||
auth_key);
|
||||
*auth_algo = SNMP_V3_AUTH_ALGO_SHA;
|
||||
}
|
||||
if(priv_key != NULL) {
|
||||
snmpv3_password_to_key_sha((const u8_t*)"maplesyrup", 10,
|
||||
(const u8_t*)engine_id, engine_id_len,
|
||||
priv_key);
|
||||
*priv_algo = SNMP_V3_PRIV_ALGO_DES;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get engine ID from persistence
|
||||
* @param id
|
||||
* @param len
|
||||
*/
|
||||
void
|
||||
snmpv3_get_engine_id(const char **id, u8_t *len)
|
||||
{
|
||||
*id = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02";
|
||||
*len = 12;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store engine ID in persistence
|
||||
* @param id
|
||||
* @param len
|
||||
*/
|
||||
err_t
|
||||
snmpv3_set_engine_id(const char *id, u8_t len)
|
||||
{
|
||||
LWIP_UNUSED_ARG(id);
|
||||
LWIP_UNUSED_ARG(len);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get engine boots from persistence. Must be increased on each boot.
|
||||
* @return
|
||||
*/
|
||||
u32_t
|
||||
snmpv3_get_engine_boots(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store engine boots in persistence
|
||||
* @param boots
|
||||
*/
|
||||
void
|
||||
snmpv3_set_engine_boots(u32_t boots)
|
||||
{
|
||||
LWIP_UNUSED_ARG(boots);
|
||||
}
|
||||
|
||||
/**
|
||||
* RFC3414 2.2.2.
|
||||
* Once the timer reaches 2147483647 it gets reset to zero and the
|
||||
* engine boot ups get incremented.
|
||||
*/
|
||||
u32_t
|
||||
snmpv3_get_engine_time(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset current engine time to 0
|
||||
*/
|
||||
void
|
||||
snmpv3_reset_engine_time(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* LWIP_SNMP && LWIP_SNMP_V3 */
|
||||
331
src/apps/snmp/snmpv3_mbedtls.c
Normal file
331
src/apps/snmp/snmpv3_mbedtls.c
Normal file
@@ -0,0 +1,331 @@
|
||||
/**
|
||||
* @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, u8_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, u8_t algo, u8_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++) {
|
||||
snmp_pbuf_stream_read(&read_stream, &in_bytes[j]);
|
||||
}
|
||||
|
||||
if(mbedtls_cipher_update(&ctx, in_bytes, LWIP_ARRAYSIZE(in_bytes), out_bytes, &out_len) != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len);
|
||||
}
|
||||
|
||||
out_len = LWIP_ARRAYSIZE(out_bytes);
|
||||
if(mbedtls_cipher_finish(&ctx, out_bytes, &out_len) != 0) {
|
||||
goto error;
|
||||
}
|
||||
snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len);
|
||||
} else if (algo == SNMP_V3_PRIV_ALGO_AES) {
|
||||
u8_t iv_local[16];
|
||||
|
||||
cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CFB128);
|
||||
if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) {
|
||||
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);
|
||||
|
||||
snmp_pbuf_stream_read(&read_stream, &in_byte);
|
||||
if(mbedtls_cipher_update(&ctx, &in_byte, sizeof(in_byte), &out_byte, &out_len) != 0) {
|
||||
goto error;
|
||||
}
|
||||
snmp_pbuf_stream_write(&write_stream, out_byte);
|
||||
}
|
||||
} 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 */
|
||||
u8_t passwordlen, /* IN */
|
||||
const u8_t *engineID, /* IN - pointer to snmpEngineID */
|
||||
u8_t engineLength,/* IN - length of snmpEngineID */
|
||||
u8_t *key) /* OUT - pointer to caller 16-octet buffer */
|
||||
{
|
||||
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 */
|
||||
u8_t passwordlen, /* IN */
|
||||
const u8_t *engineID, /* IN - pointer to snmpEngineID */
|
||||
u8_t engineLength,/* IN - length of snmpEngineID */
|
||||
u8_t *key) /* OUT - pointer to caller 20-octet buffer */
|
||||
{
|
||||
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 */
|
||||
66
src/apps/snmp/snmpv3_priv.h
Normal file
66
src/apps/snmp/snmpv3_priv.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @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 "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_AUTH_FLAG 0x01
|
||||
#define SNMP_V3_PRIV_FLAG 0x02
|
||||
|
||||
#define SNMP_V3_MD5_LEN 16
|
||||
#define SNMP_V3_SHA_LEN 20
|
||||
|
||||
u32_t snmpv3_get_engine_boots_internal(void);
|
||||
u32_t snmpv3_get_engine_time_internal(void);
|
||||
err_t snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key, u8_t algo, u8_t* hmac_out);
|
||||
err_t snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key,
|
||||
const u8_t* priv_param, const u32_t engine_boots, const u32_t engine_time, u8_t algo, u8_t mode);
|
||||
err_t snmpv3_build_priv_param(u8_t* priv_param);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_HDR_APPS_SNMP_V3_PRIV_H */
|
||||
727
src/apps/sntp/sntp.c
Normal file
727
src/apps/sntp/sntp.c
Normal file
@@ -0,0 +1,727 @@
|
||||
/**
|
||||
* @file
|
||||
* SNTP client module
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007-2009 Frédéric Bernon, 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: Frédéric Bernon, Simon Goldschmidt
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup sntp SNTP
|
||||
* @ingroup apps
|
||||
*
|
||||
* This is simple "SNTP" client for the lwIP raw API.
|
||||
* It is a minimal implementation of SNTPv4 as specified in RFC 4330.
|
||||
*
|
||||
* For a list of some public NTP servers, see this link :
|
||||
* http://support.ntp.org/bin/view/Servers/NTPPoolServers
|
||||
*
|
||||
* @todo:
|
||||
* - set/change servers at runtime
|
||||
* - complete SNTP_CHECK_RESPONSE checks 3 and 4
|
||||
*/
|
||||
|
||||
#include "lwip/apps/sntp.h"
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/timeouts.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/dhcp.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#if LWIP_UDP
|
||||
|
||||
/* Handle support for more than one server via SNTP_MAX_SERVERS */
|
||||
#if SNTP_MAX_SERVERS > 1
|
||||
#define SNTP_SUPPORT_MULTIPLE_SERVERS 1
|
||||
#else /* NTP_MAX_SERVERS > 1 */
|
||||
#define SNTP_SUPPORT_MULTIPLE_SERVERS 0
|
||||
#endif /* NTP_MAX_SERVERS > 1 */
|
||||
|
||||
#if (SNTP_UPDATE_DELAY < 15000) && !defined(SNTP_SUPPRESS_DELAY_CHECK)
|
||||
#error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!"
|
||||
#endif
|
||||
|
||||
/* Configure behaviour depending on microsecond or second precision */
|
||||
#ifdef SNTP_SET_SYSTEM_TIME_US
|
||||
#define SNTP_CALC_TIME_US 1
|
||||
#define SNTP_RECEIVE_TIME_SIZE 2
|
||||
#else
|
||||
#define SNTP_SET_SYSTEM_TIME_US(sec, us)
|
||||
#define SNTP_CALC_TIME_US 0
|
||||
#define SNTP_RECEIVE_TIME_SIZE 1
|
||||
#endif
|
||||
|
||||
|
||||
/* the various debug levels for this file */
|
||||
#define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE)
|
||||
#define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE)
|
||||
#define SNTP_DEBUG_WARN (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING)
|
||||
#define SNTP_DEBUG_WARN_STATE (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE)
|
||||
#define SNTP_DEBUG_SERIOUS (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS)
|
||||
|
||||
#define SNTP_ERR_KOD 1
|
||||
|
||||
/* SNTP protocol defines */
|
||||
#define SNTP_MSG_LEN 48
|
||||
|
||||
#define SNTP_OFFSET_LI_VN_MODE 0
|
||||
#define SNTP_LI_MASK 0xC0
|
||||
#define SNTP_LI_NO_WARNING 0x00
|
||||
#define SNTP_LI_LAST_MINUTE_61_SEC 0x01
|
||||
#define SNTP_LI_LAST_MINUTE_59_SEC 0x02
|
||||
#define SNTP_LI_ALARM_CONDITION 0x03 /* (clock not synchronized) */
|
||||
|
||||
#define SNTP_VERSION_MASK 0x38
|
||||
#define SNTP_VERSION (4/* NTP Version 4*/<<3)
|
||||
|
||||
#define SNTP_MODE_MASK 0x07
|
||||
#define SNTP_MODE_CLIENT 0x03
|
||||
#define SNTP_MODE_SERVER 0x04
|
||||
#define SNTP_MODE_BROADCAST 0x05
|
||||
|
||||
#define SNTP_OFFSET_STRATUM 1
|
||||
#define SNTP_STRATUM_KOD 0x00
|
||||
|
||||
#define SNTP_OFFSET_ORIGINATE_TIME 24
|
||||
#define SNTP_OFFSET_RECEIVE_TIME 32
|
||||
#define SNTP_OFFSET_TRANSMIT_TIME 40
|
||||
|
||||
/* number of seconds between 1900 and 1970 (MSB=1)*/
|
||||
#define DIFF_SEC_1900_1970 (2208988800UL)
|
||||
/* number of seconds between 1970 and Feb 7, 2036 (6:28:16 UTC) (MSB=0) */
|
||||
#define DIFF_SEC_1970_2036 (2085978496UL)
|
||||
|
||||
/**
|
||||
* SNTP packet format (without optional fields)
|
||||
* Timestamps are coded as 64 bits:
|
||||
* - 32 bits seconds since Jan 01, 1970, 00:00
|
||||
* - 32 bits seconds fraction (0-padded)
|
||||
* For future use, if the MSB in the seconds part is set, seconds are based
|
||||
* on Feb 07, 2036, 06:28:16.
|
||||
*/
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct sntp_msg {
|
||||
PACK_STRUCT_FLD_8(u8_t li_vn_mode);
|
||||
PACK_STRUCT_FLD_8(u8_t stratum);
|
||||
PACK_STRUCT_FLD_8(u8_t poll);
|
||||
PACK_STRUCT_FLD_8(u8_t precision);
|
||||
PACK_STRUCT_FIELD(u32_t root_delay);
|
||||
PACK_STRUCT_FIELD(u32_t root_dispersion);
|
||||
PACK_STRUCT_FIELD(u32_t reference_identifier);
|
||||
PACK_STRUCT_FIELD(u32_t reference_timestamp[2]);
|
||||
PACK_STRUCT_FIELD(u32_t originate_timestamp[2]);
|
||||
PACK_STRUCT_FIELD(u32_t receive_timestamp[2]);
|
||||
PACK_STRUCT_FIELD(u32_t transmit_timestamp[2]);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/* function prototypes */
|
||||
static void sntp_request(void *arg);
|
||||
|
||||
/** The operating mode */
|
||||
static u8_t sntp_opmode;
|
||||
|
||||
/** The UDP pcb used by the SNTP client */
|
||||
static struct udp_pcb* sntp_pcb;
|
||||
/** Names/Addresses of servers */
|
||||
struct sntp_server {
|
||||
#if SNTP_SERVER_DNS
|
||||
char* name;
|
||||
#endif /* SNTP_SERVER_DNS */
|
||||
ip_addr_t addr;
|
||||
};
|
||||
static struct sntp_server sntp_servers[SNTP_MAX_SERVERS];
|
||||
|
||||
#if SNTP_GET_SERVERS_FROM_DHCP
|
||||
static u8_t sntp_set_servers_from_dhcp;
|
||||
#endif /* SNTP_GET_SERVERS_FROM_DHCP */
|
||||
#if SNTP_SUPPORT_MULTIPLE_SERVERS
|
||||
/** The currently used server (initialized to 0) */
|
||||
static u8_t sntp_current_server;
|
||||
#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
||||
#define sntp_current_server 0
|
||||
#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
||||
|
||||
#if SNTP_RETRY_TIMEOUT_EXP
|
||||
#define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT
|
||||
/** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */
|
||||
static u32_t sntp_retry_timeout;
|
||||
#else /* SNTP_RETRY_TIMEOUT_EXP */
|
||||
#define SNTP_RESET_RETRY_TIMEOUT()
|
||||
#define sntp_retry_timeout SNTP_RETRY_TIMEOUT
|
||||
#endif /* SNTP_RETRY_TIMEOUT_EXP */
|
||||
|
||||
#if SNTP_CHECK_RESPONSE >= 1
|
||||
/** Saves the last server address to compare with response */
|
||||
static ip_addr_t sntp_last_server_address;
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 1 */
|
||||
|
||||
#if SNTP_CHECK_RESPONSE >= 2
|
||||
/** Saves the last timestamp sent (which is sent back by the server)
|
||||
* to compare against in response */
|
||||
static u32_t sntp_last_timestamp_sent[2];
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 2 */
|
||||
|
||||
/**
|
||||
* SNTP processing of received timestamp
|
||||
*/
|
||||
static void
|
||||
sntp_process(u32_t *receive_timestamp)
|
||||
{
|
||||
/* convert SNTP time (1900-based) to unix GMT time (1970-based)
|
||||
* if MSB is 0, SNTP time is 2036-based!
|
||||
*/
|
||||
u32_t rx_secs = lwip_ntohl(receive_timestamp[0]);
|
||||
int is_1900_based = ((rx_secs & 0x80000000) != 0);
|
||||
u32_t t = is_1900_based ? (rx_secs - DIFF_SEC_1900_1970) : (rx_secs + DIFF_SEC_1970_2036);
|
||||
time_t tim = t;
|
||||
|
||||
#if SNTP_CALC_TIME_US
|
||||
u32_t us = lwip_ntohl(receive_timestamp[1]) / 4295;
|
||||
SNTP_SET_SYSTEM_TIME_US(t, us);
|
||||
/* display local time from GMT time */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&tim), us));
|
||||
|
||||
#else /* SNTP_CALC_TIME_US */
|
||||
|
||||
/* change system time and/or the update the RTC clock */
|
||||
SNTP_SET_SYSTEM_TIME(t);
|
||||
/* display local time from GMT time */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s", ctime(&tim)));
|
||||
#endif /* SNTP_CALC_TIME_US */
|
||||
LWIP_UNUSED_ARG(tim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize request struct to be sent to server.
|
||||
*/
|
||||
static void
|
||||
sntp_initialize_request(struct sntp_msg *req)
|
||||
{
|
||||
memset(req, 0, SNTP_MSG_LEN);
|
||||
req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
|
||||
|
||||
#if SNTP_CHECK_RESPONSE >= 2
|
||||
{
|
||||
u32_t sntp_time_sec, sntp_time_us;
|
||||
/* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */
|
||||
SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us);
|
||||
sntp_last_timestamp_sent[0] = lwip_htonl(sntp_time_sec + DIFF_SEC_1900_1970);
|
||||
req->transmit_timestamp[0] = sntp_last_timestamp_sent[0];
|
||||
/* we send/save us instead of fraction to be faster... */
|
||||
sntp_last_timestamp_sent[1] = lwip_htonl(sntp_time_us);
|
||||
req->transmit_timestamp[1] = sntp_last_timestamp_sent[1];
|
||||
}
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry: send a new request (and increase retry timeout).
|
||||
*
|
||||
* @param arg is unused (only necessary to conform to sys_timeout)
|
||||
*/
|
||||
static void
|
||||
sntp_retry(void* arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n",
|
||||
sntp_retry_timeout));
|
||||
|
||||
/* set up a timer to send a retry and increase the retry delay */
|
||||
sys_timeout(sntp_retry_timeout, sntp_request, NULL);
|
||||
|
||||
#if SNTP_RETRY_TIMEOUT_EXP
|
||||
{
|
||||
u32_t new_retry_timeout;
|
||||
/* increase the timeout for next retry */
|
||||
new_retry_timeout = sntp_retry_timeout << 1;
|
||||
/* limit to maximum timeout and prevent overflow */
|
||||
if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) &&
|
||||
(new_retry_timeout > sntp_retry_timeout)) {
|
||||
sntp_retry_timeout = new_retry_timeout;
|
||||
}
|
||||
}
|
||||
#endif /* SNTP_RETRY_TIMEOUT_EXP */
|
||||
}
|
||||
|
||||
#if SNTP_SUPPORT_MULTIPLE_SERVERS
|
||||
/**
|
||||
* If Kiss-of-Death is received (or another packet parsing error),
|
||||
* try the next server or retry the current server and increase the retry
|
||||
* timeout if only one server is available.
|
||||
* (implicitly, SNTP_MAX_SERVERS > 1)
|
||||
*
|
||||
* @param arg is unused (only necessary to conform to sys_timeout)
|
||||
*/
|
||||
static void
|
||||
sntp_try_next_server(void* arg)
|
||||
{
|
||||
u8_t old_server, i;
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
old_server = sntp_current_server;
|
||||
for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) {
|
||||
sntp_current_server++;
|
||||
if (sntp_current_server >= SNTP_MAX_SERVERS) {
|
||||
sntp_current_server = 0;
|
||||
}
|
||||
if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr)
|
||||
#if SNTP_SERVER_DNS
|
||||
|| (sntp_servers[sntp_current_server].name != NULL)
|
||||
#endif
|
||||
) {
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n",
|
||||
(u16_t)sntp_current_server));
|
||||
/* new server: reset retry timeout */
|
||||
SNTP_RESET_RETRY_TIMEOUT();
|
||||
/* instantly send a request to the next server */
|
||||
sntp_request(NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* no other valid server found */
|
||||
sntp_current_server = old_server;
|
||||
sntp_retry(NULL);
|
||||
}
|
||||
#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
||||
/* Always retry on error if only one server is supported */
|
||||
#define sntp_try_next_server sntp_retry
|
||||
#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
|
||||
|
||||
/** UDP recv callback for the sntp pcb */
|
||||
static void
|
||||
sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
u8_t mode;
|
||||
u8_t stratum;
|
||||
u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE];
|
||||
err_t err;
|
||||
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_UNUSED_ARG(pcb);
|
||||
|
||||
/* packet received: stop retry timeout */
|
||||
sys_untimeout(sntp_try_next_server, NULL);
|
||||
sys_untimeout(sntp_request, NULL);
|
||||
|
||||
err = ERR_ARG;
|
||||
#if SNTP_CHECK_RESPONSE >= 1
|
||||
/* check server address and port */
|
||||
if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) &&
|
||||
(port == SNTP_PORT))
|
||||
#else /* SNTP_CHECK_RESPONSE >= 1 */
|
||||
LWIP_UNUSED_ARG(addr);
|
||||
LWIP_UNUSED_ARG(port);
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 1 */
|
||||
{
|
||||
/* process the response */
|
||||
if (p->tot_len == SNTP_MSG_LEN) {
|
||||
pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE);
|
||||
mode &= SNTP_MODE_MASK;
|
||||
/* if this is a SNTP response... */
|
||||
if (((sntp_opmode == SNTP_OPMODE_POLL) && (mode == SNTP_MODE_SERVER)) ||
|
||||
((sntp_opmode == SNTP_OPMODE_LISTENONLY) && (mode == SNTP_MODE_BROADCAST))) {
|
||||
pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM);
|
||||
if (stratum == SNTP_STRATUM_KOD) {
|
||||
/* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
|
||||
err = SNTP_ERR_KOD;
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n"));
|
||||
} else {
|
||||
#if SNTP_CHECK_RESPONSE >= 2
|
||||
/* check originate_timetamp against sntp_last_timestamp_sent */
|
||||
u32_t originate_timestamp[2];
|
||||
pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME);
|
||||
if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) ||
|
||||
(originate_timestamp[1] != sntp_last_timestamp_sent[1]))
|
||||
{
|
||||
LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid originate timestamp in response\n"));
|
||||
} else
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 2 */
|
||||
/* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */
|
||||
{
|
||||
/* correct answer */
|
||||
err = ERR_OK;
|
||||
pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_TRANSMIT_TIME);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode));
|
||||
/* wait for correct response */
|
||||
err = ERR_TIMEOUT;
|
||||
}
|
||||
} else {
|
||||
LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len));
|
||||
}
|
||||
}
|
||||
#if SNTP_CHECK_RESPONSE >= 1
|
||||
else {
|
||||
/* packet from wrong remote address or port, wait for correct response */
|
||||
err = ERR_TIMEOUT;
|
||||
}
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 1 */
|
||||
pbuf_free(p);
|
||||
if (err == ERR_OK) {
|
||||
sntp_process(receive_timestamp);
|
||||
|
||||
/* Set up timeout for next request (only if poll response was received)*/
|
||||
if (sntp_opmode == SNTP_OPMODE_POLL) {
|
||||
/* Correct response, reset retry timeout */
|
||||
SNTP_RESET_RETRY_TIMEOUT();
|
||||
|
||||
sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL);
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n",
|
||||
(u32_t)SNTP_UPDATE_DELAY));
|
||||
}
|
||||
} else if (err != ERR_TIMEOUT) {
|
||||
/* Errors are only processed in case of an explicit poll response */
|
||||
if (sntp_opmode == SNTP_OPMODE_POLL) {
|
||||
if (err == SNTP_ERR_KOD) {
|
||||
/* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
|
||||
sntp_try_next_server(NULL);
|
||||
} else {
|
||||
/* another error, try the same server again */
|
||||
sntp_retry(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Actually send an sntp request to a server.
|
||||
*
|
||||
* @param server_addr resolved IP address of the SNTP server
|
||||
*/
|
||||
static void
|
||||
sntp_send_request(const ip_addr_t *server_addr)
|
||||
{
|
||||
struct pbuf* p;
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);
|
||||
if (p != NULL) {
|
||||
struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload;
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n"));
|
||||
/* initialize request message */
|
||||
sntp_initialize_request(sntpmsg);
|
||||
/* send request */
|
||||
udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT);
|
||||
/* free the pbuf after sending it */
|
||||
pbuf_free(p);
|
||||
/* set up receive timeout: try next server or retry on timeout */
|
||||
sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL);
|
||||
#if SNTP_CHECK_RESPONSE >= 1
|
||||
/* save server address to verify it in sntp_recv */
|
||||
ip_addr_set(&sntp_last_server_address, server_addr);
|
||||
#endif /* SNTP_CHECK_RESPONSE >= 1 */
|
||||
} else {
|
||||
LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n",
|
||||
(u32_t)SNTP_RETRY_TIMEOUT));
|
||||
/* out of memory: set up a timer to send a retry */
|
||||
sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#if SNTP_SERVER_DNS
|
||||
/**
|
||||
* DNS found callback when using DNS names as server address.
|
||||
*/
|
||||
static void
|
||||
sntp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(hostname);
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
if (ipaddr != NULL) {
|
||||
/* Address resolved, send request */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n"));
|
||||
sntp_send_request(ipaddr);
|
||||
} else {
|
||||
/* DNS resolving failed -> try another server */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n"));
|
||||
sntp_try_next_server(NULL);
|
||||
}
|
||||
}
|
||||
#endif /* SNTP_SERVER_DNS */
|
||||
|
||||
/**
|
||||
* Send out an sntp request.
|
||||
*
|
||||
* @param arg is unused (only necessary to conform to sys_timeout)
|
||||
*/
|
||||
static void
|
||||
sntp_request(void *arg)
|
||||
{
|
||||
ip_addr_t sntp_server_address;
|
||||
err_t err;
|
||||
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
/* initialize SNTP server address */
|
||||
#if SNTP_SERVER_DNS
|
||||
if (sntp_servers[sntp_current_server].name) {
|
||||
/* always resolve the name and rely on dns-internal caching & timeout */
|
||||
ip_addr_set_zero(&sntp_servers[sntp_current_server].addr);
|
||||
err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address,
|
||||
sntp_dns_found, NULL);
|
||||
if (err == ERR_INPROGRESS) {
|
||||
/* DNS request sent, wait for sntp_dns_found being called */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n"));
|
||||
return;
|
||||
} else if (err == ERR_OK) {
|
||||
sntp_servers[sntp_current_server].addr = sntp_server_address;
|
||||
}
|
||||
} else
|
||||
#endif /* SNTP_SERVER_DNS */
|
||||
{
|
||||
sntp_server_address = sntp_servers[sntp_current_server].addr;
|
||||
err = (ip_addr_isany_val(sntp_server_address)) ? ERR_ARG : ERR_OK;
|
||||
}
|
||||
|
||||
if (err == ERR_OK) {
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %s\n",
|
||||
ipaddr_ntoa(&sntp_server_address)));
|
||||
sntp_send_request(&sntp_server_address);
|
||||
} else {
|
||||
/* address conversion failed, try another server */
|
||||
LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n"));
|
||||
sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup sntp
|
||||
* Initialize this module.
|
||||
* Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC).
|
||||
*/
|
||||
void
|
||||
sntp_init(void)
|
||||
{
|
||||
#ifdef SNTP_SERVER_ADDRESS
|
||||
#if SNTP_SERVER_DNS
|
||||
sntp_setservername(0, SNTP_SERVER_ADDRESS);
|
||||
#else
|
||||
#error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0
|
||||
#endif
|
||||
#endif /* SNTP_SERVER_ADDRESS */
|
||||
|
||||
if (sntp_pcb == NULL) {
|
||||
sntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
|
||||
LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL);
|
||||
if (sntp_pcb != NULL) {
|
||||
udp_recv(sntp_pcb, sntp_recv, NULL);
|
||||
|
||||
if (sntp_opmode == SNTP_OPMODE_POLL) {
|
||||
SNTP_RESET_RETRY_TIMEOUT();
|
||||
#if SNTP_STARTUP_DELAY
|
||||
sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL);
|
||||
#else
|
||||
sntp_request(NULL);
|
||||
#endif
|
||||
} else if (sntp_opmode == SNTP_OPMODE_LISTENONLY) {
|
||||
ip_set_option(sntp_pcb, SOF_BROADCAST);
|
||||
udp_bind(sntp_pcb, IP_ANY_TYPE, SNTP_PORT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup sntp
|
||||
* Stop this module.
|
||||
*/
|
||||
void
|
||||
sntp_stop(void)
|
||||
{
|
||||
if (sntp_pcb != NULL) {
|
||||
sys_untimeout(sntp_request, NULL);
|
||||
sys_untimeout(sntp_try_next_server, NULL);
|
||||
udp_remove(sntp_pcb);
|
||||
sntp_pcb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup sntp
|
||||
* Get enabled state.
|
||||
*/
|
||||
u8_t sntp_enabled(void)
|
||||
{
|
||||
return (sntp_pcb != NULL)? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup sntp
|
||||
* Sets the operating mode.
|
||||
* @param operating_mode one of the available operating modes
|
||||
*/
|
||||
void
|
||||
sntp_setoperatingmode(u8_t operating_mode)
|
||||
{
|
||||
LWIP_ASSERT("Invalid operating mode", operating_mode <= SNTP_OPMODE_LISTENONLY);
|
||||
LWIP_ASSERT("Operating mode must not be set while SNTP client is running", sntp_pcb == NULL);
|
||||
sntp_opmode = operating_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup sntp
|
||||
* Gets the operating mode.
|
||||
*/
|
||||
u8_t
|
||||
sntp_getoperatingmode(void)
|
||||
{
|
||||
return sntp_opmode;
|
||||
}
|
||||
|
||||
#if SNTP_GET_SERVERS_FROM_DHCP
|
||||
/**
|
||||
* Config SNTP server handling by IP address, name, or DHCP; clear table
|
||||
* @param set_servers_from_dhcp enable or disable getting server addresses from dhcp
|
||||
*/
|
||||
void
|
||||
sntp_servermode_dhcp(int set_servers_from_dhcp)
|
||||
{
|
||||
u8_t new_mode = set_servers_from_dhcp ? 1 : 0;
|
||||
if (sntp_set_servers_from_dhcp != new_mode) {
|
||||
sntp_set_servers_from_dhcp = new_mode;
|
||||
}
|
||||
}
|
||||
#endif /* SNTP_GET_SERVERS_FROM_DHCP */
|
||||
|
||||
/**
|
||||
* @ingroup sntp
|
||||
* Initialize one of the NTP servers by IP address
|
||||
*
|
||||
* @param idx the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
||||
* @param server IP address of the NTP server to set
|
||||
*/
|
||||
void
|
||||
sntp_setserver(u8_t idx, const ip_addr_t *server)
|
||||
{
|
||||
if (idx < SNTP_MAX_SERVERS) {
|
||||
if (server != NULL) {
|
||||
sntp_servers[idx].addr = (*server);
|
||||
} else {
|
||||
ip_addr_set_zero(&sntp_servers[idx].addr);
|
||||
}
|
||||
#if SNTP_SERVER_DNS
|
||||
sntp_servers[idx].name = NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP
|
||||
/**
|
||||
* Initialize one of the NTP servers by IP address, required by DHCP
|
||||
*
|
||||
* @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
||||
* @param dnsserver IP address of the NTP server to set
|
||||
*/
|
||||
void
|
||||
dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server)
|
||||
{
|
||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n",
|
||||
(sntp_set_servers_from_dhcp ? "Got" : "Rejected"),
|
||||
ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num));
|
||||
if (sntp_set_servers_from_dhcp && num) {
|
||||
u8_t i;
|
||||
for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) {
|
||||
ip_addr_t addr;
|
||||
ip_addr_copy_from_ip4(addr, server[i]);
|
||||
sntp_setserver(i, &addr);
|
||||
}
|
||||
for (i = num; i < SNTP_MAX_SERVERS; i++) {
|
||||
sntp_setserver(i, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */
|
||||
|
||||
/**
|
||||
* @ingroup sntp
|
||||
* Obtain one of the currently configured by IP address (or DHCP) NTP servers
|
||||
*
|
||||
* @param idx the index of the NTP server
|
||||
* @return IP address of the indexed NTP server or "ip_addr_any" if the NTP
|
||||
* server has not been configured by address (or at all).
|
||||
*/
|
||||
const ip_addr_t*
|
||||
sntp_getserver(u8_t idx)
|
||||
{
|
||||
if (idx < SNTP_MAX_SERVERS) {
|
||||
return &sntp_servers[idx].addr;
|
||||
}
|
||||
return IP_ADDR_ANY;
|
||||
}
|
||||
|
||||
#if SNTP_SERVER_DNS
|
||||
/**
|
||||
* Initialize one of the NTP servers by name
|
||||
*
|
||||
* @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
|
||||
* @param dnsserver DNS name of the NTP server to set, to be resolved at contact time
|
||||
*/
|
||||
void
|
||||
sntp_setservername(u8_t idx, char *server)
|
||||
{
|
||||
if (idx < SNTP_MAX_SERVERS) {
|
||||
sntp_servers[idx].name = server;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain one of the currently configured by name NTP servers.
|
||||
*
|
||||
* @param numdns the index of the NTP server
|
||||
* @return IP address of the indexed NTP server or NULL if the NTP
|
||||
* server has not been configured by name (or at all)
|
||||
*/
|
||||
char *
|
||||
sntp_getservername(u8_t idx)
|
||||
{
|
||||
if (idx < SNTP_MAX_SERVERS) {
|
||||
return sntp_servers[idx].name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif /* SNTP_SERVER_DNS */
|
||||
|
||||
#endif /* LWIP_UDP */
|
||||
417
src/apps/tftp/tftp_server.c
Normal file
417
src/apps/tftp/tftp_server.c
Normal file
@@ -0,0 +1,417 @@
|
||||
/****************************************************************//**
|
||||
*
|
||||
* @file tftp_server.c
|
||||
*
|
||||
* @author Logan Gunthorpe <logang@deltatee.com>
|
||||
* Dirk Ziegelmeier <dziegel@gmx.de>
|
||||
*
|
||||
* @brief Trivial File Transfer Protocol (RFC 1350)
|
||||
*
|
||||
* Copyright (c) Deltatee Enterprises Ltd. 2013
|
||||
* All rights reserved.
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
/*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification,are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 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: Logan Gunthorpe <logang@deltatee.com>
|
||||
* Dirk Ziegelmeier <dziegel@gmx.de>
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup tftp TFTP server
|
||||
* @ingroup apps
|
||||
*
|
||||
* This is simple TFTP server for the lwIP raw API.
|
||||
*/
|
||||
|
||||
#include "lwip/apps/tftp_server.h"
|
||||
|
||||
#if LWIP_UDP
|
||||
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/timeouts.h"
|
||||
#include "lwip/debug.h"
|
||||
|
||||
#define TFTP_MAX_PAYLOAD_SIZE 512
|
||||
#define TFTP_HEADER_LENGTH 4
|
||||
|
||||
#define TFTP_RRQ 1
|
||||
#define TFTP_WRQ 2
|
||||
#define TFTP_DATA 3
|
||||
#define TFTP_ACK 4
|
||||
#define TFTP_ERROR 5
|
||||
|
||||
enum tftp_error {
|
||||
TFTP_ERROR_FILE_NOT_FOUND = 1,
|
||||
TFTP_ERROR_ACCESS_VIOLATION = 2,
|
||||
TFTP_ERROR_DISK_FULL = 3,
|
||||
TFTP_ERROR_ILLEGAL_OPERATION = 4,
|
||||
TFTP_ERROR_UNKNOWN_TRFR_ID = 5,
|
||||
TFTP_ERROR_FILE_EXISTS = 6,
|
||||
TFTP_ERROR_NO_SUCH_USER = 7
|
||||
};
|
||||
|
||||
#include <string.h>
|
||||
|
||||
struct tftp_state {
|
||||
const struct tftp_context *ctx;
|
||||
void *handle;
|
||||
struct pbuf *last_data;
|
||||
struct udp_pcb *upcb;
|
||||
ip_addr_t addr;
|
||||
u16_t port;
|
||||
int timer;
|
||||
int last_pkt;
|
||||
u16_t blknum;
|
||||
u8_t retries;
|
||||
u8_t mode_write;
|
||||
};
|
||||
|
||||
static struct tftp_state tftp_state;
|
||||
|
||||
static void tftp_tmr(void* arg);
|
||||
|
||||
static void
|
||||
close_handle(void)
|
||||
{
|
||||
tftp_state.port = 0;
|
||||
ip_addr_set_any(0, &tftp_state.addr);
|
||||
|
||||
if(tftp_state.last_data != NULL) {
|
||||
pbuf_free(tftp_state.last_data);
|
||||
tftp_state.last_data = NULL;
|
||||
}
|
||||
|
||||
sys_untimeout(tftp_tmr, NULL);
|
||||
|
||||
if (tftp_state.handle) {
|
||||
tftp_state.ctx->close(tftp_state.handle);
|
||||
tftp_state.handle = NULL;
|
||||
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: closing\n"));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
send_error(const ip_addr_t *addr, u16_t port, enum tftp_error code, const char *str)
|
||||
{
|
||||
int str_length = strlen(str);
|
||||
struct pbuf* p;
|
||||
u16_t* payload;
|
||||
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(TFTP_HEADER_LENGTH + str_length + 1), PBUF_RAM);
|
||||
if(p == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
payload = (u16_t*) p->payload;
|
||||
payload[0] = PP_HTONS(TFTP_ERROR);
|
||||
payload[1] = lwip_htons(code);
|
||||
MEMCPY(&payload[2], str, str_length + 1);
|
||||
|
||||
udp_sendto(tftp_state.upcb, p, addr, port);
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
static void
|
||||
send_ack(u16_t blknum)
|
||||
{
|
||||
struct pbuf* p;
|
||||
u16_t* payload;
|
||||
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH, PBUF_RAM);
|
||||
if(p == NULL) {
|
||||
return;
|
||||
}
|
||||
payload = (u16_t*) p->payload;
|
||||
|
||||
payload[0] = PP_HTONS(TFTP_ACK);
|
||||
payload[1] = lwip_htons(blknum);
|
||||
udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port);
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
static void
|
||||
resend_data(void)
|
||||
{
|
||||
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, tftp_state.last_data->len, PBUF_RAM);
|
||||
if(p == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(pbuf_copy(p, tftp_state.last_data) != ERR_OK) {
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
|
||||
udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port);
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
static void
|
||||
send_data(void)
|
||||
{
|
||||
u16_t *payload;
|
||||
int ret;
|
||||
|
||||
if(tftp_state.last_data != NULL) {
|
||||
pbuf_free(tftp_state.last_data);
|
||||
}
|
||||
|
||||
tftp_state.last_data = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH + TFTP_MAX_PAYLOAD_SIZE, PBUF_RAM);
|
||||
if(tftp_state.last_data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
payload = (u16_t *) tftp_state.last_data->payload;
|
||||
payload[0] = PP_HTONS(TFTP_DATA);
|
||||
payload[1] = lwip_htons(tftp_state.blknum);
|
||||
|
||||
ret = tftp_state.ctx->read(tftp_state.handle, &payload[2], TFTP_MAX_PAYLOAD_SIZE);
|
||||
if (ret < 0) {
|
||||
send_error(&tftp_state.addr, tftp_state.port, TFTP_ERROR_ACCESS_VIOLATION, "Error occured while reading the file.");
|
||||
close_handle();
|
||||
return;
|
||||
}
|
||||
|
||||
pbuf_realloc(tftp_state.last_data, (u16_t)(TFTP_HEADER_LENGTH + ret));
|
||||
resend_data();
|
||||
}
|
||||
|
||||
static void
|
||||
recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
u16_t *sbuf = (u16_t *) p->payload;
|
||||
int opcode;
|
||||
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_UNUSED_ARG(upcb);
|
||||
|
||||
if (((tftp_state.port != 0) && (port != tftp_state.port)) ||
|
||||
(!ip_addr_isany_val(tftp_state.addr) && !ip_addr_cmp(&tftp_state.addr, addr))) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
|
||||
opcode = sbuf[0];
|
||||
|
||||
tftp_state.last_pkt = tftp_state.timer;
|
||||
tftp_state.retries = 0;
|
||||
|
||||
switch (opcode) {
|
||||
case PP_HTONS(TFTP_RRQ): /* fall through */
|
||||
case PP_HTONS(TFTP_WRQ):
|
||||
{
|
||||
const char tftp_null = 0;
|
||||
char filename[TFTP_MAX_FILENAME_LEN];
|
||||
char mode[TFTP_MAX_MODE_LEN];
|
||||
u16_t filename_end_offset;
|
||||
u16_t mode_end_offset;
|
||||
|
||||
if(tftp_state.handle != NULL) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
|
||||
break;
|
||||
}
|
||||
|
||||
sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);
|
||||
|
||||
/* find \0 in pbuf -> end of filename string */
|
||||
filename_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), 2);
|
||||
if((u16_t)(filename_end_offset-2) > sizeof(filename)) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Filename too long/not NULL terminated");
|
||||
break;
|
||||
}
|
||||
pbuf_copy_partial(p, filename, filename_end_offset-2, 2);
|
||||
|
||||
/* find \0 in pbuf -> end of mode string */
|
||||
mode_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), filename_end_offset+1);
|
||||
if((u16_t)(mode_end_offset-filename_end_offset) > sizeof(mode)) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Mode too long/not NULL terminated");
|
||||
break;
|
||||
}
|
||||
pbuf_copy_partial(p, mode, mode_end_offset-filename_end_offset, filename_end_offset+1);
|
||||
|
||||
tftp_state.handle = tftp_state.ctx->open(filename, mode, opcode == PP_HTONS(TFTP_WRQ));
|
||||
tftp_state.blknum = 1;
|
||||
|
||||
if (!tftp_state.handle) {
|
||||
send_error(addr, port, TFTP_ERROR_FILE_NOT_FOUND, "Unable to open requested file.");
|
||||
break;
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: %s request from ", (opcode == PP_HTONS(TFTP_WRQ)) ? "write" : "read"));
|
||||
ip_addr_debug_print(TFTP_DEBUG | LWIP_DBG_STATE, addr);
|
||||
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, (" for '%s' mode '%s'\n", filename, mode));
|
||||
|
||||
ip_addr_copy(tftp_state.addr, *addr);
|
||||
tftp_state.port = port;
|
||||
|
||||
if (opcode == PP_HTONS(TFTP_WRQ)) {
|
||||
tftp_state.mode_write = 1;
|
||||
send_ack(0);
|
||||
} else {
|
||||
tftp_state.mode_write = 0;
|
||||
send_data();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PP_HTONS(TFTP_DATA):
|
||||
{
|
||||
int ret;
|
||||
u16_t blknum;
|
||||
|
||||
if (tftp_state.handle == NULL) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
|
||||
break;
|
||||
}
|
||||
|
||||
if (tftp_state.mode_write != 1) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a write connection");
|
||||
break;
|
||||
}
|
||||
|
||||
blknum = lwip_ntohs(sbuf[1]);
|
||||
pbuf_header(p, -TFTP_HEADER_LENGTH);
|
||||
|
||||
ret = tftp_state.ctx->write(tftp_state.handle, p);
|
||||
if (ret < 0) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "error writing file");
|
||||
close_handle();
|
||||
} else {
|
||||
send_ack(blknum);
|
||||
}
|
||||
|
||||
if (p->tot_len < TFTP_MAX_PAYLOAD_SIZE) {
|
||||
close_handle();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PP_HTONS(TFTP_ACK):
|
||||
{
|
||||
u16_t blknum;
|
||||
int lastpkt;
|
||||
|
||||
if (tftp_state.handle == NULL) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
|
||||
break;
|
||||
}
|
||||
|
||||
if (tftp_state.mode_write != 0) {
|
||||
send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a read connection");
|
||||
break;
|
||||
}
|
||||
|
||||
blknum = lwip_ntohs(sbuf[1]);
|
||||
if (blknum != tftp_state.blknum) {
|
||||
send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number");
|
||||
break;
|
||||
}
|
||||
|
||||
lastpkt = 0;
|
||||
|
||||
if (tftp_state.last_data != NULL) {
|
||||
lastpkt = tftp_state.last_data->tot_len != (TFTP_MAX_PAYLOAD_SIZE + TFTP_HEADER_LENGTH);
|
||||
}
|
||||
|
||||
if (!lastpkt) {
|
||||
tftp_state.blknum++;
|
||||
send_data();
|
||||
} else {
|
||||
close_handle();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "Unknown operation");
|
||||
break;
|
||||
}
|
||||
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
static void
|
||||
tftp_tmr(void* arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
tftp_state.timer++;
|
||||
|
||||
if (tftp_state.handle == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);
|
||||
|
||||
if ((tftp_state.timer - tftp_state.last_pkt) > (TFTP_TIMEOUT_MSECS / TFTP_TIMER_MSECS)) {
|
||||
if ((tftp_state.last_data != NULL) && (tftp_state.retries < TFTP_MAX_RETRIES)) {
|
||||
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout, retrying\n"));
|
||||
resend_data();
|
||||
tftp_state.retries++;
|
||||
} else {
|
||||
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout\n"));
|
||||
close_handle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @ingroup tftp
|
||||
* Initialize TFTP server.
|
||||
* @param ctx TFTP callback struct
|
||||
*/
|
||||
err_t
|
||||
tftp_init(const struct tftp_context *ctx)
|
||||
{
|
||||
err_t ret;
|
||||
|
||||
struct udp_pcb *pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
|
||||
if (pcb == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
ret = udp_bind(pcb, IP_ANY_TYPE, TFTP_PORT);
|
||||
if (ret != ERR_OK) {
|
||||
udp_remove(pcb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
tftp_state.handle = NULL;
|
||||
tftp_state.port = 0;
|
||||
tftp_state.ctx = ctx;
|
||||
tftp_state.timer = 0;
|
||||
tftp_state.last_data = NULL;
|
||||
tftp_state.upcb = pcb;
|
||||
|
||||
udp_recv(pcb, recv, NULL);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#endif /* LWIP_UDP */
|
||||
190
src/core/def.c
190
src/core/def.c
@@ -2,6 +2,28 @@
|
||||
* @file
|
||||
* Common functions used throughout the stack.
|
||||
*
|
||||
* These are reference implementations of the byte swapping functions.
|
||||
* Again with the aim of being simple, correct and fully portable.
|
||||
* Byte swapping is the second thing you would want to optimize. You will
|
||||
* need to port it to your architecture and in your cc.h:
|
||||
*
|
||||
* \#define lwip_htons(x) your_htons
|
||||
* \#define lwip_htonl(x) your_htonl
|
||||
*
|
||||
* Note lwip_ntohs() and lwip_ntohl() are merely references to the htonx counterparts.
|
||||
*
|
||||
* If you \#define them to htons() and htonl(), you should
|
||||
* \#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from
|
||||
* defining htonx/ntohx compatibility macros.
|
||||
|
||||
* @defgroup sys_nonstandard Non-standard functions
|
||||
* @ingroup sys_layer
|
||||
* lwIP provides default implementations for non-standard functions.
|
||||
* These can be mapped to OS functions to reduce code footprint if desired.
|
||||
* All defines related to this section must not be placed in lwipopts.h,
|
||||
* but in arch/cc.h!
|
||||
* These options cannot be \#defined in lwipopts.h since they are not options
|
||||
* of lwIP itself, but options of the lwIP port to your system.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -39,21 +61,11 @@
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
/**
|
||||
* These are reference implementations of the byte swapping functions.
|
||||
* Again with the aim of being simple, correct and fully portable.
|
||||
* Byte swapping is the second thing you would want to optimize. You will
|
||||
* need to port it to your architecture and in your cc.h:
|
||||
*
|
||||
* #define LWIP_PLATFORM_BYTESWAP 1
|
||||
* #define LWIP_PLATFORM_HTONS(x) <your_htons>
|
||||
* #define LWIP_PLATFORM_HTONL(x) <your_htonl>
|
||||
*
|
||||
* Note ntohs() and ntohl() are merely references to the htonx counterparts.
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
|
||||
#if !defined(lwip_htons)
|
||||
/**
|
||||
* Convert an u16_t from host- to network byte order.
|
||||
*
|
||||
@@ -63,21 +75,11 @@
|
||||
u16_t
|
||||
lwip_htons(u16_t n)
|
||||
{
|
||||
return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an u16_t from network- to host byte order.
|
||||
*
|
||||
* @param n u16_t in network byte order
|
||||
* @return n in host byte order
|
||||
*/
|
||||
u16_t
|
||||
lwip_ntohs(u16_t n)
|
||||
{
|
||||
return lwip_htons(n);
|
||||
return (u16_t)PP_HTONS(n);
|
||||
}
|
||||
#endif /* lwip_htons */
|
||||
|
||||
#if !defined(lwip_htonl)
|
||||
/**
|
||||
* Convert an u32_t from host- to network byte order.
|
||||
*
|
||||
@@ -87,22 +89,134 @@ lwip_ntohs(u16_t n)
|
||||
u32_t
|
||||
lwip_htonl(u32_t n)
|
||||
{
|
||||
return ((n & 0xff) << 24) |
|
||||
((n & 0xff00) << 8) |
|
||||
((n & 0xff0000UL) >> 8) |
|
||||
((n & 0xff000000UL) >> 24);
|
||||
return (u32_t)PP_HTONL(n);
|
||||
}
|
||||
#endif /* lwip_htonl */
|
||||
|
||||
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
|
||||
|
||||
#ifndef lwip_strnstr
|
||||
/**
|
||||
* Convert an u32_t from network- to host byte order.
|
||||
*
|
||||
* @param n u32_t in network byte order
|
||||
* @return n in host byte order
|
||||
* @ingroup sys_nonstandard
|
||||
* lwIP default implementation for strnstr() non-standard function.
|
||||
* This can be \#defined to strnstr() depending on your platform port.
|
||||
*/
|
||||
u32_t
|
||||
lwip_ntohl(u32_t n)
|
||||
char*
|
||||
lwip_strnstr(const char* buffer, const char* token, size_t n)
|
||||
{
|
||||
return lwip_htonl(n);
|
||||
const char* p;
|
||||
size_t tokenlen = strlen(token);
|
||||
if (tokenlen == 0) {
|
||||
return LWIP_CONST_CAST(char *, buffer);
|
||||
}
|
||||
for (p = buffer; *p && (p + tokenlen <= buffer + n); p++) {
|
||||
if ((*p == *token) && (strncmp(p, token, tokenlen) == 0)) {
|
||||
return LWIP_CONST_CAST(char *, p);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */
|
||||
#ifndef lwip_stricmp
|
||||
/**
|
||||
* @ingroup sys_nonstandard
|
||||
* lwIP default implementation for stricmp() non-standard function.
|
||||
* This can be \#defined to stricmp() depending on your platform port.
|
||||
*/
|
||||
int
|
||||
lwip_stricmp(const char* str1, const char* str2)
|
||||
{
|
||||
char c1, c2;
|
||||
|
||||
do {
|
||||
c1 = *str1++;
|
||||
c2 = *str2++;
|
||||
if (c1 != c2) {
|
||||
char c1_upc = c1 | 0x20;
|
||||
if ((c1_upc >= 'a') && (c1_upc <= 'z')) {
|
||||
/* characters are not equal an one is in the alphabet range:
|
||||
downcase both chars and check again */
|
||||
char c2_upc = c2 | 0x20;
|
||||
if (c1_upc != c2_upc) {
|
||||
/* still not equal */
|
||||
/* don't care for < or > */
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
/* characters are not equal but none is in the alphabet range */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} while (c1 != 0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef lwip_strnicmp
|
||||
/**
|
||||
* @ingroup sys_nonstandard
|
||||
* lwIP default implementation for strnicmp() non-standard function.
|
||||
* This can be \#defined to strnicmp() depending on your platform port.
|
||||
*/
|
||||
int
|
||||
lwip_strnicmp(const char* str1, const char* str2, size_t len)
|
||||
{
|
||||
char c1, c2;
|
||||
|
||||
do {
|
||||
c1 = *str1++;
|
||||
c2 = *str2++;
|
||||
if (c1 != c2) {
|
||||
char c1_upc = c1 | 0x20;
|
||||
if ((c1_upc >= 'a') && (c1_upc <= 'z')) {
|
||||
/* characters are not equal an one is in the alphabet range:
|
||||
downcase both chars and check again */
|
||||
char c2_upc = c2 | 0x20;
|
||||
if (c1_upc != c2_upc) {
|
||||
/* still not equal */
|
||||
/* don't care for < or > */
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
/* characters are not equal but none is in the alphabet range */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} while (len-- && c1 != 0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef lwip_itoa
|
||||
/**
|
||||
* @ingroup sys_nonstandard
|
||||
* lwIP default implementation for itoa() non-standard function.
|
||||
* This can be \#defined to itoa() or snprintf(result, bufsize, "%d", number) depending on your platform port.
|
||||
*/
|
||||
void
|
||||
lwip_itoa(char* result, size_t bufsize, int number)
|
||||
{
|
||||
const int base = 10;
|
||||
char* ptr = result, *ptr1 = result, tmp_char;
|
||||
int tmp_value;
|
||||
LWIP_UNUSED_ARG(bufsize);
|
||||
|
||||
do {
|
||||
tmp_value = number;
|
||||
number /= base;
|
||||
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - number * base)];
|
||||
} while(number);
|
||||
|
||||
/* Apply negative sign */
|
||||
if (tmp_value < 0) {
|
||||
*ptr++ = '-';
|
||||
}
|
||||
*ptr-- = '\0';
|
||||
while(ptr1 < ptr) {
|
||||
tmp_char = *ptr;
|
||||
*ptr--= *ptr1;
|
||||
*ptr1++ = tmp_char;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
1345
src/core/dns.c
1345
src/core/dns.c
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,16 @@
|
||||
/**
|
||||
* @file
|
||||
* Incluse internet checksum functions.
|
||||
* Incluse internet checksum functions.\n
|
||||
*
|
||||
* These are some reference implementations of the checksum algorithm, with the
|
||||
* aim of being simple, correct and fully portable. Checksumming is the
|
||||
* first thing you would want to optimize for your platform. If you create
|
||||
* your own version, link it in and in your cc.h put:
|
||||
*
|
||||
* \#define LWIP_CHKSUM your_checksum_routine
|
||||
*
|
||||
* Or you can select from the implementations below by defining
|
||||
* LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -40,26 +49,16 @@
|
||||
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
/* These are some reference implementations of the checksum algorithm, with the
|
||||
* aim of being simple, correct and fully portable. Checksumming is the
|
||||
* first thing you would want to optimize for your platform. If you create
|
||||
* your own version, link it in and in your cc.h put:
|
||||
*
|
||||
* #define LWIP_CHKSUM <your_checksum_routine>
|
||||
*
|
||||
* Or you can select from the implementations below by defining
|
||||
* LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
|
||||
*/
|
||||
|
||||
#ifndef LWIP_CHKSUM
|
||||
# define LWIP_CHKSUM lwip_standard_chksum
|
||||
# ifndef LWIP_CHKSUM_ALGORITHM
|
||||
# define LWIP_CHKSUM_ALGORITHM 2
|
||||
# endif
|
||||
u16_t lwip_standard_chksum(const void *dataptr, int len);
|
||||
#endif
|
||||
/* If none set: */
|
||||
#ifndef LWIP_CHKSUM_ALGORITHM
|
||||
@@ -72,21 +71,21 @@
|
||||
*
|
||||
* @param dataptr points to start of data to be summed at any boundary
|
||||
* @param len length of data to be summed
|
||||
* @return host order (!) lwip checksum (non-inverted Internet sum)
|
||||
* @return host order (!) lwip checksum (non-inverted Internet sum)
|
||||
*
|
||||
* @note accumulator size limits summable length to 64k
|
||||
* @note host endianess is irrelevant (p3 RFC1071)
|
||||
*/
|
||||
static u16_t
|
||||
lwip_standard_chksum(void *dataptr, u16_t len)
|
||||
u16_t
|
||||
lwip_standard_chksum(const void *dataptr, int len)
|
||||
{
|
||||
u32_t acc;
|
||||
u16_t src;
|
||||
u8_t *octetptr;
|
||||
const u8_t *octetptr;
|
||||
|
||||
acc = 0;
|
||||
/* dataptr may be at odd or even addresses */
|
||||
octetptr = (u8_t*)dataptr;
|
||||
octetptr = (const u8_t*)dataptr;
|
||||
while (len > 1) {
|
||||
/* declare first octet as most significant
|
||||
thus assume network order, ignoring host order */
|
||||
@@ -108,10 +107,10 @@ lwip_standard_chksum(void *dataptr, u16_t len)
|
||||
if ((acc & 0xffff0000UL) != 0) {
|
||||
acc = (acc >> 16) + (acc & 0x0000ffffUL);
|
||||
}
|
||||
/* This maybe a little confusing: reorder sum using htons()
|
||||
instead of ntohs() since it has a little less call overhead.
|
||||
/* This maybe a little confusing: reorder sum using lwip_htons()
|
||||
instead of lwip_ntohs() since it has a little less call overhead.
|
||||
The caller must invert bits for Internet sum ! */
|
||||
return htons((u16_t)acc);
|
||||
return lwip_htons((u16_t)acc);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -128,14 +127,14 @@ lwip_standard_chksum(void *dataptr, u16_t len)
|
||||
*
|
||||
* @param dataptr points to start of data to be summed at any boundary
|
||||
* @param len length of data to be summed
|
||||
* @return host order (!) lwip checksum (non-inverted Internet sum)
|
||||
* @return host order (!) lwip checksum (non-inverted Internet sum)
|
||||
*/
|
||||
|
||||
static u16_t
|
||||
lwip_standard_chksum(void *dataptr, int len)
|
||||
u16_t
|
||||
lwip_standard_chksum(const void *dataptr, int len)
|
||||
{
|
||||
u8_t *pb = (u8_t *)dataptr;
|
||||
u16_t *ps, t = 0;
|
||||
const u8_t *pb = (const u8_t *)dataptr;
|
||||
const u16_t *ps;
|
||||
u16_t t = 0;
|
||||
u32_t sum = 0;
|
||||
int odd = ((mem_ptr_t)pb & 1);
|
||||
|
||||
@@ -146,7 +145,7 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
}
|
||||
|
||||
/* Add the bulk of the data */
|
||||
ps = (u16_t *)(void *)pb;
|
||||
ps = (const u16_t *)(const void *)pb;
|
||||
while (len > 1) {
|
||||
sum += *ps++;
|
||||
len -= 2;
|
||||
@@ -154,14 +153,14 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
|
||||
/* Consume left-over byte, if any */
|
||||
if (len > 0) {
|
||||
((u8_t *)&t)[0] = *(u8_t *)ps;
|
||||
((u8_t *)&t)[0] = *(const u8_t *)ps;
|
||||
}
|
||||
|
||||
/* Add end bytes */
|
||||
sum += t;
|
||||
|
||||
/* Fold 32-bit sum to 16 bits
|
||||
calling this twice is propably faster than if statements... */
|
||||
calling this twice is probably faster than if statements... */
|
||||
sum = FOLD_U32T(sum);
|
||||
sum = FOLD_U32T(sum);
|
||||
|
||||
@@ -178,21 +177,21 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
/**
|
||||
* An optimized checksum routine. Basically, it uses loop-unrolling on
|
||||
* the checksum loop, treating the head and tail bytes specially, whereas
|
||||
* the inner loop acts on 8 bytes at a time.
|
||||
* the inner loop acts on 8 bytes at a time.
|
||||
*
|
||||
* @arg start of buffer to be checksummed. May be an odd byte address.
|
||||
* @len number of bytes in the buffer to be checksummed.
|
||||
* @return host order (!) lwip checksum (non-inverted Internet sum)
|
||||
*
|
||||
* @return host order (!) lwip checksum (non-inverted Internet sum)
|
||||
*
|
||||
* by Curt McDowell, Broadcom Corp. December 8th, 2005
|
||||
*/
|
||||
|
||||
static u16_t
|
||||
lwip_standard_chksum(void *dataptr, int len)
|
||||
u16_t
|
||||
lwip_standard_chksum(const void *dataptr, int len)
|
||||
{
|
||||
u8_t *pb = (u8_t *)dataptr;
|
||||
u16_t *ps, t = 0;
|
||||
u32_t *pl;
|
||||
const u8_t *pb = (const u8_t *)dataptr;
|
||||
const u16_t *ps;
|
||||
u16_t t = 0;
|
||||
const u32_t *pl;
|
||||
u32_t sum = 0, tmp;
|
||||
/* starts at odd byte address? */
|
||||
int odd = ((mem_ptr_t)pb & 1);
|
||||
@@ -202,14 +201,14 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
len--;
|
||||
}
|
||||
|
||||
ps = (u16_t *)pb;
|
||||
ps = (const u16_t *)(const void*)pb;
|
||||
|
||||
if (((mem_ptr_t)ps & 3) && len > 1) {
|
||||
sum += *ps++;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
pl = (u32_t *)ps;
|
||||
pl = (const u32_t *)(const void*)ps;
|
||||
|
||||
while (len > 7) {
|
||||
tmp = sum + *pl++; /* ping */
|
||||
@@ -228,7 +227,7 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
/* make room in upper bits */
|
||||
sum = FOLD_U32T(sum);
|
||||
|
||||
ps = (u16_t *)pl;
|
||||
ps = (const u16_t *)pl;
|
||||
|
||||
/* 16-bit aligned word remaining? */
|
||||
while (len > 1) {
|
||||
@@ -238,13 +237,13 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
|
||||
/* dangling tail byte remaining? */
|
||||
if (len > 0) { /* include odd byte */
|
||||
((u8_t *)&t)[0] = *(u8_t *)ps;
|
||||
((u8_t *)&t)[0] = *(const u8_t *)ps;
|
||||
}
|
||||
|
||||
sum += t; /* add end bytes */
|
||||
|
||||
/* Fold 32-bit sum to 16 bits
|
||||
calling this twice is propably faster than if statements... */
|
||||
calling this twice is probably faster than if statements... */
|
||||
sum = FOLD_U32T(sum);
|
||||
sum = FOLD_U32T(sum);
|
||||
|
||||
@@ -256,32 +255,15 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* inet_chksum_pseudo:
|
||||
*
|
||||
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
|
||||
* IP addresses are expected to be in network byte order.
|
||||
*
|
||||
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
|
||||
* @param src source ip address (used for checksum of pseudo header)
|
||||
* @param dst destination ip address (used for checksum of pseudo header)
|
||||
* @param proto ip protocol (used for checksum of pseudo header)
|
||||
* @param proto_len length of the ip data part (used for checksum of pseudo header)
|
||||
* @return checksum (as u16_t) to be saved directly in the protocol header
|
||||
*/
|
||||
u16_t
|
||||
inet_chksum_pseudo(struct pbuf *p,
|
||||
ip_addr_t *src, ip_addr_t *dest,
|
||||
u8_t proto, u16_t proto_len)
|
||||
/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */
|
||||
static u16_t
|
||||
inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc)
|
||||
{
|
||||
u32_t acc;
|
||||
u32_t addr;
|
||||
struct pbuf *q;
|
||||
u8_t swapped;
|
||||
u8_t swapped = 0;
|
||||
|
||||
acc = 0;
|
||||
swapped = 0;
|
||||
/* iterate through all pbuf in chain */
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
|
||||
(void *)q, (void *)q->next));
|
||||
acc += LWIP_CHKSUM(q->payload, q->len);
|
||||
@@ -299,26 +281,22 @@ inet_chksum_pseudo(struct pbuf *p,
|
||||
if (swapped) {
|
||||
acc = SWAP_BYTES_IN_WORD(acc);
|
||||
}
|
||||
addr = ip4_addr_get_u32(src);
|
||||
acc += (addr & 0xffffUL);
|
||||
acc += ((addr >> 16) & 0xffffUL);
|
||||
addr = ip4_addr_get_u32(dest);
|
||||
acc += (addr & 0xffffUL);
|
||||
acc += ((addr >> 16) & 0xffffUL);
|
||||
acc += (u32_t)htons((u16_t)proto);
|
||||
acc += (u32_t)htons(proto_len);
|
||||
|
||||
acc += (u32_t)lwip_htons((u16_t)proto);
|
||||
acc += (u32_t)lwip_htons(proto_len);
|
||||
|
||||
/* Fold 32-bit sum to 16 bits
|
||||
calling this twice is propably faster than if statements... */
|
||||
calling this twice is probably faster than if statements... */
|
||||
acc = FOLD_U32T(acc);
|
||||
acc = FOLD_U32T(acc);
|
||||
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
|
||||
return (u16_t)~(acc & 0xffffUL);
|
||||
}
|
||||
|
||||
#if LWIP_IPV4
|
||||
/* inet_chksum_pseudo:
|
||||
*
|
||||
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
|
||||
* Calculates the IPv4 pseudo Internet checksum used by TCP and UDP for a pbuf chain.
|
||||
* IP addresses are expected to be in network byte order.
|
||||
*
|
||||
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
|
||||
@@ -329,20 +307,104 @@ inet_chksum_pseudo(struct pbuf *p,
|
||||
* @return checksum (as u16_t) to be saved directly in the protocol header
|
||||
*/
|
||||
u16_t
|
||||
inet_chksum_pseudo_partial(struct pbuf *p,
|
||||
ip_addr_t *src, ip_addr_t *dest,
|
||||
u8_t proto, u16_t proto_len, u16_t chksum_len)
|
||||
inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
|
||||
const ip4_addr_t *src, const ip4_addr_t *dest)
|
||||
{
|
||||
u32_t acc;
|
||||
u32_t addr;
|
||||
|
||||
addr = ip4_addr_get_u32(src);
|
||||
acc = (addr & 0xffffUL);
|
||||
acc += ((addr >> 16) & 0xffffUL);
|
||||
addr = ip4_addr_get_u32(dest);
|
||||
acc += (addr & 0xffffUL);
|
||||
acc += ((addr >> 16) & 0xffffUL);
|
||||
/* fold down to 16 bits */
|
||||
acc = FOLD_U32T(acc);
|
||||
acc = FOLD_U32T(acc);
|
||||
|
||||
return inet_cksum_pseudo_base(p, proto, proto_len, acc);
|
||||
}
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
#if LWIP_IPV6
|
||||
/**
|
||||
* Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain.
|
||||
* IPv6 addresses are expected to be in network byte order.
|
||||
*
|
||||
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
|
||||
* @param proto ipv6 protocol/next header (used for checksum of pseudo header)
|
||||
* @param proto_len length of the ipv6 payload (used for checksum of pseudo header)
|
||||
* @param src source ipv6 address (used for checksum of pseudo header)
|
||||
* @param dest destination ipv6 address (used for checksum of pseudo header)
|
||||
* @return checksum (as u16_t) to be saved directly in the protocol header
|
||||
*/
|
||||
u16_t
|
||||
ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
|
||||
const ip6_addr_t *src, const ip6_addr_t *dest)
|
||||
{
|
||||
u32_t acc = 0;
|
||||
u32_t addr;
|
||||
u8_t addr_part;
|
||||
|
||||
for (addr_part = 0; addr_part < 4; addr_part++) {
|
||||
addr = src->addr[addr_part];
|
||||
acc += (addr & 0xffffUL);
|
||||
acc += ((addr >> 16) & 0xffffUL);
|
||||
addr = dest->addr[addr_part];
|
||||
acc += (addr & 0xffffUL);
|
||||
acc += ((addr >> 16) & 0xffffUL);
|
||||
}
|
||||
/* fold down to 16 bits */
|
||||
acc = FOLD_U32T(acc);
|
||||
acc = FOLD_U32T(acc);
|
||||
|
||||
return inet_cksum_pseudo_base(p, proto, proto_len, acc);
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
/* ip_chksum_pseudo:
|
||||
*
|
||||
* Calculates the IPv4 or IPv6 pseudo Internet checksum used by TCP and UDP for a pbuf chain.
|
||||
* IP addresses are expected to be in network byte order.
|
||||
*
|
||||
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
|
||||
* @param src source ip address (used for checksum of pseudo header)
|
||||
* @param dst destination ip address (used for checksum of pseudo header)
|
||||
* @param proto ip protocol (used for checksum of pseudo header)
|
||||
* @param proto_len length of the ip data part (used for checksum of pseudo header)
|
||||
* @return checksum (as u16_t) to be saved directly in the protocol header
|
||||
*/
|
||||
u16_t
|
||||
ip_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
|
||||
const ip_addr_t *src, const ip_addr_t *dest)
|
||||
{
|
||||
#if LWIP_IPV6
|
||||
if (IP_IS_V6(dest)) {
|
||||
return ip6_chksum_pseudo(p, proto, proto_len, ip_2_ip6(src), ip_2_ip6(dest));
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
else
|
||||
#endif /* LWIP_IPV4 && LWIP_IPV6 */
|
||||
#if LWIP_IPV4
|
||||
{
|
||||
return inet_chksum_pseudo(p, proto, proto_len, ip_2_ip4(src), ip_2_ip4(dest));
|
||||
}
|
||||
#endif /* LWIP_IPV4 */
|
||||
}
|
||||
|
||||
/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */
|
||||
static u16_t
|
||||
inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len,
|
||||
u16_t chksum_len, u32_t acc)
|
||||
{
|
||||
struct pbuf *q;
|
||||
u8_t swapped;
|
||||
u8_t swapped = 0;
|
||||
u16_t chklen;
|
||||
|
||||
acc = 0;
|
||||
swapped = 0;
|
||||
/* iterate through all pbuf in chain */
|
||||
for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
|
||||
for (q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
|
||||
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
|
||||
(void *)q, (void *)q->next));
|
||||
chklen = q->len;
|
||||
@@ -365,23 +427,120 @@ inet_chksum_pseudo_partial(struct pbuf *p,
|
||||
if (swapped) {
|
||||
acc = SWAP_BYTES_IN_WORD(acc);
|
||||
}
|
||||
addr = ip4_addr_get_u32(src);
|
||||
acc += (addr & 0xffffUL);
|
||||
acc += ((addr >> 16) & 0xffffUL);
|
||||
addr = ip4_addr_get_u32(dest);
|
||||
acc += (addr & 0xffffUL);
|
||||
acc += ((addr >> 16) & 0xffffUL);
|
||||
acc += (u32_t)htons((u16_t)proto);
|
||||
acc += (u32_t)htons(proto_len);
|
||||
|
||||
acc += (u32_t)lwip_htons((u16_t)proto);
|
||||
acc += (u32_t)lwip_htons(proto_len);
|
||||
|
||||
/* Fold 32-bit sum to 16 bits
|
||||
calling this twice is propably faster than if statements... */
|
||||
calling this twice is probably faster than if statements... */
|
||||
acc = FOLD_U32T(acc);
|
||||
acc = FOLD_U32T(acc);
|
||||
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
|
||||
return (u16_t)~(acc & 0xffffUL);
|
||||
}
|
||||
|
||||
#if LWIP_IPV4
|
||||
/* inet_chksum_pseudo_partial:
|
||||
*
|
||||
* Calculates the IPv4 pseudo Internet checksum used by TCP and UDP for a pbuf chain.
|
||||
* IP addresses are expected to be in network byte order.
|
||||
*
|
||||
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
|
||||
* @param src source ip address (used for checksum of pseudo header)
|
||||
* @param dst destination ip address (used for checksum of pseudo header)
|
||||
* @param proto ip protocol (used for checksum of pseudo header)
|
||||
* @param proto_len length of the ip data part (used for checksum of pseudo header)
|
||||
* @return checksum (as u16_t) to be saved directly in the protocol header
|
||||
*/
|
||||
u16_t
|
||||
inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
|
||||
u16_t chksum_len, const ip4_addr_t *src, const ip4_addr_t *dest)
|
||||
{
|
||||
u32_t acc;
|
||||
u32_t addr;
|
||||
|
||||
addr = ip4_addr_get_u32(src);
|
||||
acc = (addr & 0xffffUL);
|
||||
acc += ((addr >> 16) & 0xffffUL);
|
||||
addr = ip4_addr_get_u32(dest);
|
||||
acc += (addr & 0xffffUL);
|
||||
acc += ((addr >> 16) & 0xffffUL);
|
||||
/* fold down to 16 bits */
|
||||
acc = FOLD_U32T(acc);
|
||||
acc = FOLD_U32T(acc);
|
||||
|
||||
return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc);
|
||||
}
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
#if LWIP_IPV6
|
||||
/**
|
||||
* Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain.
|
||||
* IPv6 addresses are expected to be in network byte order. Will only compute for a
|
||||
* portion of the payload.
|
||||
*
|
||||
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
|
||||
* @param proto ipv6 protocol/next header (used for checksum of pseudo header)
|
||||
* @param proto_len length of the ipv6 payload (used for checksum of pseudo header)
|
||||
* @param chksum_len number of payload bytes used to compute chksum
|
||||
* @param src source ipv6 address (used for checksum of pseudo header)
|
||||
* @param dest destination ipv6 address (used for checksum of pseudo header)
|
||||
* @return checksum (as u16_t) to be saved directly in the protocol header
|
||||
*/
|
||||
u16_t
|
||||
ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
|
||||
u16_t chksum_len, const ip6_addr_t *src, const ip6_addr_t *dest)
|
||||
{
|
||||
u32_t acc = 0;
|
||||
u32_t addr;
|
||||
u8_t addr_part;
|
||||
|
||||
for (addr_part = 0; addr_part < 4; addr_part++) {
|
||||
addr = src->addr[addr_part];
|
||||
acc += (addr & 0xffffUL);
|
||||
acc += ((addr >> 16) & 0xffffUL);
|
||||
addr = dest->addr[addr_part];
|
||||
acc += (addr & 0xffffUL);
|
||||
acc += ((addr >> 16) & 0xffffUL);
|
||||
}
|
||||
/* fold down to 16 bits */
|
||||
acc = FOLD_U32T(acc);
|
||||
acc = FOLD_U32T(acc);
|
||||
|
||||
return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc);
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
/* ip_chksum_pseudo_partial:
|
||||
*
|
||||
* Calculates the IPv4 or IPv6 pseudo Internet checksum used by TCP and UDP for a pbuf chain.
|
||||
*
|
||||
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
|
||||
* @param src source ip address (used for checksum of pseudo header)
|
||||
* @param dst destination ip address (used for checksum of pseudo header)
|
||||
* @param proto ip protocol (used for checksum of pseudo header)
|
||||
* @param proto_len length of the ip data part (used for checksum of pseudo header)
|
||||
* @return checksum (as u16_t) to be saved directly in the protocol header
|
||||
*/
|
||||
u16_t
|
||||
ip_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
|
||||
u16_t chksum_len, const ip_addr_t *src, const ip_addr_t *dest)
|
||||
{
|
||||
#if LWIP_IPV6
|
||||
if (IP_IS_V6(dest)) {
|
||||
return ip6_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ip_2_ip6(src), ip_2_ip6(dest));
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
else
|
||||
#endif /* LWIP_IPV4 && LWIP_IPV6 */
|
||||
#if LWIP_IPV4
|
||||
{
|
||||
return inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ip_2_ip4(src), ip_2_ip4(dest));
|
||||
}
|
||||
#endif /* LWIP_IPV4 */
|
||||
}
|
||||
|
||||
/* inet_chksum:
|
||||
*
|
||||
* Calculates the Internet checksum over a portion of memory. Used primarily for IP
|
||||
@@ -393,9 +552,9 @@ inet_chksum_pseudo_partial(struct pbuf *p,
|
||||
*/
|
||||
|
||||
u16_t
|
||||
inet_chksum(void *dataptr, u16_t len)
|
||||
inet_chksum(const void *dataptr, u16_t len)
|
||||
{
|
||||
return ~LWIP_CHKSUM(dataptr, len);
|
||||
return (u16_t)~(unsigned int)LWIP_CHKSUM(dataptr, len);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -414,7 +573,7 @@ inet_chksum_pbuf(struct pbuf *p)
|
||||
|
||||
acc = 0;
|
||||
swapped = 0;
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
acc += LWIP_CHKSUM(q->payload, q->len);
|
||||
acc = FOLD_U32T(acc);
|
||||
if (q->len % 2 != 0) {
|
||||
319
src/core/init.c
319
src/core/init.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,23 +17,22 @@
|
||||
* 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>
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
@@ -49,13 +48,37 @@
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/raw.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/tcp_impl.h"
|
||||
#include "lwip/snmp_msg.h"
|
||||
#include "lwip/autoip.h"
|
||||
#include "lwip/priv/tcp_priv.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/timers.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "lwip/timeouts.h"
|
||||
#include "lwip/etharp.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/nd6.h"
|
||||
#include "lwip/mld6.h"
|
||||
#include "lwip/api.h"
|
||||
|
||||
#include "netif/ppp/ppp_opts.h"
|
||||
#include "netif/ppp/ppp_impl.h"
|
||||
|
||||
#ifndef LWIP_SKIP_PACKING_CHECK
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct packed_struct_test
|
||||
{
|
||||
PACK_STRUCT_FLD_8(u8_t dummy1);
|
||||
PACK_STRUCT_FIELD(u32_t dummy2);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
#define PACKED_STRUCT_TEST_EXPECTED_SIZE 5
|
||||
|
||||
#endif
|
||||
|
||||
/* Compile-time sanity checks for configuration errors.
|
||||
* These can be done independently of LWIP_DEBUG, without penalty.
|
||||
@@ -66,27 +89,19 @@
|
||||
#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV)
|
||||
#error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (!LWIP_ARP && ARP_QUEUEING)
|
||||
#error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (!LWIP_UDP && LWIP_UDPLITE)
|
||||
#error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (!LWIP_UDP && LWIP_SNMP)
|
||||
#error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (!LWIP_UDP && LWIP_DHCP)
|
||||
#error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (!LWIP_UDP && LWIP_IGMP)
|
||||
#error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (!LWIP_UDP && LWIP_SNMP)
|
||||
#error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||
#if (!LWIP_UDP && LWIP_MULTICAST_TX_OPTIONS)
|
||||
#error "If you want to use IGMP/LWIP_MULTICAST_TX_OPTIONS, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (!LWIP_UDP && LWIP_DNS)
|
||||
#error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if !MEMP_MEM_MALLOC /* MEMP_NUM_* checks are disabled when not using the pool allocator */
|
||||
#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0))
|
||||
#error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h"
|
||||
#endif
|
||||
@@ -99,9 +114,47 @@
|
||||
#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0))
|
||||
#error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (LWIP_TCP && (TCP_WND > 0xffff))
|
||||
#error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
|
||||
#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))
|
||||
#error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (LWIP_IGMP && !LWIP_MULTICAST_TX_OPTIONS)
|
||||
#error "If you want to use IGMP, you have to define LWIP_MULTICAST_TX_OPTIONS==1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (LWIP_IGMP && !LWIP_IPV4)
|
||||
#error "IGMP needs LWIP_IPV4 enabled in your lwipopts.h"
|
||||
#endif
|
||||
#if (LWIP_MULTICAST_TX_OPTIONS && !LWIP_IPV4)
|
||||
#error "LWIP_MULTICAST_TX_OPTIONS needs LWIP_IPV4 enabled in your lwipopts.h"
|
||||
#endif
|
||||
#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))
|
||||
#error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h"
|
||||
#endif
|
||||
/* There must be sufficient timeouts, taking into account requirements of the subsystems. */
|
||||
#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0)))
|
||||
#error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts"
|
||||
#endif
|
||||
#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))
|
||||
#error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!"
|
||||
#endif
|
||||
#endif /* !MEMP_MEM_MALLOC */
|
||||
#if LWIP_WND_SCALE
|
||||
#if (LWIP_TCP && (TCP_WND > 0xffffffff))
|
||||
#error "If you want to use TCP, TCP_WND must fit in an u32_t, so, you have to reduce it in your lwipopts.h"
|
||||
#endif
|
||||
#if (LWIP_TCP && (TCP_RCV_SCALE > 14))
|
||||
#error "The maximum valid window scale value is 14!"
|
||||
#endif
|
||||
#if (LWIP_TCP && (TCP_WND > (0xFFFFU << TCP_RCV_SCALE)))
|
||||
#error "TCP_WND is bigger than the configured LWIP_WND_SCALE allows!"
|
||||
#endif
|
||||
#if (LWIP_TCP && ((TCP_WND >> TCP_RCV_SCALE) == 0))
|
||||
#error "TCP_WND is too small for the configured LWIP_WND_SCALE (results in zero window)!"
|
||||
#endif
|
||||
#else /* LWIP_WND_SCALE */
|
||||
#if (LWIP_TCP && (TCP_WND > 0xffff))
|
||||
#error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h (or enable window scaling)"
|
||||
#endif
|
||||
#endif /* LWIP_WND_SCALE */
|
||||
#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff))
|
||||
#error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
|
||||
#endif
|
||||
@@ -111,23 +164,20 @@
|
||||
#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12)))
|
||||
#error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h"
|
||||
#endif
|
||||
#if (LWIP_TCP && TCP_LISTEN_BACKLOG && (TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))
|
||||
#if (LWIP_TCP && TCP_LISTEN_BACKLOG && ((TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff)))
|
||||
#error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t"
|
||||
#endif
|
||||
#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))
|
||||
#error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (LWIP_NETIF_API && (NO_SYS==1))
|
||||
#error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h"
|
||||
#endif
|
||||
#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))
|
||||
#error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h"
|
||||
#endif
|
||||
#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))
|
||||
#error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h"
|
||||
#if (LWIP_PPP_API && (NO_SYS==1))
|
||||
#error "If you want to use PPP API, you have to define NO_SYS=0 in your lwipopts.h"
|
||||
#endif
|
||||
#if (!LWIP_NETCONN && LWIP_SOCKET)
|
||||
#error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h"
|
||||
#if (LWIP_PPP_API && (PPP_SUPPORT==0))
|
||||
#error "If you want to use PPP API, you have to enable PPP_SUPPORT in your lwipopts.h"
|
||||
#endif
|
||||
#if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP)
|
||||
#error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h"
|
||||
@@ -138,22 +188,9 @@
|
||||
#if (!LWIP_ARP && LWIP_AUTOIP)
|
||||
#error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (LWIP_SNMP && (SNMP_CONCURRENT_REQUESTS<=0))
|
||||
#error "If you want to use SNMP, you have to define SNMP_CONCURRENT_REQUESTS>=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0))
|
||||
#error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h"
|
||||
#endif
|
||||
#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API)))
|
||||
#error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h"
|
||||
#endif
|
||||
/* There must be sufficient timeouts, taking into account requirements of the subsystems. */
|
||||
#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT))
|
||||
#error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts"
|
||||
#endif
|
||||
#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))
|
||||
#error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!"
|
||||
#endif
|
||||
#if (MEM_LIBC_MALLOC && MEM_USE_POOLS)
|
||||
#error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h"
|
||||
#endif
|
||||
@@ -163,30 +200,50 @@
|
||||
#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT)
|
||||
#error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf"
|
||||
#endif
|
||||
#if (TCP_QUEUE_OOSEQ && !LWIP_TCP)
|
||||
#error "TCP_QUEUE_OOSEQ requires LWIP_TCP"
|
||||
#endif
|
||||
#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT)))
|
||||
#error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST"
|
||||
#endif
|
||||
#if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT
|
||||
#error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on"
|
||||
#if PPP_SUPPORT && !PPPOS_SUPPORT && !PPPOE_SUPPORT && !PPPOL2TP_SUPPORT
|
||||
#error "PPP_SUPPORT needs at least one of PPPOS_SUPPORT, PPPOE_SUPPORT or PPPOL2TP_SUPPORT turned on"
|
||||
#endif
|
||||
#if PPP_SUPPORT && !PPP_IPV4_SUPPORT && !PPP_IPV6_SUPPORT
|
||||
#error "PPP_SUPPORT needs PPP_IPV4_SUPPORT and/or PPP_IPV6_SUPPORT turned on"
|
||||
#endif
|
||||
#if PPP_SUPPORT && PPP_IPV4_SUPPORT && !LWIP_IPV4
|
||||
#error "PPP_IPV4_SUPPORT needs LWIP_IPV4 turned on"
|
||||
#endif
|
||||
#if PPP_SUPPORT && PPP_IPV6_SUPPORT && !LWIP_IPV6
|
||||
#error "PPP_IPV6_SUPPORT needs LWIP_IPV6 turned on"
|
||||
#endif
|
||||
#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT)
|
||||
#error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT"
|
||||
#endif
|
||||
#if LWIP_IGMP && !defined(LWIP_RAND)
|
||||
#error "When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value"
|
||||
#endif
|
||||
#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING
|
||||
#error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too"
|
||||
#endif
|
||||
#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE
|
||||
#error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets"
|
||||
#endif
|
||||
#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF
|
||||
#error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues"
|
||||
#if LWIP_NETCONN && LWIP_TCP
|
||||
#if NETCONN_COPY != TCP_WRITE_FLAG_COPY
|
||||
#error "NETCONN_COPY != TCP_WRITE_FLAG_COPY"
|
||||
#endif
|
||||
#if NETCONN_MORE != TCP_WRITE_FLAG_MORE
|
||||
#error "NETCONN_MORE != TCP_WRITE_FLAG_MORE"
|
||||
#endif
|
||||
#endif /* LWIP_NETCONN && LWIP_TCP */
|
||||
#if LWIP_SOCKET
|
||||
/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */
|
||||
#if SO_REUSEADDR != SOF_REUSEADDR
|
||||
#error "WARNING: SO_REUSEADDR != SOF_REUSEADDR"
|
||||
#endif
|
||||
#if SO_KEEPALIVE != SOF_KEEPALIVE
|
||||
#error "WARNING: SO_KEEPALIVE != SOF_KEEPALIVE"
|
||||
#endif
|
||||
#if SO_BROADCAST != SOF_BROADCAST
|
||||
#error "WARNING: SO_BROADCAST != SOF_BROADCAST"
|
||||
#endif
|
||||
#endif /* LWIP_SOCKET */
|
||||
|
||||
|
||||
/* Compile-time checks for deprecated options.
|
||||
@@ -194,9 +251,6 @@
|
||||
#ifdef MEMP_NUM_TCPIP_MSG
|
||||
#error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h."
|
||||
#endif
|
||||
#ifdef MEMP_NUM_API_MSG
|
||||
#error "MEMP_NUM_API_MSG option is deprecated. Remove it from your lwipopts.h."
|
||||
#endif
|
||||
#ifdef TCP_REXMIT_DEBUG
|
||||
#error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h."
|
||||
#endif
|
||||
@@ -209,58 +263,87 @@
|
||||
#ifdef ETHARP_ALWAYS_INSERT
|
||||
#error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h."
|
||||
#endif
|
||||
#if !NO_SYS && LWIP_TCPIP_CORE_LOCKING && LWIP_COMPAT_MUTEX && !defined(LWIP_COMPAT_MUTEX_ALLOWED)
|
||||
#error "LWIP_COMPAT_MUTEX cannot prevent priority inversion. It is recommended to implement priority-aware mutexes. (Define LWIP_COMPAT_MUTEX_ALLOWED to disable this error.)"
|
||||
#endif
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
static void
|
||||
lwip_sanity_check(void)
|
||||
{
|
||||
/* Warnings */
|
||||
#if LWIP_NETCONN
|
||||
if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB))
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN\n"));
|
||||
#endif /* LWIP_NETCONN */
|
||||
#ifndef LWIP_DISABLE_TCP_SANITY_CHECKS
|
||||
#define LWIP_DISABLE_TCP_SANITY_CHECKS 0
|
||||
#endif
|
||||
#ifndef LWIP_DISABLE_MEMP_SANITY_CHECKS
|
||||
#define LWIP_DISABLE_MEMP_SANITY_CHECKS 0
|
||||
#endif
|
||||
|
||||
/* MEMP sanity checks */
|
||||
#if MEMP_MEM_MALLOC
|
||||
#if !LWIP_DISABLE_MEMP_SANITY_CHECKS
|
||||
#if LWIP_NETCONN || LWIP_SOCKET
|
||||
#if !MEMP_NUM_NETCONN && LWIP_SOCKET
|
||||
#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN cannot be 0 when using sockets!"
|
||||
#endif
|
||||
#else /* MEMP_MEM_MALLOC */
|
||||
#if MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB)
|
||||
#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN. If you know what you are doing, define LWIP_DISABLE_MEMP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#endif /* LWIP_NETCONN || LWIP_SOCKET */
|
||||
#endif /* !LWIP_DISABLE_MEMP_SANITY_CHECKS */
|
||||
#if MEM_USE_POOLS
|
||||
#error "MEMP_MEM_MALLOC and MEM_USE_POOLS cannot be enabled at the same time"
|
||||
#endif
|
||||
#ifdef LWIP_HOOK_MEMP_AVAILABLE
|
||||
#error "LWIP_HOOK_MEMP_AVAILABLE doesn't make sense with MEMP_MEM_MALLOC"
|
||||
#endif
|
||||
#endif /* MEMP_MEM_MALLOC */
|
||||
|
||||
/* TCP sanity checks */
|
||||
#if !LWIP_DISABLE_TCP_SANITY_CHECKS
|
||||
#if LWIP_TCP
|
||||
if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n"));
|
||||
if (TCP_SND_BUF < 2 * TCP_MSS)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly\n"));
|
||||
if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS)))
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n"));
|
||||
if (TCP_SNDLOWAT >= TCP_SND_BUF)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF.\n"));
|
||||
if (TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN.\n"));
|
||||
if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE))
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n"));
|
||||
if (TCP_WND < TCP_MSS)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n"));
|
||||
#if !MEMP_MEM_MALLOC && (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)
|
||||
#error "lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#if TCP_SND_BUF < (2 * TCP_MSS)
|
||||
#error "lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#if TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF / TCP_MSS))
|
||||
#error "lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#if TCP_SNDLOWAT >= TCP_SND_BUF
|
||||
#error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#if TCP_SNDLOWAT >= (0xFFFF - (4 * TCP_MSS))
|
||||
#error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must at least be 4*MSS below u16_t overflow!"
|
||||
#endif
|
||||
#if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN
|
||||
#error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#if !MEMP_MEM_MALLOC && PBUF_POOL_SIZE && (PBUF_POOL_BUFSIZE <= (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))
|
||||
#error "lwip_sanity_check: WARNING: PBUF_POOL_BUFSIZE does not provide enough space for protocol headers. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#if !MEMP_MEM_MALLOC && PBUF_POOL_SIZE && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))))
|
||||
#error "lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - protocol headers). If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#if TCP_WND < TCP_MSS
|
||||
#error "lwip_sanity_check: WARNING: TCP_WND is smaller than MSS. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
|
||||
#endif
|
||||
#endif /* LWIP_TCP */
|
||||
#if LWIP_SOCKET
|
||||
/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */
|
||||
if (SO_ACCEPTCONN != SOF_ACCEPTCONN)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_ACCEPTCONN != SOF_ACCEPTCONN\n"));
|
||||
if (SO_REUSEADDR != SOF_REUSEADDR)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_REUSEADDR != SOF_REUSEADDR\n"));
|
||||
if (SO_KEEPALIVE != SOF_KEEPALIVE)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_KEEPALIVE != SOF_KEEPALIVE\n"));
|
||||
if (SO_BROADCAST != SOF_BROADCAST)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_BROADCAST != SOF_BROADCAST\n"));
|
||||
if (SO_LINGER != SOF_LINGER)
|
||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_LINGER != SOF_LINGER\n"));
|
||||
#endif /* LWIP_SOCKET */
|
||||
}
|
||||
#else /* LWIP_DEBUG */
|
||||
#define lwip_sanity_check()
|
||||
#endif /* LWIP_DEBUG */
|
||||
#endif /* !LWIP_DISABLE_TCP_SANITY_CHECKS */
|
||||
|
||||
/**
|
||||
* Perform Sanity check of user-configurable values, and initialize all modules.
|
||||
* @ingroup lwip_nosys
|
||||
* Initialize all modules.
|
||||
* Use this in NO_SYS mode. Use tcpip_init() otherwise.
|
||||
*/
|
||||
void
|
||||
lwip_init(void)
|
||||
{
|
||||
/* Sanity check user-configurable values */
|
||||
lwip_sanity_check();
|
||||
#ifndef LWIP_SKIP_CONST_CHECK
|
||||
int a;
|
||||
LWIP_UNUSED_ARG(a);
|
||||
LWIP_ASSERT("LWIP_CONST_CAST not implemented correctly. Check your lwIP port.", LWIP_CONST_CAST(void*, &a) == &a);
|
||||
#endif
|
||||
#ifndef LWIP_SKIP_PACKING_CHECK
|
||||
LWIP_ASSERT("Struct packing not implemented correctly. Check your lwIP port.", sizeof(struct packed_struct_test) == PACKED_STRUCT_TEST_EXPECTED_SIZE);
|
||||
#endif
|
||||
|
||||
/* Modules initialization */
|
||||
stats_init();
|
||||
@@ -271,13 +354,12 @@ lwip_init(void)
|
||||
memp_init();
|
||||
pbuf_init();
|
||||
netif_init();
|
||||
#if LWIP_SOCKET
|
||||
lwip_socket_init();
|
||||
#endif /* LWIP_SOCKET */
|
||||
#if LWIP_IPV4
|
||||
ip_init();
|
||||
#if LWIP_ARP
|
||||
etharp_init();
|
||||
#endif /* LWIP_ARP */
|
||||
#endif /* LWIP_IPV4 */
|
||||
#if LWIP_RAW
|
||||
raw_init();
|
||||
#endif /* LWIP_RAW */
|
||||
@@ -287,19 +369,16 @@ lwip_init(void)
|
||||
#if LWIP_TCP
|
||||
tcp_init();
|
||||
#endif /* LWIP_TCP */
|
||||
#if LWIP_SNMP
|
||||
snmp_init();
|
||||
#endif /* LWIP_SNMP */
|
||||
#if LWIP_AUTOIP
|
||||
autoip_init();
|
||||
#endif /* LWIP_AUTOIP */
|
||||
#if LWIP_IGMP
|
||||
igmp_init();
|
||||
#endif /* LWIP_IGMP */
|
||||
#if LWIP_DNS
|
||||
dns_init();
|
||||
#endif /* LWIP_DNS */
|
||||
|
||||
#if PPP_SUPPORT
|
||||
ppp_init();
|
||||
#endif
|
||||
|
||||
#if LWIP_TIMERS
|
||||
sys_timeouts_init();
|
||||
#endif /* LWIP_TIMERS */
|
||||
|
||||
124
src/core/ip.c
Normal file
124
src/core/ip.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* @file
|
||||
* Common IPv4 and IPv6 code
|
||||
*
|
||||
* @defgroup ip IP
|
||||
* @ingroup callbackstyle_api
|
||||
*
|
||||
* @defgroup ip4 IPv4
|
||||
* @ingroup ip
|
||||
*
|
||||
* @defgroup ip6 IPv6
|
||||
* @ingroup ip
|
||||
*
|
||||
* @defgroup ipaddr IP address handling
|
||||
* @ingroup infrastructure
|
||||
*
|
||||
* @defgroup ip4addr IPv4 only
|
||||
* @ingroup ipaddr
|
||||
*
|
||||
* @defgroup ip6addr IPv6 only
|
||||
* @ingroup ipaddr
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_IPV4 || LWIP_IPV6
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/ip.h"
|
||||
|
||||
/** Global data for both IPv4 and IPv6 */
|
||||
struct ip_globals ip_data;
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
|
||||
const ip_addr_t ip_addr_any_type = IPADDR_ANY_TYPE_INIT;
|
||||
|
||||
/**
|
||||
* @ingroup ipaddr
|
||||
* Convert IP address string (both versions) to numeric.
|
||||
* The version is auto-detected from the string.
|
||||
*
|
||||
* @param cp IP address string to convert
|
||||
* @param addr conversion result is stored here
|
||||
* @return 1 on success, 0 on error
|
||||
*/
|
||||
int
|
||||
ipaddr_aton(const char *cp, ip_addr_t *addr)
|
||||
{
|
||||
if (cp != NULL) {
|
||||
const char* c;
|
||||
for (c = cp; *c != 0; c++) {
|
||||
if (*c == ':') {
|
||||
/* contains a colon: IPv6 address */
|
||||
if (addr) {
|
||||
IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V6);
|
||||
}
|
||||
return ip6addr_aton(cp, ip_2_ip6(addr));
|
||||
} else if (*c == '.') {
|
||||
/* contains a dot: IPv4 address */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* call ip4addr_aton as fallback or if IPv4 was found */
|
||||
if (addr) {
|
||||
IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V4);
|
||||
}
|
||||
return ip4addr_aton(cp, ip_2_ip4(addr));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup lwip_nosys
|
||||
* If both IP versions are enabled, this function can dispatch packets to the correct one.
|
||||
* Don't call directly, pass to netif_add() and call netif->input().
|
||||
*/
|
||||
err_t
|
||||
ip_input(struct pbuf *p, struct netif *inp)
|
||||
{
|
||||
if (p != NULL) {
|
||||
if (IP_HDR_GET_VERSION(p->payload) == 6) {
|
||||
return ip6_input(p, inp);
|
||||
}
|
||||
return ip4_input(p, inp);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
#endif /* LWIP_IPV4 && LWIP_IPV6 */
|
||||
|
||||
#endif /* LWIP_IPV4 || LWIP_IPV6 */
|
||||
@@ -2,6 +2,28 @@
|
||||
* @file
|
||||
* AutoIP Automatic LinkLocal IP Configuration
|
||||
*
|
||||
* This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
|
||||
* with RFC 3927.
|
||||
*
|
||||
* @defgroup autoip AUTOIP
|
||||
* @ingroup ip4
|
||||
* AUTOIP related functions
|
||||
* USAGE:
|
||||
*
|
||||
* define @ref LWIP_AUTOIP 1 in your lwipopts.h
|
||||
* Options:
|
||||
* AUTOIP_TMR_INTERVAL msecs,
|
||||
* I recommend a value of 100. The value must divide 1000 with a remainder almost 0.
|
||||
* Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....
|
||||
*
|
||||
* Without DHCP:
|
||||
* - Call autoip_start() after netif_add().
|
||||
*
|
||||
* With DHCP:
|
||||
* - define @ref LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.
|
||||
* - Configure your DHCP Client.
|
||||
*
|
||||
* @see netifapi_autoip
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -32,58 +54,22 @@
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* Author: Dominik Spies <kontakt@dspies.de>
|
||||
*
|
||||
* This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
|
||||
* with RFC 3927.
|
||||
*
|
||||
*
|
||||
* Please coordinate changes and requests with Dominik Spies
|
||||
* <kontakt@dspies.de>
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* USAGE:
|
||||
*
|
||||
* define LWIP_AUTOIP 1 in your lwipopts.h
|
||||
*
|
||||
* If you don't use tcpip.c (so, don't call, you don't call tcpip_init):
|
||||
* - First, call autoip_init().
|
||||
* - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces,
|
||||
* that should be defined in autoip.h.
|
||||
* I recommend a value of 100. The value must divide 1000 with a remainder almost 0.
|
||||
* Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....
|
||||
*
|
||||
* Without DHCP:
|
||||
* - Call autoip_start() after netif_add().
|
||||
*
|
||||
* With DHCP:
|
||||
* - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.
|
||||
* - Configure your DHCP Client.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
|
||||
#if LWIP_IPV4 && LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/udp.h"
|
||||
/* #include "lwip/udp.h" */
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/autoip.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "lwip/etharp.h"
|
||||
#include "lwip/prot/autoip.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* 169.254.0.0 */
|
||||
#define AUTOIP_NET 0xA9FE0000
|
||||
/* 169.254.1.0 */
|
||||
#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100)
|
||||
/* 169.254.254.255 */
|
||||
#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF)
|
||||
|
||||
|
||||
/** Pseudo random macro based on netif informations.
|
||||
* You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */
|
||||
#ifndef LWIP_AUTOIP_RAND
|
||||
@@ -91,7 +77,7 @@
|
||||
((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \
|
||||
((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \
|
||||
((u32_t)((netif->hwaddr[4]) & 0xff))) + \
|
||||
(netif->autoip?netif->autoip->tried_llipaddr:0))
|
||||
(netif_autoip_data(netif)? netif_autoip_data(netif)->tried_llipaddr : 0))
|
||||
#endif /* LWIP_AUTOIP_RAND */
|
||||
|
||||
/**
|
||||
@@ -100,54 +86,34 @@
|
||||
*/
|
||||
#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
|
||||
#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
|
||||
htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
|
||||
lwip_htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
|
||||
((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))
|
||||
#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */
|
||||
|
||||
/* static functions */
|
||||
static void autoip_handle_arp_conflict(struct netif *netif);
|
||||
|
||||
/* creates a pseudo random LL IP-Address for a network interface */
|
||||
static void autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr);
|
||||
|
||||
/* sends an ARP probe */
|
||||
static err_t autoip_arp_probe(struct netif *netif);
|
||||
|
||||
/* sends an ARP announce */
|
||||
static err_t autoip_arp_announce(struct netif *netif);
|
||||
|
||||
/* configure interface for use with current LL IP-Address */
|
||||
static err_t autoip_bind(struct netif *netif);
|
||||
|
||||
/* start sending probes for llipaddr */
|
||||
static void autoip_start_probing(struct netif *netif);
|
||||
|
||||
/**
|
||||
* Initialize this module
|
||||
*/
|
||||
void
|
||||
autoip_init(void)
|
||||
{
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n"));
|
||||
}
|
||||
|
||||
/** Set a statically allocated struct autoip to work with.
|
||||
* @ingroup autoip
|
||||
* Set a statically allocated struct autoip to work with.
|
||||
* Using this prevents autoip_start to allocate it using mem_malloc.
|
||||
*
|
||||
* @param netif the netif for which to set the struct autoip
|
||||
* @param dhcp (uninitialised) dhcp struct allocated by the application
|
||||
* @param autoip (uninitialised) autoip struct allocated by the application
|
||||
*/
|
||||
void
|
||||
autoip_set_struct(struct netif *netif, struct autoip *autoip)
|
||||
{
|
||||
LWIP_ASSERT("netif != NULL", netif != NULL);
|
||||
LWIP_ASSERT("autoip != NULL", autoip != NULL);
|
||||
LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL);
|
||||
LWIP_ASSERT("netif already has a struct autoip set",
|
||||
netif_autoip_data(netif) == NULL);
|
||||
|
||||
/* clear data structure */
|
||||
memset(autoip, 0, sizeof(struct autoip));
|
||||
/* autoip->state = AUTOIP_STATE_OFF; */
|
||||
netif->autoip = autoip;
|
||||
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip);
|
||||
}
|
||||
|
||||
/** Restart AutoIP client and check the next address (conflict detected)
|
||||
@@ -157,7 +123,8 @@ autoip_set_struct(struct netif *netif, struct autoip *autoip)
|
||||
static void
|
||||
autoip_restart(struct netif *netif)
|
||||
{
|
||||
netif->autoip->tried_llipaddr++;
|
||||
struct autoip* autoip = netif_autoip_data(netif);
|
||||
autoip->tried_llipaddr++;
|
||||
autoip_start(netif);
|
||||
}
|
||||
|
||||
@@ -167,30 +134,27 @@ autoip_restart(struct netif *netif)
|
||||
static void
|
||||
autoip_handle_arp_conflict(struct netif *netif)
|
||||
{
|
||||
/* Somehow detect if we are defending or retreating */
|
||||
unsigned char defend = 1; /* tbd */
|
||||
struct autoip* autoip = netif_autoip_data(netif);
|
||||
|
||||
if(defend) {
|
||||
if(netif->autoip->lastconflict > 0) {
|
||||
/* retreat, there was a conflicting ARP in the last
|
||||
* DEFEND_INTERVAL seconds
|
||||
*/
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
|
||||
/* RFC3927, 2.5 "Conflict Detection and Defense" allows two options where
|
||||
a) means retreat on the first conflict and
|
||||
b) allows to keep an already configured address when having only one
|
||||
conflict in 10 seconds
|
||||
We use option b) since it helps to improve the chance that one of the two
|
||||
conflicting hosts may be able to retain its address. */
|
||||
|
||||
/* TODO: close all TCP sessions */
|
||||
autoip_restart(netif);
|
||||
} else {
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
|
||||
autoip_arp_announce(netif);
|
||||
netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||
}
|
||||
if (autoip->lastconflict > 0) {
|
||||
/* retreat, there was a conflicting ARP in the last DEFEND_INTERVAL seconds */
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
|
||||
|
||||
/* Active TCP sessions are aborted when removing the ip addresss */
|
||||
autoip_restart(netif);
|
||||
} else {
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("autoip_handle_arp_conflict(): we do not defend, retreating\n"));
|
||||
/* TODO: close all TCP sessions */
|
||||
autoip_restart(netif);
|
||||
("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
|
||||
autoip_arp_announce(netif);
|
||||
autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,16 +165,18 @@ autoip_handle_arp_conflict(struct netif *netif)
|
||||
* @param ipaddr ip address to initialize
|
||||
*/
|
||||
static void
|
||||
autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr)
|
||||
autoip_create_addr(struct netif *netif, ip4_addr_t *ipaddr)
|
||||
{
|
||||
struct autoip* autoip = netif_autoip_data(netif);
|
||||
|
||||
/* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255
|
||||
* compliant to RFC 3927 Section 2.1
|
||||
* We have 254 * 256 possibilities */
|
||||
|
||||
u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
|
||||
addr += netif->autoip->tried_llipaddr;
|
||||
u32_t addr = lwip_ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
|
||||
addr += autoip->tried_llipaddr;
|
||||
addr = AUTOIP_NET | (addr & 0xffff);
|
||||
/* Now, 169.254.0.0 <= addr <= 169.254.255.255 */
|
||||
/* Now, 169.254.0.0 <= addr <= 169.254.255.255 */
|
||||
|
||||
if (addr < AUTOIP_RANGE_START) {
|
||||
addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
|
||||
@@ -220,11 +186,11 @@ autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr)
|
||||
}
|
||||
LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
|
||||
(addr <= AUTOIP_RANGE_END));
|
||||
ip4_addr_set_u32(ipaddr, htonl(addr));
|
||||
|
||||
ip4_addr_set_u32(ipaddr, lwip_htonl(addr));
|
||||
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
(u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr),
|
||||
(u16_t)(autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr),
|
||||
ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
|
||||
}
|
||||
|
||||
@@ -236,9 +202,9 @@ autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr)
|
||||
static err_t
|
||||
autoip_arp_probe(struct netif *netif)
|
||||
{
|
||||
return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast,
|
||||
(struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, ðzero,
|
||||
&netif->autoip->llipaddr, ARP_REQUEST);
|
||||
struct autoip* autoip = netif_autoip_data(netif);
|
||||
/* this works because netif->ip_addr is ANY */
|
||||
return etharp_request(netif, &autoip->llipaddr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,9 +215,7 @@ autoip_arp_probe(struct netif *netif)
|
||||
static err_t
|
||||
autoip_arp_announce(struct netif *netif)
|
||||
{
|
||||
return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast,
|
||||
(struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, ðzero,
|
||||
&netif->autoip->llipaddr, ARP_REQUEST);
|
||||
return etharp_gratuitous(netif);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,8 +226,8 @@ autoip_arp_announce(struct netif *netif)
|
||||
static err_t
|
||||
autoip_bind(struct netif *netif)
|
||||
{
|
||||
struct autoip *autoip = netif->autoip;
|
||||
ip_addr_t sn_mask, gw_addr;
|
||||
struct autoip* autoip = netif_autoip_data(netif);
|
||||
ip4_addr_t sn_mask, gw_addr;
|
||||
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||
("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
@@ -274,17 +238,14 @@ autoip_bind(struct netif *netif)
|
||||
IP4_ADDR(&sn_mask, 255, 255, 0, 0);
|
||||
IP4_ADDR(&gw_addr, 0, 0, 0, 0);
|
||||
|
||||
netif_set_ipaddr(netif, &autoip->llipaddr);
|
||||
netif_set_netmask(netif, &sn_mask);
|
||||
netif_set_gw(netif, &gw_addr);
|
||||
|
||||
/* bring the interface up */
|
||||
netif_set_up(netif);
|
||||
netif_set_addr(netif, &autoip->llipaddr, &sn_mask, &gw_addr);
|
||||
/* interface is used by routing now that an address is set */
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup autoip
|
||||
* Start AutoIP client
|
||||
*
|
||||
* @param netif network interface on which start the AutoIP client
|
||||
@@ -292,42 +253,38 @@ autoip_bind(struct netif *netif)
|
||||
err_t
|
||||
autoip_start(struct netif *netif)
|
||||
{
|
||||
struct autoip *autoip = netif->autoip;
|
||||
struct autoip* autoip = netif_autoip_data(netif);
|
||||
err_t result = ERR_OK;
|
||||
|
||||
if(netif_is_up(netif)) {
|
||||
netif_set_down(netif);
|
||||
}
|
||||
LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;);
|
||||
|
||||
/* Set IP-Address, Netmask and Gateway to 0 to make sure that
|
||||
* ARP Packets are formed correctly
|
||||
*/
|
||||
ip_addr_set_zero(&netif->ip_addr);
|
||||
ip_addr_set_zero(&netif->netmask);
|
||||
ip_addr_set_zero(&netif->gw);
|
||||
netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
|
||||
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0],
|
||||
netif->name[1], (u16_t)netif->num));
|
||||
if(autoip == NULL) {
|
||||
if (autoip == NULL) {
|
||||
/* no AutoIP client attached yet? */
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||
("autoip_start(): starting new AUTOIP client\n"));
|
||||
autoip = (struct autoip *)mem_malloc(sizeof(struct autoip));
|
||||
if(autoip == NULL) {
|
||||
if (autoip == NULL) {
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||
("autoip_start(): could not allocate autoip\n"));
|
||||
return ERR_MEM;
|
||||
}
|
||||
memset(autoip, 0, sizeof(struct autoip));
|
||||
/* store this AutoIP client in the netif */
|
||||
netif->autoip = autoip;
|
||||
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip);
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));
|
||||
} else {
|
||||
autoip->state = AUTOIP_STATE_OFF;
|
||||
autoip->ttw = 0;
|
||||
autoip->sent_num = 0;
|
||||
ip_addr_set_zero(&autoip->llipaddr);
|
||||
ip4_addr_set_zero(&autoip->llipaddr);
|
||||
autoip->lastconflict = 0;
|
||||
}
|
||||
|
||||
@@ -340,27 +297,27 @@ autoip_start(struct netif *netif)
|
||||
static void
|
||||
autoip_start_probing(struct netif *netif)
|
||||
{
|
||||
struct autoip *autoip = netif->autoip;
|
||||
struct autoip* autoip = netif_autoip_data(netif);
|
||||
|
||||
autoip->state = AUTOIP_STATE_PROBING;
|
||||
autoip->sent_num = 0;
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
|
||||
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
|
||||
ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
|
||||
ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
|
||||
|
||||
/* time to wait to first probe, this is randomly
|
||||
* choosen out of 0 to PROBE_WAIT seconds.
|
||||
* chosen out of 0 to PROBE_WAIT seconds.
|
||||
* compliant to RFC 3927 Section 2.2.1
|
||||
*/
|
||||
autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND));
|
||||
|
||||
/*
|
||||
* if we tried more then MAX_CONFLICTS we must limit our rate for
|
||||
* accquiring and probing address
|
||||
* acquiring and probing address
|
||||
* compliant to RFC 3927 Section 2.2.1
|
||||
*/
|
||||
if(autoip->tried_llipaddr > MAX_CONFLICTS) {
|
||||
if (autoip->tried_llipaddr > MAX_CONFLICTS) {
|
||||
autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
@@ -374,13 +331,15 @@ autoip_start_probing(struct netif *netif)
|
||||
void
|
||||
autoip_network_changed(struct netif *netif)
|
||||
{
|
||||
if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {
|
||||
netif_set_down(netif);
|
||||
struct autoip* autoip = netif_autoip_data(netif);
|
||||
|
||||
if (autoip && (autoip->state != AUTOIP_STATE_OFF)) {
|
||||
autoip_start_probing(netif);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup autoip
|
||||
* Stop AutoIP client
|
||||
*
|
||||
* @param netif network interface on which stop the AutoIP client
|
||||
@@ -388,8 +347,14 @@ autoip_network_changed(struct netif *netif)
|
||||
err_t
|
||||
autoip_stop(struct netif *netif)
|
||||
{
|
||||
netif->autoip->state = AUTOIP_STATE_OFF;
|
||||
netif_set_down(netif);
|
||||
struct autoip* autoip = netif_autoip_data(netif);
|
||||
|
||||
if (autoip != NULL) {
|
||||
autoip->state = AUTOIP_STATE_OFF;
|
||||
if (ip4_addr_islinklocal(netif_ip4_addr(netif))) {
|
||||
netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -397,78 +362,80 @@ autoip_stop(struct netif *netif)
|
||||
* Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds
|
||||
*/
|
||||
void
|
||||
autoip_tmr()
|
||||
autoip_tmr(void)
|
||||
{
|
||||
struct netif *netif = netif_list;
|
||||
/* loop through netif's */
|
||||
while (netif != NULL) {
|
||||
struct autoip* autoip = netif_autoip_data(netif);
|
||||
/* only act on AutoIP configured interfaces */
|
||||
if (netif->autoip != NULL) {
|
||||
if(netif->autoip->lastconflict > 0) {
|
||||
netif->autoip->lastconflict--;
|
||||
if (autoip != NULL) {
|
||||
if (autoip->lastconflict > 0) {
|
||||
autoip->lastconflict--;
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||
("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n",
|
||||
(u16_t)(netif->autoip->state), netif->autoip->ttw));
|
||||
(u16_t)(autoip->state), autoip->ttw));
|
||||
|
||||
switch(netif->autoip->state) {
|
||||
if (autoip->ttw > 0) {
|
||||
autoip->ttw--;
|
||||
}
|
||||
|
||||
switch(autoip->state) {
|
||||
case AUTOIP_STATE_PROBING:
|
||||
if(netif->autoip->ttw > 0) {
|
||||
netif->autoip->ttw--;
|
||||
} else {
|
||||
if(netif->autoip->sent_num >= PROBE_NUM) {
|
||||
netif->autoip->state = AUTOIP_STATE_ANNOUNCING;
|
||||
netif->autoip->sent_num = 0;
|
||||
netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
|
||||
if (autoip->ttw == 0) {
|
||||
if (autoip->sent_num >= PROBE_NUM) {
|
||||
/* Switch to ANNOUNCING: now we can bind to an IP address and use it */
|
||||
autoip->state = AUTOIP_STATE_ANNOUNCING;
|
||||
autoip_bind(netif);
|
||||
/* autoip_bind() calls netif_set_addr(): this triggers a gratuitous ARP
|
||||
which counts as an announcement */
|
||||
autoip->sent_num = 1;
|
||||
autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
|
||||
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
|
||||
ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
|
||||
ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
|
||||
} else {
|
||||
autoip_arp_probe(netif);
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||
("autoip_tmr() PROBING Sent Probe\n"));
|
||||
netif->autoip->sent_num++;
|
||||
/* calculate time to wait to next probe */
|
||||
netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %
|
||||
((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +
|
||||
PROBE_MIN * AUTOIP_TICKS_PER_SECOND);
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() PROBING Sent Probe\n"));
|
||||
autoip->sent_num++;
|
||||
if (autoip->sent_num == PROBE_NUM) {
|
||||
/* calculate time to wait to for announce */
|
||||
autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
|
||||
} else {
|
||||
/* calculate time to wait to next probe */
|
||||
autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %
|
||||
((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +
|
||||
PROBE_MIN * AUTOIP_TICKS_PER_SECOND);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AUTOIP_STATE_ANNOUNCING:
|
||||
if(netif->autoip->ttw > 0) {
|
||||
netif->autoip->ttw--;
|
||||
} else {
|
||||
if(netif->autoip->sent_num == 0) {
|
||||
/* We are here the first time, so we waited ANNOUNCE_WAIT seconds
|
||||
* Now we can bind to an IP address and use it.
|
||||
*
|
||||
* autoip_bind calls netif_set_up. This triggers a gratuitous ARP
|
||||
* which counts as an announcement.
|
||||
*/
|
||||
autoip_bind(netif);
|
||||
} else {
|
||||
autoip_arp_announce(netif);
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||
("autoip_tmr() ANNOUNCING Sent Announce\n"));
|
||||
}
|
||||
netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||
netif->autoip->sent_num++;
|
||||
if (autoip->ttw == 0) {
|
||||
autoip_arp_announce(netif);
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() ANNOUNCING Sent Announce\n"));
|
||||
autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||
autoip->sent_num++;
|
||||
|
||||
if(netif->autoip->sent_num >= ANNOUNCE_NUM) {
|
||||
netif->autoip->state = AUTOIP_STATE_BOUND;
|
||||
netif->autoip->sent_num = 0;
|
||||
netif->autoip->ttw = 0;
|
||||
if (autoip->sent_num >= ANNOUNCE_NUM) {
|
||||
autoip->state = AUTOIP_STATE_BOUND;
|
||||
autoip->sent_num = 0;
|
||||
autoip->ttw = 0;
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
|
||||
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
|
||||
ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
|
||||
ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* nothing to do in other states */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* proceed to next network interface */
|
||||
@@ -477,7 +444,7 @@ autoip_tmr()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles every incoming ARP Packet, called by etharp_arp_input.
|
||||
* Handles every incoming ARP Packet, called by etharp_input().
|
||||
*
|
||||
* @param netif network interface to use for autoip processing
|
||||
* @param hdr Incoming ARP packet
|
||||
@@ -485,34 +452,35 @@ autoip_tmr()
|
||||
void
|
||||
autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
|
||||
{
|
||||
struct autoip* autoip = netif_autoip_data(netif);
|
||||
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n"));
|
||||
if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) {
|
||||
if ((autoip != NULL) && (autoip->state != AUTOIP_STATE_OFF)) {
|
||||
/* when ip.src == llipaddr && hw.src != netif->hwaddr
|
||||
*
|
||||
* when probing ip.dst == llipaddr && hw.src != netif->hwaddr
|
||||
* we have a conflict and must solve it
|
||||
*/
|
||||
ip_addr_t sipaddr, dipaddr;
|
||||
ip4_addr_t sipaddr, dipaddr;
|
||||
struct eth_addr netifaddr;
|
||||
ETHADDR16_COPY(netifaddr.addr, netif->hwaddr);
|
||||
|
||||
/* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
|
||||
/* Copy struct ip4_addr2 to aligned ip4_addr, to support compilers without
|
||||
* structure packing (not using structure copy which breaks strict-aliasing rules).
|
||||
*/
|
||||
IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
|
||||
IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
|
||||
|
||||
if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||
|
||||
((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&
|
||||
(netif->autoip->sent_num == 0))) {
|
||||
|
||||
if (autoip->state == AUTOIP_STATE_PROBING) {
|
||||
/* RFC 3927 Section 2.2.1:
|
||||
* from beginning to after ANNOUNCE_WAIT
|
||||
* seconds we have a conflict if
|
||||
* ip.src == llipaddr OR
|
||||
* ip.dst == llipaddr && hw.src != own hwaddr
|
||||
*/
|
||||
if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||
|
||||
(ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) &&
|
||||
if ((ip4_addr_cmp(&sipaddr, &autoip->llipaddr)) ||
|
||||
(ip4_addr_isany_val(sipaddr) &&
|
||||
ip4_addr_cmp(&dipaddr, &autoip->llipaddr) &&
|
||||
!eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
|
||||
("autoip_arp_reply(): Probe Conflict detected\n"));
|
||||
@@ -523,7 +491,7 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
|
||||
* in any state we have a conflict if
|
||||
* ip.src == llipaddr && hw.src != own hwaddr
|
||||
*/
|
||||
if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&
|
||||
if (ip4_addr_cmp(&sipaddr, &autoip->llipaddr) &&
|
||||
!eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
|
||||
("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
|
||||
@@ -533,4 +501,27 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LWIP_AUTOIP */
|
||||
/** check if AutoIP supplied netif->ip_addr
|
||||
*
|
||||
* @param netif the netif to check
|
||||
* @return 1 if AutoIP supplied netif->ip_addr (state BOUND or ANNOUNCING),
|
||||
* 0 otherwise
|
||||
*/
|
||||
u8_t
|
||||
autoip_supplied_address(const struct netif *netif)
|
||||
{
|
||||
if ((netif != NULL) && (netif_autoip_data(netif) != NULL)) {
|
||||
struct autoip* autoip = netif_autoip_data(netif);
|
||||
return (autoip->state == AUTOIP_STATE_BOUND) || (autoip->state == AUTOIP_STATE_ANNOUNCING);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8_t
|
||||
autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr)
|
||||
{
|
||||
struct autoip* autoip = netif_autoip_data(netif);
|
||||
return (autoip != NULL) && ip4_addr_cmp(addr, &(autoip->llipaddr));
|
||||
}
|
||||
|
||||
#endif /* LWIP_IPV4 && LWIP_AUTOIP */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -41,17 +41,20 @@
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
|
||||
#if LWIP_IPV4 && LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef LWIP_HOOK_FILENAME
|
||||
#include LWIP_HOOK_FILENAME
|
||||
#endif
|
||||
|
||||
/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be
|
||||
* used to modify and send a response packet (and to 1 if this is not the case,
|
||||
* e.g. when link header is stripped of when receiving) */
|
||||
@@ -70,7 +73,7 @@ static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
|
||||
* Currently only processes icmp echo requests and sends
|
||||
* out the echo response.
|
||||
*
|
||||
* @param p the icmp echo request packet, p->payload pointing to the ip header
|
||||
* @param p the icmp echo request packet, p->payload pointing to the icmp header
|
||||
* @param inp the netif on which this packet was received
|
||||
*/
|
||||
void
|
||||
@@ -81,16 +84,20 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
u8_t code;
|
||||
#endif /* LWIP_DEBUG */
|
||||
struct icmp_echo_hdr *iecho;
|
||||
struct ip_hdr *iphdr;
|
||||
s16_t hlen;
|
||||
const struct ip_hdr *iphdr_in;
|
||||
u16_t hlen;
|
||||
const ip4_addr_t* src;
|
||||
|
||||
ICMP_STATS_INC(icmp.recv);
|
||||
snmp_inc_icmpinmsgs();
|
||||
MIB2_STATS_INC(mib2.icmpinmsgs);
|
||||
|
||||
|
||||
iphdr = (struct ip_hdr *)p->payload;
|
||||
hlen = IPH_HL(iphdr) * 4;
|
||||
if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
|
||||
iphdr_in = ip4_current_header();
|
||||
hlen = IPH_HL(iphdr_in) * 4;
|
||||
if (hlen < IP_HLEN) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short IP header (%"S16_F" bytes) received\n", hlen));
|
||||
goto lenerr;
|
||||
}
|
||||
if (p->len < sizeof(u16_t)*2) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
|
||||
goto lenerr;
|
||||
}
|
||||
@@ -103,83 +110,87 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
case ICMP_ER:
|
||||
/* This is OK, echo reply might have been parsed by a raw PCB
|
||||
(as obviously, an echo request has been sent, too). */
|
||||
break;
|
||||
MIB2_STATS_INC(mib2.icmpinechoreps);
|
||||
break;
|
||||
case ICMP_ECHO:
|
||||
#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
|
||||
{
|
||||
int accepted = 1;
|
||||
#if !LWIP_MULTICAST_PING
|
||||
/* multicast destination address? */
|
||||
if (ip_addr_ismulticast(¤t_iphdr_dest)) {
|
||||
accepted = 0;
|
||||
}
|
||||
MIB2_STATS_INC(mib2.icmpinechos);
|
||||
src = ip4_current_dest_addr();
|
||||
/* multicast destination address? */
|
||||
if (ip4_addr_ismulticast(ip4_current_dest_addr())) {
|
||||
#if LWIP_MULTICAST_PING
|
||||
/* For multicast, use address of receiving interface as source address */
|
||||
src = netif_ip4_addr(inp);
|
||||
#else /* LWIP_MULTICAST_PING */
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast pings\n"));
|
||||
goto icmperr;
|
||||
#endif /* LWIP_MULTICAST_PING */
|
||||
#if !LWIP_BROADCAST_PING
|
||||
/* broadcast destination address? */
|
||||
if (ip_addr_isbroadcast(¤t_iphdr_dest, inp)) {
|
||||
accepted = 0;
|
||||
}
|
||||
#endif /* LWIP_BROADCAST_PING */
|
||||
/* broadcast or multicast destination address not acceptd? */
|
||||
if (!accepted) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
|
||||
ICMP_STATS_INC(icmp.err);
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */
|
||||
/* broadcast destination address? */
|
||||
if (ip4_addr_isbroadcast(ip4_current_dest_addr(), ip_current_netif())) {
|
||||
#if LWIP_BROADCAST_PING
|
||||
/* For broadcast, use address of receiving interface as source address */
|
||||
src = netif_ip4_addr(inp);
|
||||
#else /* LWIP_BROADCAST_PING */
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to broadcast pings\n"));
|
||||
goto icmperr;
|
||||
#endif /* LWIP_BROADCAST_PING */
|
||||
}
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
|
||||
if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
|
||||
goto lenerr;
|
||||
}
|
||||
if (inet_chksum_pbuf(p) != 0) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
|
||||
pbuf_free(p);
|
||||
ICMP_STATS_INC(icmp.chkerr);
|
||||
snmp_inc_icmpinerrors();
|
||||
return;
|
||||
#if CHECKSUM_CHECK_ICMP
|
||||
IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP) {
|
||||
if (inet_chksum_pbuf(p) != 0) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
|
||||
pbuf_free(p);
|
||||
ICMP_STATS_INC(icmp.chkerr);
|
||||
MIB2_STATS_INC(mib2.icmpinerrors);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
||||
if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
|
||||
if (pbuf_header(p, (s16_t)(hlen + PBUF_LINK_HLEN + PBUF_LINK_ENCAPSULATION_HLEN))) {
|
||||
/* p is not big enough to contain link headers
|
||||
* allocate a new one and copy p into it
|
||||
*/
|
||||
struct pbuf *r;
|
||||
/* switch p->payload to ip header */
|
||||
if (pbuf_header(p, hlen)) {
|
||||
LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0);
|
||||
goto memerr;
|
||||
}
|
||||
/* allocate new packet buffer with space for link headers */
|
||||
r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
|
||||
r = pbuf_alloc(PBUF_LINK, p->tot_len + hlen, PBUF_RAM);
|
||||
if (r == NULL) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n"));
|
||||
goto memerr;
|
||||
goto icmperr;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold struct the ICMP header",
|
||||
(r->len >= hlen + sizeof(struct icmp_echo_hdr)));
|
||||
/* copy the whole packet including ip header */
|
||||
if (r->len < hlen + sizeof(struct icmp_echo_hdr)) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("first pbuf cannot hold the ICMP header"));
|
||||
pbuf_free(r);
|
||||
goto icmperr;
|
||||
}
|
||||
/* copy the ip header */
|
||||
MEMCPY(r->payload, iphdr_in, hlen);
|
||||
/* switch r->payload back to icmp header (cannot fail) */
|
||||
if (pbuf_header(r, (s16_t)-hlen)) {
|
||||
LWIP_ASSERT("icmp_input: moving r->payload to icmp header failed\n", 0);
|
||||
pbuf_free(r);
|
||||
goto icmperr;
|
||||
}
|
||||
/* copy the rest of the packet without ip header */
|
||||
if (pbuf_copy(r, p) != ERR_OK) {
|
||||
LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
|
||||
goto memerr;
|
||||
}
|
||||
iphdr = (struct ip_hdr *)r->payload;
|
||||
/* switch r->payload back to icmp header */
|
||||
if (pbuf_header(r, -hlen)) {
|
||||
LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
|
||||
goto memerr;
|
||||
LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("icmp_input: copying to new pbuf failed"));
|
||||
pbuf_free(r);
|
||||
goto icmperr;
|
||||
}
|
||||
/* free the original p */
|
||||
pbuf_free(p);
|
||||
/* we now have an identical copy of p that has room for link headers */
|
||||
p = r;
|
||||
} else {
|
||||
/* restore p->payload to point to icmp header */
|
||||
if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
|
||||
/* restore p->payload to point to icmp header (cannot fail) */
|
||||
if (pbuf_header(p, -(s16_t)(hlen + PBUF_LINK_HLEN + PBUF_LINK_ENCAPSULATION_HLEN))) {
|
||||
LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
|
||||
goto memerr;
|
||||
goto icmperr;
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
|
||||
@@ -187,43 +198,76 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
/* We generate an answer by switching the dest and src ip addresses,
|
||||
* setting the icmp type to ECHO_RESPONSE and updating the checksum. */
|
||||
iecho = (struct icmp_echo_hdr *)p->payload;
|
||||
ip_addr_copy(iphdr->src, *ip_current_dest_addr());
|
||||
ip_addr_copy(iphdr->dest, *ip_current_src_addr());
|
||||
ICMPH_TYPE_SET(iecho, ICMP_ER);
|
||||
/* adjust the checksum */
|
||||
if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) {
|
||||
iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
|
||||
} else {
|
||||
iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
|
||||
}
|
||||
|
||||
/* Set the correct TTL and recalculate the header checksum. */
|
||||
IPH_TTL_SET(iphdr, ICMP_TTL);
|
||||
IPH_CHKSUM_SET(iphdr, 0);
|
||||
#if CHECKSUM_GEN_IP
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
||||
#endif /* CHECKSUM_GEN_IP */
|
||||
|
||||
ICMP_STATS_INC(icmp.xmit);
|
||||
/* increase number of messages attempted to send */
|
||||
snmp_inc_icmpoutmsgs();
|
||||
/* increase number of echo replies attempted to send */
|
||||
snmp_inc_icmpoutechoreps();
|
||||
|
||||
if(pbuf_header(p, hlen)) {
|
||||
LWIP_ASSERT("Can't move over header in packet", 0);
|
||||
if (pbuf_header(p, (s16_t)hlen)) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Can't move over header in packet"));
|
||||
} else {
|
||||
err_t ret;
|
||||
/* send an ICMP packet, src addr is the dest addr of the curren packet */
|
||||
ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL,
|
||||
struct ip_hdr *iphdr = (struct ip_hdr*)p->payload;
|
||||
ip4_addr_copy(iphdr->src, *src);
|
||||
ip4_addr_copy(iphdr->dest, *ip4_current_src_addr());
|
||||
ICMPH_TYPE_SET(iecho, ICMP_ER);
|
||||
#if CHECKSUM_GEN_ICMP
|
||||
IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP) {
|
||||
/* adjust the checksum */
|
||||
if (iecho->chksum > PP_HTONS(0xffffU - (ICMP_ECHO << 8))) {
|
||||
iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
|
||||
} else {
|
||||
iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
|
||||
}
|
||||
}
|
||||
#if LWIP_CHECKSUM_CTRL_PER_NETIF
|
||||
else {
|
||||
iecho->chksum = 0;
|
||||
}
|
||||
#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */
|
||||
#else /* CHECKSUM_GEN_ICMP */
|
||||
iecho->chksum = 0;
|
||||
#endif /* CHECKSUM_GEN_ICMP */
|
||||
|
||||
/* Set the correct TTL and recalculate the header checksum. */
|
||||
IPH_TTL_SET(iphdr, ICMP_TTL);
|
||||
IPH_CHKSUM_SET(iphdr, 0);
|
||||
#if CHECKSUM_GEN_IP
|
||||
IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_IP) {
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, hlen));
|
||||
}
|
||||
#endif /* CHECKSUM_GEN_IP */
|
||||
|
||||
ICMP_STATS_INC(icmp.xmit);
|
||||
/* increase number of messages attempted to send */
|
||||
MIB2_STATS_INC(mib2.icmpoutmsgs);
|
||||
/* increase number of echo replies attempted to send */
|
||||
MIB2_STATS_INC(mib2.icmpoutechoreps);
|
||||
|
||||
/* send an ICMP packet */
|
||||
ret = ip4_output_if(p, src, LWIP_IP_HDRINCL,
|
||||
ICMP_TTL, 0, IP_PROTO_ICMP, inp);
|
||||
if (ret != ERR_OK) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %s\n", lwip_strerr(ret)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n",
|
||||
if (type == ICMP_DUR) {
|
||||
MIB2_STATS_INC(mib2.icmpindestunreachs);
|
||||
} else if (type == ICMP_TE) {
|
||||
MIB2_STATS_INC(mib2.icmpintimeexcds);
|
||||
} else if (type == ICMP_PP) {
|
||||
MIB2_STATS_INC(mib2.icmpinparmprobs);
|
||||
} else if (type == ICMP_SQ) {
|
||||
MIB2_STATS_INC(mib2.icmpinsrcquenchs);
|
||||
} else if (type == ICMP_RD) {
|
||||
MIB2_STATS_INC(mib2.icmpinredirects);
|
||||
} else if (type == ICMP_TS) {
|
||||
MIB2_STATS_INC(mib2.icmpintimestamps);
|
||||
} else if (type == ICMP_TSR) {
|
||||
MIB2_STATS_INC(mib2.icmpintimestampreps);
|
||||
} else if (type == ICMP_AM) {
|
||||
MIB2_STATS_INC(mib2.icmpinaddrmasks);
|
||||
} else if (type == ICMP_AMR) {
|
||||
MIB2_STATS_INC(mib2.icmpinaddrmaskreps);
|
||||
}
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n",
|
||||
(s16_t)type, (s16_t)code));
|
||||
ICMP_STATS_INC(icmp.proterr);
|
||||
ICMP_STATS_INC(icmp.drop);
|
||||
@@ -233,15 +277,15 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
lenerr:
|
||||
pbuf_free(p);
|
||||
ICMP_STATS_INC(icmp.lenerr);
|
||||
snmp_inc_icmpinerrors();
|
||||
MIB2_STATS_INC(mib2.icmpinerrors);
|
||||
return;
|
||||
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
||||
memerr:
|
||||
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN || !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
|
||||
icmperr:
|
||||
pbuf_free(p);
|
||||
ICMP_STATS_INC(icmp.err);
|
||||
snmp_inc_icmpinerrors();
|
||||
MIB2_STATS_INC(mib2.icmpinerrors);
|
||||
return;
|
||||
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
|
||||
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN || !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,6 +300,7 @@ memerr:
|
||||
void
|
||||
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
|
||||
{
|
||||
MIB2_STATS_INC(mib2.icmpoutdestunreachs);
|
||||
icmp_send_response(p, ICMP_DUR, t);
|
||||
}
|
||||
|
||||
@@ -270,6 +315,7 @@ icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
|
||||
void
|
||||
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
|
||||
{
|
||||
MIB2_STATS_INC(mib2.icmpouttimeexcds);
|
||||
icmp_send_response(p, ICMP_TE, t);
|
||||
}
|
||||
|
||||
@@ -290,13 +336,18 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
|
||||
struct ip_hdr *iphdr;
|
||||
/* we can use the echo header here */
|
||||
struct icmp_echo_hdr *icmphdr;
|
||||
ip_addr_t iphdr_src;
|
||||
ip4_addr_t iphdr_src;
|
||||
struct netif *netif;
|
||||
|
||||
/* increase number of messages attempted to send */
|
||||
MIB2_STATS_INC(mib2.icmpoutmsgs);
|
||||
|
||||
/* ICMP header + IP header + 8 bytes of data */
|
||||
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
|
||||
PBUF_RAM);
|
||||
if (q == NULL) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
|
||||
MIB2_STATS_INC(mib2.icmpouterrors);
|
||||
return;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold icmp message",
|
||||
@@ -304,9 +355,9 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
|
||||
|
||||
iphdr = (struct ip_hdr *)p->payload;
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
|
||||
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
|
||||
ip4_addr_debug_print_val(ICMP_DEBUG, iphdr->src);
|
||||
LWIP_DEBUGF(ICMP_DEBUG, (" to "));
|
||||
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
|
||||
ip4_addr_debug_print_val(ICMP_DEBUG, iphdr->dest);
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
|
||||
|
||||
icmphdr = (struct icmp_echo_hdr *)q->payload;
|
||||
@@ -319,17 +370,28 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
|
||||
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
|
||||
IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
|
||||
|
||||
/* calculate checksum */
|
||||
icmphdr->chksum = 0;
|
||||
icmphdr->chksum = inet_chksum(icmphdr, q->len);
|
||||
ICMP_STATS_INC(icmp.xmit);
|
||||
/* increase number of messages attempted to send */
|
||||
snmp_inc_icmpoutmsgs();
|
||||
/* increase number of destination unreachable messages attempted to send */
|
||||
snmp_inc_icmpouttimeexcds();
|
||||
ip_addr_copy(iphdr_src, iphdr->src);
|
||||
ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);
|
||||
ip4_addr_copy(iphdr_src, iphdr->src);
|
||||
#ifdef LWIP_HOOK_IP4_ROUTE_SRC
|
||||
{
|
||||
ip4_addr_t iphdr_dst;
|
||||
ip4_addr_copy(iphdr_dst, iphdr->dest);
|
||||
netif = ip4_route_src(&iphdr_src, &iphdr_dst);
|
||||
}
|
||||
#else
|
||||
netif = ip4_route(&iphdr_src);
|
||||
#endif
|
||||
if (netif != NULL) {
|
||||
/* calculate checksum */
|
||||
icmphdr->chksum = 0;
|
||||
#if CHECKSUM_GEN_ICMP
|
||||
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP) {
|
||||
icmphdr->chksum = inet_chksum(icmphdr, q->len);
|
||||
}
|
||||
#endif
|
||||
ICMP_STATS_INC(icmp.xmit);
|
||||
ip4_output_if(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP, netif);
|
||||
}
|
||||
pbuf_free(q);
|
||||
}
|
||||
|
||||
#endif /* LWIP_ICMP */
|
||||
#endif /* LWIP_IPV4 && LWIP_ICMP */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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,44 +17,47 @@
|
||||
* 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/opt.h"
|
||||
|
||||
#if LWIP_IPV4
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
|
||||
const ip_addr_t ip_addr_any = { IPADDR_ANY };
|
||||
const ip_addr_t ip_addr_broadcast = { IPADDR_BROADCAST };
|
||||
/* used by IP4_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
|
||||
const ip_addr_t ip_addr_any = IPADDR4_INIT(IPADDR_ANY);
|
||||
const ip_addr_t ip_addr_broadcast = IPADDR4_INIT(IPADDR_BROADCAST);
|
||||
|
||||
/**
|
||||
* Determine if an address is a broadcast address on a network interface
|
||||
*
|
||||
* Determine if an address is a broadcast address on a network interface
|
||||
*
|
||||
* @param addr address to be checked
|
||||
* @param netif the network interface against which the address is checked
|
||||
* @return returns non-zero if the address is a broadcast address
|
||||
*/
|
||||
u8_t
|
||||
ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)
|
||||
ip4_addr_isbroadcast_u32(u32_t addr, const struct netif *netif)
|
||||
{
|
||||
ip_addr_t ipaddr;
|
||||
ip4_addr_t ipaddr;
|
||||
ip4_addr_set_u32(&ipaddr, addr);
|
||||
|
||||
/* all ones (broadcast) or all zeroes (old skool broadcast) */
|
||||
@@ -67,13 +70,13 @@ ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)
|
||||
* nor can we check against any broadcast addresses */
|
||||
return 0;
|
||||
/* address matches network interface address exactly? => no broadcast */
|
||||
} else if (addr == ip4_addr_get_u32(&netif->ip_addr)) {
|
||||
} else if (addr == ip4_addr_get_u32(netif_ip4_addr(netif))) {
|
||||
return 0;
|
||||
/* on the same (sub) network... */
|
||||
} else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask))
|
||||
} else if (ip4_addr_netcmp(&ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif))
|
||||
/* ...and host identifier bits are all ones? =>... */
|
||||
&& ((addr & ~ip4_addr_get_u32(&netif->netmask)) ==
|
||||
(IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) {
|
||||
&& ((addr & ~ip4_addr_get_u32(netif_ip4_netmask(netif))) ==
|
||||
(IPADDR_BROADCAST & ~ip4_addr_get_u32(netif_ip4_netmask(netif))))) {
|
||||
/* => network broadcast address */
|
||||
return 1;
|
||||
} else {
|
||||
@@ -123,15 +126,15 @@ ip4_addr_netmask_valid(u32_t netmask)
|
||||
* Ascii internet address interpretation routine.
|
||||
* The value returned is in network order.
|
||||
*
|
||||
* @param cp IP address in ascii represenation (e.g. "127.0.0.1")
|
||||
* @param cp IP address in ascii representation (e.g. "127.0.0.1")
|
||||
* @return ip address in network order
|
||||
*/
|
||||
u32_t
|
||||
ipaddr_addr(const char *cp)
|
||||
{
|
||||
ip_addr_t val;
|
||||
ip4_addr_t val;
|
||||
|
||||
if (ipaddr_aton(cp, &val)) {
|
||||
if (ip4addr_aton(cp, &val)) {
|
||||
return ip4_addr_get_u32(&val);
|
||||
}
|
||||
return (IPADDR_NONE);
|
||||
@@ -144,12 +147,12 @@ ipaddr_addr(const char *cp)
|
||||
* This replaces inet_addr, the return value from which
|
||||
* cannot distinguish between failure and a local broadcast address.
|
||||
*
|
||||
* @param cp IP address in ascii represenation (e.g. "127.0.0.1")
|
||||
* @param cp IP address in ascii representation (e.g. "127.0.0.1")
|
||||
* @param addr pointer to which to save the ip address in network order
|
||||
* @return 1 if cp could be converted to addr, 0 on failure
|
||||
*/
|
||||
int
|
||||
ipaddr_aton(const char *cp, ip_addr_t *addr)
|
||||
ip4addr_aton(const char *cp, ip4_addr_t *addr)
|
||||
{
|
||||
u32_t val;
|
||||
u8_t base;
|
||||
@@ -164,8 +167,9 @@ ipaddr_aton(const char *cp, ip_addr_t *addr)
|
||||
* Values are specified as for C:
|
||||
* 0x=hex, 0=octal, 1-9=decimal.
|
||||
*/
|
||||
if (!isdigit(c))
|
||||
return (0);
|
||||
if (!isdigit(c)) {
|
||||
return 0;
|
||||
}
|
||||
val = 0;
|
||||
base = 10;
|
||||
if (c == '0') {
|
||||
@@ -173,18 +177,20 @@ ipaddr_aton(const char *cp, ip_addr_t *addr)
|
||||
if (c == 'x' || c == 'X') {
|
||||
base = 16;
|
||||
c = *++cp;
|
||||
} else
|
||||
} else {
|
||||
base = 8;
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
if (isdigit(c)) {
|
||||
val = (val * base) + (int)(c - '0');
|
||||
val = (val * base) + (u32_t)(c - '0');
|
||||
c = *++cp;
|
||||
} else if (base == 16 && isxdigit(c)) {
|
||||
val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));
|
||||
val = (val << 4) | (u32_t)(c + 10 - (islower(c) ? 'a' : 'A'));
|
||||
c = *++cp;
|
||||
} else
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c == '.') {
|
||||
/*
|
||||
@@ -194,18 +200,19 @@ ipaddr_aton(const char *cp, ip_addr_t *addr)
|
||||
* a.b (with b treated as 24 bits)
|
||||
*/
|
||||
if (pp >= parts + 3) {
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
*pp++ = val;
|
||||
c = *++cp;
|
||||
} else
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Check for trailing characters.
|
||||
*/
|
||||
if (c != '\0' && !isspace(c)) {
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Concoct the address according to
|
||||
@@ -214,28 +221,37 @@ ipaddr_aton(const char *cp, ip_addr_t *addr)
|
||||
switch (pp - parts + 1) {
|
||||
|
||||
case 0:
|
||||
return (0); /* initial nondigit */
|
||||
return 0; /* initial nondigit */
|
||||
|
||||
case 1: /* a -- 32 bits */
|
||||
break;
|
||||
|
||||
case 2: /* a.b -- 8.24 bits */
|
||||
if (val > 0xffffffUL) {
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
if (parts[0] > 0xff) {
|
||||
return 0;
|
||||
}
|
||||
val |= parts[0] << 24;
|
||||
break;
|
||||
|
||||
case 3: /* a.b.c -- 8.8.16 bits */
|
||||
if (val > 0xffff) {
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
if ((parts[0] > 0xff) || (parts[1] > 0xff)) {
|
||||
return 0;
|
||||
}
|
||||
val |= (parts[0] << 24) | (parts[1] << 16);
|
||||
break;
|
||||
|
||||
case 4: /* a.b.c.d -- 8.8.8.8 bits */
|
||||
if (val > 0xff) {
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
if ((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) {
|
||||
return 0;
|
||||
}
|
||||
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
|
||||
break;
|
||||
@@ -244,9 +260,9 @@ ipaddr_aton(const char *cp, ip_addr_t *addr)
|
||||
break;
|
||||
}
|
||||
if (addr) {
|
||||
ip4_addr_set_u32(addr, htonl(val));
|
||||
ip4_addr_set_u32(addr, lwip_htonl(val));
|
||||
}
|
||||
return (1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -255,13 +271,13 @@ ipaddr_aton(const char *cp, ip_addr_t *addr)
|
||||
*
|
||||
* @param addr ip address in network order to convert
|
||||
* @return pointer to a global static (!) buffer that holds the ASCII
|
||||
* represenation of addr
|
||||
* representation of addr
|
||||
*/
|
||||
char *
|
||||
ipaddr_ntoa(const ip_addr_t *addr)
|
||||
char*
|
||||
ip4addr_ntoa(const ip4_addr_t *addr)
|
||||
{
|
||||
static char str[16];
|
||||
return ipaddr_ntoa_r(addr, str, 16);
|
||||
static char str[IP4ADDR_STRLEN_MAX];
|
||||
return ip4addr_ntoa_r(addr, str, IP4ADDR_STRLEN_MAX);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,7 +289,8 @@ ipaddr_ntoa(const ip_addr_t *addr)
|
||||
* @return either pointer to buf which now holds the ASCII
|
||||
* representation of addr or NULL if buf was too small
|
||||
*/
|
||||
char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)
|
||||
char*
|
||||
ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen)
|
||||
{
|
||||
u32_t s_addr;
|
||||
char inv[3];
|
||||
@@ -288,14 +305,14 @@ char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)
|
||||
|
||||
rp = buf;
|
||||
ap = (u8_t *)&s_addr;
|
||||
for(n = 0; n < 4; n++) {
|
||||
for (n = 0; n < 4; n++) {
|
||||
i = 0;
|
||||
do {
|
||||
rem = *ap % (u8_t)10;
|
||||
*ap /= (u8_t)10;
|
||||
inv[i++] = '0' + rem;
|
||||
} while(*ap);
|
||||
while(i--) {
|
||||
inv[i++] = (char)('0' + rem);
|
||||
} while (*ap);
|
||||
while (i--) {
|
||||
if (len++ >= buflen) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -310,3 +327,5 @@ char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)
|
||||
*--rp = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif /* LWIP_IPV4 */
|
||||
@@ -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,33 +17,35 @@
|
||||
* 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: Jani Monoses <jani@iv.ro>
|
||||
*
|
||||
* Author: Jani Monoses <jani@iv.ro>
|
||||
* Simon Goldschmidt
|
||||
* original reassembly code by Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/ip_frag.h"
|
||||
|
||||
#if LWIP_IPV4
|
||||
|
||||
#include "lwip/ip4_frag.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/icmp.h"
|
||||
|
||||
@@ -100,8 +102,8 @@ PACK_STRUCT_END
|
||||
#endif
|
||||
|
||||
#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \
|
||||
(ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
|
||||
ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \
|
||||
(ip4_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
|
||||
ip4_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \
|
||||
IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0
|
||||
|
||||
/* global variables */
|
||||
@@ -158,7 +160,7 @@ static int
|
||||
ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
|
||||
{
|
||||
u16_t pbufs_freed = 0;
|
||||
u8_t clen;
|
||||
u16_t clen;
|
||||
struct pbuf *p;
|
||||
struct ip_reass_helper *iprh;
|
||||
|
||||
@@ -167,7 +169,7 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p
|
||||
LWIP_ASSERT("prev->next == ipr", prev->next == ipr);
|
||||
}
|
||||
|
||||
snmp_inc_ipreasmfails();
|
||||
MIB2_STATS_INC(mib2.ipreasmfails);
|
||||
#if LWIP_ICMP
|
||||
iprh = (struct ip_reass_helper *)ipr->p->payload;
|
||||
if (iprh->start == 0) {
|
||||
@@ -185,7 +187,7 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p
|
||||
}
|
||||
#endif /* LWIP_ICMP */
|
||||
|
||||
/* First, free all received pbufs. The individual pbufs need to be released
|
||||
/* First, free all received pbufs. The individual pbufs need to be released
|
||||
separately as they have not yet been chained */
|
||||
p = ipr->p;
|
||||
while (p != NULL) {
|
||||
@@ -223,7 +225,7 @@ ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
|
||||
/* @todo Can't we simply remove the last datagram in the
|
||||
* linked list behind reassdatagrams?
|
||||
*/
|
||||
struct ip_reassdata *r, *oldest, *prev;
|
||||
struct ip_reassdata *r, *oldest, *prev, *oldest_prev;
|
||||
int pbufs_freed = 0, pbufs_freed_current;
|
||||
int other_datagrams;
|
||||
|
||||
@@ -232,6 +234,7 @@ ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
|
||||
do {
|
||||
oldest = NULL;
|
||||
prev = NULL;
|
||||
oldest_prev = NULL;
|
||||
other_datagrams = 0;
|
||||
r = reassdatagrams;
|
||||
while (r != NULL) {
|
||||
@@ -240,9 +243,11 @@ ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
|
||||
other_datagrams++;
|
||||
if (oldest == NULL) {
|
||||
oldest = r;
|
||||
oldest_prev = prev;
|
||||
} else if (r->timer <= oldest->timer) {
|
||||
/* older than the previous oldest */
|
||||
oldest = r;
|
||||
oldest_prev = prev;
|
||||
}
|
||||
}
|
||||
if (r->next != NULL) {
|
||||
@@ -251,7 +256,7 @@ ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
|
||||
r = r->next;
|
||||
}
|
||||
if (oldest != NULL) {
|
||||
pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev);
|
||||
pbufs_freed_current = ip_reass_free_complete_datagram(oldest, oldest_prev);
|
||||
pbufs_freed += pbufs_freed_current;
|
||||
}
|
||||
} while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));
|
||||
@@ -269,6 +274,10 @@ static struct ip_reassdata*
|
||||
ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)
|
||||
{
|
||||
struct ip_reassdata* ipr;
|
||||
#if ! IP_REASS_FREE_OLDEST
|
||||
LWIP_UNUSED_ARG(clen);
|
||||
#endif
|
||||
|
||||
/* No matching previous fragment found, allocate a new reassdata struct */
|
||||
ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
|
||||
if (ipr == NULL) {
|
||||
@@ -303,7 +312,6 @@ ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)
|
||||
static void
|
||||
ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
|
||||
{
|
||||
|
||||
/* dequeue the reass struct */
|
||||
if (reassdatagrams == ipr) {
|
||||
/* it was the first in the list */
|
||||
@@ -314,7 +322,7 @@ ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
|
||||
prev->next = ipr->next;
|
||||
}
|
||||
|
||||
/* now we can free the ip_reass struct */
|
||||
/* now we can free the ip_reassdata struct */
|
||||
memp_free(MEMP_REASSDATA, ipr);
|
||||
}
|
||||
|
||||
@@ -323,7 +331,7 @@ ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
|
||||
* will grow over time as new pbufs are rx.
|
||||
* Also checks that the datagram passes basic continuity checks (if the last
|
||||
* fragment was received at least once).
|
||||
* @param root_p points to the 'root' pbuf for the current datagram being assembled.
|
||||
* @param ipr points to the reassembly state
|
||||
* @param new_p points to the pbuf for the current fragment
|
||||
* @return 0 if invalid, >0 otherwise
|
||||
*/
|
||||
@@ -332,14 +340,14 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct
|
||||
{
|
||||
struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
|
||||
struct pbuf *q;
|
||||
u16_t offset,len;
|
||||
u16_t offset, len;
|
||||
struct ip_hdr *fraghdr;
|
||||
int valid = 1;
|
||||
|
||||
/* Extract length and fragment offset from current fragment */
|
||||
fraghdr = (struct ip_hdr*)new_p->payload;
|
||||
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
|
||||
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
|
||||
fraghdr = (struct ip_hdr*)new_p->payload;
|
||||
len = lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
|
||||
offset = (lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
|
||||
|
||||
/* overwrite the fragment's ip header from the pbuf with our helper struct,
|
||||
* and setup the embedded helper structure. */
|
||||
@@ -352,7 +360,7 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct
|
||||
iprh->end = offset + len;
|
||||
|
||||
/* Iterate through until we either get to the end of the list (append),
|
||||
* or we find on with a larger offset (insert). */
|
||||
* or we find one with a larger offset (insert). */
|
||||
for (q = ipr->p; q != NULL;) {
|
||||
iprh_tmp = (struct ip_reass_helper*)q->payload;
|
||||
if (iprh->start < iprh_tmp->start) {
|
||||
@@ -372,16 +380,16 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct
|
||||
ipr->p = new_p;
|
||||
}
|
||||
break;
|
||||
} else if(iprh->start == iprh_tmp->start) {
|
||||
} else if (iprh->start == iprh_tmp->start) {
|
||||
/* received the same datagram twice: no need to keep the datagram */
|
||||
goto freepbuf;
|
||||
#if IP_REASS_CHECK_OVERLAP
|
||||
} else if(iprh->start < iprh_tmp->end) {
|
||||
} else if (iprh->start < iprh_tmp->end) {
|
||||
/* overlap: no need to keep the new datagram */
|
||||
goto freepbuf;
|
||||
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||
} else {
|
||||
/* Check if the fragments received so far have no wholes. */
|
||||
/* Check if the fragments received so far have no holes. */
|
||||
if (iprh_prev != NULL) {
|
||||
if (iprh_prev->end != iprh_tmp->start) {
|
||||
/* There is a fragment missing between the current
|
||||
@@ -419,14 +427,14 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct
|
||||
/* At this point, the validation part begins: */
|
||||
/* If we already received the last fragment */
|
||||
if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
|
||||
/* and had no wholes so far */
|
||||
/* and had no holes so far */
|
||||
if (valid) {
|
||||
/* then check if the rest of the fragments is here */
|
||||
/* Check if the queue starts with the first datagram */
|
||||
if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) {
|
||||
if ((ipr->p == NULL) || (((struct ip_reass_helper*)ipr->p->payload)->start != 0)) {
|
||||
valid = 0;
|
||||
} else {
|
||||
/* and check that there are no wholes after this datagram */
|
||||
/* and check that there are no holes after this datagram */
|
||||
iprh_prev = iprh;
|
||||
q = iprh->next_pbuf;
|
||||
while (q != NULL) {
|
||||
@@ -473,29 +481,27 @@ freepbuf:
|
||||
* @return NULL if reassembly is incomplete, ? otherwise
|
||||
*/
|
||||
struct pbuf *
|
||||
ip_reass(struct pbuf *p)
|
||||
ip4_reass(struct pbuf *p)
|
||||
{
|
||||
struct pbuf *r;
|
||||
struct ip_hdr *fraghdr;
|
||||
struct ip_reassdata *ipr;
|
||||
struct ip_reass_helper *iprh;
|
||||
u16_t offset, len;
|
||||
u8_t clen;
|
||||
struct ip_reassdata *ipr_prev = NULL;
|
||||
u16_t offset, len, clen;
|
||||
|
||||
IPFRAG_STATS_INC(ip_frag.recv);
|
||||
snmp_inc_ipreasmreqds();
|
||||
MIB2_STATS_INC(mib2.ipreasmreqds);
|
||||
|
||||
fraghdr = (struct ip_hdr*)p->payload;
|
||||
|
||||
if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {
|
||||
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n"));
|
||||
LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: IP options currently not supported!\n"));
|
||||
IPFRAG_STATS_INC(ip_frag.err);
|
||||
goto nullreturn;
|
||||
}
|
||||
|
||||
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
|
||||
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
|
||||
offset = (lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
|
||||
len = lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
|
||||
|
||||
/* Check if we are allowed to enqueue more datagrams. */
|
||||
clen = pbuf_clen(p);
|
||||
@@ -506,7 +512,7 @@ ip_reass(struct pbuf *p)
|
||||
#endif /* IP_REASS_FREE_OLDEST */
|
||||
{
|
||||
/* No datagram could be freed and still too many pbufs enqueued */
|
||||
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
|
||||
LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
|
||||
ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));
|
||||
IPFRAG_STATS_INC(ip_frag.memerr);
|
||||
/* @todo: send ICMP time exceeded here? */
|
||||
@@ -522,24 +528,23 @@ ip_reass(struct pbuf *p)
|
||||
in the reassembly buffer. If so, we proceed with copying the
|
||||
fragment into the buffer. */
|
||||
if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
|
||||
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",
|
||||
ntohs(IPH_ID(fraghdr))));
|
||||
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip4_reass: matching previous fragment ID=%"X16_F"\n",
|
||||
lwip_ntohs(IPH_ID(fraghdr))));
|
||||
IPFRAG_STATS_INC(ip_frag.cachehit);
|
||||
break;
|
||||
}
|
||||
ipr_prev = ipr;
|
||||
}
|
||||
|
||||
if (ipr == NULL) {
|
||||
/* Enqueue a new datagram into the datagram queue */
|
||||
ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
|
||||
/* Bail if unable to enqueue */
|
||||
if(ipr == NULL) {
|
||||
if (ipr == NULL) {
|
||||
goto nullreturn;
|
||||
}
|
||||
} else {
|
||||
if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
|
||||
((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
|
||||
if (((lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
|
||||
((lwip_ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
|
||||
/* ipr->iphdr is not the header from the first fragment, but fraghdr is
|
||||
* -> copy fraghdr into ipr->iphdr since we want to have the header
|
||||
* of the first fragment (for ICMP time exceeded and later, for copying
|
||||
@@ -547,11 +552,11 @@ ip_reass(struct pbuf *p)
|
||||
SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
|
||||
}
|
||||
}
|
||||
/* Track the current number of pbufs current 'in-flight', in order to limit
|
||||
/* Track the current number of pbufs current 'in-flight', in order to limit
|
||||
the number of fragments that may be enqueued at any one time */
|
||||
ip_reass_pbufcount += clen;
|
||||
|
||||
/* At this point, we have either created a new entry or pointing
|
||||
/* At this point, we have either created a new entry or pointing
|
||||
* to an existing one */
|
||||
|
||||
/* check for 'no more fragments', and update queue entry*/
|
||||
@@ -559,12 +564,13 @@ ip_reass(struct pbuf *p)
|
||||
ipr->flags |= IP_REASS_FLAG_LASTFRAG;
|
||||
ipr->datagram_len = offset + len;
|
||||
LWIP_DEBUGF(IP_REASS_DEBUG,
|
||||
("ip_reass: last fragment seen, total len %"S16_F"\n",
|
||||
("ip4_reass: last fragment seen, total len %"S16_F"\n",
|
||||
ipr->datagram_len));
|
||||
}
|
||||
/* find the right place to insert this pbuf */
|
||||
/* @todo: trim pbufs if fragments are overlapping */
|
||||
if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {
|
||||
struct ip_reassdata *ipr_prev;
|
||||
/* the totally last fragment (flag more fragments = 0) was received at least
|
||||
* once AND all fragments are received */
|
||||
ipr->datagram_len += IP_HLEN;
|
||||
@@ -575,29 +581,47 @@ ip_reass(struct pbuf *p)
|
||||
/* copy the original ip header back to the first pbuf */
|
||||
fraghdr = (struct ip_hdr*)(ipr->p->payload);
|
||||
SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
|
||||
IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));
|
||||
IPH_LEN_SET(fraghdr, lwip_htons(ipr->datagram_len));
|
||||
IPH_OFFSET_SET(fraghdr, 0);
|
||||
IPH_CHKSUM_SET(fraghdr, 0);
|
||||
/* @todo: do we need to set calculate the correct checksum? */
|
||||
IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
|
||||
/* @todo: do we need to set/calculate the correct checksum? */
|
||||
#if CHECKSUM_GEN_IP
|
||||
IF__NETIF_CHECKSUM_ENABLED(ip_current_input_netif(), NETIF_CHECKSUM_GEN_IP) {
|
||||
IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
|
||||
}
|
||||
#endif /* CHECKSUM_GEN_IP */
|
||||
|
||||
p = ipr->p;
|
||||
|
||||
/* chain together the pbufs contained within the reass_data list. */
|
||||
while(r != NULL) {
|
||||
while (r != NULL) {
|
||||
iprh = (struct ip_reass_helper*)r->payload;
|
||||
|
||||
/* hide the ip header for every succeding fragment */
|
||||
/* hide the ip header for every succeeding fragment */
|
||||
pbuf_header(r, -IP_HLEN);
|
||||
pbuf_cat(p, r);
|
||||
r = iprh->next_pbuf;
|
||||
}
|
||||
|
||||
/* find the previous entry in the linked list */
|
||||
if (ipr == reassdatagrams) {
|
||||
ipr_prev = NULL;
|
||||
} else {
|
||||
for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) {
|
||||
if (ipr_prev->next == ipr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* release the sources allocate for the fragment queue entry */
|
||||
ip_reass_dequeue_datagram(ipr, ipr_prev);
|
||||
|
||||
/* and adjust the number of pbufs currently queued for reassembly. */
|
||||
ip_reass_pbufcount -= pbuf_clen(p);
|
||||
|
||||
MIB2_STATS_INC(mib2.ipreasmoks);
|
||||
|
||||
/* Return the pbuf chain */
|
||||
return p;
|
||||
}
|
||||
@@ -606,7 +630,7 @@ ip_reass(struct pbuf *p)
|
||||
return NULL;
|
||||
|
||||
nullreturn:
|
||||
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n"));
|
||||
LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: nullreturn\n"));
|
||||
IPFRAG_STATS_INC(ip_frag.drop);
|
||||
pbuf_free(p);
|
||||
return NULL;
|
||||
@@ -614,10 +638,6 @@ nullreturn:
|
||||
#endif /* IP_REASSEMBLY */
|
||||
|
||||
#if IP_FRAG
|
||||
#if IP_FRAG_USES_STATIC_BUF
|
||||
static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];
|
||||
#else /* IP_FRAG_USES_STATIC_BUF */
|
||||
|
||||
#if !LWIP_NETIF_TX_SINGLE_PBUF
|
||||
/** Allocate a new struct pbuf_custom_ref */
|
||||
static struct pbuf_custom_ref*
|
||||
@@ -648,14 +668,12 @@ ipfrag_free_pbuf_custom(struct pbuf *p)
|
||||
ip_frag_free_pbuf_custom_ref(pcr);
|
||||
}
|
||||
#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
|
||||
#endif /* IP_FRAG_USES_STATIC_BUF */
|
||||
|
||||
/**
|
||||
* Fragment an IP datagram if too large for the netif.
|
||||
*
|
||||
* Chop the datagram in MTU sized chunks and send them in order
|
||||
* by using a fixed size static memory buffer (PBUF_REF) or
|
||||
* point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).
|
||||
* by pointing PBUF_REFs into p.
|
||||
*
|
||||
* @param p ip packet to send
|
||||
* @param netif the netif on which to send
|
||||
@@ -663,93 +681,55 @@ ipfrag_free_pbuf_custom(struct pbuf *p)
|
||||
*
|
||||
* @return ERR_OK if sent successfully, err_t otherwise
|
||||
*/
|
||||
err_t
|
||||
ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
|
||||
err_t
|
||||
ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
|
||||
{
|
||||
struct pbuf *rambuf;
|
||||
#if IP_FRAG_USES_STATIC_BUF
|
||||
struct pbuf *header;
|
||||
#else
|
||||
#if !LWIP_NETIF_TX_SINGLE_PBUF
|
||||
struct pbuf *newpbuf;
|
||||
#endif
|
||||
struct ip_hdr *original_iphdr;
|
||||
#endif
|
||||
struct ip_hdr *iphdr;
|
||||
u16_t nfb;
|
||||
u16_t left, cop;
|
||||
u16_t mtu = netif->mtu;
|
||||
u16_t ofo, omf;
|
||||
u16_t last;
|
||||
u16_t poff = IP_HLEN;
|
||||
u16_t tmp;
|
||||
#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
|
||||
u16_t newpbuflen = 0;
|
||||
u16_t left_to_copy;
|
||||
#endif
|
||||
struct ip_hdr *original_iphdr;
|
||||
struct ip_hdr *iphdr;
|
||||
const u16_t nfb = (netif->mtu - IP_HLEN) / 8;
|
||||
u16_t left, fragsize;
|
||||
u16_t ofo;
|
||||
int last;
|
||||
u16_t poff = IP_HLEN;
|
||||
u16_t tmp;
|
||||
|
||||
/* Get a RAM based MTU sized pbuf */
|
||||
#if IP_FRAG_USES_STATIC_BUF
|
||||
/* When using a static buffer, we use a PBUF_REF, which we will
|
||||
* use to reference the packet (without link header).
|
||||
* Layer and length is irrelevant.
|
||||
*/
|
||||
rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
|
||||
if (rambuf == NULL) {
|
||||
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));
|
||||
return ERR_MEM;
|
||||
}
|
||||
rambuf->tot_len = rambuf->len = mtu;
|
||||
rambuf->payload = LWIP_MEM_ALIGN((void *)buf);
|
||||
|
||||
/* Copy the IP header in it */
|
||||
iphdr = (struct ip_hdr *)rambuf->payload;
|
||||
SMEMCPY(iphdr, p->payload, IP_HLEN);
|
||||
#else /* IP_FRAG_USES_STATIC_BUF */
|
||||
original_iphdr = (struct ip_hdr *)p->payload;
|
||||
iphdr = original_iphdr;
|
||||
#endif /* IP_FRAG_USES_STATIC_BUF */
|
||||
LWIP_ERROR("ip4_frag() does not support IP options", IPH_HL(iphdr) * 4 == IP_HLEN, return ERR_VAL);
|
||||
|
||||
/* Save original offset */
|
||||
tmp = ntohs(IPH_OFFSET(iphdr));
|
||||
tmp = lwip_ntohs(IPH_OFFSET(iphdr));
|
||||
ofo = tmp & IP_OFFMASK;
|
||||
omf = tmp & IP_MF;
|
||||
LWIP_ERROR("ip_frag(): MF already set", (tmp & IP_MF) == 0, return ERR_VAL);
|
||||
|
||||
left = p->tot_len - IP_HLEN;
|
||||
|
||||
nfb = (mtu - IP_HLEN) / 8;
|
||||
|
||||
while (left) {
|
||||
last = (left <= mtu - IP_HLEN);
|
||||
|
||||
/* Set new offset and MF flag */
|
||||
tmp = omf | (IP_OFFMASK & (ofo));
|
||||
if (!last) {
|
||||
tmp = tmp | IP_MF;
|
||||
}
|
||||
|
||||
/* Fill this fragment */
|
||||
cop = last ? left : nfb * 8;
|
||||
fragsize = LWIP_MIN(left, nfb * 8);
|
||||
|
||||
#if IP_FRAG_USES_STATIC_BUF
|
||||
poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);
|
||||
#else /* IP_FRAG_USES_STATIC_BUF */
|
||||
#if LWIP_NETIF_TX_SINGLE_PBUF
|
||||
rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM);
|
||||
rambuf = pbuf_alloc(PBUF_IP, fragsize, PBUF_RAM);
|
||||
if (rambuf == NULL) {
|
||||
return ERR_MEM;
|
||||
goto memerr;
|
||||
}
|
||||
LWIP_ASSERT("this needs a pbuf in one piece!",
|
||||
(rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
|
||||
poff += pbuf_copy_partial(p, rambuf->payload, cop, poff);
|
||||
poff += pbuf_copy_partial(p, rambuf->payload, fragsize, poff);
|
||||
/* make room for the IP header */
|
||||
if(pbuf_header(rambuf, IP_HLEN)) {
|
||||
if (pbuf_header(rambuf, IP_HLEN)) {
|
||||
pbuf_free(rambuf);
|
||||
return ERR_MEM;
|
||||
goto memerr;
|
||||
}
|
||||
/* fill in the IP header */
|
||||
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
|
||||
iphdr = rambuf->payload;
|
||||
iphdr = (struct ip_hdr*)rambuf->payload;
|
||||
#else /* LWIP_NETIF_TX_SINGLE_PBUF */
|
||||
/* When not using a static buffer, create a chain of pbufs.
|
||||
* The first will be a PBUF_RAM holding the link and IP header.
|
||||
@@ -758,37 +738,36 @@ ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
|
||||
*/
|
||||
rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);
|
||||
if (rambuf == NULL) {
|
||||
return ERR_MEM;
|
||||
goto memerr;
|
||||
}
|
||||
LWIP_ASSERT("this needs a pbuf in one piece!",
|
||||
(p->len >= (IP_HLEN)));
|
||||
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
|
||||
iphdr = (struct ip_hdr *)rambuf->payload;
|
||||
|
||||
/* Can just adjust p directly for needed offset. */
|
||||
p->payload = (u8_t *)p->payload + poff;
|
||||
p->len -= poff;
|
||||
|
||||
left_to_copy = cop;
|
||||
left_to_copy = fragsize;
|
||||
while (left_to_copy) {
|
||||
struct pbuf_custom_ref *pcr;
|
||||
newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
|
||||
u16_t plen = p->len - poff;
|
||||
newpbuflen = LWIP_MIN(left_to_copy, plen);
|
||||
/* Is this pbuf already empty? */
|
||||
if (!newpbuflen) {
|
||||
poff = 0;
|
||||
p = p->next;
|
||||
continue;
|
||||
}
|
||||
pcr = ip_frag_alloc_pbuf_custom_ref();
|
||||
if (pcr == NULL) {
|
||||
pbuf_free(rambuf);
|
||||
return ERR_MEM;
|
||||
goto memerr;
|
||||
}
|
||||
/* Mirror this pbuf, although we might not need all of it. */
|
||||
newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
|
||||
newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc,
|
||||
(u8_t*)p->payload + poff, newpbuflen);
|
||||
if (newpbuf == NULL) {
|
||||
ip_frag_free_pbuf_custom_ref(pcr);
|
||||
pbuf_free(rambuf);
|
||||
return ERR_MEM;
|
||||
goto memerr;
|
||||
}
|
||||
pbuf_ref(p);
|
||||
pcr->original = p;
|
||||
@@ -800,42 +779,30 @@ ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
|
||||
pbuf_cat(rambuf, newpbuf);
|
||||
left_to_copy -= newpbuflen;
|
||||
if (left_to_copy) {
|
||||
poff = 0;
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
poff = newpbuflen;
|
||||
poff += newpbuflen;
|
||||
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
|
||||
#endif /* IP_FRAG_USES_STATIC_BUF */
|
||||
|
||||
/* Correct header */
|
||||
IPH_OFFSET_SET(iphdr, htons(tmp));
|
||||
IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
|
||||
last = (left <= netif->mtu - IP_HLEN);
|
||||
|
||||
/* Set new offset and MF flag */
|
||||
tmp = (IP_OFFMASK & (ofo));
|
||||
if (!last) {
|
||||
tmp = tmp | IP_MF;
|
||||
}
|
||||
IPH_OFFSET_SET(iphdr, lwip_htons(tmp));
|
||||
IPH_LEN_SET(iphdr, lwip_htons(fragsize + IP_HLEN));
|
||||
IPH_CHKSUM_SET(iphdr, 0);
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
||||
|
||||
#if IP_FRAG_USES_STATIC_BUF
|
||||
if (last) {
|
||||
pbuf_realloc(rambuf, left + IP_HLEN);
|
||||
#if CHECKSUM_GEN_IP
|
||||
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) {
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
||||
}
|
||||
#endif /* CHECKSUM_GEN_IP */
|
||||
|
||||
/* This part is ugly: we alloc a RAM based pbuf for
|
||||
* the link level header for each chunk and then
|
||||
* free it.A PBUF_ROM style pbuf for which pbuf_header
|
||||
* worked would make things simpler.
|
||||
*/
|
||||
header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
|
||||
if (header != NULL) {
|
||||
pbuf_chain(header, rambuf);
|
||||
netif->output(netif, header, dest);
|
||||
IPFRAG_STATS_INC(ip_frag.xmit);
|
||||
snmp_inc_ipfragcreates();
|
||||
pbuf_free(header);
|
||||
} else {
|
||||
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));
|
||||
pbuf_free(rambuf);
|
||||
return ERR_MEM;
|
||||
}
|
||||
#else /* IP_FRAG_USES_STATIC_BUF */
|
||||
/* No need for separate header pbuf - we allowed room for it in rambuf
|
||||
* when allocated.
|
||||
*/
|
||||
@@ -848,16 +815,17 @@ ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
|
||||
* will have already sent the packet, the free will really free, and
|
||||
* there will be zero memory penalty.
|
||||
*/
|
||||
|
||||
|
||||
pbuf_free(rambuf);
|
||||
#endif /* IP_FRAG_USES_STATIC_BUF */
|
||||
left -= cop;
|
||||
left -= fragsize;
|
||||
ofo += nfb;
|
||||
}
|
||||
#if IP_FRAG_USES_STATIC_BUF
|
||||
pbuf_free(rambuf);
|
||||
#endif /* IP_FRAG_USES_STATIC_BUF */
|
||||
snmp_inc_ipfragoks();
|
||||
MIB2_STATS_INC(mib2.ipfragoks);
|
||||
return ERR_OK;
|
||||
memerr:
|
||||
MIB2_STATS_INC(mib2.ipfragfails);
|
||||
return ERR_MEM;
|
||||
}
|
||||
#endif /* IP_FRAG */
|
||||
|
||||
#endif /* LWIP_IPV4 */
|
||||
@@ -1 +0,0 @@
|
||||
IPv6 support in lwIP is very experimental.
|
||||
50
src/core/ipv6/dhcp6.c
Normal file
50
src/core/ipv6/dhcp6.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* DHCPv6.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Inico Technologies Ltd.
|
||||
* 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: Ivan Delamer <delamer@inicotech.com>
|
||||
*
|
||||
*
|
||||
* Please coordinate changes and requests with Ivan Delamer
|
||||
* <delamer@inicotech.com>
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_IPV6 && LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_DHCP6 */
|
||||
118
src/core/ipv6/ethip6.c
Normal file
118
src/core/ipv6/ethip6.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Ethernet output for IPv6. Uses ND tables for link-layer addressing.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Inico Technologies Ltd.
|
||||
* 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: Ivan Delamer <delamer@inicotech.com>
|
||||
*
|
||||
*
|
||||
* Please coordinate changes and requests with Ivan Delamer
|
||||
* <delamer@inicotech.com>
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_IPV6 && LWIP_ETHERNET
|
||||
|
||||
#include "lwip/ethip6.h"
|
||||
#include "lwip/nd6.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/icmp6.h"
|
||||
#include "lwip/prot/ethernet.h"
|
||||
#include "netif/ethernet.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Resolve and fill-in Ethernet address header for outgoing IPv6 packet.
|
||||
*
|
||||
* For IPv6 multicast, corresponding Ethernet addresses
|
||||
* are selected and the packet is transmitted on the link.
|
||||
*
|
||||
* For unicast addresses, ask the ND6 module what to do. It will either let us
|
||||
* send the the packet right away, or queue the packet for later itself, unless
|
||||
* an error occurs.
|
||||
*
|
||||
* @todo anycast addresses
|
||||
*
|
||||
* @param netif The lwIP network interface which the IP packet will be sent on.
|
||||
* @param q The pbuf(s) containing the IP packet to be sent.
|
||||
* @param ip6addr The IP address of the packet destination.
|
||||
*
|
||||
* @return
|
||||
* - ERR_OK or the return value of @ref nd6_get_next_hop_addr_or_queue.
|
||||
*/
|
||||
err_t
|
||||
ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr)
|
||||
{
|
||||
struct eth_addr dest;
|
||||
const u8_t *hwaddr;
|
||||
err_t result;
|
||||
|
||||
/* multicast destination IP address? */
|
||||
if (ip6_addr_ismulticast(ip6addr)) {
|
||||
/* Hash IP multicast address to MAC address.*/
|
||||
dest.addr[0] = 0x33;
|
||||
dest.addr[1] = 0x33;
|
||||
dest.addr[2] = ((const u8_t *)(&(ip6addr->addr[3])))[0];
|
||||
dest.addr[3] = ((const u8_t *)(&(ip6addr->addr[3])))[1];
|
||||
dest.addr[4] = ((const u8_t *)(&(ip6addr->addr[3])))[2];
|
||||
dest.addr[5] = ((const u8_t *)(&(ip6addr->addr[3])))[3];
|
||||
|
||||
/* Send out. */
|
||||
return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6);
|
||||
}
|
||||
|
||||
/* We have a unicast destination IP address */
|
||||
/* @todo anycast? */
|
||||
|
||||
/* Ask ND6 what to do with the packet. */
|
||||
result = nd6_get_next_hop_addr_or_queue(netif, q, ip6addr, &hwaddr);
|
||||
if (result != ERR_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* If no hardware address is returned, nd6 has queued the packet for later. */
|
||||
if (hwaddr == NULL) {
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* Send out the packet using the returned hardware address. */
|
||||
SMEMCPY(dest.addr, hwaddr, 6);
|
||||
return ethernet_output(netif, q, (const struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6);
|
||||
}
|
||||
|
||||
#endif /* LWIP_IPV6 && LWIP_ETHERNET */
|
||||
@@ -1,5 +1,11 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* IPv6 version of ICMP, as per RFC 4443.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* Copyright (c) 2010 Inico Technologies Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -26,154 +32,319 @@
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
* Author: Ivan Delamer <delamer@inicotech.com>
|
||||
*
|
||||
*
|
||||
* Please coordinate changes and requests with Ivan Delamer
|
||||
* <delamer@inicotech.com>
|
||||
*/
|
||||
|
||||
/* Some ICMP messages should be passed to the transport protocols. This
|
||||
is not implemented. */
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
|
||||
#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/icmp6.h"
|
||||
#include "lwip/prot/icmp6.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/nd6.h"
|
||||
#include "lwip/mld6.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef LWIP_ICMP6_DATASIZE
|
||||
#define LWIP_ICMP6_DATASIZE 8
|
||||
#endif
|
||||
#if LWIP_ICMP6_DATASIZE == 0
|
||||
#define LWIP_ICMP6_DATASIZE 8
|
||||
#endif
|
||||
|
||||
/* Forward declarations */
|
||||
static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type);
|
||||
|
||||
|
||||
/**
|
||||
* Process an input ICMPv6 message. Called by ip6_input.
|
||||
*
|
||||
* Will generate a reply for echo requests. Other messages are forwarded
|
||||
* to nd6_input, or mld6_input.
|
||||
*
|
||||
* @param p the mld packet, p->payload pointing to the icmpv6 header
|
||||
* @param inp the netif on which this packet was received
|
||||
*/
|
||||
void
|
||||
icmp_input(struct pbuf *p, struct netif *inp)
|
||||
icmp6_input(struct pbuf *p, struct netif *inp)
|
||||
{
|
||||
u8_t type;
|
||||
struct icmp_echo_hdr *iecho;
|
||||
struct ip_hdr *iphdr;
|
||||
struct ip_addr tmpaddr;
|
||||
struct icmp6_hdr *icmp6hdr;
|
||||
struct pbuf *r;
|
||||
const ip6_addr_t *reply_src;
|
||||
|
||||
ICMP_STATS_INC(icmp.recv);
|
||||
ICMP6_STATS_INC(icmp6.recv);
|
||||
|
||||
/* TODO: check length before accessing payload! */
|
||||
/* Check that ICMPv6 header fits in payload */
|
||||
if (p->len < sizeof(struct icmp6_hdr)) {
|
||||
/* drop short packets */
|
||||
pbuf_free(p);
|
||||
ICMP6_STATS_INC(icmp6.lenerr);
|
||||
ICMP6_STATS_INC(icmp6.drop);
|
||||
return;
|
||||
}
|
||||
|
||||
type = ((u8_t *)p->payload)[0];
|
||||
|
||||
switch (type) {
|
||||
case ICMP6_ECHO:
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
|
||||
|
||||
if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
|
||||
icmp6hdr = (struct icmp6_hdr *)p->payload;
|
||||
|
||||
#if CHECKSUM_CHECK_ICMP6
|
||||
IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP6) {
|
||||
if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(),
|
||||
ip6_current_dest_addr()) != 0) {
|
||||
/* Checksum failed */
|
||||
pbuf_free(p);
|
||||
ICMP_STATS_INC(icmp.lenerr);
|
||||
ICMP6_STATS_INC(icmp6.chkerr);
|
||||
ICMP6_STATS_INC(icmp6.drop);
|
||||
return;
|
||||
}
|
||||
iecho = p->payload;
|
||||
iphdr = (struct ip_hdr *)((u8_t *)p->payload - IP_HLEN);
|
||||
if (inet_chksum_pbuf(p) != 0) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
|
||||
ICMP_STATS_INC(icmp.chkerr);
|
||||
/* return;*/
|
||||
}
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp: p->len %"S16_F" p->tot_len %"S16_F"\n", p->len, p->tot_len));
|
||||
ip_addr_set(&tmpaddr, &(iphdr->src));
|
||||
ip_addr_set(&(iphdr->src), &(iphdr->dest));
|
||||
ip_addr_set(&(iphdr->dest), &tmpaddr);
|
||||
iecho->type = ICMP6_ER;
|
||||
/* adjust the checksum */
|
||||
if (iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) {
|
||||
iecho->chksum += htons(ICMP6_ECHO << 8) + 1;
|
||||
} else {
|
||||
iecho->chksum += htons(ICMP6_ECHO << 8);
|
||||
}
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
|
||||
ICMP_STATS_INC(icmp.xmit);
|
||||
}
|
||||
#endif /* CHECKSUM_CHECK_ICMP6 */
|
||||
|
||||
switch (icmp6hdr->type) {
|
||||
case ICMP6_TYPE_NA: /* Neighbor advertisement */
|
||||
case ICMP6_TYPE_NS: /* Neighbor solicitation */
|
||||
case ICMP6_TYPE_RA: /* Router advertisement */
|
||||
case ICMP6_TYPE_RD: /* Redirect */
|
||||
case ICMP6_TYPE_PTB: /* Packet too big */
|
||||
nd6_input(p, inp);
|
||||
return;
|
||||
break;
|
||||
case ICMP6_TYPE_RS:
|
||||
#if LWIP_IPV6_FORWARD
|
||||
/* @todo implement router functionality */
|
||||
#endif
|
||||
break;
|
||||
#if LWIP_IPV6_MLD
|
||||
case ICMP6_TYPE_MLQ:
|
||||
case ICMP6_TYPE_MLR:
|
||||
case ICMP6_TYPE_MLD:
|
||||
mld6_input(p, inp);
|
||||
return;
|
||||
break;
|
||||
#endif
|
||||
case ICMP6_TYPE_EREQ:
|
||||
#if !LWIP_MULTICAST_PING
|
||||
/* multicast destination address? */
|
||||
if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
|
||||
/* drop */
|
||||
pbuf_free(p);
|
||||
ICMP6_STATS_INC(icmp6.drop);
|
||||
return;
|
||||
}
|
||||
#endif /* LWIP_MULTICAST_PING */
|
||||
|
||||
/* Allocate reply. */
|
||||
r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM);
|
||||
if (r == NULL) {
|
||||
/* drop */
|
||||
pbuf_free(p);
|
||||
ICMP6_STATS_INC(icmp6.memerr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Copy echo request. */
|
||||
if (pbuf_copy(r, p) != ERR_OK) {
|
||||
/* drop */
|
||||
pbuf_free(p);
|
||||
pbuf_free(r);
|
||||
ICMP6_STATS_INC(icmp6.err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Determine reply source IPv6 address. */
|
||||
#if LWIP_MULTICAST_PING
|
||||
if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
|
||||
reply_src = ip_2_ip6(ip6_select_source_address(inp, ip6_current_src_addr()));
|
||||
if (reply_src == NULL) {
|
||||
/* drop */
|
||||
pbuf_free(p);
|
||||
pbuf_free(r);
|
||||
ICMP6_STATS_INC(icmp6.rterr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_MULTICAST_PING */
|
||||
{
|
||||
reply_src = ip6_current_dest_addr();
|
||||
}
|
||||
|
||||
/* Set fields in reply. */
|
||||
((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP;
|
||||
((struct icmp6_echo_hdr *)(r->payload))->chksum = 0;
|
||||
#if CHECKSUM_GEN_ICMP6
|
||||
IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP6) {
|
||||
((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r,
|
||||
IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr());
|
||||
}
|
||||
#endif /* CHECKSUM_GEN_ICMP6 */
|
||||
|
||||
/* Send reply. */
|
||||
ICMP6_STATS_INC(icmp6.xmit);
|
||||
ip6_output_if(r, reply_src, ip6_current_src_addr(),
|
||||
LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp);
|
||||
pbuf_free(r);
|
||||
|
||||
/* LWIP_DEBUGF("icmp: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/
|
||||
ip_output_if (p, &(iphdr->src), IP_HDRINCL,
|
||||
iphdr->hoplim, IP_PROTO_ICMP, inp);
|
||||
break;
|
||||
default:
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" not supported.\n", (s16_t)type));
|
||||
ICMP_STATS_INC(icmp.proterr);
|
||||
ICMP_STATS_INC(icmp.drop);
|
||||
ICMP6_STATS_INC(icmp6.proterr);
|
||||
ICMP6_STATS_INC(icmp6.drop);
|
||||
break;
|
||||
}
|
||||
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send an icmpv6 'destination unreachable' packet.
|
||||
*
|
||||
* @param p the input packet for which the 'unreachable' should be sent,
|
||||
* p->payload pointing to the IPv6 header
|
||||
* @param c ICMPv6 code for the unreachable type
|
||||
*/
|
||||
void
|
||||
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
|
||||
icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c)
|
||||
{
|
||||
struct pbuf *q;
|
||||
struct ip_hdr *iphdr;
|
||||
struct icmp_dur_hdr *idur;
|
||||
|
||||
/* @todo: can this be PBUF_LINK instead of PBUF_IP? */
|
||||
q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
|
||||
/* ICMP header + IP header + 8 bytes of data */
|
||||
if (q == NULL) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold icmp message",
|
||||
(q->len >= (8 + IP_HLEN + 8)));
|
||||
|
||||
iphdr = p->payload;
|
||||
|
||||
idur = q->payload;
|
||||
idur->type = (u8_t)ICMP6_DUR;
|
||||
idur->icode = (u8_t)t;
|
||||
|
||||
SMEMCPY((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8);
|
||||
|
||||
/* calculate checksum */
|
||||
idur->chksum = 0;
|
||||
idur->chksum = inet_chksum(idur, q->len);
|
||||
ICMP_STATS_INC(icmp.xmit);
|
||||
|
||||
ip_output(q, NULL,
|
||||
(struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
|
||||
pbuf_free(q);
|
||||
icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an icmpv6 'packet too big' packet.
|
||||
*
|
||||
* @param p the input packet for which the 'packet too big' should be sent,
|
||||
* p->payload pointing to the IPv6 header
|
||||
* @param mtu the maximum mtu that we can accept
|
||||
*/
|
||||
void
|
||||
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
|
||||
icmp6_packet_too_big(struct pbuf *p, u32_t mtu)
|
||||
{
|
||||
icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an icmpv6 'time exceeded' packet.
|
||||
*
|
||||
* @param p the input packet for which the 'unreachable' should be sent,
|
||||
* p->payload pointing to the IPv6 header
|
||||
* @param c ICMPv6 code for the time exceeded type
|
||||
*/
|
||||
void
|
||||
icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c)
|
||||
{
|
||||
icmp6_send_response(p, c, 0, ICMP6_TYPE_TE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an icmpv6 'parameter problem' packet.
|
||||
*
|
||||
* @param p the input packet for which the 'param problem' should be sent,
|
||||
* p->payload pointing to the IP header
|
||||
* @param c ICMPv6 code for the param problem type
|
||||
* @param pointer the pointer to the byte where the parameter is found
|
||||
*/
|
||||
void
|
||||
icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer)
|
||||
{
|
||||
icmp6_send_response(p, c, pointer, ICMP6_TYPE_PP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an ICMPv6 packet in response to an incoming packet.
|
||||
*
|
||||
* @param p the input packet for which the response should be sent,
|
||||
* p->payload pointing to the IPv6 header
|
||||
* @param code Code of the ICMPv6 header
|
||||
* @param data Additional 32-bit parameter in the ICMPv6 header
|
||||
* @param type Type of the ICMPv6 header
|
||||
*/
|
||||
static void
|
||||
icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type)
|
||||
{
|
||||
struct pbuf *q;
|
||||
struct ip_hdr *iphdr;
|
||||
struct icmp_te_hdr *tehdr;
|
||||
struct icmp6_hdr *icmp6hdr;
|
||||
const ip6_addr_t *reply_src;
|
||||
ip6_addr_t *reply_dest;
|
||||
ip6_addr_t reply_src_local, reply_dest_local;
|
||||
struct ip6_hdr *ip6hdr;
|
||||
struct netif *netif;
|
||||
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n"));
|
||||
|
||||
/* @todo: can this be PBUF_LINK instead of PBUF_IP? */
|
||||
q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
|
||||
/* ICMP header + IP header + 8 bytes of data */
|
||||
/* ICMPv6 header + IPv6 header + data */
|
||||
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE,
|
||||
PBUF_RAM);
|
||||
if (q == NULL) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
|
||||
pbuf_free(p);
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n"));
|
||||
ICMP6_STATS_INC(icmp6.memerr);
|
||||
return;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold icmp message",
|
||||
(q->len >= (8 + IP_HLEN + 8)));
|
||||
LWIP_ASSERT("check that first pbuf can hold icmp 6message",
|
||||
(q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE)));
|
||||
|
||||
iphdr = p->payload;
|
||||
|
||||
tehdr = q->payload;
|
||||
tehdr->type = (u8_t)ICMP6_TE;
|
||||
tehdr->icode = (u8_t)t;
|
||||
icmp6hdr = (struct icmp6_hdr *)q->payload;
|
||||
icmp6hdr->type = type;
|
||||
icmp6hdr->code = code;
|
||||
icmp6hdr->data = data;
|
||||
|
||||
/* copy fields from original packet */
|
||||
SMEMCPY((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8);
|
||||
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload,
|
||||
IP6_HLEN + LWIP_ICMP6_DATASIZE);
|
||||
|
||||
/* Get the destination address and netif for this ICMP message. */
|
||||
if ((ip_current_netif() == NULL) ||
|
||||
((code == ICMP6_TE_FRAG) && (type == ICMP6_TYPE_TE))) {
|
||||
/* Special case, as ip6_current_xxx is either NULL, or points
|
||||
* to a different packet than the one that expired.
|
||||
* We must use the addresses that are stored in the expired packet. */
|
||||
ip6hdr = (struct ip6_hdr *)p->payload;
|
||||
/* copy from packed address to aligned address */
|
||||
ip6_addr_copy(reply_dest_local, ip6hdr->src);
|
||||
ip6_addr_copy(reply_src_local, ip6hdr->dest);
|
||||
reply_dest = &reply_dest_local;
|
||||
reply_src = &reply_src_local;
|
||||
netif = ip6_route(reply_src, reply_dest);
|
||||
if (netif == NULL) {
|
||||
/* drop */
|
||||
pbuf_free(q);
|
||||
ICMP6_STATS_INC(icmp6.rterr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
netif = ip_current_netif();
|
||||
reply_dest = ip6_current_src_addr();
|
||||
|
||||
/* Select an address to use as source. */
|
||||
reply_src = ip_2_ip6(ip6_select_source_address(netif, reply_dest));
|
||||
if (reply_src == NULL) {
|
||||
/* drop */
|
||||
pbuf_free(q);
|
||||
ICMP6_STATS_INC(icmp6.rterr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate checksum */
|
||||
tehdr->chksum = 0;
|
||||
tehdr->chksum = inet_chksum(tehdr, q->len);
|
||||
ICMP_STATS_INC(icmp.xmit);
|
||||
ip_output(q, NULL,
|
||||
(struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
|
||||
icmp6hdr->chksum = 0;
|
||||
#if CHECKSUM_GEN_ICMP6
|
||||
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) {
|
||||
icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len,
|
||||
reply_src, reply_dest);
|
||||
}
|
||||
#endif /* CHECKSUM_GEN_ICMP6 */
|
||||
|
||||
ICMP6_STATS_INC(icmp6.xmit);
|
||||
ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif);
|
||||
pbuf_free(q);
|
||||
}
|
||||
|
||||
#endif /* LWIP_ICMP */
|
||||
#endif /* LWIP_ICMP6 && LWIP_IPV6 */
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
/**
|
||||
* @file
|
||||
* Functions common to all TCP/IPv6 modules, such as the Internet checksum and the
|
||||
* byte order functions.
|
||||
*
|
||||
* INET v6 addresses.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* Copyright (c) 2010 Inico Technologies Ltd.
|
||||
* 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,
|
||||
@@ -18,146 +17,37 @@
|
||||
* 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>
|
||||
*
|
||||
* Author: Ivan Delamer <delamer@inicotech.com>
|
||||
*
|
||||
*
|
||||
* Please coordinate changes and requests with Ivan Delamer
|
||||
* <delamer@inicotech.com>
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/inet.h"
|
||||
|
||||
/* chksum:
|
||||
*
|
||||
* Sums up all 16 bit words in a memory portion. Also includes any odd byte.
|
||||
* This function is used by the other checksum functions.
|
||||
*
|
||||
* For now, this is not optimized. Must be optimized for the particular processor
|
||||
* arcitecture on which it is to run. Preferebly coded in assembler.
|
||||
/** This variable is initialized by the system to contain the wildcard IPv6 address.
|
||||
*/
|
||||
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
|
||||
|
||||
static u32_t
|
||||
chksum(void *dataptr, u16_t len)
|
||||
{
|
||||
u16_t *sdataptr = dataptr;
|
||||
u32_t acc;
|
||||
|
||||
|
||||
for(acc = 0; len > 1; len -= 2) {
|
||||
acc += *sdataptr++;
|
||||
}
|
||||
|
||||
/* add up any odd byte */
|
||||
if (len == 1) {
|
||||
acc += htons((u16_t)(*(u8_t *)dataptr) << 8);
|
||||
}
|
||||
|
||||
return acc;
|
||||
|
||||
}
|
||||
|
||||
/* inet_chksum_pseudo:
|
||||
*
|
||||
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
|
||||
*/
|
||||
|
||||
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 acc;
|
||||
struct pbuf *q;
|
||||
u8_t swapped, i;
|
||||
|
||||
acc = 0;
|
||||
swapped = 0;
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
acc += chksum(q->payload, q->len);
|
||||
while (acc >> 16) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
if (q->len % 2 != 0) {
|
||||
swapped = 1 - swapped;
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (swapped) {
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
for(i = 0; i < 8; i++) {
|
||||
acc += ((u16_t *)src->addr)[i] & 0xffff;
|
||||
acc += ((u16_t *)dest->addr)[i] & 0xffff;
|
||||
while (acc >> 16) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
}
|
||||
acc += (u16_t)htons((u16_t)proto);
|
||||
acc += ((u16_t *)&proto_len)[0] & 0xffff;
|
||||
acc += ((u16_t *)&proto_len)[1] & 0xffff;
|
||||
|
||||
while (acc >> 16) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
return ~(acc & 0xffff);
|
||||
}
|
||||
|
||||
/* inet_chksum:
|
||||
*
|
||||
* Calculates the Internet checksum over a portion of memory. Used primarely for IP
|
||||
* and ICMP.
|
||||
*/
|
||||
|
||||
u16_t
|
||||
inet_chksum(void *dataptr, u16_t len)
|
||||
{
|
||||
u32_t acc, sum;
|
||||
|
||||
acc = chksum(dataptr, len);
|
||||
sum = (acc & 0xffff) + (acc >> 16);
|
||||
sum += (sum >> 16);
|
||||
return ~(sum & 0xffff);
|
||||
}
|
||||
|
||||
u16_t
|
||||
inet_chksum_pbuf(struct pbuf *p)
|
||||
{
|
||||
u32_t acc;
|
||||
struct pbuf *q;
|
||||
u8_t swapped;
|
||||
|
||||
acc = 0;
|
||||
swapped = 0;
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
acc += chksum(q->payload, q->len);
|
||||
while (acc >> 16) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
if (q->len % 2 != 0) {
|
||||
swapped = 1 - swapped;
|
||||
acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (swapped) {
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
|
||||
}
|
||||
return ~(acc & 0xffff);
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
1255
src/core/ipv6/ip6.c
1255
src/core/ipv6/ip6.c
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,14 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* IPv6 addresses.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* Copyright (c) 2010 Inico Technologies Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
@@ -11,62 +17,276 @@
|
||||
* 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>
|
||||
*
|
||||
* Author: Ivan Delamer <delamer@inicotech.com>
|
||||
*
|
||||
* Functions for handling IPv6 addresses.
|
||||
*
|
||||
* Please coordinate changes and requests with Ivan Delamer
|
||||
* <delamer@inicotech.com>
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
u8_t
|
||||
ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
|
||||
struct ip_addr *mask)
|
||||
/* used by IP6_ADDR_ANY(6) in ip6_addr.h */
|
||||
const ip_addr_t ip6_addr_any = IPADDR6_INIT(0ul, 0ul, 0ul, 0ul);
|
||||
|
||||
#ifndef isprint
|
||||
#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up)
|
||||
#define isprint(c) in_range(c, 0x20, 0x7f)
|
||||
#define isdigit(c) in_range(c, '0', '9')
|
||||
#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
|
||||
#define islower(c) in_range(c, 'a', 'z')
|
||||
#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
|
||||
#define xchar(i) ((i) < 10 ? '0' + (i) : 'A' + (i) - 10)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Check whether "cp" is a valid ascii representation
|
||||
* of an IPv6 address and convert to a binary address.
|
||||
* Returns 1 if the address is valid, 0 if not.
|
||||
*
|
||||
* @param cp IPv6 address in ascii representation (e.g. "FF01::1")
|
||||
* @param addr pointer to which to save the ip address in network order
|
||||
* @return 1 if cp could be converted to addr, 0 on failure
|
||||
*/
|
||||
int
|
||||
ip6addr_aton(const char *cp, ip6_addr_t *addr)
|
||||
{
|
||||
return((addr1->addr[0] & mask->addr[0]) == (addr2->addr[0] & mask->addr[0]) &&
|
||||
(addr1->addr[1] & mask->addr[1]) == (addr2->addr[1] & mask->addr[1]) &&
|
||||
(addr1->addr[2] & mask->addr[2]) == (addr2->addr[2] & mask->addr[2]) &&
|
||||
(addr1->addr[3] & mask->addr[3]) == (addr2->addr[3] & mask->addr[3]));
|
||||
|
||||
u32_t addr_index, zero_blocks, current_block_index, current_block_value;
|
||||
const char *s;
|
||||
|
||||
/* Count the number of colons, to count the number of blocks in a "::" sequence
|
||||
zero_blocks may be 1 even if there are no :: sequences */
|
||||
zero_blocks = 8;
|
||||
for (s = cp; *s != 0; s++) {
|
||||
if (*s == ':') {
|
||||
zero_blocks--;
|
||||
} else if (!isxdigit(*s)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* parse each block */
|
||||
addr_index = 0;
|
||||
current_block_index = 0;
|
||||
current_block_value = 0;
|
||||
for (s = cp; *s != 0; s++) {
|
||||
if (*s == ':') {
|
||||
if (addr) {
|
||||
if (current_block_index & 0x1) {
|
||||
addr->addr[addr_index++] |= current_block_value;
|
||||
}
|
||||
else {
|
||||
addr->addr[addr_index] = current_block_value << 16;
|
||||
}
|
||||
}
|
||||
current_block_index++;
|
||||
current_block_value = 0;
|
||||
if (current_block_index > 7) {
|
||||
/* address too long! */
|
||||
return 0;
|
||||
}
|
||||
if (s[1] == ':') {
|
||||
if (s[2] == ':') {
|
||||
/* invalid format: three successive colons */
|
||||
return 0;
|
||||
}
|
||||
s++;
|
||||
/* "::" found, set zeros */
|
||||
while (zero_blocks > 0) {
|
||||
zero_blocks--;
|
||||
if (current_block_index & 0x1) {
|
||||
addr_index++;
|
||||
} else {
|
||||
if (addr) {
|
||||
addr->addr[addr_index] = 0;
|
||||
}
|
||||
}
|
||||
current_block_index++;
|
||||
if (current_block_index > 7) {
|
||||
/* address too long! */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isxdigit(*s)) {
|
||||
/* add current digit */
|
||||
current_block_value = (current_block_value << 4) +
|
||||
(isdigit(*s) ? (u32_t)(*s - '0') :
|
||||
(u32_t)(10 + (islower(*s) ? *s - 'a' : *s - 'A')));
|
||||
} else {
|
||||
/* unexpected digit, space? CRLF? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (addr) {
|
||||
if (current_block_index & 0x1) {
|
||||
addr->addr[addr_index++] |= current_block_value;
|
||||
}
|
||||
else {
|
||||
addr->addr[addr_index] = current_block_value << 16;
|
||||
}
|
||||
}
|
||||
|
||||
/* convert to network byte order. */
|
||||
if (addr) {
|
||||
for (addr_index = 0; addr_index < 4; addr_index++) {
|
||||
addr->addr[addr_index] = lwip_htonl(addr->addr[addr_index]);
|
||||
}
|
||||
}
|
||||
|
||||
if (current_block_index != 7) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
u8_t
|
||||
ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2)
|
||||
/**
|
||||
* Convert numeric IPv6 address into ASCII representation.
|
||||
* returns ptr to static buffer; not reentrant!
|
||||
*
|
||||
* @param addr ip6 address in network order to convert
|
||||
* @return pointer to a global static (!) buffer that holds the ASCII
|
||||
* representation of addr
|
||||
*/
|
||||
char *
|
||||
ip6addr_ntoa(const ip6_addr_t *addr)
|
||||
{
|
||||
return(addr1->addr[0] == addr2->addr[0] &&
|
||||
addr1->addr[1] == addr2->addr[1] &&
|
||||
addr1->addr[2] == addr2->addr[2] &&
|
||||
addr1->addr[3] == addr2->addr[3]);
|
||||
static char str[40];
|
||||
return ip6addr_ntoa_r(addr, str, 40);
|
||||
}
|
||||
|
||||
void
|
||||
ip_addr_set(struct ip_addr *dest, struct ip_addr *src)
|
||||
/**
|
||||
* Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
|
||||
*
|
||||
* @param addr ip6 address in network order to convert
|
||||
* @param buf target buffer where the string is stored
|
||||
* @param buflen length of buf
|
||||
* @return either pointer to buf which now holds the ASCII
|
||||
* representation of addr or NULL if buf was too small
|
||||
*/
|
||||
char *
|
||||
ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen)
|
||||
{
|
||||
SMEMCPY(dest, src, sizeof(struct ip_addr));
|
||||
/* dest->addr[0] = src->addr[0];
|
||||
dest->addr[1] = src->addr[1];
|
||||
dest->addr[2] = src->addr[2];
|
||||
dest->addr[3] = src->addr[3];*/
|
||||
u32_t current_block_index, current_block_value, next_block_value;
|
||||
s32_t i;
|
||||
u8_t zero_flag, empty_block_flag;
|
||||
|
||||
i = 0;
|
||||
empty_block_flag = 0; /* used to indicate a zero chain for "::' */
|
||||
|
||||
for (current_block_index = 0; current_block_index < 8; current_block_index++) {
|
||||
/* get the current 16-bit block */
|
||||
current_block_value = lwip_htonl(addr->addr[current_block_index >> 1]);
|
||||
if ((current_block_index & 0x1) == 0) {
|
||||
current_block_value = current_block_value >> 16;
|
||||
}
|
||||
current_block_value &= 0xffff;
|
||||
|
||||
/* Check for empty block. */
|
||||
if (current_block_value == 0) {
|
||||
if (current_block_index == 7 && empty_block_flag == 1) {
|
||||
/* special case, we must render a ':' for the last block. */
|
||||
buf[i++] = ':';
|
||||
if (i >= buflen) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (empty_block_flag == 0) {
|
||||
/* generate empty block "::", but only if more than one contiguous zero block,
|
||||
* according to current formatting suggestions RFC 5952. */
|
||||
next_block_value = lwip_htonl(addr->addr[(current_block_index + 1) >> 1]);
|
||||
if ((current_block_index & 0x1) == 0x01) {
|
||||
next_block_value = next_block_value >> 16;
|
||||
}
|
||||
next_block_value &= 0xffff;
|
||||
if (next_block_value == 0) {
|
||||
empty_block_flag = 1;
|
||||
buf[i++] = ':';
|
||||
if (i >= buflen) {
|
||||
return NULL;
|
||||
}
|
||||
continue; /* move on to next block. */
|
||||
}
|
||||
} else if (empty_block_flag == 1) {
|
||||
/* move on to next block. */
|
||||
continue;
|
||||
}
|
||||
} else if (empty_block_flag == 1) {
|
||||
/* Set this flag value so we don't produce multiple empty blocks. */
|
||||
empty_block_flag = 2;
|
||||
}
|
||||
|
||||
if (current_block_index > 0) {
|
||||
buf[i++] = ':';
|
||||
if (i >= buflen) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((current_block_value & 0xf000) == 0) {
|
||||
zero_flag = 1;
|
||||
} else {
|
||||
buf[i++] = xchar(((current_block_value & 0xf000) >> 12));
|
||||
zero_flag = 0;
|
||||
if (i >= buflen) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (((current_block_value & 0xf00) == 0) && (zero_flag)) {
|
||||
/* do nothing */
|
||||
} else {
|
||||
buf[i++] = xchar(((current_block_value & 0xf00) >> 8));
|
||||
zero_flag = 0;
|
||||
if (i >= buflen) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (((current_block_value & 0xf0) == 0) && (zero_flag)) {
|
||||
/* do nothing */
|
||||
}
|
||||
else {
|
||||
buf[i++] = xchar(((current_block_value & 0xf0) >> 4));
|
||||
zero_flag = 0;
|
||||
if (i >= buflen) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
buf[i++] = xchar((current_block_value & 0xf));
|
||||
if (i >= buflen) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
buf[i] = 0;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
u8_t
|
||||
ip_addr_isany(struct ip_addr *addr)
|
||||
{
|
||||
if (addr == NULL) return 1;
|
||||
return((addr->addr[0] | addr->addr[1] | addr->addr[2] | addr->addr[3]) == 0);
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
805
src/core/ipv6/ip6_frag.c
Normal file
805
src/core/ipv6/ip6_frag.c
Normal file
@@ -0,0 +1,805 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* IPv6 fragmentation and reassembly.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Inico Technologies Ltd.
|
||||
* 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: Ivan Delamer <delamer@inicotech.com>
|
||||
*
|
||||
*
|
||||
* Please coordinate changes and requests with Ivan Delamer
|
||||
* <delamer@inicotech.com>
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/ip6_frag.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/icmp6.h"
|
||||
#include "lwip/nd6.h"
|
||||
#include "lwip/ip.h"
|
||||
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
|
||||
/** Setting this to 0, you can turn off checking the fragments for overlapping
|
||||
* regions. The code gets a little smaller. Only use this if you know that
|
||||
* overlapping won't occur on your network! */
|
||||
#ifndef IP_REASS_CHECK_OVERLAP
|
||||
#define IP_REASS_CHECK_OVERLAP 1
|
||||
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||
|
||||
/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is
|
||||
* full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller.
|
||||
* Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA
|
||||
* is set to 1, so one datagram can be reassembled at a time, only. */
|
||||
#ifndef IP_REASS_FREE_OLDEST
|
||||
#define IP_REASS_FREE_OLDEST 1
|
||||
#endif /* IP_REASS_FREE_OLDEST */
|
||||
|
||||
#if IPV6_FRAG_COPYHEADER
|
||||
#define IPV6_FRAG_REQROOM ((s16_t)(sizeof(struct ip6_reass_helper) - IP6_FRAG_HLEN))
|
||||
#endif
|
||||
|
||||
#define IP_REASS_FLAG_LASTFRAG 0x01
|
||||
|
||||
/** This is a helper struct which holds the starting
|
||||
* offset and the ending offset of this fragment to
|
||||
* easily chain the fragments.
|
||||
* It has the same packing requirements as the IPv6 header, since it replaces
|
||||
* the Fragment Header in memory in incoming fragments to keep
|
||||
* track of the various fragments.
|
||||
*/
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip6_reass_helper {
|
||||
PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
|
||||
PACK_STRUCT_FIELD(u16_t start);
|
||||
PACK_STRUCT_FIELD(u16_t end);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/* static variables */
|
||||
static struct ip6_reassdata *reassdatagrams;
|
||||
static u16_t ip6_reass_pbufcount;
|
||||
|
||||
/* Forward declarations. */
|
||||
static void ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr);
|
||||
#if IP_REASS_FREE_OLDEST
|
||||
static void ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed);
|
||||
#endif /* IP_REASS_FREE_OLDEST */
|
||||
|
||||
void
|
||||
ip6_reass_tmr(void)
|
||||
{
|
||||
struct ip6_reassdata *r, *tmp;
|
||||
|
||||
#if !IPV6_FRAG_COPYHEADER
|
||||
LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1",
|
||||
sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN);
|
||||
#endif /* !IPV6_FRAG_COPYHEADER */
|
||||
|
||||
r = reassdatagrams;
|
||||
while (r != NULL) {
|
||||
/* Decrement the timer. Once it reaches 0,
|
||||
* clean up the incomplete fragment assembly */
|
||||
if (r->timer > 0) {
|
||||
r->timer--;
|
||||
r = r->next;
|
||||
} else {
|
||||
/* reassembly timed out */
|
||||
tmp = r;
|
||||
/* get the next pointer before freeing */
|
||||
r = r->next;
|
||||
/* free the helper struct and all enqueued pbufs */
|
||||
ip6_reass_free_complete_datagram(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a datagram (struct ip6_reassdata) and all its pbufs.
|
||||
* Updates the total count of enqueued pbufs (ip6_reass_pbufcount),
|
||||
* sends an ICMP time exceeded packet.
|
||||
*
|
||||
* @param ipr datagram to free
|
||||
*/
|
||||
static void
|
||||
ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr)
|
||||
{
|
||||
struct ip6_reassdata *prev;
|
||||
u16_t pbufs_freed = 0;
|
||||
u16_t clen;
|
||||
struct pbuf *p;
|
||||
struct ip6_reass_helper *iprh;
|
||||
|
||||
#if LWIP_ICMP6
|
||||
iprh = (struct ip6_reass_helper *)ipr->p->payload;
|
||||
if (iprh->start == 0) {
|
||||
/* The first fragment was received, send ICMP time exceeded. */
|
||||
/* First, de-queue the first pbuf from r->p. */
|
||||
p = ipr->p;
|
||||
ipr->p = iprh->next_pbuf;
|
||||
/* Then, move back to the original ipv6 header (we are now pointing to Fragment header).
|
||||
This cannot fail since we already checked when receiving this fragment. */
|
||||
if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)IPV6_FRAG_HDRREF(ipr->iphdr)))) {
|
||||
LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed\n", 0);
|
||||
}
|
||||
else {
|
||||
icmp6_time_exceeded(p, ICMP6_TE_FRAG);
|
||||
}
|
||||
clen = pbuf_clen(p);
|
||||
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
|
||||
pbufs_freed += clen;
|
||||
pbuf_free(p);
|
||||
}
|
||||
#endif /* LWIP_ICMP6 */
|
||||
|
||||
/* First, free all received pbufs. The individual pbufs need to be released
|
||||
separately as they have not yet been chained */
|
||||
p = ipr->p;
|
||||
while (p != NULL) {
|
||||
struct pbuf *pcur;
|
||||
iprh = (struct ip6_reass_helper *)p->payload;
|
||||
pcur = p;
|
||||
/* get the next pointer before freeing */
|
||||
p = iprh->next_pbuf;
|
||||
clen = pbuf_clen(pcur);
|
||||
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
|
||||
pbufs_freed += clen;
|
||||
pbuf_free(pcur);
|
||||
}
|
||||
|
||||
/* Then, unchain the struct ip6_reassdata from the list and free it. */
|
||||
if (ipr == reassdatagrams) {
|
||||
reassdatagrams = ipr->next;
|
||||
} else {
|
||||
prev = reassdatagrams;
|
||||
while (prev != NULL) {
|
||||
if (prev->next == ipr) {
|
||||
break;
|
||||
}
|
||||
prev = prev->next;
|
||||
}
|
||||
if (prev != NULL) {
|
||||
prev->next = ipr->next;
|
||||
}
|
||||
}
|
||||
memp_free(MEMP_IP6_REASSDATA, ipr);
|
||||
|
||||
/* Finally, update number of pbufs in reassembly queue */
|
||||
LWIP_ASSERT("ip_reass_pbufcount >= clen", ip6_reass_pbufcount >= pbufs_freed);
|
||||
ip6_reass_pbufcount -= pbufs_freed;
|
||||
}
|
||||
|
||||
#if IP_REASS_FREE_OLDEST
|
||||
/**
|
||||
* Free the oldest datagram to make room for enqueueing new fragments.
|
||||
* The datagram ipr is not freed!
|
||||
*
|
||||
* @param ipr ip6_reassdata for the current fragment
|
||||
* @param pbufs_needed number of pbufs needed to enqueue
|
||||
* (used for freeing other datagrams if not enough space)
|
||||
*/
|
||||
static void
|
||||
ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed)
|
||||
{
|
||||
struct ip6_reassdata *r, *oldest;
|
||||
|
||||
/* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,
|
||||
* but don't free the current datagram! */
|
||||
do {
|
||||
r = oldest = reassdatagrams;
|
||||
while (r != NULL) {
|
||||
if (r != ipr) {
|
||||
if (r->timer <= oldest->timer) {
|
||||
/* older than the previous oldest */
|
||||
oldest = r;
|
||||
}
|
||||
}
|
||||
r = r->next;
|
||||
}
|
||||
if (oldest == ipr) {
|
||||
/* nothing to free, ipr is the only element on the list */
|
||||
return;
|
||||
}
|
||||
if (oldest != NULL) {
|
||||
ip6_reass_free_complete_datagram(oldest);
|
||||
}
|
||||
} while (((ip6_reass_pbufcount + pbufs_needed) > IP_REASS_MAX_PBUFS) && (reassdatagrams != NULL));
|
||||
}
|
||||
#endif /* IP_REASS_FREE_OLDEST */
|
||||
|
||||
/**
|
||||
* Reassembles incoming IPv6 fragments into an IPv6 datagram.
|
||||
*
|
||||
* @param p points to the IPv6 Fragment Header
|
||||
* @return NULL if reassembly is incomplete, pbuf pointing to
|
||||
* IPv6 Header if reassembly is complete
|
||||
*/
|
||||
struct pbuf *
|
||||
ip6_reass(struct pbuf *p)
|
||||
{
|
||||
struct ip6_reassdata *ipr, *ipr_prev;
|
||||
struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
|
||||
struct ip6_frag_hdr *frag_hdr;
|
||||
u16_t offset, len;
|
||||
u16_t clen;
|
||||
u8_t valid = 1;
|
||||
struct pbuf *q;
|
||||
|
||||
IP6_FRAG_STATS_INC(ip6_frag.recv);
|
||||
|
||||
if ((const void*)ip6_current_header() != ((u8_t*)p->payload) - IP6_HLEN) {
|
||||
/* ip6_frag_hdr must be in the first pbuf, not chained */
|
||||
IP6_FRAG_STATS_INC(ip6_frag.proterr);
|
||||
IP6_FRAG_STATS_INC(ip6_frag.drop);
|
||||
goto nullreturn;
|
||||
}
|
||||
|
||||
frag_hdr = (struct ip6_frag_hdr *) p->payload;
|
||||
|
||||
clen = pbuf_clen(p);
|
||||
|
||||
offset = lwip_ntohs(frag_hdr->_fragment_offset);
|
||||
|
||||
/* Calculate fragment length from IPv6 payload length.
|
||||
* Adjust for headers before Fragment Header.
|
||||
* And finally adjust by Fragment Header length. */
|
||||
len = lwip_ntohs(ip6_current_header()->_plen);
|
||||
len -= (u16_t)(((u8_t*)p->payload - (const u8_t*)ip6_current_header()) - IP6_HLEN);
|
||||
len -= IP6_FRAG_HLEN;
|
||||
|
||||
/* Look for the datagram the fragment belongs to in the current datagram queue,
|
||||
* remembering the previous in the queue for later dequeueing. */
|
||||
for (ipr = reassdatagrams, ipr_prev = NULL; ipr != NULL; ipr = ipr->next) {
|
||||
/* Check if the incoming fragment matches the one currently present
|
||||
in the reassembly buffer. If so, we proceed with copying the
|
||||
fragment into the buffer. */
|
||||
if ((frag_hdr->_identification == ipr->identification) &&
|
||||
ip6_addr_cmp(ip6_current_src_addr(), &(IPV6_FRAG_HDRREF(ipr->iphdr)->src)) &&
|
||||
ip6_addr_cmp(ip6_current_dest_addr(), &(IPV6_FRAG_HDRREF(ipr->iphdr)->dest))) {
|
||||
IP6_FRAG_STATS_INC(ip6_frag.cachehit);
|
||||
break;
|
||||
}
|
||||
ipr_prev = ipr;
|
||||
}
|
||||
|
||||
if (ipr == NULL) {
|
||||
/* Enqueue a new datagram into the datagram queue */
|
||||
ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA);
|
||||
if (ipr == NULL) {
|
||||
#if IP_REASS_FREE_OLDEST
|
||||
/* Make room and try again. */
|
||||
ip6_reass_remove_oldest_datagram(ipr, clen);
|
||||
ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA);
|
||||
if (ipr != NULL) {
|
||||
/* re-search ipr_prev since it might have been removed */
|
||||
for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) {
|
||||
if (ipr_prev->next == ipr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif /* IP_REASS_FREE_OLDEST */
|
||||
{
|
||||
IP6_FRAG_STATS_INC(ip6_frag.memerr);
|
||||
IP6_FRAG_STATS_INC(ip6_frag.drop);
|
||||
goto nullreturn;
|
||||
}
|
||||
}
|
||||
|
||||
memset(ipr, 0, sizeof(struct ip6_reassdata));
|
||||
ipr->timer = IP_REASS_MAXAGE;
|
||||
|
||||
/* enqueue the new structure to the front of the list */
|
||||
ipr->next = reassdatagrams;
|
||||
reassdatagrams = ipr;
|
||||
|
||||
/* Use the current IPv6 header for src/dest address reference.
|
||||
* Eventually, we will replace it when we get the first fragment
|
||||
* (it might be this one, in any case, it is done later). */
|
||||
#if IPV6_FRAG_COPYHEADER
|
||||
MEMCPY(&ipr->iphdr, ip6_current_header(), IP6_HLEN);
|
||||
#else /* IPV6_FRAG_COPYHEADER */
|
||||
/* need to use the none-const pointer here: */
|
||||
ipr->iphdr = ip_data.current_ip6_header;
|
||||
#endif /* IPV6_FRAG_COPYHEADER */
|
||||
|
||||
/* copy the fragmented packet id. */
|
||||
ipr->identification = frag_hdr->_identification;
|
||||
|
||||
/* copy the nexth field */
|
||||
ipr->nexth = frag_hdr->_nexth;
|
||||
}
|
||||
|
||||
/* Check if we are allowed to enqueue more datagrams. */
|
||||
if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
|
||||
#if IP_REASS_FREE_OLDEST
|
||||
ip6_reass_remove_oldest_datagram(ipr, clen);
|
||||
if ((ip6_reass_pbufcount + clen) <= IP_REASS_MAX_PBUFS) {
|
||||
/* re-search ipr_prev since it might have been removed */
|
||||
for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) {
|
||||
if (ipr_prev->next == ipr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif /* IP_REASS_FREE_OLDEST */
|
||||
{
|
||||
/* @todo: send ICMPv6 time exceeded here? */
|
||||
/* drop this pbuf */
|
||||
IP6_FRAG_STATS_INC(ip6_frag.memerr);
|
||||
IP6_FRAG_STATS_INC(ip6_frag.drop);
|
||||
goto nullreturn;
|
||||
}
|
||||
}
|
||||
|
||||
/* Overwrite Fragment Header with our own helper struct. */
|
||||
#if IPV6_FRAG_COPYHEADER
|
||||
if (IPV6_FRAG_REQROOM > 0) {
|
||||
/* Make room for struct ip6_reass_helper (only required if sizeof(void*) > 4).
|
||||
This cannot fail since we already checked when receiving this fragment. */
|
||||
u8_t hdrerr = pbuf_header_force(p, IPV6_FRAG_REQROOM);
|
||||
LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */
|
||||
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0);
|
||||
}
|
||||
#else /* IPV6_FRAG_COPYHEADER */
|
||||
LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1",
|
||||
sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN);
|
||||
#endif /* IPV6_FRAG_COPYHEADER */
|
||||
iprh = (struct ip6_reass_helper *)p->payload;
|
||||
iprh->next_pbuf = NULL;
|
||||
iprh->start = (offset & IP6_FRAG_OFFSET_MASK);
|
||||
iprh->end = (offset & IP6_FRAG_OFFSET_MASK) + len;
|
||||
|
||||
/* find the right place to insert this pbuf */
|
||||
/* Iterate through until we either get to the end of the list (append),
|
||||
* or we find on with a larger offset (insert). */
|
||||
for (q = ipr->p; q != NULL;) {
|
||||
iprh_tmp = (struct ip6_reass_helper*)q->payload;
|
||||
if (iprh->start < iprh_tmp->start) {
|
||||
#if IP_REASS_CHECK_OVERLAP
|
||||
if (iprh->end > iprh_tmp->start) {
|
||||
/* fragment overlaps with following, throw away */
|
||||
IP6_FRAG_STATS_INC(ip6_frag.proterr);
|
||||
IP6_FRAG_STATS_INC(ip6_frag.drop);
|
||||
goto nullreturn;
|
||||
}
|
||||
if (iprh_prev != NULL) {
|
||||
if (iprh->start < iprh_prev->end) {
|
||||
/* fragment overlaps with previous, throw away */
|
||||
IP6_FRAG_STATS_INC(ip6_frag.proterr);
|
||||
IP6_FRAG_STATS_INC(ip6_frag.drop);
|
||||
goto nullreturn;
|
||||
}
|
||||
}
|
||||
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||
/* the new pbuf should be inserted before this */
|
||||
iprh->next_pbuf = q;
|
||||
if (iprh_prev != NULL) {
|
||||
/* not the fragment with the lowest offset */
|
||||
iprh_prev->next_pbuf = p;
|
||||
} else {
|
||||
/* fragment with the lowest offset */
|
||||
ipr->p = p;
|
||||
}
|
||||
break;
|
||||
} else if (iprh->start == iprh_tmp->start) {
|
||||
/* received the same datagram twice: no need to keep the datagram */
|
||||
IP6_FRAG_STATS_INC(ip6_frag.drop);
|
||||
goto nullreturn;
|
||||
#if IP_REASS_CHECK_OVERLAP
|
||||
} else if (iprh->start < iprh_tmp->end) {
|
||||
/* overlap: no need to keep the new datagram */
|
||||
IP6_FRAG_STATS_INC(ip6_frag.proterr);
|
||||
IP6_FRAG_STATS_INC(ip6_frag.drop);
|
||||
goto nullreturn;
|
||||
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||
} else {
|
||||
/* Check if the fragments received so far have no gaps. */
|
||||
if (iprh_prev != NULL) {
|
||||
if (iprh_prev->end != iprh_tmp->start) {
|
||||
/* There is a fragment missing between the current
|
||||
* and the previous fragment */
|
||||
valid = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
q = iprh_tmp->next_pbuf;
|
||||
iprh_prev = iprh_tmp;
|
||||
}
|
||||
|
||||
/* If q is NULL, then we made it to the end of the list. Determine what to do now */
|
||||
if (q == NULL) {
|
||||
if (iprh_prev != NULL) {
|
||||
/* this is (for now), the fragment with the highest offset:
|
||||
* chain it to the last fragment */
|
||||
#if IP_REASS_CHECK_OVERLAP
|
||||
LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);
|
||||
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||
iprh_prev->next_pbuf = p;
|
||||
if (iprh_prev->end != iprh->start) {
|
||||
valid = 0;
|
||||
}
|
||||
} else {
|
||||
#if IP_REASS_CHECK_OVERLAP
|
||||
LWIP_ASSERT("no previous fragment, this must be the first fragment!",
|
||||
ipr->p == NULL);
|
||||
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||
/* this is the first fragment we ever received for this ip datagram */
|
||||
ipr->p = p;
|
||||
}
|
||||
}
|
||||
|
||||
/* Track the current number of pbufs current 'in-flight', in order to limit
|
||||
the number of fragments that may be enqueued at any one time */
|
||||
ip6_reass_pbufcount += clen;
|
||||
|
||||
/* Remember IPv6 header if this is the first fragment. */
|
||||
if (iprh->start == 0) {
|
||||
#if IPV6_FRAG_COPYHEADER
|
||||
if (iprh->next_pbuf != NULL) {
|
||||
MEMCPY(&ipr->iphdr, ip6_current_header(), IP6_HLEN);
|
||||
}
|
||||
#else /* IPV6_FRAG_COPYHEADER */
|
||||
/* need to use the none-const pointer here: */
|
||||
ipr->iphdr = ip_data.current_ip6_header;
|
||||
#endif /* IPV6_FRAG_COPYHEADER */
|
||||
}
|
||||
|
||||
/* If this is the last fragment, calculate total packet length. */
|
||||
if ((offset & IP6_FRAG_MORE_FLAG) == 0) {
|
||||
ipr->datagram_len = iprh->end;
|
||||
}
|
||||
|
||||
/* Additional validity tests: we have received first and last fragment. */
|
||||
iprh_tmp = (struct ip6_reass_helper*)ipr->p->payload;
|
||||
if (iprh_tmp->start != 0) {
|
||||
valid = 0;
|
||||
}
|
||||
if (ipr->datagram_len == 0) {
|
||||
valid = 0;
|
||||
}
|
||||
|
||||
/* Final validity test: no gaps between current and last fragment. */
|
||||
iprh_prev = iprh;
|
||||
q = iprh->next_pbuf;
|
||||
while ((q != NULL) && valid) {
|
||||
iprh = (struct ip6_reass_helper*)q->payload;
|
||||
if (iprh_prev->end != iprh->start) {
|
||||
valid = 0;
|
||||
break;
|
||||
}
|
||||
iprh_prev = iprh;
|
||||
q = iprh->next_pbuf;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
/* All fragments have been received */
|
||||
struct ip6_hdr* iphdr_ptr;
|
||||
|
||||
/* chain together the pbufs contained within the ip6_reassdata list. */
|
||||
iprh = (struct ip6_reass_helper*) ipr->p->payload;
|
||||
while (iprh != NULL) {
|
||||
struct pbuf* next_pbuf = iprh->next_pbuf;
|
||||
if (next_pbuf != NULL) {
|
||||
/* Save next helper struct (will be hidden in next step). */
|
||||
iprh_tmp = (struct ip6_reass_helper*)next_pbuf->payload;
|
||||
|
||||
/* hide the fragment header for every succeeding fragment */
|
||||
pbuf_header(next_pbuf, -IP6_FRAG_HLEN);
|
||||
#if IPV6_FRAG_COPYHEADER
|
||||
if (IPV6_FRAG_REQROOM > 0) {
|
||||
/* hide the extra bytes borrowed from ip6_hdr for struct ip6_reass_helper */
|
||||
u8_t hdrerr = pbuf_header(next_pbuf, -(s16_t)(IPV6_FRAG_REQROOM));
|
||||
LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */
|
||||
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0);
|
||||
}
|
||||
#endif
|
||||
pbuf_cat(ipr->p, next_pbuf);
|
||||
}
|
||||
else {
|
||||
iprh_tmp = NULL;
|
||||
}
|
||||
|
||||
iprh = iprh_tmp;
|
||||
}
|
||||
|
||||
#if IPV6_FRAG_COPYHEADER
|
||||
if (IPV6_FRAG_REQROOM > 0) {
|
||||
/* get back room for struct ip6_reass_helper (only required if sizeof(void*) > 4) */
|
||||
u8_t hdrerr = pbuf_header(ipr->p, -(s16_t)(IPV6_FRAG_REQROOM));
|
||||
LWIP_UNUSED_ARG(hdrerr); /* in case of LWIP_NOASSERT */
|
||||
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == 0);
|
||||
}
|
||||
iphdr_ptr = (struct ip6_hdr*)((u8_t*)ipr->p->payload - IP6_HLEN);
|
||||
MEMCPY(iphdr_ptr, &ipr->iphdr, IP6_HLEN);
|
||||
#else
|
||||
iphdr_ptr = ipr->iphdr;
|
||||
#endif
|
||||
|
||||
/* Adjust datagram length by adding header lengths. */
|
||||
ipr->datagram_len += (u16_t)(((u8_t*)ipr->p->payload - (u8_t*)iphdr_ptr)
|
||||
+ IP6_FRAG_HLEN
|
||||
- IP6_HLEN);
|
||||
|
||||
/* Set payload length in ip header. */
|
||||
iphdr_ptr->_plen = lwip_htons(ipr->datagram_len);
|
||||
|
||||
/* Get the first pbuf. */
|
||||
p = ipr->p;
|
||||
|
||||
/* Restore Fragment Header in first pbuf. Mark as "single fragment"
|
||||
* packet. Restore nexth. */
|
||||
frag_hdr = (struct ip6_frag_hdr *) p->payload;
|
||||
frag_hdr->_nexth = ipr->nexth;
|
||||
frag_hdr->reserved = 0;
|
||||
frag_hdr->_fragment_offset = 0;
|
||||
frag_hdr->_identification = 0;
|
||||
|
||||
/* release the sources allocate for the fragment queue entry */
|
||||
if (reassdatagrams == ipr) {
|
||||
/* it was the first in the list */
|
||||
reassdatagrams = ipr->next;
|
||||
} else {
|
||||
/* it wasn't the first, so it must have a valid 'prev' */
|
||||
LWIP_ASSERT("sanity check linked list", ipr_prev != NULL);
|
||||
ipr_prev->next = ipr->next;
|
||||
}
|
||||
memp_free(MEMP_IP6_REASSDATA, ipr);
|
||||
|
||||
/* adjust the number of pbufs currently queued for reassembly. */
|
||||
ip6_reass_pbufcount -= pbuf_clen(p);
|
||||
|
||||
/* Move pbuf back to IPv6 header.
|
||||
This cannot fail since we already checked when receiving this fragment. */
|
||||
if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)iphdr_ptr))) {
|
||||
LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0);
|
||||
pbuf_free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return the pbuf chain */
|
||||
return p;
|
||||
}
|
||||
/* the datagram is not (yet?) reassembled completely */
|
||||
return NULL;
|
||||
|
||||
nullreturn:
|
||||
pbuf_free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */
|
||||
|
||||
#if LWIP_IPV6 && LWIP_IPV6_FRAG
|
||||
|
||||
#if !LWIP_NETIF_TX_SINGLE_PBUF
|
||||
/** Allocate a new struct pbuf_custom_ref */
|
||||
static struct pbuf_custom_ref*
|
||||
ip6_frag_alloc_pbuf_custom_ref(void)
|
||||
{
|
||||
return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
|
||||
}
|
||||
|
||||
/** Free a struct pbuf_custom_ref */
|
||||
static void
|
||||
ip6_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p)
|
||||
{
|
||||
LWIP_ASSERT("p != NULL", p != NULL);
|
||||
memp_free(MEMP_FRAG_PBUF, p);
|
||||
}
|
||||
|
||||
/** Free-callback function to free a 'struct pbuf_custom_ref', called by
|
||||
* pbuf_free. */
|
||||
static void
|
||||
ip6_frag_free_pbuf_custom(struct pbuf *p)
|
||||
{
|
||||
struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p;
|
||||
LWIP_ASSERT("pcr != NULL", pcr != NULL);
|
||||
LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p);
|
||||
if (pcr->original != NULL) {
|
||||
pbuf_free(pcr->original);
|
||||
}
|
||||
ip6_frag_free_pbuf_custom_ref(pcr);
|
||||
}
|
||||
#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
|
||||
|
||||
/**
|
||||
* Fragment an IPv6 datagram if too large for the netif or path MTU.
|
||||
*
|
||||
* Chop the datagram in MTU sized chunks and send them in order
|
||||
* by pointing PBUF_REFs into p
|
||||
*
|
||||
* @param p ipv6 packet to send
|
||||
* @param netif the netif on which to send
|
||||
* @param dest destination ipv6 address to which to send
|
||||
*
|
||||
* @return ERR_OK if sent successfully, err_t otherwise
|
||||
*/
|
||||
err_t
|
||||
ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest)
|
||||
{
|
||||
struct ip6_hdr *original_ip6hdr;
|
||||
struct ip6_hdr *ip6hdr;
|
||||
struct ip6_frag_hdr *frag_hdr;
|
||||
struct pbuf *rambuf;
|
||||
#if !LWIP_NETIF_TX_SINGLE_PBUF
|
||||
struct pbuf *newpbuf;
|
||||
u16_t newpbuflen = 0;
|
||||
u16_t left_to_copy;
|
||||
#endif
|
||||
static u32_t identification;
|
||||
u16_t nfb;
|
||||
u16_t left, cop;
|
||||
u16_t mtu;
|
||||
u16_t fragment_offset = 0;
|
||||
u16_t last;
|
||||
u16_t poff = IP6_HLEN;
|
||||
|
||||
identification++;
|
||||
|
||||
original_ip6hdr = (struct ip6_hdr *)p->payload;
|
||||
|
||||
mtu = nd6_get_destination_mtu(dest, netif);
|
||||
|
||||
/* @todo we assume there are no options in the unfragmentable part (IPv6 header). */
|
||||
left = p->tot_len - IP6_HLEN;
|
||||
|
||||
nfb = (mtu - (IP6_HLEN + IP6_FRAG_HLEN)) & IP6_FRAG_OFFSET_MASK;
|
||||
|
||||
while (left) {
|
||||
last = (left <= nfb);
|
||||
|
||||
/* Fill this fragment */
|
||||
cop = last ? left : nfb;
|
||||
|
||||
#if LWIP_NETIF_TX_SINGLE_PBUF
|
||||
rambuf = pbuf_alloc(PBUF_IP, cop + IP6_FRAG_HLEN, PBUF_RAM);
|
||||
if (rambuf == NULL) {
|
||||
IP6_FRAG_STATS_INC(ip6_frag.memerr);
|
||||
return ERR_MEM;
|
||||
}
|
||||
LWIP_ASSERT("this needs a pbuf in one piece!",
|
||||
(rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
|
||||
poff += pbuf_copy_partial(p, (u8_t*)rambuf->payload + IP6_FRAG_HLEN, cop, poff);
|
||||
/* make room for the IP header */
|
||||
if (pbuf_header(rambuf, IP6_HLEN)) {
|
||||
pbuf_free(rambuf);
|
||||
IP6_FRAG_STATS_INC(ip6_frag.memerr);
|
||||
return ERR_MEM;
|
||||
}
|
||||
/* fill in the IP header */
|
||||
SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN);
|
||||
ip6hdr = (struct ip6_hdr *)rambuf->payload;
|
||||
frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN);
|
||||
#else
|
||||
/* When not using a static buffer, create a chain of pbufs.
|
||||
* The first will be a PBUF_RAM holding the link, IPv6, and Fragment header.
|
||||
* The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
|
||||
* but limited to the size of an mtu.
|
||||
*/
|
||||
rambuf = pbuf_alloc(PBUF_LINK, IP6_HLEN + IP6_FRAG_HLEN, PBUF_RAM);
|
||||
if (rambuf == NULL) {
|
||||
IP6_FRAG_STATS_INC(ip6_frag.memerr);
|
||||
return ERR_MEM;
|
||||
}
|
||||
LWIP_ASSERT("this needs a pbuf in one piece!",
|
||||
(p->len >= (IP6_HLEN)));
|
||||
SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN);
|
||||
ip6hdr = (struct ip6_hdr *)rambuf->payload;
|
||||
frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN);
|
||||
|
||||
/* Can just adjust p directly for needed offset. */
|
||||
p->payload = (u8_t *)p->payload + poff;
|
||||
p->len -= poff;
|
||||
p->tot_len -= poff;
|
||||
|
||||
left_to_copy = cop;
|
||||
while (left_to_copy) {
|
||||
struct pbuf_custom_ref *pcr;
|
||||
newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
|
||||
/* Is this pbuf already empty? */
|
||||
if (!newpbuflen) {
|
||||
p = p->next;
|
||||
continue;
|
||||
}
|
||||
pcr = ip6_frag_alloc_pbuf_custom_ref();
|
||||
if (pcr == NULL) {
|
||||
pbuf_free(rambuf);
|
||||
IP6_FRAG_STATS_INC(ip6_frag.memerr);
|
||||
return ERR_MEM;
|
||||
}
|
||||
/* Mirror this pbuf, although we might not need all of it. */
|
||||
newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
|
||||
if (newpbuf == NULL) {
|
||||
ip6_frag_free_pbuf_custom_ref(pcr);
|
||||
pbuf_free(rambuf);
|
||||
IP6_FRAG_STATS_INC(ip6_frag.memerr);
|
||||
return ERR_MEM;
|
||||
}
|
||||
pbuf_ref(p);
|
||||
pcr->original = p;
|
||||
pcr->pc.custom_free_function = ip6_frag_free_pbuf_custom;
|
||||
|
||||
/* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
|
||||
* so that it is removed when pbuf_dechain is later called on rambuf.
|
||||
*/
|
||||
pbuf_cat(rambuf, newpbuf);
|
||||
left_to_copy -= newpbuflen;
|
||||
if (left_to_copy) {
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
poff = newpbuflen;
|
||||
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
|
||||
|
||||
/* Set headers */
|
||||
frag_hdr->_nexth = original_ip6hdr->_nexth;
|
||||
frag_hdr->reserved = 0;
|
||||
frag_hdr->_fragment_offset = lwip_htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG));
|
||||
frag_hdr->_identification = lwip_htonl(identification);
|
||||
|
||||
IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT);
|
||||
IP6H_PLEN_SET(ip6hdr, cop + IP6_FRAG_HLEN);
|
||||
|
||||
/* No need for separate header pbuf - we allowed room for it in rambuf
|
||||
* when allocated.
|
||||
*/
|
||||
IP6_FRAG_STATS_INC(ip6_frag.xmit);
|
||||
netif->output_ip6(netif, rambuf, dest);
|
||||
|
||||
/* Unfortunately we can't reuse rambuf - the hardware may still be
|
||||
* using the buffer. Instead we free it (and the ensuing chain) and
|
||||
* recreate it next time round the loop. If we're lucky the hardware
|
||||
* will have already sent the packet, the free will really free, and
|
||||
* there will be zero memory penalty.
|
||||
*/
|
||||
|
||||
pbuf_free(rambuf);
|
||||
left -= cop;
|
||||
fragment_offset += cop;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */
|
||||
588
src/core/ipv6/mld6.c
Normal file
588
src/core/ipv6/mld6.c
Normal file
@@ -0,0 +1,588 @@
|
||||
/**
|
||||
* @file
|
||||
* Multicast listener discovery
|
||||
*
|
||||
* @defgroup mld6 MLD6
|
||||
* @ingroup ip6
|
||||
* Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710.
|
||||
* No support for MLDv2.\n
|
||||
* To be called from TCPIP thread
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Inico Technologies Ltd.
|
||||
* 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: Ivan Delamer <delamer@inicotech.com>
|
||||
*
|
||||
*
|
||||
* Please coordinate changes and requests with Ivan Delamer
|
||||
* <delamer@inicotech.com>
|
||||
*/
|
||||
|
||||
/* Based on igmp.c implementation of igmp v2 protocol */
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/mld6.h"
|
||||
#include "lwip/prot/mld6.h"
|
||||
#include "lwip/icmp6.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/*
|
||||
* MLD constants
|
||||
*/
|
||||
#define MLD6_HL 1
|
||||
#define MLD6_JOIN_DELAYING_MEMBER_TMR_MS (500)
|
||||
|
||||
#define MLD6_GROUP_NON_MEMBER 0
|
||||
#define MLD6_GROUP_DELAYING_MEMBER 1
|
||||
#define MLD6_GROUP_IDLE_MEMBER 2
|
||||
|
||||
/* Forward declarations. */
|
||||
static struct mld_group *mld6_new_group(struct netif *ifp, const ip6_addr_t *addr);
|
||||
static err_t mld6_remove_group(struct netif *netif, struct mld_group *group);
|
||||
static void mld6_delayed_report(struct mld_group *group, u16_t maxresp);
|
||||
static void mld6_send(struct netif *netif, struct mld_group *group, u8_t type);
|
||||
|
||||
|
||||
/**
|
||||
* Stop MLD processing on interface
|
||||
*
|
||||
* @param netif network interface on which stop MLD processing
|
||||
*/
|
||||
err_t
|
||||
mld6_stop(struct netif *netif)
|
||||
{
|
||||
struct mld_group *group = netif_mld6_data(netif);
|
||||
|
||||
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, NULL);
|
||||
|
||||
while (group != NULL) {
|
||||
struct mld_group *next = group->next; /* avoid use-after-free below */
|
||||
|
||||
/* disable the group at the MAC level */
|
||||
if (netif->mld_mac_filter != NULL) {
|
||||
netif->mld_mac_filter(netif, &(group->group_address), NETIF_DEL_MAC_FILTER);
|
||||
}
|
||||
|
||||
/* free group */
|
||||
memp_free(MEMP_MLD6_GROUP, group);
|
||||
|
||||
/* move to "next" */
|
||||
group = next;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report MLD memberships for this interface
|
||||
*
|
||||
* @param netif network interface on which report MLD memberships
|
||||
*/
|
||||
void
|
||||
mld6_report_groups(struct netif *netif)
|
||||
{
|
||||
struct mld_group *group = netif_mld6_data(netif);
|
||||
|
||||
while (group != NULL) {
|
||||
mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
|
||||
group = group->next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for a group that is joined on a netif
|
||||
*
|
||||
* @param ifp the network interface for which to look
|
||||
* @param addr the group ipv6 address to search for
|
||||
* @return a struct mld_group* if the group has been found,
|
||||
* NULL if the group wasn't found.
|
||||
*/
|
||||
struct mld_group *
|
||||
mld6_lookfor_group(struct netif *ifp, const ip6_addr_t *addr)
|
||||
{
|
||||
struct mld_group *group = netif_mld6_data(ifp);
|
||||
|
||||
while (group != NULL) {
|
||||
if (ip6_addr_cmp(&(group->group_address), addr)) {
|
||||
return group;
|
||||
}
|
||||
group = group->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* create a new group
|
||||
*
|
||||
* @param ifp the network interface for which to create
|
||||
* @param addr the new group ipv6
|
||||
* @return a struct mld_group*,
|
||||
* NULL on memory error.
|
||||
*/
|
||||
static struct mld_group *
|
||||
mld6_new_group(struct netif *ifp, const ip6_addr_t *addr)
|
||||
{
|
||||
struct mld_group *group;
|
||||
|
||||
group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP);
|
||||
if (group != NULL) {
|
||||
ip6_addr_set(&(group->group_address), addr);
|
||||
group->timer = 0; /* Not running */
|
||||
group->group_state = MLD6_GROUP_IDLE_MEMBER;
|
||||
group->last_reporter_flag = 0;
|
||||
group->use = 0;
|
||||
group->next = netif_mld6_data(ifp);
|
||||
|
||||
netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, group);
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a group from the mld_group_list, but do not free it yet
|
||||
*
|
||||
* @param group the group to remove
|
||||
* @return ERR_OK if group was removed from the list, an err_t otherwise
|
||||
*/
|
||||
static err_t
|
||||
mld6_remove_group(struct netif *netif, struct mld_group *group)
|
||||
{
|
||||
err_t err = ERR_OK;
|
||||
|
||||
/* Is it the first group? */
|
||||
if (netif_mld6_data(netif) == group) {
|
||||
netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, group->next);
|
||||
} else {
|
||||
/* look for group further down the list */
|
||||
struct mld_group *tmpGroup;
|
||||
for (tmpGroup = netif_mld6_data(netif); tmpGroup != NULL; tmpGroup = tmpGroup->next) {
|
||||
if (tmpGroup->next == group) {
|
||||
tmpGroup->next = group->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Group not find group */
|
||||
if (tmpGroup == NULL) {
|
||||
err = ERR_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process an input MLD message. Called by icmp6_input.
|
||||
*
|
||||
* @param p the mld packet, p->payload pointing to the icmpv6 header
|
||||
* @param inp the netif on which this packet was received
|
||||
*/
|
||||
void
|
||||
mld6_input(struct pbuf *p, struct netif *inp)
|
||||
{
|
||||
struct mld_header *mld_hdr;
|
||||
struct mld_group *group;
|
||||
|
||||
MLD6_STATS_INC(mld6.recv);
|
||||
|
||||
/* Check that mld header fits in packet. */
|
||||
if (p->len < sizeof(struct mld_header)) {
|
||||
/* @todo debug message */
|
||||
pbuf_free(p);
|
||||
MLD6_STATS_INC(mld6.lenerr);
|
||||
MLD6_STATS_INC(mld6.drop);
|
||||
return;
|
||||
}
|
||||
|
||||
mld_hdr = (struct mld_header *)p->payload;
|
||||
|
||||
switch (mld_hdr->type) {
|
||||
case ICMP6_TYPE_MLQ: /* Multicast listener query. */
|
||||
/* Is it a general query? */
|
||||
if (ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) &&
|
||||
ip6_addr_isany(&(mld_hdr->multicast_address))) {
|
||||
MLD6_STATS_INC(mld6.rx_general);
|
||||
/* Report all groups, except all nodes group, and if-local groups. */
|
||||
group = netif_mld6_data(inp);
|
||||
while (group != NULL) {
|
||||
if ((!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) &&
|
||||
(!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) {
|
||||
mld6_delayed_report(group, mld_hdr->max_resp_delay);
|
||||
}
|
||||
group = group->next;
|
||||
}
|
||||
} else {
|
||||
/* Have we joined this group?
|
||||
* We use IP6 destination address to have a memory aligned copy.
|
||||
* mld_hdr->multicast_address should be the same. */
|
||||
MLD6_STATS_INC(mld6.rx_group);
|
||||
group = mld6_lookfor_group(inp, ip6_current_dest_addr());
|
||||
if (group != NULL) {
|
||||
/* Schedule a report. */
|
||||
mld6_delayed_report(group, mld_hdr->max_resp_delay);
|
||||
}
|
||||
}
|
||||
break; /* ICMP6_TYPE_MLQ */
|
||||
case ICMP6_TYPE_MLR: /* Multicast listener report. */
|
||||
/* Have we joined this group?
|
||||
* We use IP6 destination address to have a memory aligned copy.
|
||||
* mld_hdr->multicast_address should be the same. */
|
||||
MLD6_STATS_INC(mld6.rx_report);
|
||||
group = mld6_lookfor_group(inp, ip6_current_dest_addr());
|
||||
if (group != NULL) {
|
||||
/* If we are waiting to report, cancel it. */
|
||||
if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) {
|
||||
group->timer = 0; /* stopped */
|
||||
group->group_state = MLD6_GROUP_IDLE_MEMBER;
|
||||
group->last_reporter_flag = 0;
|
||||
}
|
||||
}
|
||||
break; /* ICMP6_TYPE_MLR */
|
||||
case ICMP6_TYPE_MLD: /* Multicast listener done. */
|
||||
/* Do nothing, router will query us. */
|
||||
break; /* ICMP6_TYPE_MLD */
|
||||
default:
|
||||
MLD6_STATS_INC(mld6.proterr);
|
||||
MLD6_STATS_INC(mld6.drop);
|
||||
break;
|
||||
}
|
||||
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup mld6
|
||||
* Join a group on a network interface.
|
||||
*
|
||||
* @param srcaddr ipv6 address of the network interface which should
|
||||
* join a new group. If IP6_ADDR_ANY, join on all netifs
|
||||
* @param groupaddr the ipv6 address of the group to join
|
||||
* @return ERR_OK if group was joined on the netif(s), an err_t otherwise
|
||||
*/
|
||||
err_t
|
||||
mld6_joingroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr)
|
||||
{
|
||||
err_t err = ERR_VAL; /* no matching interface */
|
||||
struct netif *netif;
|
||||
|
||||
/* loop through netif's */
|
||||
netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
/* Should we join this interface ? */
|
||||
if (ip6_addr_isany(srcaddr) ||
|
||||
netif_get_ip6_addr_match(netif, srcaddr) >= 0) {
|
||||
err = mld6_joingroup_netif(netif, groupaddr);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* proceed to next network interface */
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup mld6
|
||||
* Join a group on a network interface.
|
||||
*
|
||||
* @param netif the network interface which should join a new group.
|
||||
* @param groupaddr the ipv6 address of the group to join
|
||||
* @return ERR_OK if group was joined on the netif, an err_t otherwise
|
||||
*/
|
||||
err_t
|
||||
mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr)
|
||||
{
|
||||
struct mld_group *group;
|
||||
|
||||
/* find group or create a new one if not found */
|
||||
group = mld6_lookfor_group(netif, groupaddr);
|
||||
|
||||
if (group == NULL) {
|
||||
/* Joining a new group. Create a new group entry. */
|
||||
group = mld6_new_group(netif, groupaddr);
|
||||
if (group == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
/* Activate this address on the MAC layer. */
|
||||
if (netif->mld_mac_filter != NULL) {
|
||||
netif->mld_mac_filter(netif, groupaddr, NETIF_ADD_MAC_FILTER);
|
||||
}
|
||||
|
||||
/* Report our membership. */
|
||||
MLD6_STATS_INC(mld6.tx_report);
|
||||
mld6_send(netif, group, ICMP6_TYPE_MLR);
|
||||
mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
|
||||
}
|
||||
|
||||
/* Increment group use */
|
||||
group->use++;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup mld6
|
||||
* Leave a group on a network interface.
|
||||
*
|
||||
* @param srcaddr ipv6 address of the network interface which should
|
||||
* leave the group. If IP6_ISANY, leave on all netifs
|
||||
* @param groupaddr the ipv6 address of the group to leave
|
||||
* @return ERR_OK if group was left on the netif(s), an err_t otherwise
|
||||
*/
|
||||
err_t
|
||||
mld6_leavegroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr)
|
||||
{
|
||||
err_t err = ERR_VAL; /* no matching interface */
|
||||
struct netif *netif;
|
||||
|
||||
/* loop through netif's */
|
||||
netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
/* Should we leave this interface ? */
|
||||
if (ip6_addr_isany(srcaddr) ||
|
||||
netif_get_ip6_addr_match(netif, srcaddr) >= 0) {
|
||||
err_t res = mld6_leavegroup_netif(netif, groupaddr);
|
||||
if (err != ERR_OK) {
|
||||
/* Store this result if we have not yet gotten a success */
|
||||
err = res;
|
||||
}
|
||||
}
|
||||
/* proceed to next network interface */
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup mld6
|
||||
* Leave a group on a network interface.
|
||||
*
|
||||
* @param netif the network interface which should leave the group.
|
||||
* @param groupaddr the ipv6 address of the group to leave
|
||||
* @return ERR_OK if group was left on the netif, an err_t otherwise
|
||||
*/
|
||||
err_t
|
||||
mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr)
|
||||
{
|
||||
struct mld_group *group;
|
||||
|
||||
/* find group */
|
||||
group = mld6_lookfor_group(netif, groupaddr);
|
||||
|
||||
if (group != NULL) {
|
||||
/* Leave if there is no other use of the group */
|
||||
if (group->use <= 1) {
|
||||
/* Remove the group from the list */
|
||||
mld6_remove_group(netif, group);
|
||||
|
||||
/* If we are the last reporter for this group */
|
||||
if (group->last_reporter_flag) {
|
||||
MLD6_STATS_INC(mld6.tx_leave);
|
||||
mld6_send(netif, group, ICMP6_TYPE_MLD);
|
||||
}
|
||||
|
||||
/* Disable the group at the MAC level */
|
||||
if (netif->mld_mac_filter != NULL) {
|
||||
netif->mld_mac_filter(netif, groupaddr, NETIF_DEL_MAC_FILTER);
|
||||
}
|
||||
|
||||
/* free group struct */
|
||||
memp_free(MEMP_MLD6_GROUP, group);
|
||||
} else {
|
||||
/* Decrement group use */
|
||||
group->use--;
|
||||
}
|
||||
|
||||
/* Left group */
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* Group not found */
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Periodic timer for mld processing. Must be called every
|
||||
* MLD6_TMR_INTERVAL milliseconds (100).
|
||||
*
|
||||
* When a delaying member expires, a membership report is sent.
|
||||
*/
|
||||
void
|
||||
mld6_tmr(void)
|
||||
{
|
||||
struct netif *netif = netif_list;
|
||||
|
||||
while (netif != NULL) {
|
||||
struct mld_group *group = netif_mld6_data(netif);
|
||||
|
||||
while (group != NULL) {
|
||||
if (group->timer > 0) {
|
||||
group->timer--;
|
||||
if (group->timer == 0) {
|
||||
/* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */
|
||||
if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) {
|
||||
MLD6_STATS_INC(mld6.tx_report);
|
||||
mld6_send(netif, group, ICMP6_TYPE_MLR);
|
||||
group->group_state = MLD6_GROUP_IDLE_MEMBER;
|
||||
}
|
||||
}
|
||||
}
|
||||
group = group->next;
|
||||
}
|
||||
netif = netif->next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a delayed membership report for a group
|
||||
*
|
||||
* @param group the mld_group for which "delaying" membership report
|
||||
* should be sent
|
||||
* @param maxresp the max resp delay provided in the query
|
||||
*/
|
||||
static void
|
||||
mld6_delayed_report(struct mld_group *group, u16_t maxresp)
|
||||
{
|
||||
/* Convert maxresp from milliseconds to tmr ticks */
|
||||
maxresp = maxresp / MLD6_TMR_INTERVAL;
|
||||
if (maxresp == 0) {
|
||||
maxresp = 1;
|
||||
}
|
||||
|
||||
#ifdef LWIP_RAND
|
||||
/* Randomize maxresp. (if LWIP_RAND is supported) */
|
||||
maxresp = LWIP_RAND() % maxresp;
|
||||
if (maxresp == 0) {
|
||||
maxresp = 1;
|
||||
}
|
||||
#endif /* LWIP_RAND */
|
||||
|
||||
/* Apply timer value if no report has been scheduled already. */
|
||||
if ((group->group_state == MLD6_GROUP_IDLE_MEMBER) ||
|
||||
((group->group_state == MLD6_GROUP_DELAYING_MEMBER) &&
|
||||
((group->timer == 0) || (maxresp < group->timer)))) {
|
||||
group->timer = maxresp;
|
||||
group->group_state = MLD6_GROUP_DELAYING_MEMBER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a MLD message (report or done).
|
||||
*
|
||||
* An IPv6 hop-by-hop options header with a router alert option
|
||||
* is prepended.
|
||||
*
|
||||
* @param group the group to report or quit
|
||||
* @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done)
|
||||
*/
|
||||
static void
|
||||
mld6_send(struct netif *netif, struct mld_group *group, u8_t type)
|
||||
{
|
||||
struct mld_header *mld_hdr;
|
||||
struct pbuf *p;
|
||||
const ip6_addr_t *src_addr;
|
||||
|
||||
/* Allocate a packet. Size is MLD header + IPv6 Hop-by-hop options header. */
|
||||
p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr), PBUF_RAM);
|
||||
if (p == NULL) {
|
||||
MLD6_STATS_INC(mld6.memerr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Move to make room for Hop-by-hop options header. */
|
||||
if (pbuf_header(p, -IP6_HBH_HLEN)) {
|
||||
pbuf_free(p);
|
||||
MLD6_STATS_INC(mld6.lenerr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Select our source address. */
|
||||
if (!ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) {
|
||||
/* This is a special case, when we are performing duplicate address detection.
|
||||
* We must join the multicast group, but we don't have a valid address yet. */
|
||||
src_addr = IP6_ADDR_ANY6;
|
||||
} else {
|
||||
/* Use link-local address as source address. */
|
||||
src_addr = netif_ip6_addr(netif, 0);
|
||||
}
|
||||
|
||||
/* MLD message header pointer. */
|
||||
mld_hdr = (struct mld_header *)p->payload;
|
||||
|
||||
/* Set fields. */
|
||||
mld_hdr->type = type;
|
||||
mld_hdr->code = 0;
|
||||
mld_hdr->chksum = 0;
|
||||
mld_hdr->max_resp_delay = 0;
|
||||
mld_hdr->reserved = 0;
|
||||
ip6_addr_set(&(mld_hdr->multicast_address), &(group->group_address));
|
||||
|
||||
#if CHECKSUM_GEN_ICMP6
|
||||
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) {
|
||||
mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len,
|
||||
src_addr, &(group->group_address));
|
||||
}
|
||||
#endif /* CHECKSUM_GEN_ICMP6 */
|
||||
|
||||
/* Add hop-by-hop headers options: router alert with MLD value. */
|
||||
ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD);
|
||||
|
||||
if (type == ICMP6_TYPE_MLR) {
|
||||
/* Remember we were the last to report */
|
||||
group->last_reporter_flag = 1;
|
||||
}
|
||||
|
||||
/* Send the packet out. */
|
||||
MLD6_STATS_INC(mld6.xmit);
|
||||
ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address),
|
||||
MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, netif);
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
#endif /* LWIP_IPV6 */
|
||||
2102
src/core/ipv6/nd6.c
Normal file
2102
src/core/ipv6/nd6.c
Normal file
File diff suppressed because it is too large
Load Diff
237
src/core/mem.c
237
src/core/mem.c
@@ -9,7 +9,7 @@
|
||||
*
|
||||
* To let mem_malloc() use pools (prevents fragmentation and is much faster than
|
||||
* a heap but might waste some memory), define MEM_USE_POOLS to 1, define
|
||||
* MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list
|
||||
* MEMP_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list
|
||||
* of pools like this (more pools can be added between _START and _END):
|
||||
*
|
||||
* Define three pools with sizes 256, 512, and 1512 bytes
|
||||
@@ -54,19 +54,106 @@
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/err.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if MEM_USE_POOLS
|
||||
/* lwIP head implemented with different sized pools */
|
||||
#if MEM_LIBC_MALLOC
|
||||
#include <stdlib.h> /* for malloc()/free() */
|
||||
#endif
|
||||
|
||||
#if MEM_LIBC_MALLOC || MEM_USE_POOLS
|
||||
|
||||
/** mem_init is not used when using pools instead of a heap or using
|
||||
* C library malloc().
|
||||
*/
|
||||
void
|
||||
mem_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
/** mem_trim is not used when using pools instead of a heap or using
|
||||
* C library malloc(): we can't free part of a pool element and the stack
|
||||
* support mem_trim() to return a different pointer
|
||||
*/
|
||||
void*
|
||||
mem_trim(void *mem, mem_size_t size)
|
||||
{
|
||||
LWIP_UNUSED_ARG(size);
|
||||
return mem;
|
||||
}
|
||||
#endif /* MEM_LIBC_MALLOC || MEM_USE_POOLS */
|
||||
|
||||
#if MEM_LIBC_MALLOC
|
||||
/* lwIP heap implemented using C library malloc() */
|
||||
|
||||
/* in case C library malloc() needs extra protection,
|
||||
* allow these defines to be overridden.
|
||||
*/
|
||||
#ifndef mem_clib_free
|
||||
#define mem_clib_free free
|
||||
#endif
|
||||
#ifndef mem_clib_malloc
|
||||
#define mem_clib_malloc malloc
|
||||
#endif
|
||||
#ifndef mem_clib_calloc
|
||||
#define mem_clib_calloc calloc
|
||||
#endif
|
||||
|
||||
#if LWIP_STATS && MEM_STATS
|
||||
#define MEM_LIBC_STATSHELPER_SIZE LWIP_MEM_ALIGN_SIZE(sizeof(mem_size_t))
|
||||
#else
|
||||
#define MEM_LIBC_STATSHELPER_SIZE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Allocate a block of memory with a minimum of 'size' bytes.
|
||||
*
|
||||
* @param size is the minimum size of the requested block in bytes.
|
||||
* @return pointer to allocated memory or NULL if no free memory was found.
|
||||
*
|
||||
* Note that the returned value must always be aligned (as defined by MEM_ALIGNMENT).
|
||||
*/
|
||||
void *
|
||||
mem_malloc(mem_size_t size)
|
||||
{
|
||||
void* ret = mem_clib_malloc(size + MEM_LIBC_STATSHELPER_SIZE);
|
||||
if (ret == NULL) {
|
||||
MEM_STATS_INC(err);
|
||||
} else {
|
||||
LWIP_ASSERT("malloc() must return aligned memory", LWIP_MEM_ALIGN(ret) == ret);
|
||||
#if LWIP_STATS && MEM_STATS
|
||||
*(mem_size_t*)ret = size;
|
||||
ret = (u8_t*)ret + MEM_LIBC_STATSHELPER_SIZE;
|
||||
MEM_STATS_INC_USED(used, size);
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Put memory back on the heap
|
||||
*
|
||||
* @param rmem is the pointer as returned by a previous call to mem_malloc()
|
||||
*/
|
||||
void
|
||||
mem_free(void *rmem)
|
||||
{
|
||||
LWIP_ASSERT("rmem != NULL", (rmem != NULL));
|
||||
LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
|
||||
#if LWIP_STATS && MEM_STATS
|
||||
rmem = (u8_t*)rmem - MEM_LIBC_STATSHELPER_SIZE;
|
||||
MEM_STATS_DEC_USED(used, *(mem_size_t*)rmem);
|
||||
#endif
|
||||
mem_clib_free(rmem);
|
||||
}
|
||||
|
||||
#elif MEM_USE_POOLS
|
||||
|
||||
/* lwIP heap implemented with different sized pools */
|
||||
|
||||
/**
|
||||
* Allocate memory: determine the smallest pool that is big enough
|
||||
@@ -78,44 +165,51 @@
|
||||
void *
|
||||
mem_malloc(mem_size_t size)
|
||||
{
|
||||
struct memp_malloc_helper *element;
|
||||
void *ret;
|
||||
struct memp_malloc_helper *element = NULL;
|
||||
memp_t poolnr;
|
||||
mem_size_t required_size = size + sizeof(struct memp_malloc_helper);
|
||||
mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));
|
||||
|
||||
for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) {
|
||||
#if MEM_USE_POOLS_TRY_BIGGER_POOL
|
||||
again:
|
||||
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
|
||||
/* is this pool big enough to hold an element of the required size
|
||||
plus a struct memp_malloc_helper that saves the pool this element came from? */
|
||||
if (required_size <= memp_sizes[poolnr]) {
|
||||
if (required_size <= memp_pools[poolnr]->size) {
|
||||
element = (struct memp_malloc_helper*)memp_malloc(poolnr);
|
||||
if (element == NULL) {
|
||||
/* No need to DEBUGF or ASSERT: This error is already taken care of in memp.c */
|
||||
#if MEM_USE_POOLS_TRY_BIGGER_POOL
|
||||
/** Try a bigger pool if this one is empty! */
|
||||
if (poolnr < MEMP_POOL_LAST) {
|
||||
continue;
|
||||
}
|
||||
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
|
||||
MEM_STATS_INC(err);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (poolnr > MEMP_POOL_LAST) {
|
||||
LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
|
||||
return NULL;
|
||||
}
|
||||
element = (struct memp_malloc_helper*)memp_malloc(poolnr);
|
||||
if (element == NULL) {
|
||||
/* No need to DEBUGF or ASSERT: This error is already
|
||||
taken care of in memp.c */
|
||||
#if MEM_USE_POOLS_TRY_BIGGER_POOL
|
||||
/** Try a bigger pool if this one is empty! */
|
||||
if (poolnr < MEMP_POOL_LAST) {
|
||||
poolnr++;
|
||||
goto again;
|
||||
}
|
||||
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
|
||||
MEM_STATS_INC(err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* save the pool number this element came from */
|
||||
element->poolnr = poolnr;
|
||||
/* and return a pointer to the memory directly after the struct memp_malloc_helper */
|
||||
element++;
|
||||
ret = (u8_t*)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));
|
||||
|
||||
return element;
|
||||
#if MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS)
|
||||
/* truncating to u16_t is safe because struct memp_desc::size is u16_t */
|
||||
element->size = (u16_t)size;
|
||||
MEM_STATS_INC_USED(used, element->size);
|
||||
#endif /* MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS) */
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
/* initialize unused memory (diff between requested size and selected pool's size) */
|
||||
memset((u8_t*)ret + size, 0xcd, memp_pools[poolnr]->size - size);
|
||||
#endif /* MEMP_OVERFLOW_CHECK */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,18 +222,33 @@ again:
|
||||
void
|
||||
mem_free(void *rmem)
|
||||
{
|
||||
struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem;
|
||||
struct memp_malloc_helper *hmem;
|
||||
|
||||
LWIP_ASSERT("rmem != NULL", (rmem != NULL));
|
||||
LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
|
||||
|
||||
/* get the original struct memp_malloc_helper */
|
||||
hmem--;
|
||||
/* cast through void* to get rid of alignment warnings */
|
||||
hmem = (struct memp_malloc_helper*)(void*)((u8_t*)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)));
|
||||
|
||||
LWIP_ASSERT("hmem != NULL", (hmem != NULL));
|
||||
LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem)));
|
||||
LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX));
|
||||
|
||||
MEM_STATS_DEC_USED(used, hmem->size);
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
{
|
||||
u16_t i;
|
||||
LWIP_ASSERT("MEM_USE_POOLS: invalid chunk size",
|
||||
hmem->size <= memp_pools[hmem->poolnr]->size);
|
||||
/* check that unused memory remained untouched (diff between requested size and selected pool's size) */
|
||||
for (i = hmem->size; i < memp_pools[hmem->poolnr]->size; i++) {
|
||||
u8_t data = *((u8_t*)rmem + i);
|
||||
LWIP_ASSERT("MEM_USE_POOLS: mem overflow detected", data == 0xcd);
|
||||
}
|
||||
}
|
||||
#endif /* MEMP_OVERFLOW_CHECK */
|
||||
|
||||
/* and put it in the pool we saved earlier */
|
||||
memp_free(hmem->poolnr, hmem);
|
||||
}
|
||||
@@ -150,7 +259,7 @@ mem_free(void *rmem)
|
||||
/**
|
||||
* The heap is made up as a list of structs of this type.
|
||||
* This does not have to be aligned since for getting its size,
|
||||
* we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes.
|
||||
* we only use the macro SIZEOF_STRUCT_MEM, which automatically aligns.
|
||||
*/
|
||||
struct mem {
|
||||
/** index (-> ram[next]) of the next struct */
|
||||
@@ -178,7 +287,7 @@ struct mem {
|
||||
* how that space is calculated). */
|
||||
#ifndef LWIP_RAM_HEAP_POINTER
|
||||
/** the heap. we need one struct mem at the end and some room for alignment */
|
||||
u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];
|
||||
LWIP_DECLARE_MEMORY_ALIGNED(ram_heap, MEM_SIZE_ALIGNED + (2U*SIZEOF_STRUCT_MEM));
|
||||
#define LWIP_RAM_HEAP_POINTER ram_heap
|
||||
#endif /* LWIP_RAM_HEAP_POINTER */
|
||||
|
||||
@@ -190,7 +299,9 @@ static struct mem *ram_end;
|
||||
static struct mem *lfree;
|
||||
|
||||
/** concurrent access protection */
|
||||
#if !NO_SYS
|
||||
static sys_mutex_t mem_mutex;
|
||||
#endif
|
||||
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
|
||||
@@ -293,7 +404,7 @@ mem_init(void)
|
||||
|
||||
MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
|
||||
|
||||
if(sys_mutex_new(&mem_mutex) != ERR_OK) {
|
||||
if (sys_mutex_new(&mem_mutex) != ERR_OK) {
|
||||
LWIP_ASSERT("failed to create mem_mutex", 0);
|
||||
}
|
||||
}
|
||||
@@ -331,6 +442,7 @@ mem_free(void *rmem)
|
||||
/* protect the heap from concurrent access */
|
||||
LWIP_MEM_FREE_PROTECT();
|
||||
/* Get the corresponding struct mem ... */
|
||||
/* cast through void* to get rid of alignment warnings */
|
||||
mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
|
||||
/* ... which has to be in a used state ... */
|
||||
LWIP_ASSERT("mem_free: mem->used", mem->used);
|
||||
@@ -375,7 +487,7 @@ mem_trim(void *rmem, mem_size_t newsize)
|
||||
adjust for alignment. */
|
||||
newsize = LWIP_MEM_ALIGN_SIZE(newsize);
|
||||
|
||||
if(newsize < MIN_SIZE_ALIGNED) {
|
||||
if (newsize < MIN_SIZE_ALIGNED) {
|
||||
/* every data block must be at least MIN_SIZE_ALIGNED long */
|
||||
newsize = MIN_SIZE_ALIGNED;
|
||||
}
|
||||
@@ -397,6 +509,7 @@ mem_trim(void *rmem, mem_size_t newsize)
|
||||
return rmem;
|
||||
}
|
||||
/* Get the corresponding struct mem ... */
|
||||
/* cast through void* to get rid of alignment warnings */
|
||||
mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
|
||||
/* ... and its offset pointer */
|
||||
ptr = (mem_size_t)((u8_t *)mem - ram);
|
||||
@@ -416,7 +529,7 @@ mem_trim(void *rmem, mem_size_t newsize)
|
||||
LWIP_MEM_FREE_PROTECT();
|
||||
|
||||
mem2 = (struct mem *)(void *)&ram[mem->next];
|
||||
if(mem2->used == 0) {
|
||||
if (mem2->used == 0) {
|
||||
/* The next struct is unused, we can simply move it at little */
|
||||
mem_size_t next;
|
||||
/* remember the old next pointer */
|
||||
@@ -468,7 +581,7 @@ mem_trim(void *rmem, mem_size_t newsize)
|
||||
/* else {
|
||||
next struct mem is used but size between mem and mem2 is not big enough
|
||||
to create another struct mem
|
||||
-> don't do anyhting.
|
||||
-> don't do anyhting.
|
||||
-> the remaining space stays unused since it is too small
|
||||
} */
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
@@ -479,7 +592,6 @@ mem_trim(void *rmem, mem_size_t newsize)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adam's mem_malloc() plus solution for bug #17922
|
||||
* Allocate a block of memory with a minimum of 'size' bytes.
|
||||
*
|
||||
* @param size is the minimum size of the requested block in bytes.
|
||||
@@ -505,7 +617,7 @@ mem_malloc(mem_size_t size)
|
||||
adjust for alignment. */
|
||||
size = LWIP_MEM_ALIGN_SIZE(size);
|
||||
|
||||
if(size < MIN_SIZE_ALIGNED) {
|
||||
if (size < MIN_SIZE_ALIGNED) {
|
||||
/* every data block must be at least MIN_SIZE_ALIGNED long */
|
||||
size = MIN_SIZE_ALIGNED;
|
||||
}
|
||||
@@ -518,7 +630,7 @@ mem_malloc(mem_size_t size)
|
||||
sys_mutex_lock(&mem_mutex);
|
||||
LWIP_MEM_ALLOC_PROTECT();
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
/* run as long as a mem_free disturbed mem_malloc */
|
||||
/* run as long as a mem_free disturbed mem_malloc or mem_trim */
|
||||
do {
|
||||
local_mem_free_count = 0;
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
@@ -532,12 +644,14 @@ mem_malloc(mem_size_t size)
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
mem_free_count = 0;
|
||||
LWIP_MEM_ALLOC_UNPROTECT();
|
||||
/* allow mem_free to run */
|
||||
/* allow mem_free or mem_trim to run */
|
||||
LWIP_MEM_ALLOC_PROTECT();
|
||||
if (mem_free_count != 0) {
|
||||
local_mem_free_count = mem_free_count;
|
||||
/* If mem_free or mem_trim have run, we have to restart since they
|
||||
could have altered our current struct mem. */
|
||||
local_mem_free_count = 1;
|
||||
break;
|
||||
}
|
||||
mem_free_count = 0;
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
|
||||
if ((!mem->used) &&
|
||||
@@ -574,22 +688,34 @@ mem_malloc(mem_size_t size)
|
||||
/* (a mem2 struct does no fit into the user data space of mem and mem->next will always
|
||||
* be used at this point: if not we have 2 unused structs in a row, plug_holes should have
|
||||
* take care of this).
|
||||
* -> near fit or excact fit: do not split, no mem2 creation
|
||||
* -> near fit or exact fit: do not split, no mem2 creation
|
||||
* also can't move mem->next directly behind mem, since mem->next
|
||||
* will always be used at this point!
|
||||
*/
|
||||
mem->used = 1;
|
||||
MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram));
|
||||
}
|
||||
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
mem_malloc_adjust_lfree:
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
if (mem == lfree) {
|
||||
struct mem *cur = lfree;
|
||||
/* Find next free block after mem and update lowest free pointer */
|
||||
while (lfree->used && lfree != ram_end) {
|
||||
while (cur->used && cur != ram_end) {
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
mem_free_count = 0;
|
||||
LWIP_MEM_ALLOC_UNPROTECT();
|
||||
/* prevent high interrupt latency... */
|
||||
LWIP_MEM_ALLOC_PROTECT();
|
||||
lfree = (struct mem *)(void *)&ram[lfree->next];
|
||||
if (mem_free_count != 0) {
|
||||
/* If mem_free or mem_trim have run, we have to restart since they
|
||||
could have altered our current struct mem or lfree. */
|
||||
goto mem_malloc_adjust_lfree;
|
||||
}
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
cur = (struct mem *)(void *)&ram[cur->next];
|
||||
}
|
||||
lfree = cur;
|
||||
LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
|
||||
}
|
||||
LWIP_MEM_ALLOC_UNPROTECT();
|
||||
@@ -606,7 +732,7 @@ mem_malloc(mem_size_t size)
|
||||
}
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
/* if we got interrupted by a mem_free, try again */
|
||||
} while(local_mem_free_count != 0);
|
||||
} while (local_mem_free_count != 0);
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
|
||||
MEM_STATS_INC(err);
|
||||
@@ -616,6 +742,15 @@ mem_malloc(mem_size_t size)
|
||||
}
|
||||
|
||||
#endif /* MEM_USE_POOLS */
|
||||
|
||||
#if MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS)
|
||||
void *
|
||||
mem_calloc(mem_size_t count, mem_size_t size)
|
||||
{
|
||||
return mem_clib_calloc(count, size);
|
||||
}
|
||||
|
||||
#else /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */
|
||||
/**
|
||||
* Contiguously allocates enough space for count objects that are size bytes
|
||||
* of memory each and returns a pointer to the allocated memory.
|
||||
@@ -626,7 +761,8 @@ mem_malloc(mem_size_t size)
|
||||
* @param size size of the objects to allocate
|
||||
* @return pointer to allocated memory / NULL pointer if there is an error
|
||||
*/
|
||||
void *mem_calloc(mem_size_t count, mem_size_t size)
|
||||
void *
|
||||
mem_calloc(mem_size_t count, mem_size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
@@ -634,9 +770,8 @@ void *mem_calloc(mem_size_t count, mem_size_t size)
|
||||
p = mem_malloc(count * size);
|
||||
if (p) {
|
||||
/* zero the memory */
|
||||
memset(p, 0, count * size);
|
||||
memset(p, 0, (size_t)count * (size_t)size);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif /* !MEM_LIBC_MALLOC */
|
||||
#endif /* MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS) */
|
||||
|
||||
635
src/core/memp.c
635
src/core/memp.c
@@ -4,13 +4,18 @@
|
||||
*
|
||||
* lwIP has dedicated pools for many structures (netconn, protocol control blocks,
|
||||
* packet buffers, ...). All these pools are managed here.
|
||||
*
|
||||
* @defgroup mempool Memory pools
|
||||
* @ingroup infrastructure
|
||||
* Custom memory pools
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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,
|
||||
@@ -19,21 +24,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>
|
||||
*
|
||||
*/
|
||||
@@ -41,201 +46,102 @@
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/raw.h"
|
||||
#include "lwip/tcp_impl.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/api.h"
|
||||
#include "lwip/api_msg.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/timers.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "lwip/ip_frag.h"
|
||||
#include "lwip/snmp_structs.h"
|
||||
#include "lwip/snmp_msg.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "netif/ppp_oe.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
|
||||
/* Make sure we include everything we need for size calculation required by memp_std.h */
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/raw.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/priv/tcp_priv.h"
|
||||
#include "lwip/ip4_frag.h"
|
||||
#include "lwip/netbuf.h"
|
||||
#include "lwip/api.h"
|
||||
#include "lwip/priv/tcpip_priv.h"
|
||||
#include "lwip/priv/api_msg.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/netifapi.h"
|
||||
#include "lwip/etharp.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/timeouts.h"
|
||||
/* needed by default MEMP_NUM_SYS_TIMEOUT */
|
||||
#include "netif/ppp/ppp_opts.h"
|
||||
#include "lwip/netdb.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/priv/nd6_priv.h"
|
||||
#include "lwip/ip6_frag.h"
|
||||
#include "lwip/mld6.h"
|
||||
|
||||
struct memp {
|
||||
struct memp *next;
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
const char *file;
|
||||
int line;
|
||||
#endif /* MEMP_OVERFLOW_CHECK */
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc)
|
||||
#include "lwip/priv/memp_std.h"
|
||||
|
||||
const struct memp_desc* const memp_pools[MEMP_MAX] = {
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name,
|
||||
#include "lwip/priv/memp_std.h"
|
||||
};
|
||||
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning
|
||||
* and at the end of each element, initialize them as 0xcd and check
|
||||
* them later. */
|
||||
/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,
|
||||
* every single element in each pool is checked!
|
||||
* This is VERY SLOW but also very helpful. */
|
||||
/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in
|
||||
* lwipopts.h to change the amount reserved for checking. */
|
||||
#ifndef MEMP_SANITY_REGION_BEFORE
|
||||
#define MEMP_SANITY_REGION_BEFORE 16
|
||||
#endif /* MEMP_SANITY_REGION_BEFORE*/
|
||||
#if MEMP_SANITY_REGION_BEFORE > 0
|
||||
#define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)
|
||||
#else
|
||||
#define MEMP_SANITY_REGION_BEFORE_ALIGNED 0
|
||||
#endif /* MEMP_SANITY_REGION_BEFORE*/
|
||||
#ifndef MEMP_SANITY_REGION_AFTER
|
||||
#define MEMP_SANITY_REGION_AFTER 16
|
||||
#endif /* MEMP_SANITY_REGION_AFTER*/
|
||||
#if MEMP_SANITY_REGION_AFTER > 0
|
||||
#define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)
|
||||
#else
|
||||
#define MEMP_SANITY_REGION_AFTER_ALIGNED 0
|
||||
#endif /* MEMP_SANITY_REGION_AFTER*/
|
||||
|
||||
/* MEMP_SIZE: save space for struct memp and for sanity check */
|
||||
#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)
|
||||
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)
|
||||
|
||||
#else /* MEMP_OVERFLOW_CHECK */
|
||||
|
||||
/* No sanity checks
|
||||
* We don't need to preserve the struct memp while not allocated, so we
|
||||
* can save a little space and set MEMP_SIZE to 0.
|
||||
*/
|
||||
#define MEMP_SIZE 0
|
||||
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
|
||||
|
||||
#endif /* MEMP_OVERFLOW_CHECK */
|
||||
|
||||
/** This array holds the first free element of each pool.
|
||||
* Elements form a linked list. */
|
||||
static struct memp *memp_tab[MEMP_MAX];
|
||||
|
||||
#else /* MEMP_MEM_MALLOC */
|
||||
|
||||
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
|
||||
|
||||
#endif /* MEMP_MEM_MALLOC */
|
||||
|
||||
/** This array holds the element sizes of each pool. */
|
||||
#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
|
||||
static
|
||||
#ifdef LWIP_HOOK_FILENAME
|
||||
#include LWIP_HOOK_FILENAME
|
||||
#endif
|
||||
const u16_t memp_sizes[MEMP_MAX] = {
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEM_ALIGN_SIZE(size),
|
||||
#include "lwip/memp_std.h"
|
||||
};
|
||||
|
||||
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
|
||||
#if MEMP_MEM_MALLOC && MEMP_OVERFLOW_CHECK >= 2
|
||||
#undef MEMP_OVERFLOW_CHECK
|
||||
/* MEMP_OVERFLOW_CHECK >= 2 does not work with MEMP_MEM_MALLOC, use 1 instead */
|
||||
#define MEMP_OVERFLOW_CHECK 1
|
||||
#endif
|
||||
|
||||
/** This array holds the number of elements in each pool. */
|
||||
static const u16_t memp_num[MEMP_MAX] = {
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) (num),
|
||||
#include "lwip/memp_std.h"
|
||||
};
|
||||
|
||||
/** This array holds a textual description of each pool. */
|
||||
#ifdef LWIP_DEBUG
|
||||
static const char *memp_desc[MEMP_MAX] = {
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) (desc),
|
||||
#include "lwip/memp_std.h"
|
||||
};
|
||||
#endif /* LWIP_DEBUG */
|
||||
|
||||
#if MEMP_SEPARATE_POOLS
|
||||
|
||||
/** This creates each memory pool. These are named memp_memory_XXX_base (where
|
||||
* XXX is the name of the pool defined in memp_std.h).
|
||||
* To relocate a pool, declare it as extern in cc.h. Example for GCC:
|
||||
* extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_UDP_PCB_base[];
|
||||
*/
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) u8_t memp_memory_ ## name ## _base \
|
||||
[((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))];
|
||||
#include "lwip/memp_std.h"
|
||||
|
||||
/** This array holds the base of each memory pool. */
|
||||
static u8_t *const memp_bases[] = {
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) memp_memory_ ## name ## _base,
|
||||
#include "lwip/memp_std.h"
|
||||
};
|
||||
|
||||
#else /* MEMP_SEPARATE_POOLS */
|
||||
|
||||
/** This is the actual memory used by the pools (all pools in one big block). */
|
||||
static u8_t memp_memory[MEM_ALIGNMENT - 1
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
|
||||
#include "lwip/memp_std.h"
|
||||
];
|
||||
|
||||
#endif /* MEMP_SEPARATE_POOLS */
|
||||
|
||||
#if MEMP_SANITY_CHECK
|
||||
#if MEMP_SANITY_CHECK && !MEMP_MEM_MALLOC
|
||||
/**
|
||||
* Check that memp-lists don't form a circle
|
||||
* Check that memp-lists don't form a circle, using "Floyd's cycle-finding algorithm".
|
||||
*/
|
||||
static int
|
||||
memp_sanity(void)
|
||||
memp_sanity(const struct memp_desc *desc)
|
||||
{
|
||||
s16_t i, c;
|
||||
struct memp *m, *n;
|
||||
struct memp *t, *h;
|
||||
|
||||
for (i = 0; i < MEMP_MAX; i++) {
|
||||
for (m = memp_tab[i]; m != NULL; m = m->next) {
|
||||
c = 1;
|
||||
for (n = memp_tab[i]; n != NULL; n = n->next) {
|
||||
if (n == m && --c < 0) {
|
||||
return 0;
|
||||
}
|
||||
t = *desc->tab;
|
||||
if (t != NULL) {
|
||||
for (h = t->next; (t != NULL) && (h != NULL); t = t->next,
|
||||
h = ((h->next != NULL) ? h->next->next : NULL)) {
|
||||
if (t == h) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* MEMP_SANITY_CHECK*/
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
#if defined(LWIP_DEBUG) && MEMP_STATS
|
||||
static const char * memp_overflow_names[] = {
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) "/"desc,
|
||||
#include "lwip/memp_std.h"
|
||||
};
|
||||
#endif
|
||||
#endif /* MEMP_SANITY_CHECK && !MEMP_MEM_MALLOC */
|
||||
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
/**
|
||||
* Check if a memp element was victim of an overflow
|
||||
* (e.g. the restricted area after it has been altered)
|
||||
*
|
||||
* @param p the memp element to check
|
||||
* @param memp_type the pool p comes from
|
||||
* @param desc the pool p comes from
|
||||
*/
|
||||
static void
|
||||
memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type)
|
||||
memp_overflow_check_element_overflow(struct memp *p, const struct memp_desc *desc)
|
||||
{
|
||||
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
|
||||
u16_t k;
|
||||
u8_t *m;
|
||||
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
|
||||
m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type];
|
||||
m = (u8_t*)p + MEMP_SIZE + desc->size;
|
||||
for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
|
||||
if (m[k] != 0xcd) {
|
||||
char errstr[128] = "detected memp overflow in pool ";
|
||||
char digit[] = "0";
|
||||
if(memp_type >= 10) {
|
||||
digit[0] = '0' + (memp_type/10);
|
||||
strcat(errstr, digit);
|
||||
}
|
||||
digit[0] = '0' + (memp_type%10);
|
||||
strcat(errstr, digit);
|
||||
#if defined(LWIP_DEBUG) && MEMP_STATS
|
||||
strcat(errstr, memp_overflow_names[memp_type]);
|
||||
#endif
|
||||
strcat(errstr, desc->desc);
|
||||
LWIP_ASSERT(errstr, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#else /* MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
|
||||
LWIP_UNUSED_ARG(p);
|
||||
LWIP_UNUSED_ARG(desc);
|
||||
#endif /* MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,34 +149,51 @@ memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type)
|
||||
* (e.g. the restricted area before it has been altered)
|
||||
*
|
||||
* @param p the memp element to check
|
||||
* @param memp_type the pool p comes from
|
||||
* @param desc the pool p comes from
|
||||
*/
|
||||
static void
|
||||
memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type)
|
||||
memp_overflow_check_element_underflow(struct memp *p, const struct memp_desc *desc)
|
||||
{
|
||||
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
|
||||
u16_t k;
|
||||
u8_t *m;
|
||||
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
|
||||
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
|
||||
for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {
|
||||
if (m[k] != 0xcd) {
|
||||
char errstr[128] = "detected memp underflow in pool ";
|
||||
char digit[] = "0";
|
||||
if(memp_type >= 10) {
|
||||
digit[0] = '0' + (memp_type/10);
|
||||
strcat(errstr, digit);
|
||||
}
|
||||
digit[0] = '0' + (memp_type%10);
|
||||
strcat(errstr, digit);
|
||||
#if defined(LWIP_DEBUG) && MEMP_STATS
|
||||
strcat(errstr, memp_overflow_names[memp_type]);
|
||||
#endif
|
||||
strcat(errstr, desc->desc);
|
||||
LWIP_ASSERT(errstr, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#else /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 */
|
||||
LWIP_UNUSED_ARG(p);
|
||||
LWIP_UNUSED_ARG(desc);
|
||||
#endif /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the restricted area of on memp element.
|
||||
*/
|
||||
static void
|
||||
memp_overflow_init_element(struct memp *p, const struct memp_desc *desc)
|
||||
{
|
||||
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 || MEMP_SANITY_REGION_AFTER_ALIGNED > 0
|
||||
u8_t *m;
|
||||
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
|
||||
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
|
||||
memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);
|
||||
#endif
|
||||
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
|
||||
m = (u8_t*)p + MEMP_SIZE + desc->size;
|
||||
memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
|
||||
#endif
|
||||
#else /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 || MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
|
||||
LWIP_UNUSED_ARG(p);
|
||||
LWIP_UNUSED_ARG(desc);
|
||||
#endif /* MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 || MEMP_SANITY_REGION_AFTER_ALIGNED > 0 */
|
||||
}
|
||||
|
||||
#if MEMP_OVERFLOW_CHECK >= 2
|
||||
/**
|
||||
* Do an overflow check for all elements in every pool.
|
||||
*
|
||||
@@ -281,96 +204,173 @@ memp_overflow_check_all(void)
|
||||
{
|
||||
u16_t i, j;
|
||||
struct memp *p;
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
|
||||
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
|
||||
for (i = 0; i < MEMP_MAX; ++i) {
|
||||
p = p;
|
||||
for (j = 0; j < memp_num[i]; ++j) {
|
||||
memp_overflow_check_element_overflow(p, i);
|
||||
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
|
||||
}
|
||||
}
|
||||
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
|
||||
for (i = 0; i < MEMP_MAX; ++i) {
|
||||
p = p;
|
||||
for (j = 0; j < memp_num[i]; ++j) {
|
||||
memp_overflow_check_element_underflow(p, i);
|
||||
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the restricted areas of all memp elements in every pool.
|
||||
*/
|
||||
static void
|
||||
memp_overflow_init(void)
|
||||
{
|
||||
u16_t i, j;
|
||||
struct memp *p;
|
||||
u8_t *m;
|
||||
|
||||
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
|
||||
for (i = 0; i < MEMP_MAX; ++i) {
|
||||
p = p;
|
||||
for (j = 0; j < memp_num[i]; ++j) {
|
||||
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
|
||||
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
|
||||
memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);
|
||||
#endif
|
||||
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
|
||||
m = (u8_t*)p + MEMP_SIZE + memp_sizes[i];
|
||||
memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
|
||||
#endif
|
||||
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
|
||||
p = (struct memp*)LWIP_MEM_ALIGN(memp_pools[i]->base);
|
||||
for (j = 0; j < memp_pools[i]->num; ++j) {
|
||||
memp_overflow_check_element_overflow(p, memp_pools[i]);
|
||||
memp_overflow_check_element_underflow(p, memp_pools[i]);
|
||||
p = LWIP_ALIGNMENT_CAST(struct memp*, ((u8_t*)p + MEMP_SIZE + memp_pools[i]->size + MEMP_SANITY_REGION_AFTER_ALIGNED));
|
||||
}
|
||||
}
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
}
|
||||
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
|
||||
#endif /* MEMP_OVERFLOW_CHECK */
|
||||
|
||||
/**
|
||||
* Initialize this module.
|
||||
*
|
||||
* Initialize custom memory pool.
|
||||
* Related functions: memp_malloc_pool, memp_free_pool
|
||||
*
|
||||
* @param desc pool to initialize
|
||||
*/
|
||||
void
|
||||
memp_init_pool(const struct memp_desc *desc)
|
||||
{
|
||||
#if MEMP_MEM_MALLOC
|
||||
LWIP_UNUSED_ARG(desc);
|
||||
#else
|
||||
int i;
|
||||
struct memp *memp;
|
||||
|
||||
*desc->tab = NULL;
|
||||
memp = (struct memp*)LWIP_MEM_ALIGN(desc->base);
|
||||
/* create a linked list of memp elements */
|
||||
for (i = 0; i < desc->num; ++i) {
|
||||
memp->next = *desc->tab;
|
||||
*desc->tab = memp;
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
memp_overflow_init_element(memp, desc);
|
||||
#endif /* MEMP_OVERFLOW_CHECK */
|
||||
/* cast through void* to get rid of alignment warnings */
|
||||
memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
+ MEMP_SANITY_REGION_AFTER_ALIGNED
|
||||
#endif
|
||||
);
|
||||
}
|
||||
#if MEMP_STATS
|
||||
desc->stats->avail = desc->num;
|
||||
#endif /* MEMP_STATS */
|
||||
#endif /* !MEMP_MEM_MALLOC */
|
||||
|
||||
#if MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY)
|
||||
desc->stats->name = desc->desc;
|
||||
#endif /* MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY) */
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes lwIP built-in pools.
|
||||
* Related functions: memp_malloc, memp_free
|
||||
*
|
||||
* Carves out memp_memory into linked lists for each pool-type.
|
||||
*/
|
||||
void
|
||||
memp_init(void)
|
||||
{
|
||||
struct memp *memp;
|
||||
u16_t i, j;
|
||||
u16_t i;
|
||||
|
||||
for (i = 0; i < MEMP_MAX; ++i) {
|
||||
MEMP_STATS_AVAIL(used, i, 0);
|
||||
MEMP_STATS_AVAIL(max, i, 0);
|
||||
MEMP_STATS_AVAIL(err, i, 0);
|
||||
MEMP_STATS_AVAIL(avail, i, memp_num[i]);
|
||||
}
|
||||
|
||||
#if !MEMP_SEPARATE_POOLS
|
||||
memp = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
|
||||
#endif /* !MEMP_SEPARATE_POOLS */
|
||||
/* for every pool: */
|
||||
for (i = 0; i < MEMP_MAX; ++i) {
|
||||
memp_tab[i] = NULL;
|
||||
#if MEMP_SEPARATE_POOLS
|
||||
memp = (struct memp*)memp_bases[i];
|
||||
#endif /* MEMP_SEPARATE_POOLS */
|
||||
/* create a linked list of memp elements */
|
||||
for (j = 0; j < memp_num[i]; ++j) {
|
||||
memp->next = memp_tab[i];
|
||||
memp_tab[i] = memp;
|
||||
memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
+ MEMP_SANITY_REGION_AFTER_ALIGNED
|
||||
for (i = 0; i < LWIP_ARRAYSIZE(memp_pools); i++) {
|
||||
memp_init_pool(memp_pools[i]);
|
||||
|
||||
#if LWIP_STATS && MEMP_STATS
|
||||
lwip_stats.memp[i] = memp_pools[i]->stats;
|
||||
#endif
|
||||
);
|
||||
}
|
||||
}
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
memp_overflow_init();
|
||||
|
||||
#if MEMP_OVERFLOW_CHECK >= 2
|
||||
/* check everything a first time to see if it worked */
|
||||
memp_overflow_check_all();
|
||||
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
|
||||
}
|
||||
|
||||
static void*
|
||||
#if !MEMP_OVERFLOW_CHECK
|
||||
do_memp_malloc_pool(const struct memp_desc *desc)
|
||||
#else
|
||||
do_memp_malloc_pool_fn(const struct memp_desc *desc, const char* file, const int line)
|
||||
#endif
|
||||
{
|
||||
struct memp *memp;
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
|
||||
#if MEMP_MEM_MALLOC
|
||||
memp = (struct memp *)mem_malloc(MEMP_SIZE + MEMP_ALIGN_SIZE(desc->size));
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
#else /* MEMP_MEM_MALLOC */
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
|
||||
memp = *desc->tab;
|
||||
#endif /* MEMP_MEM_MALLOC */
|
||||
|
||||
if (memp != NULL) {
|
||||
#if !MEMP_MEM_MALLOC
|
||||
#if MEMP_OVERFLOW_CHECK == 1
|
||||
memp_overflow_check_element_overflow(memp, desc);
|
||||
memp_overflow_check_element_underflow(memp, desc);
|
||||
#endif /* MEMP_OVERFLOW_CHECK */
|
||||
|
||||
*desc->tab = memp->next;
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
memp->next = NULL;
|
||||
#endif /* MEMP_OVERFLOW_CHECK */
|
||||
#endif /* !MEMP_MEM_MALLOC */
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
memp->file = file;
|
||||
memp->line = line;
|
||||
#if MEMP_MEM_MALLOC
|
||||
memp_overflow_init_element(memp, desc);
|
||||
#endif /* MEMP_MEM_MALLOC */
|
||||
#endif /* MEMP_OVERFLOW_CHECK */
|
||||
LWIP_ASSERT("memp_malloc: memp properly aligned",
|
||||
((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
|
||||
#if MEMP_STATS
|
||||
desc->stats->used++;
|
||||
if (desc->stats->used > desc->stats->max) {
|
||||
desc->stats->max = desc->stats->used;
|
||||
}
|
||||
#endif
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
/* cast through u8_t* to get rid of alignment warnings */
|
||||
return ((u8_t*)memp + MEMP_SIZE);
|
||||
} else {
|
||||
LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", desc->desc));
|
||||
#if MEMP_STATS
|
||||
desc->stats->err++;
|
||||
#endif
|
||||
}
|
||||
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an element from a custom pool.
|
||||
*
|
||||
* @param desc the pool to get an element from
|
||||
*
|
||||
* @return a pointer to the allocated memory or a NULL pointer on error
|
||||
*/
|
||||
void *
|
||||
#if !MEMP_OVERFLOW_CHECK
|
||||
memp_malloc_pool(const struct memp_desc *desc)
|
||||
#else
|
||||
memp_malloc_pool_fn(const struct memp_desc *desc, const char* file, const int line)
|
||||
#endif
|
||||
{
|
||||
LWIP_ASSERT("invalid pool desc", desc != NULL);
|
||||
if (desc == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if !MEMP_OVERFLOW_CHECK
|
||||
return do_memp_malloc_pool(desc);
|
||||
#else
|
||||
return do_memp_malloc_pool_fn(desc, file, line);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -378,10 +378,6 @@ memp_init(void)
|
||||
*
|
||||
* @param type the pool to get an element from
|
||||
*
|
||||
* the debug version has two more parameters:
|
||||
* @param file file name calling this function
|
||||
* @param line number of line where this function is called
|
||||
*
|
||||
* @return a pointer to the allocated memory or a NULL pointer on error
|
||||
*/
|
||||
void *
|
||||
@@ -391,39 +387,78 @@ memp_malloc(memp_t type)
|
||||
memp_malloc_fn(memp_t type, const char* file, const int line)
|
||||
#endif
|
||||
{
|
||||
struct memp *memp;
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
|
||||
void *memp;
|
||||
LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);
|
||||
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
#if MEMP_OVERFLOW_CHECK >= 2
|
||||
memp_overflow_check_all();
|
||||
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
|
||||
|
||||
memp = memp_tab[type];
|
||||
|
||||
if (memp != NULL) {
|
||||
memp_tab[type] = memp->next;
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
memp->next = NULL;
|
||||
memp->file = file;
|
||||
memp->line = line;
|
||||
#endif /* MEMP_OVERFLOW_CHECK */
|
||||
MEMP_STATS_INC_USED(used, type);
|
||||
LWIP_ASSERT("memp_malloc: memp properly aligned",
|
||||
((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
|
||||
memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE);
|
||||
} else {
|
||||
LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
|
||||
MEMP_STATS_INC(err, type);
|
||||
}
|
||||
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
#if !MEMP_OVERFLOW_CHECK
|
||||
memp = do_memp_malloc_pool(memp_pools[type]);
|
||||
#else
|
||||
memp = do_memp_malloc_pool_fn(memp_pools[type], file, line);
|
||||
#endif
|
||||
|
||||
return memp;
|
||||
}
|
||||
|
||||
static void
|
||||
do_memp_free_pool(const struct memp_desc* desc, void *mem)
|
||||
{
|
||||
struct memp *memp;
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
|
||||
LWIP_ASSERT("memp_free: mem properly aligned",
|
||||
((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);
|
||||
|
||||
/* cast through void* to get rid of alignment warnings */
|
||||
memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE);
|
||||
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
|
||||
#if MEMP_OVERFLOW_CHECK == 1
|
||||
memp_overflow_check_element_overflow(memp, desc);
|
||||
memp_overflow_check_element_underflow(memp, desc);
|
||||
#endif /* MEMP_OVERFLOW_CHECK */
|
||||
|
||||
#if MEMP_STATS
|
||||
desc->stats->used--;
|
||||
#endif
|
||||
|
||||
#if MEMP_MEM_MALLOC
|
||||
LWIP_UNUSED_ARG(desc);
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
mem_free(memp);
|
||||
#else /* MEMP_MEM_MALLOC */
|
||||
memp->next = *desc->tab;
|
||||
*desc->tab = memp;
|
||||
|
||||
#if MEMP_SANITY_CHECK
|
||||
LWIP_ASSERT("memp sanity", memp_sanity(desc));
|
||||
#endif /* MEMP_SANITY_CHECK */
|
||||
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
#endif /* !MEMP_MEM_MALLOC */
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a custom pool element back into its pool.
|
||||
*
|
||||
* @param desc the pool where to put mem
|
||||
* @param mem the memp element to free
|
||||
*/
|
||||
void
|
||||
memp_free_pool(const struct memp_desc* desc, void *mem)
|
||||
{
|
||||
LWIP_ASSERT("invalid pool desc", desc != NULL);
|
||||
if ((desc == NULL) || (mem == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
do_memp_free_pool(desc, mem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put an element back into its pool.
|
||||
*
|
||||
@@ -433,37 +468,29 @@ memp_malloc_fn(memp_t type, const char* file, const int line)
|
||||
void
|
||||
memp_free(memp_t type, void *mem)
|
||||
{
|
||||
struct memp *memp;
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
#ifdef LWIP_HOOK_MEMP_AVAILABLE
|
||||
struct memp *old_first;
|
||||
#endif
|
||||
|
||||
LWIP_ERROR("memp_free: type < MEMP_MAX", (type < MEMP_MAX), return;);
|
||||
|
||||
if (mem == NULL) {
|
||||
return;
|
||||
}
|
||||
LWIP_ASSERT("memp_free: mem properly aligned",
|
||||
((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);
|
||||
|
||||
memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE);
|
||||
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
#if MEMP_OVERFLOW_CHECK >= 2
|
||||
memp_overflow_check_all();
|
||||
#else
|
||||
memp_overflow_check_element_overflow(memp, type);
|
||||
memp_overflow_check_element_underflow(memp, type);
|
||||
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
|
||||
#endif /* MEMP_OVERFLOW_CHECK */
|
||||
|
||||
MEMP_STATS_DEC(used, type);
|
||||
|
||||
memp->next = memp_tab[type];
|
||||
memp_tab[type] = memp;
|
||||
#ifdef LWIP_HOOK_MEMP_AVAILABLE
|
||||
old_first = *memp_pools[type]->tab;
|
||||
#endif
|
||||
|
||||
#if MEMP_SANITY_CHECK
|
||||
LWIP_ASSERT("memp sanity", memp_sanity());
|
||||
#endif /* MEMP_SANITY_CHECK */
|
||||
do_memp_free_pool(memp_pools[type], mem);
|
||||
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
#ifdef LWIP_HOOK_MEMP_AVAILABLE
|
||||
if (old_first == NULL) {
|
||||
LWIP_HOOK_MEMP_AVAILABLE(type);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* MEMP_MEM_MALLOC */
|
||||
|
||||
989
src/core/netif.c
989
src/core/netif.c
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user