mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2025-11-16 12:34:34 +00:00
Compare commits
746 Commits
STABLE-1_3
...
cvs-reposi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
3a267586f4 | ||
|
|
52271e0366 | ||
|
|
e4739da961 | ||
|
|
80b344e9fc | ||
|
|
036cb26fa3 | ||
|
|
33d6dcec5b | ||
|
|
791505ab6e | ||
|
|
88e1719d8e | ||
|
|
0885555521 | ||
|
|
36c1750b8f | ||
|
|
11b1c9f19f | ||
|
|
b5dd87b184 | ||
|
|
b54c7bedfd | ||
|
|
783404d8d4 | ||
|
|
3bad9f013e | ||
|
|
4495516497 | ||
|
|
3f849848a4 | ||
|
|
7203680146 | ||
|
|
d793ed3b9b | ||
|
|
c6de17d1e5 | ||
|
|
5b084f4b95 | ||
|
|
4e3b2b9f6b | ||
|
|
856ccb5bb7 | ||
|
|
dbf5659cd9 | ||
|
|
fee0c6afe9 | ||
|
|
fb7d3a159a | ||
|
|
dc6b4e65e0 | ||
|
|
17d4ef4053 | ||
|
|
03be8f88fe | ||
|
|
effcb90fdf | ||
|
|
1bd06bee82 | ||
|
|
92cdc1e33f | ||
|
|
377628216e | ||
|
|
f7627929d5 | ||
|
|
b49cf5e7a2 | ||
|
|
231a6cecb4 | ||
|
|
32f02325f9 | ||
|
|
f418782c2c | ||
|
|
e52730d1fb | ||
|
|
d2679e58a6 | ||
|
|
e3817cd549 | ||
|
|
4ace50a7d7 | ||
|
|
fa092c47c8 | ||
|
|
704d90f693 | ||
|
|
93dc36e091 | ||
|
|
4cc36b2284 | ||
|
|
aaa8d2795e | ||
|
|
229137cad1 | ||
|
|
d73262a0e5 | ||
|
|
cd22a8d851 | ||
|
|
7f7df4ae19 | ||
|
|
3c5723e49d | ||
|
|
960fb14bf5 | ||
|
|
21e17f649a | ||
|
|
9782c40d21 | ||
|
|
04beab4f7d | ||
|
|
194a85387b | ||
|
|
a99219ad1f | ||
|
|
691410ba18 | ||
|
|
714a43b18c | ||
|
|
9f457d3331 | ||
|
|
60a456f757 | ||
|
|
2b355d6b34 | ||
|
|
48be546357 | ||
|
|
0f74a57267 | ||
|
|
272270c7f4 | ||
|
|
e2f014f457 | ||
|
|
1fba33628d | ||
|
|
7d604a23f0 | ||
|
|
6929a786aa | ||
|
|
f61b80ca6a | ||
|
|
1aba9f031d | ||
|
|
2ffcc52f03 | ||
|
|
72518a0d6e | ||
|
|
1242575f0f | ||
|
|
6ccc2ef804 | ||
|
|
b3dc6f2b5b | ||
|
|
2427917db8 | ||
|
|
5ab40f016d | ||
|
|
435115d4fb | ||
|
|
24d823dae6 | ||
|
|
2c60a48d02 | ||
|
|
4b0be4a477 | ||
|
|
505dd10d3c | ||
|
|
ddd2b69f27 | ||
|
|
66b57f89df | ||
|
|
69bd5a29d9 | ||
|
|
f7479781c1 | ||
|
|
9bfeb4e5af | ||
|
|
d3e5ade2da | ||
|
|
3833dd86aa | ||
|
|
25f33c8444 | ||
|
|
dae247809b | ||
|
|
81df8bdabd | ||
|
|
03e4eb4de8 | ||
|
|
290bd400c3 | ||
|
|
5d0785e47a | ||
|
|
16434568b0 | ||
|
|
c0e7d54e37 | ||
|
|
ccb53d9e7d | ||
|
|
03bd61c799 | ||
|
|
6ffd29507c | ||
|
|
a880709776 | ||
|
|
874d1641df | ||
|
|
d8d964d09e | ||
|
|
46b3cb580d | ||
|
|
02f5e19420 | ||
|
|
a945bf07af | ||
|
|
7e5b0a9eb6 | ||
|
|
a56795c149 | ||
|
|
baeb41f5f4 | ||
|
|
d0348e0c60 | ||
|
|
ef0a7ecbcd | ||
|
|
778c65d27c | ||
|
|
f3face9f0c | ||
|
|
2edd5230c9 | ||
|
|
1551bb702d | ||
|
|
d656e9f28e | ||
|
|
597764e35b | ||
|
|
f9f77876a1 | ||
|
|
67d8c7999a | ||
|
|
a7fdb67e8f | ||
|
|
4d1ff2418e | ||
|
|
71f5fdef42 | ||
|
|
abc36471d9 | ||
|
|
4b7288e8f4 | ||
|
|
108ed3c81a | ||
|
|
f98e5717e5 | ||
|
|
3685bc4828 | ||
|
|
72c580236e | ||
|
|
01d2a87f5d | ||
|
|
51061fb61e | ||
|
|
49e8e28cf6 | ||
|
|
d2c632fb18 | ||
|
|
3562be2188 | ||
|
|
2e18a9be63 | ||
|
|
3347762df3 | ||
|
|
f1bc73c3ed | ||
|
|
a96fa7d221 | ||
|
|
cc3e01a9f5 | ||
|
|
6caa389c48 | ||
|
|
e86446b785 | ||
|
|
a00448c35a | ||
|
|
82b9152b8d | ||
|
|
d778fbb24f | ||
|
|
3803a0021d | ||
|
|
3c96819a2c | ||
|
|
846a2fb933 | ||
|
|
7e9eb55350 | ||
|
|
46b7bd6ec3 | ||
|
|
8bbe3d2fe0 | ||
|
|
25f59761b3 | ||
|
|
4b038f13de | ||
|
|
da3d84d1dc | ||
|
|
5ef976aed5 | ||
|
|
cf0b831971 | ||
|
|
d861daeb4e | ||
|
|
0a2eb3fdc8 | ||
|
|
6fb248c9e0 | ||
|
|
40946a79d3 | ||
|
|
124ca0fed2 | ||
|
|
5d153ca1b3 | ||
|
|
a5b0ea97d6 | ||
|
|
0a49f2e068 | ||
|
|
57594ad7b6 | ||
|
|
75bb43698c | ||
|
|
f70014b8ea | ||
|
|
5fd410db4b | ||
|
|
385d044f7d | ||
|
|
d0f1c552e2 | ||
|
|
a54bb7205d | ||
|
|
7466474365 | ||
|
|
c4bc9ce59a | ||
|
|
e25c9f7951 | ||
|
|
94cbed5096 | ||
|
|
f83ace2034 | ||
|
|
84ed9de21a | ||
|
|
4e764017c1 | ||
|
|
67f5e17588 | ||
|
|
d13ac66cc4 | ||
|
|
9f0b7261e5 | ||
|
|
ad4a869b94 | ||
|
|
79d3b41e13 | ||
|
|
839befe68a | ||
|
|
097e8c8eb4 | ||
|
|
90c7d3aaff | ||
|
|
2621e3fa19 | ||
|
|
36d7f50d77 | ||
|
|
ffbb582dde | ||
|
|
3bfc07eb92 | ||
|
|
d91caf1cd3 | ||
|
|
2a2be49d2c | ||
|
|
d47a04456b | ||
|
|
b9499d07c2 | ||
|
|
5d20e690fd | ||
|
|
1c23bfdc7f | ||
|
|
d5531a239b | ||
|
|
9e37d70163 | ||
|
|
99ff7efe80 | ||
|
|
43a08bef14 | ||
|
|
92beddd72f | ||
|
|
f5b783d107 | ||
|
|
a5a870c683 | ||
|
|
19ab25c861 | ||
|
|
38fcfcdfac | ||
|
|
957f4d8096 | ||
|
|
5d4438e652 | ||
|
|
4649c14856 | ||
|
|
fcf6434b4b | ||
|
|
464950d51e | ||
|
|
0b5d60db5e | ||
|
|
b6542b977e | ||
|
|
2bf1184c39 | ||
|
|
103b5a760f | ||
|
|
2b1c389955 | ||
|
|
8d9fa63460 | ||
|
|
52b87b751f | ||
|
|
e934f8aac6 | ||
|
|
311d16df7d | ||
|
|
ea78d69c6d | ||
|
|
402597c2cb | ||
|
|
68678e21df | ||
|
|
19a9b52c06 | ||
|
|
db38ee6630 | ||
|
|
1d8538bca4 | ||
|
|
b73dcfb8cf | ||
|
|
bcd4b76d31 | ||
|
|
7c57ee0c17 | ||
|
|
d9157a71bb | ||
|
|
eae9798276 | ||
|
|
e131d3e32a | ||
|
|
36043a92e7 | ||
|
|
9b48657444 | ||
|
|
52970c2459 | ||
|
|
8336796c1a | ||
|
|
16a63c6554 | ||
|
|
c637441f52 | ||
|
|
5b221ecd4f | ||
|
|
7af77aefa7 | ||
|
|
7c2054091d | ||
|
|
e04e0cb98e | ||
|
|
e983865ad5 | ||
|
|
4c9fe60693 | ||
|
|
c5dfa4099d | ||
|
|
524b7bc36b | ||
|
|
8908055b63 | ||
|
|
10abe8aba2 | ||
|
|
7b24a6360c | ||
|
|
96e9689dbd | ||
|
|
7e0204bb7b | ||
|
|
dfb80c6b86 | ||
|
|
838c35acf6 | ||
|
|
c858aa5686 | ||
|
|
b1736b13d7 | ||
|
|
cbb86fe590 | ||
|
|
a61f5f3a78 | ||
|
|
0792effc2a | ||
|
|
49c6ce3703 | ||
|
|
0f05a6aede | ||
|
|
7ccf8cb731 | ||
|
|
7c28c66d32 | ||
|
|
c49a3ab2d6 | ||
|
|
8fbaf0304a | ||
|
|
f89c08872c | ||
|
|
29eb56a2f6 | ||
|
|
2e795d2706 | ||
|
|
8768e4488a | ||
|
|
bd3f86e505 | ||
|
|
82e4716784 | ||
|
|
d3635c5eef | ||
|
|
c73b1b4fa2 | ||
|
|
39df7d048c | ||
|
|
3529349470 | ||
|
|
0030d1ade5 | ||
|
|
2d1631792a | ||
|
|
b6babe38ea | ||
|
|
df7e435b86 | ||
|
|
9e59f661bc | ||
|
|
87c2d911c9 | ||
|
|
44af02aa1e | ||
|
|
45e51d1929 | ||
|
|
59a623e648 | ||
|
|
306f2203fa | ||
|
|
7699b59e27 | ||
|
|
1550c4215d | ||
|
|
a84590273d | ||
|
|
6fe258c6bc | ||
|
|
27c1c7a0f7 | ||
|
|
a668a4e4d1 | ||
|
|
b1250f003d | ||
|
|
3f8e6c423c | ||
|
|
077caac76d | ||
|
|
91d70a3364 | ||
|
|
6af20340dd | ||
|
|
68ab197b68 | ||
|
|
79e6b4c819 | ||
|
|
ececc3ca45 | ||
|
|
630f575017 | ||
|
|
49274c1507 | ||
|
|
27d4cf6aef | ||
|
|
b156d392cb | ||
|
|
b0b4290c29 | ||
|
|
90bed0c5ac | ||
|
|
b3caddab30 | ||
|
|
1017279e68 | ||
|
|
f74cebcbcd | ||
|
|
848debf999 | ||
|
|
47756a8faa | ||
|
|
6c027c153b | ||
|
|
28dc5f491c | ||
|
|
758e99f362 | ||
|
|
010dc6258e | ||
|
|
a5c5949009 | ||
|
|
d51d6b2d89 | ||
|
|
c58dfa2156 | ||
|
|
5d360a6711 | ||
|
|
24fcf9a86e | ||
|
|
a23b446ddf | ||
|
|
258fe88232 | ||
|
|
9ff7d29696 | ||
|
|
30d69d68e3 | ||
|
|
4495d9ef5b | ||
|
|
a66039b86c | ||
|
|
81c5d9e983 | ||
|
|
c6f7a34abe | ||
|
|
72d6f1a418 | ||
|
|
8cb3ea1398 | ||
|
|
8712deb0b2 | ||
|
|
2e8de4f601 | ||
|
|
c22d3b4c98 | ||
|
|
f8c22c7428 | ||
|
|
855dcadf7a | ||
|
|
9c41e1eea3 | ||
|
|
c70c3eac62 | ||
|
|
e58f4c567a | ||
|
|
1dd8300e69 | ||
|
|
5fa0347e64 | ||
|
|
32c16fad42 | ||
|
|
ea3b8f52d5 | ||
|
|
95445fc328 | ||
|
|
21e3cde95c | ||
|
|
d587940801 | ||
|
|
f5d4f3d83c | ||
|
|
04a8b0f85d | ||
|
|
853e33bdb4 | ||
|
|
0644c4c08e | ||
|
|
606fed8896 | ||
|
|
a5463f0400 | ||
|
|
96338314f1 | ||
|
|
5d3cab0042 | ||
|
|
e678e1bdcb | ||
|
|
1811a344f5 | ||
|
|
ef31aa12e2 | ||
|
|
9dd6c28523 | ||
|
|
61e5301d49 | ||
|
|
408829bcf6 | ||
|
|
dbcce3a4be | ||
|
|
426dd9bfad | ||
|
|
82318c0ef1 | ||
|
|
60696a8485 | ||
|
|
7044385d8e | ||
|
|
a7139ef06b | ||
|
|
52389fc09a | ||
|
|
972ca9e6c1 | ||
|
|
e0c5c4de88 | ||
|
|
149f21dc58 | ||
|
|
9632632b85 | ||
|
|
cc1e9370af | ||
|
|
34139606ca | ||
|
|
3e1cca65bd | ||
|
|
0e3c256667 | ||
|
|
618355f5a7 | ||
|
|
ca11baf1cd | ||
|
|
7ede02ca8b | ||
|
|
2d4e76874c | ||
|
|
b463562241 | ||
|
|
04f17c4709 | ||
|
|
97f797e859 | ||
|
|
9521f54741 | ||
|
|
0e38a52edc | ||
|
|
6df94d3c76 | ||
|
|
59005b544f | ||
|
|
8596bb7e7e | ||
|
|
1c47d15577 | ||
|
|
67c587f9f7 | ||
|
|
052be0a328 | ||
|
|
68ddcc6ca7 | ||
|
|
9a2d97ec41 | ||
|
|
47e770dffa | ||
|
|
8292cebfd9 | ||
|
|
c483c13dc4 | ||
|
|
86f2942c2a | ||
|
|
e4d19dc4a0 | ||
|
|
763760503b | ||
|
|
13c9d2dade | ||
|
|
97f6c5b239 | ||
|
|
f4a9d173a1 | ||
|
|
d85a18752f | ||
|
|
aa7dd9a8ad | ||
|
|
27c9670718 | ||
|
|
32833bcd56 | ||
|
|
53bc34f3e2 | ||
|
|
81640c4a83 | ||
|
|
533e6b5f8d | ||
|
|
28f0bbd575 | ||
|
|
39717b2d9d | ||
|
|
79c88cdcfd | ||
|
|
8a34c16aee | ||
|
|
cce192a671 | ||
|
|
cfe4a12a46 | ||
|
|
3269da52cc | ||
|
|
9c51487d1a | ||
|
|
3ba5ddefa7 | ||
|
|
1d45aa8d45 | ||
|
|
a7bcdf4398 | ||
|
|
9a0dac5885 | ||
|
|
c9e0652526 | ||
|
|
a566f9d8f2 | ||
|
|
1740b0d421 | ||
|
|
802a048302 | ||
|
|
fa08823ac4 | ||
|
|
a1c0b9da7b | ||
|
|
bf261f4f13 | ||
|
|
dc8639bc06 | ||
|
|
125efd8396 | ||
|
|
4a9557fa84 | ||
|
|
6b6c82aaee | ||
|
|
feca27d69e | ||
|
|
fbef894674 | ||
|
|
2e4bb8b3b7 | ||
|
|
e9940acb54 | ||
|
|
957331fff4 | ||
|
|
faba395cae | ||
|
|
1d5809679b | ||
|
|
b5014b0966 | ||
|
|
b1ad36eece | ||
|
|
1b42286bda | ||
|
|
5da0620c6b | ||
|
|
96e8f16c05 | ||
|
|
b5d28e0a9c | ||
|
|
73251bc9c1 | ||
|
|
3fa63b35b3 | ||
|
|
65f006e52e | ||
|
|
7d46e06824 | ||
|
|
32acb82bc0 | ||
|
|
3a1c5944e7 | ||
|
|
04c5246e02 | ||
|
|
46dc1c9bfb | ||
|
|
b900253c09 | ||
|
|
59a5fb7ce8 | ||
|
|
c5d2e536cf | ||
|
|
aeef0a21f3 | ||
|
|
902ad897b8 | ||
|
|
478ccee5fc | ||
|
|
43fd5c28b5 | ||
|
|
4391463832 | ||
|
|
c8d2d2a8ea | ||
|
|
6795aabecf | ||
|
|
a939c09a6b | ||
|
|
35d1c33e0a | ||
|
|
10edf64873 | ||
|
|
6d22c38e59 | ||
|
|
8a81cb4ba0 | ||
|
|
6bb7f987f2 | ||
|
|
1c018caefe | ||
|
|
0c136893e5 | ||
|
|
f4c0655190 | ||
|
|
49bdf32765 | ||
|
|
88d02a624a | ||
|
|
98a58f9e67 | ||
|
|
b30c6f8b9e | ||
|
|
94a7fee8c8 | ||
|
|
6f38b63a47 | ||
|
|
70b05c8096 | ||
|
|
28ac4347d4 | ||
|
|
dee1d82c11 | ||
|
|
6d73f82f41 | ||
|
|
71ddff4964 | ||
|
|
af3b796488 | ||
|
|
e2de2c6bb2 | ||
|
|
2ff0ce2d0a | ||
|
|
b09b8a0ccc | ||
|
|
db259c3557 | ||
|
|
bcc87ef851 | ||
|
|
650f16b6d9 | ||
|
|
ae2dd38e0d | ||
|
|
0319c1cf90 | ||
|
|
81f9442ac7 | ||
|
|
18ab274af3 | ||
|
|
65d1f52423 | ||
|
|
f1b82e0e9a | ||
|
|
67411c4299 | ||
|
|
a37e62b7d0 | ||
|
|
e2c1f7d5b5 | ||
|
|
ec97fbd101 | ||
|
|
b7d7559cc9 | ||
|
|
b4404ff0c8 | ||
|
|
502e89f4ad | ||
|
|
d8d8cf7e98 | ||
|
|
d9a5094068 | ||
|
|
a9740c6a44 | ||
|
|
2dc027401f | ||
|
|
ac638c85f3 | ||
|
|
c0e22c255c | ||
|
|
1309e5e86f | ||
|
|
c34c024dd5 | ||
|
|
6ef69ece95 | ||
|
|
a9cbdc141b | ||
|
|
9e5cf1cf8e | ||
|
|
ddc783bee7 | ||
|
|
68f92050e9 | ||
|
|
bd2bc2ee14 | ||
|
|
8a7c1c4926 | ||
|
|
cff3e0cad2 | ||
|
|
b55cfbc342 | ||
|
|
3115087d26 | ||
|
|
057c51ff6d | ||
|
|
f2f20cf133 | ||
|
|
2c618705f0 | ||
|
|
bc10ad2356 | ||
|
|
857fac1168 | ||
|
|
103ba9b0fc | ||
|
|
d83fc6893b | ||
|
|
e7d5739ce7 | ||
|
|
8bf57c0e14 | ||
|
|
dea7255fc5 | ||
|
|
ce3082976c | ||
|
|
362a295e06 | ||
|
|
0e91e2adf2 | ||
|
|
4d49d952b6 | ||
|
|
ae7a7a0abf | ||
|
|
4f265dce60 | ||
|
|
bd96db8c9f | ||
|
|
0b75917121 | ||
|
|
fa2dbc2b1b | ||
|
|
3a6165f0b9 | ||
|
|
62c27f7fce | ||
|
|
7feb116bae | ||
|
|
730a938912 | ||
|
|
3553efb75e | ||
|
|
6111230fe9 | ||
|
|
6bce84e070 | ||
|
|
a6e316a92d | ||
|
|
22bcf5892a | ||
|
|
cc4b968f0a | ||
|
|
893ddcf61b | ||
|
|
cf81dbcca4 | ||
|
|
5830200029 | ||
|
|
972592cf8a | ||
|
|
ce5699f41b | ||
|
|
1eee0be951 | ||
|
|
fb555a0633 | ||
|
|
2b87f899ab | ||
|
|
776e1926a3 | ||
|
|
c232edb83a | ||
|
|
aefeba3fc0 | ||
|
|
6d4064799a | ||
|
|
e0e9a63e63 | ||
|
|
bcdffce6ce | ||
|
|
ff97c8a1a9 | ||
|
|
30acd1662d | ||
|
|
078e2f60d6 | ||
|
|
c7ce2792c8 | ||
|
|
22d6558f13 | ||
|
|
105d72a3c2 | ||
|
|
c752e5731c | ||
|
|
72e9cf53e7 | ||
|
|
e66d315c9b | ||
|
|
95f6dc7011 | ||
|
|
ac9e758f41 | ||
|
|
518b18dad0 | ||
|
|
bdd5586cee | ||
|
|
14dba4ae2b | ||
|
|
99d82c4980 | ||
|
|
fb46e0f192 | ||
|
|
b055128ec4 | ||
|
|
e29f94a980 | ||
|
|
24342eaab0 | ||
|
|
152d22d4f9 | ||
|
|
41eecb67d2 | ||
|
|
9317105c37 | ||
|
|
23d7f5425d | ||
|
|
217f279fdb | ||
|
|
d4ecb23015 | ||
|
|
42c59e1079 | ||
|
|
3b5993e6ee | ||
|
|
4b8255a588 | ||
|
|
36e3d24331 | ||
|
|
261dfdf010 | ||
|
|
cbfacb7ed9 | ||
|
|
4eda29abf9 | ||
|
|
c3f7107e2b | ||
|
|
67a3976a24 | ||
|
|
4fba1b1430 | ||
|
|
029b786c77 | ||
|
|
51e02176da | ||
|
|
ed65d9cd75 | ||
|
|
542b8fffb1 | ||
|
|
12c50ed87b | ||
|
|
9d5bf57dd9 | ||
|
|
04df18bcd3 | ||
|
|
422ba5bcec | ||
|
|
27b28a9306 | ||
|
|
620b3e6739 | ||
|
|
580f334274 | ||
|
|
4f52183a39 | ||
|
|
a55f354687 | ||
|
|
9630c9136b | ||
|
|
dbd6d7ec8d | ||
|
|
b3a5d6df0d | ||
|
|
3587e8481d | ||
|
|
4f8f6ba205 | ||
|
|
f81ed216db | ||
|
|
f1a9f7ea70 | ||
|
|
4b14621208 | ||
|
|
baf30f5eae | ||
|
|
e7a2ab5de9 | ||
|
|
fd41c5de2d | ||
|
|
efac109803 | ||
|
|
84505d4cc8 | ||
|
|
7d8fac62ec | ||
|
|
b6e18d9c6f | ||
|
|
c05e968278 | ||
|
|
103fe60362 | ||
|
|
638020ec70 | ||
|
|
56038b6457 | ||
|
|
96b788bea7 | ||
|
|
7b6c11360f | ||
|
|
ea1eb45e3f | ||
|
|
e001a021d5 | ||
|
|
14cb4eb735 | ||
|
|
d976c8e85f | ||
|
|
d2d33cb984 | ||
|
|
eeae59ecb7 | ||
|
|
466f4e699c | ||
|
|
bf09400c4c | ||
|
|
c4509e700d | ||
|
|
6472e3b35e | ||
|
|
f9bd5019fa | ||
|
|
8c7705bbf9 | ||
|
|
243e3d0d91 | ||
|
|
19884f40b8 | ||
|
|
10c3ce08af | ||
|
|
878532a30d | ||
|
|
102d69004a | ||
|
|
b0c61ffbb1 | ||
|
|
9f96f09652 | ||
|
|
aa568727d1 | ||
|
|
411cb39eb4 | ||
|
|
6777ae2ada | ||
|
|
2cf3e6e9bc | ||
|
|
491b73d5f2 | ||
|
|
1f3fe200df | ||
|
|
299e2a7077 | ||
|
|
13a139eef7 | ||
|
|
06df1647e1 | ||
|
|
1d2804d6a2 | ||
|
|
ba98bcdc60 | ||
|
|
0d7dccba5e | ||
|
|
c231e95cce | ||
|
|
6f6c8c5434 | ||
|
|
edf72a7dfb | ||
|
|
ba636e19a2 | ||
|
|
6374766a55 | ||
|
|
c779a9f29f | ||
|
|
ae2d5266c5 | ||
|
|
99db244124 | ||
|
|
8367feafa9 | ||
|
|
f6a28808e3 | ||
|
|
13d8ae859d | ||
|
|
95b15fe463 | ||
|
|
779938ea68 | ||
|
|
139944a3ac | ||
|
|
b94e3a874d | ||
|
|
3d8e5003af | ||
|
|
94cd14e90d | ||
|
|
c93cfb2c74 | ||
|
|
521d439a07 | ||
|
|
460b18e82c | ||
|
|
ef3666ef26 | ||
|
|
e0aaa87b1f | ||
|
|
eba83ab740 | ||
|
|
a8141c53a8 | ||
|
|
88ff8c83e9 | ||
|
|
24e0b25215 | ||
|
|
7bc881ccc5 | ||
|
|
a3bc6cd666 | ||
|
|
40d4a8fc2f | ||
|
|
7be9e292dc | ||
|
|
9ccd31a12e | ||
|
|
a9aefcc1be | ||
|
|
05587f5da9 | ||
|
|
43dd38df0a | ||
|
|
64fa8d78bc | ||
|
|
aee9c4c8e6 |
2
README
2
README
@@ -72,7 +72,7 @@ current CVS sources and is available from this web page:
|
||||
http://www.nongnu.org/lwip/
|
||||
|
||||
There is now a constantly growin wiki about lwIP at
|
||||
http://lwip.scribblewiki.com/
|
||||
http://lwip.wikia.com/wiki/LwIP_Wiki
|
||||
|
||||
Also, there are mailing lists you can subscribe at
|
||||
http://savannah.nongnu.org/mail/?group=lwip
|
||||
|
||||
144
UPGRADING
Normal file
144
UPGRADING
Normal file
@@ -0,0 +1,144 @@
|
||||
This file lists major changes between release versions that require
|
||||
ports or applications to be changed. Use it to update a port or an
|
||||
application written for an older version of lwIP to correctly work
|
||||
with newer versions.
|
||||
|
||||
|
||||
(CVS HEAD)
|
||||
|
||||
* [Enter new changes just after this line - do not remove this line]
|
||||
|
||||
++ Application changes:
|
||||
|
||||
* Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for
|
||||
compatibility to old applications, but will be removed in the future).
|
||||
|
||||
* Renamed mem_realloc() to mem_trim() to prevent confusion with realloc()
|
||||
|
||||
+++ Raw API:
|
||||
* Changed the semantics of tcp_close() (since it was rather a
|
||||
shutdown before): Now the application does *NOT* get any calls to the recv
|
||||
callback (aside from NULL/closed) after calling tcp_close()
|
||||
|
||||
* When calling tcp_abort() from a raw API TCP callback function,
|
||||
make sure you return ERR_ABRT to prevent accessing unallocated memory.
|
||||
(ERR_ABRT now means the applicaiton has called tcp_abort!)
|
||||
|
||||
+++ Netconn API:
|
||||
* Changed netconn_receive() and netconn_accept() to return
|
||||
err_t, not a pointer to new data/netconn.
|
||||
|
||||
+++ Socket API:
|
||||
* LWIP_SO_RCVTIMEO: when accept() or recv() time out, they
|
||||
now set errno to EWOULDBLOCK/EAGAIN, not ETIMEDOUT.
|
||||
|
||||
* Added a minimal version of posix fctl() to have a
|
||||
standardised way to set O_NONBLOCK for nonblocking sockets.
|
||||
|
||||
+++ all APIs:
|
||||
* correctly implemented SO(F)_REUSEADDR
|
||||
|
||||
++ Port changes
|
||||
|
||||
+++ new files:
|
||||
|
||||
* Added 4 new files: def.c, timers.c, timers.h, tcp_impl.h:
|
||||
|
||||
* Moved stack-internal parts of tcp.h to tcp_impl.h, tcp.h now only contains
|
||||
the actual application programmer's API
|
||||
|
||||
* Separated timer implementation from sys.h/.c, moved to timers.h/.c;
|
||||
Added timer implementation for NO_SYS==1, set NO_SYS_NO_TIMERS==1 if you
|
||||
still want to use your own timer implementation for NO_SYS==0 (as before).
|
||||
|
||||
+++ sys layer:
|
||||
|
||||
* Converted mbox- and semaphore-functions to take pointers to sys_mbox_t/
|
||||
sys_sem_t;
|
||||
|
||||
* Converted sys_mbox_new/sys_sem_new to take pointers and return err_t;
|
||||
|
||||
* Added Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX to let sys.h use
|
||||
binary semaphores instead of mutexes - as before)
|
||||
|
||||
+++ new options:
|
||||
|
||||
* Don't waste memory when chaining segments, added option TCP_OVERSIZE to
|
||||
prevent creating many small pbufs when calling tcp_write with many small
|
||||
blocks of data. Instead, pbufs are allocated larger than needed and the
|
||||
space is used for later calls to tcp_write.
|
||||
|
||||
* Added LWIP_NETIF_TX_SINGLE_PBUF to always copy to try to create single pbufs
|
||||
in tcp_write/udp_send.
|
||||
|
||||
* Added an additional option LWIP_ETHERNET to support ethernet without ARP
|
||||
(necessary for pure PPPoE)
|
||||
|
||||
* Add MEMP_SEPARATE_POOLS to place memory pools in separate arrays. This may
|
||||
be used to place these pools into user-defined memory by using external
|
||||
declaration.
|
||||
|
||||
* Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT
|
||||
|
||||
+++ new pools:
|
||||
|
||||
* Netdb uses a memp pool for allocating memory when getaddrinfo() is called,
|
||||
so MEMP_NUM_NETDB has to be set accordingly.
|
||||
|
||||
* DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses a memp pool instead of the heap, so
|
||||
MEMP_NUM_LOCALHOSTLIST has to be set accordingly.
|
||||
|
||||
* Snmp-agent uses a memp pools instead of the heap, so MEMP_NUM_SNMP_* have
|
||||
to be set accordingly.
|
||||
|
||||
* PPPoE uses a MEMP pool instead of the heap, so MEMP_NUM_PPPOE_INTERFACES
|
||||
has to be set accordingly
|
||||
|
||||
* Integrated loopif into netif.c - loopif does not have to be created by the
|
||||
port any more, just define LWIP_HAVE_LOOPIF to 1.
|
||||
|
||||
* Added define LWIP_RAND() for lwip-wide randomization (needs to be defined
|
||||
in cc.h, e.g. used by igmp)
|
||||
|
||||
* Added printf-formatter X8_F to printf u8_t as hex
|
||||
|
||||
* The heap now may be moved to user-defined memory by defining
|
||||
LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address
|
||||
|
||||
* added autoip_set_struct() and dhcp_set_struct() to let autoip and dhcp work
|
||||
with user-allocated structs instead of calling mem_malloc
|
||||
|
||||
* Added const char* name to mem- and memp-stats for easier debugging.
|
||||
|
||||
* Calculate the TCP/UDP checksum while copying to only fetch data once:
|
||||
Define LWIP_CHKSUM_COPY to a memcpy-like function that returns the checksum
|
||||
|
||||
* Added SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to
|
||||
more than one pcb.
|
||||
|
||||
* Changed the semantics of ARP_QUEUEING==0: ARP_QUEUEING now cannot be turned
|
||||
off any more, if this is set to 0, only one packet (the most recent one) is
|
||||
queued (like demanded by RFC 1122).
|
||||
|
||||
|
||||
++ Major bugfixes/improvements
|
||||
|
||||
* Implemented tcp_shutdown() to only shut down one end of a connection
|
||||
* Implemented shutdown() at socket- and netconn-level
|
||||
* Added errorset support to select() + improved select speed overhead
|
||||
* Merged pppd to v2.3.11 (including some backported bugfixes from 2.4.x)
|
||||
* Added timer implementation for NO_SYS==1 (may be disabled with NO_SYS_NO_TIMERS==1
|
||||
* Use macros defined in ip_addr.h to work with IP addresses
|
||||
* Implemented many nonblocking socket/netconn functions
|
||||
* Fixed ARP input processing: only add a new entry if a request was directed as us
|
||||
* mem_realloc() to mem_trim() to prevent confusion with realloc()
|
||||
* Some improvements for AutoIP (don't route/forward link-local addresses, don't break
|
||||
existing connections when assigning a routable address)
|
||||
* Correctly handle remote side overrunning our rcv_wnd in ooseq case
|
||||
* Removed packing from ip_addr_t, the packed version is now only used in protocol headers
|
||||
* Corrected PBUF_POOL_BUFSIZE for ports where ETH_PAD_SIZE > 0
|
||||
* Added support for static ARP table entries
|
||||
|
||||
(STABLE-1.3.2)
|
||||
|
||||
* initial version of this file
|
||||
@@ -1,5 +1,6 @@
|
||||
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.
|
||||
|
||||
118
doc/rawapi.txt
118
doc/rawapi.txt
@@ -2,10 +2,11 @@ Raw TCP/IP interface for lwIP
|
||||
|
||||
Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons
|
||||
|
||||
lwIP provides two Application Program's Interfaces (APIs) for programs
|
||||
lwIP provides three Application Program's Interfaces (APIs) for programs
|
||||
to use for communication with the TCP/IP code:
|
||||
* low-level "core" / "callback" or "raw" API.
|
||||
* higher-level "sequential" API.
|
||||
* BSD-style socket API.
|
||||
|
||||
The sequential API provides a way for ordinary, sequential, programs
|
||||
to use the lwIP stack. It is quite similar to the BSD socket API. The
|
||||
@@ -14,6 +15,45 @@ paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP
|
||||
code and the application program must reside in different execution
|
||||
contexts (threads).
|
||||
|
||||
The socket API is a compatibility API for existing applications,
|
||||
currently it is built on top of the sequential API. It is meant to
|
||||
provide all functions needed to run socket API applications running
|
||||
on other platforms (e.g. unix / windows etc.). However, due to limitations
|
||||
in the specification of this API, there might be incompatibilities
|
||||
that require small modifications of existing programs.
|
||||
|
||||
** Threading
|
||||
|
||||
lwIP started targeting single-threaded environments. When adding multi-
|
||||
threading support, instead of making the core thread-safe, another
|
||||
approach was chosen: there is one main thread running the lwIP core
|
||||
(also known as the "tcpip_thread"). The raw API may only be used from
|
||||
this thread! Application threads using the sequential- or socket API
|
||||
communicate with this main thread through message passing.
|
||||
|
||||
As such, the list of functions that may be called from
|
||||
other threads or an ISR is very limited! Only functions
|
||||
from these API header files are thread-safe:
|
||||
- api.h
|
||||
- netbuf.h
|
||||
- netdb.h
|
||||
- netifapi.h
|
||||
- sockets.h
|
||||
- sys.h
|
||||
|
||||
Additionaly, memory (de-)allocation functions may be
|
||||
called from multiple threads (not ISR!) with NO_SYS=0
|
||||
since they are protected by SYS_LIGHTWEIGHT_PROT and/or
|
||||
semaphores.
|
||||
|
||||
Only since 1.3.0, if SYS_LIGHTWEIGHT_PROT is set to 1
|
||||
and LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1,
|
||||
pbuf_free() may also be called from another thread or
|
||||
an ISR (since only then, mem_free - for PBUF_RAM - may
|
||||
be called from an ISR: otherwise, the HEAP is only
|
||||
protected by semaphores).
|
||||
|
||||
|
||||
** The remainder of this document discusses the "raw" API. **
|
||||
|
||||
The raw TCP/IP interface allows the application program to integrate
|
||||
@@ -67,7 +107,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
|
||||
@@ -107,6 +147,8 @@ incoming connections or be explicitly connected to another host.
|
||||
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.
|
||||
ATTENTION: the PCB passed in must be the listening pcb, not the pcb passed
|
||||
into the accept callback!
|
||||
|
||||
- void tcp_accept(struct tcp_pcb *pcb,
|
||||
err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
|
||||
@@ -114,8 +156,8 @@ incoming connections or be explicitly connected to another host.
|
||||
|
||||
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));
|
||||
@@ -128,14 +170,15 @@ incoming connections or be explicitly connected to another host.
|
||||
function specified as the fourth argument (the "connected" argument)
|
||||
when the connection is established. If the connection could not be
|
||||
properly established, either because the other host refused the
|
||||
connection or because the other host didn't answer, the "connected"
|
||||
function will be called with an the "err" argument set accordingly.
|
||||
connection or because the other host didn't answer, the "err"
|
||||
callback function of this pcb (registered with tcp_err, see below)
|
||||
will be called.
|
||||
|
||||
The tcp_connect() function can return ERR_MEM if no memory is
|
||||
available for enqueueing the SYN segment. If the SYN indeed was
|
||||
enqueued successfully, the tcp_connect() function returns ERR_OK.
|
||||
|
||||
|
||||
|
||||
--- Sending TCP data
|
||||
|
||||
TCP data is sent by enqueueing the data with a call to
|
||||
@@ -143,15 +186,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 given,
|
||||
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
|
||||
@@ -197,7 +244,7 @@ window.
|
||||
|
||||
Must be called when the application has received the data. The len
|
||||
argument indicates the length of the received data.
|
||||
|
||||
|
||||
|
||||
--- Application polling
|
||||
|
||||
@@ -210,8 +257,9 @@ if a call to tcp_write() has failed because memory wasn't available,
|
||||
the application may use the polling functionality to call tcp_write()
|
||||
again when the connection has been idle for a while.
|
||||
|
||||
- void tcp_poll(struct tcp_pcb *pcb, u8_t interval,
|
||||
err_t (* poll)(void *arg, struct tcp_pcb *tpcb))
|
||||
- void tcp_poll(struct tcp_pcb *pcb,
|
||||
err_t (* poll)(void *arg, struct tcp_pcb *tpcb),
|
||||
u8_t interval)
|
||||
|
||||
Specifies the polling interval and the callback function that should
|
||||
be called to poll the application. The interval is specified in
|
||||
@@ -237,6 +285,11 @@ again when the connection has been idle for a while.
|
||||
Aborts the connection by sending a RST (reset) segment to the remote
|
||||
host. The pcb is deallocated. This function never fails.
|
||||
|
||||
ATTENTION: When calling this from one of the TCP callbacks, make
|
||||
sure you always return ERR_ABRT (and never return ERR_ABRT otherwise
|
||||
or you will risk accessing deallocated memory or memory leaks!
|
||||
|
||||
|
||||
If a connection is aborted because of an error, the application is
|
||||
alerted of this event by the err callback. Errors that might abort a
|
||||
connection are when there is a shortage of memory. The callback
|
||||
@@ -275,14 +328,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
|
||||
@@ -300,7 +353,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)
|
||||
|
||||
@@ -361,8 +414,8 @@ Call these functions in the order of appearance:
|
||||
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,
|
||||
- netif_add(struct netif *netif, ip_addr_t *ipaddr,
|
||||
ip_addr_t *netmask, ip_addr_t *gw,
|
||||
void *state, err_t (* init)(struct netif *netif),
|
||||
err_t (* input)(struct pbuf *p, struct netif *netif))
|
||||
|
||||
@@ -435,3 +488,24 @@ to match your application and network.
|
||||
For a production release it is recommended to set LWIP_STATS to 0.
|
||||
Note that speed performance isn't influenced much by simply setting
|
||||
high values to the memory options.
|
||||
|
||||
For more optimization hints take a look at the lwIP wiki.
|
||||
|
||||
--- Zero-copy MACs
|
||||
|
||||
To achieve zero-copy on transmit, the data passed to the raw API must
|
||||
remain unchanged until sent. Because the send- (or write-)functions return
|
||||
when the packets have been enqueued for sending, data must be kept stable
|
||||
after that, too.
|
||||
|
||||
This implies that PBUF_RAM/PBUF_POOL pbufs passed to raw-API send functions
|
||||
must *not* be reused by the application unless their ref-count is 1.
|
||||
|
||||
For no-copy pbufs (PBUF_ROM/PBUF_REF), data must be kept unchanged, too,
|
||||
but the stack/driver will/must copy PBUF_REF'ed data when enqueueing, while
|
||||
PBUF_ROM-pbufs are just enqueued (as ROM-data is expected to never change).
|
||||
|
||||
Also, data passed to tcp_write without the copy-flag must not be changed!
|
||||
|
||||
Therefore, be careful which type of PBUF you use and if you copy TCP data
|
||||
or not!
|
||||
|
||||
@@ -46,7 +46,7 @@ Loading additional MIBs
|
||||
|
||||
Large SNMP message support
|
||||
The packet decoding and encoding routines are designed
|
||||
to use pbuf-chains. Larger payloads then the minimum
|
||||
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.
|
||||
@@ -170,7 +170,7 @@ 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 an dynamically
|
||||
However RAM location is possible for a dynamically
|
||||
changing private tree.
|
||||
|
||||
The index part is handled by functions which in
|
||||
|
||||
@@ -34,26 +34,36 @@ 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.
|
||||
|
||||
Since lwIP 1.4.0, semaphore and mailbox functions are prototyped in a way that
|
||||
allows both using pointers or actual OS structures to be used. This way, memory
|
||||
required for such types can be either allocated in place (globally or on the
|
||||
stack) or on the heap (allocated internally in the "*_new()" functions).
|
||||
|
||||
The following functions must be implemented by the sys_arch:
|
||||
|
||||
- void sys_init(void)
|
||||
|
||||
Is called to initialize the sys_arch layer.
|
||||
|
||||
- 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 +80,47 @@ 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.
|
||||
|
||||
- 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 +137,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,19 +149,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.
|
||||
|
||||
- struct sys_timeouts *sys_arch_timeouts(void)
|
||||
|
||||
Returns a pointer to the per-thread sys_timeouts structure. In lwIP,
|
||||
each thread has a list of timeouts which is repressented as a linked
|
||||
list of sys_timeout structures. The sys_timeouts structure holds a
|
||||
pointer to a linked list of timeouts. This function is called by
|
||||
the lwIP timeout scheduler and must not return a NULL value.
|
||||
- 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.
|
||||
|
||||
In a single thread sys_arch implementation, this function will
|
||||
simply return a pointer to a global sys_timeouts variable stored in
|
||||
the sys_arch module.
|
||||
|
||||
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:
|
||||
@@ -168,6 +197,16 @@ 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
|
||||
@@ -195,6 +234,8 @@ cc.h - Architecture environment, some compiler specific, some
|
||||
Platform specific diagnostic output -
|
||||
LWIP_PLATFORM_DIAG(x) - non-fatal, print a message.
|
||||
LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution.
|
||||
Portability defines for printf formatters:
|
||||
U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F
|
||||
|
||||
"lightweight" synchronization mechanisms -
|
||||
SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.
|
||||
|
||||
@@ -71,19 +71,19 @@ netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_cal
|
||||
struct api_msg msg;
|
||||
|
||||
conn = netconn_alloc(t, callback);
|
||||
if (conn != NULL ) {
|
||||
if (conn != NULL) {
|
||||
msg.function = do_newconn;
|
||||
msg.msg.msg.n.proto = proto;
|
||||
msg.msg.conn = conn;
|
||||
TCPIP_APIMSG(&msg);
|
||||
|
||||
if (conn->err != ERR_OK) {
|
||||
if (TCPIP_APIMSG(&msg) != ERR_OK) {
|
||||
LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
|
||||
LWIP_ASSERT("conn has no op_completed", conn->op_completed != SYS_SEM_NULL);
|
||||
LWIP_ASSERT("conn has no recvmbox", conn->recvmbox != SYS_MBOX_NULL);
|
||||
LWIP_ASSERT("conn->acceptmbox shouldn't exist", conn->acceptmbox == SYS_MBOX_NULL);
|
||||
sys_sem_free(conn->op_completed);
|
||||
sys_mbox_free(conn->recvmbox);
|
||||
LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
|
||||
LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
|
||||
#if LWIP_TCP
|
||||
LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
|
||||
#endif /* LWIP_TCP */
|
||||
sys_sem_free(&conn->op_completed);
|
||||
sys_mbox_free(&conn->recvmbox);
|
||||
memp_free(MEMP_NETCONN, conn);
|
||||
return NULL;
|
||||
}
|
||||
@@ -113,23 +113,11 @@ netconn_delete(struct netconn *conn)
|
||||
msg.msg.conn = conn;
|
||||
tcpip_apimsg(&msg);
|
||||
|
||||
conn->pcb.tcp = NULL;
|
||||
netconn_free(conn);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
/* don't care for return value of do_delconn since it only calls void functions */
|
||||
|
||||
/**
|
||||
* Get the type of a netconn (as enum netconn_type).
|
||||
*
|
||||
* @param conn the netconn of which to get the type
|
||||
* @return the netconn_type of conn
|
||||
*/
|
||||
enum netconn_type
|
||||
netconn_type(struct netconn *conn)
|
||||
{
|
||||
LWIP_ERROR("netconn_type: invalid conn", (conn != NULL), return NETCONN_INVALID;);
|
||||
return conn->type;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,9 +132,10 @@ netconn_type(struct netconn *conn)
|
||||
* ERR_OK if the information was retrieved
|
||||
*/
|
||||
err_t
|
||||
netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t local)
|
||||
netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
|
||||
@@ -154,12 +143,13 @@ netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t lo
|
||||
|
||||
msg.function = do_getaddr;
|
||||
msg.msg.conn = conn;
|
||||
msg.msg.msg.ad.ipaddr = addr;
|
||||
msg.msg.msg.ad.ipaddr = ip_2_ipX(addr);
|
||||
msg.msg.msg.ad.port = port;
|
||||
msg.msg.msg.ad.local = local;
|
||||
TCPIP_APIMSG(&msg);
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
|
||||
return conn->err;
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,9 +163,10 @@ netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t lo
|
||||
* @return ERR_OK if bound, any other err_t on failure
|
||||
*/
|
||||
err_t
|
||||
netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port)
|
||||
netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
@@ -183,8 +174,10 @@ netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port)
|
||||
msg.msg.conn = conn;
|
||||
msg.msg.msg.bc.ipaddr = addr;
|
||||
msg.msg.msg.bc.port = port;
|
||||
TCPIP_APIMSG(&msg);
|
||||
return conn->err;
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,9 +189,10 @@ netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port)
|
||||
* @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
|
||||
*/
|
||||
err_t
|
||||
netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port)
|
||||
netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
@@ -207,8 +201,10 @@ netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port)
|
||||
msg.msg.msg.bc.ipaddr = addr;
|
||||
msg.msg.msg.bc.port = port;
|
||||
/* This is the only function which need to not block tcpip_thread */
|
||||
tcpip_apimsg(&msg);
|
||||
return conn->err;
|
||||
err = tcpip_apimsg(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,13 +217,16 @@ err_t
|
||||
netconn_disconnect(struct netconn *conn)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
msg.function = do_disconnect;
|
||||
msg.msg.conn = conn;
|
||||
TCPIP_APIMSG(&msg);
|
||||
return conn->err;
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,7 +240,9 @@ netconn_disconnect(struct netconn *conn)
|
||||
err_t
|
||||
netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
|
||||
{
|
||||
#if LWIP_TCP
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
/* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
|
||||
LWIP_UNUSED_ARG(backlog);
|
||||
@@ -253,155 +254,276 @@ netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
msg.msg.msg.lb.backlog = backlog;
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
TCPIP_APIMSG(&msg);
|
||||
return conn->err;
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
#else /* LWIP_TCP */
|
||||
LWIP_UNUSED_ARG(conn);
|
||||
LWIP_UNUSED_ARG(backlog);
|
||||
return ERR_ARG;
|
||||
#endif /* LWIP_TCP */
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept a new connection on a TCP listening netconn.
|
||||
*
|
||||
* @param conn the TCP listen netconn
|
||||
* @return the newly accepted netconn or NULL on timeout
|
||||
* @param new_conn pointer where the new connection is stored
|
||||
* @return ERR_OK if a new connection has been received or an error
|
||||
* code otherwise
|
||||
*/
|
||||
struct netconn *
|
||||
netconn_accept(struct netconn *conn)
|
||||
err_t
|
||||
netconn_accept(struct netconn *conn, struct netconn **new_conn)
|
||||
{
|
||||
#if LWIP_TCP
|
||||
struct netconn *newconn;
|
||||
|
||||
LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return NULL;);
|
||||
LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return NULL;);
|
||||
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
|
||||
newconn = NULL;
|
||||
} else
|
||||
#else
|
||||
sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0);
|
||||
#endif /* LWIP_SO_RCVTIMEO*/
|
||||
{
|
||||
/* Register event with callback */
|
||||
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
|
||||
|
||||
err_t err;
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
if (newconn != NULL) {
|
||||
/* Let the stack know that we have accepted the connection. */
|
||||
struct api_msg msg;
|
||||
msg.function = do_recv;
|
||||
msg.msg.conn = conn;
|
||||
TCPIP_APIMSG(&msg);
|
||||
}
|
||||
struct api_msg msg;
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
|
||||
LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;);
|
||||
*new_conn = NULL;
|
||||
LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netconn_accept: invalid acceptmbox", sys_mbox_valid(&conn->acceptmbox), return ERR_ARG;);
|
||||
|
||||
err = conn->last_err;
|
||||
if (ERR_IS_FATAL(err)) {
|
||||
/* don't recv on fatal errors: this might block the application task
|
||||
waiting on acceptmbox forever! */
|
||||
return err;
|
||||
}
|
||||
|
||||
return newconn;
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
if (sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
|
||||
NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
|
||||
return ERR_TIMEOUT;
|
||||
}
|
||||
#else
|
||||
sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0);
|
||||
#endif /* LWIP_SO_RCVTIMEO*/
|
||||
/* Register event with callback */
|
||||
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
|
||||
|
||||
if (newconn == NULL) {
|
||||
/* connection has been aborted */
|
||||
NETCONN_SET_SAFE_ERR(conn, ERR_ABRT);
|
||||
return ERR_ABRT;
|
||||
}
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
/* Let the stack know that we have accepted the connection. */
|
||||
msg.function = do_recv;
|
||||
msg.msg.conn = conn;
|
||||
/* don't care for the return value of do_recv */
|
||||
TCPIP_APIMSG(&msg);
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
|
||||
*new_conn = newconn;
|
||||
/* don't set conn->last_err: it's only ERR_OK, anyway */
|
||||
return ERR_OK;
|
||||
#else /* LWIP_TCP */
|
||||
LWIP_UNUSED_ARG(conn);
|
||||
LWIP_UNUSED_ARG(new_conn);
|
||||
return ERR_ARG;
|
||||
#endif /* LWIP_TCP */
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive data: actual implementation that doesn't care whether pbuf or netbuf
|
||||
* is received
|
||||
*
|
||||
* @param conn the netconn from which to receive data
|
||||
* @param new_buf pointer where a new pbuf/netbuf is stored when received data
|
||||
* @return ERR_OK if data has been received, an error code otherwise (timeout,
|
||||
* memory error or another error)
|
||||
*/
|
||||
static err_t
|
||||
netconn_recv_data(struct netconn *conn, void **new_buf)
|
||||
{
|
||||
void *buf = NULL;
|
||||
u16_t len;
|
||||
err_t err;
|
||||
#if LWIP_TCP
|
||||
struct api_msg msg;
|
||||
#endif /* LWIP_TCP */
|
||||
|
||||
LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
|
||||
*new_buf = NULL;
|
||||
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
|
||||
|
||||
err = conn->last_err;
|
||||
if (ERR_IS_FATAL(err)) {
|
||||
/* don't recv on fatal errors: this might block the application task
|
||||
waiting on recvmbox forever! */
|
||||
/* @todo: this does not allow us to fetch data that has been put into recvmbox
|
||||
before the fatal error occurred - is that a problem? */
|
||||
return err;
|
||||
}
|
||||
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
|
||||
NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
|
||||
return ERR_TIMEOUT;
|
||||
}
|
||||
#else
|
||||
sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
|
||||
#endif /* LWIP_SO_RCVTIMEO*/
|
||||
|
||||
#if LWIP_TCP
|
||||
if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
|
||||
if (!netconn_get_noautorecved(conn) || (buf == NULL)) {
|
||||
/* Let the stack know that we have taken the data. */
|
||||
/* TODO: Speedup: Don't block and wait for the answer here
|
||||
(to prevent multiple thread-switches). */
|
||||
msg.function = do_recv;
|
||||
msg.msg.conn = conn;
|
||||
if (buf != NULL) {
|
||||
msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len;
|
||||
} else {
|
||||
msg.msg.msg.r.len = 1;
|
||||
}
|
||||
/* don't care for the return value of do_recv */
|
||||
TCPIP_APIMSG(&msg);
|
||||
}
|
||||
|
||||
/* If we are closed, we indicate that we no longer wish to use the socket */
|
||||
if (buf == NULL) {
|
||||
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
|
||||
/* Avoid to lose any previous error code */
|
||||
NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
|
||||
return ERR_CLSD;
|
||||
}
|
||||
len = ((struct pbuf *)buf)->tot_len;
|
||||
}
|
||||
#endif /* LWIP_TCP */
|
||||
#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
|
||||
else
|
||||
#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
|
||||
#if (LWIP_UDP || LWIP_RAW)
|
||||
{
|
||||
LWIP_ASSERT("buf != NULL", buf != NULL);
|
||||
len = netbuf_len((struct netbuf *)buf);
|
||||
}
|
||||
#endif /* (LWIP_UDP || LWIP_RAW) */
|
||||
|
||||
#if LWIP_SO_RCVBUF
|
||||
SYS_ARCH_DEC(conn->recv_avail, len);
|
||||
#endif /* LWIP_SO_RCVBUF */
|
||||
/* Register event with callback */
|
||||
API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
|
||||
|
||||
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
|
||||
|
||||
*new_buf = buf;
|
||||
/* don't set conn->last_err: it's only ERR_OK, anyway */
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive data (in form of a pbuf) from a TCP netconn
|
||||
*
|
||||
* @param conn the netconn from which to receive data
|
||||
* @param new_buf pointer where a new pbuf is stored when received data
|
||||
* @return ERR_OK if data has been received, an error code otherwise (timeout,
|
||||
* memory error or another error)
|
||||
* ERR_ARG if conn is not a TCP netconn
|
||||
*/
|
||||
err_t
|
||||
netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
|
||||
{
|
||||
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
|
||||
NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
|
||||
|
||||
return netconn_recv_data(conn, (void **)new_buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive data (in form of a netbuf containing a packet buffer) from a netconn
|
||||
*
|
||||
* @param conn the netconn from which to receive data
|
||||
* @return a new netbuf containing received data or NULL on memory error or timeout
|
||||
* @param new_buf pointer where a new netbuf is stored when received data
|
||||
* @return ERR_OK if data has been received, an error code otherwise (timeout,
|
||||
* memory error or another error)
|
||||
*/
|
||||
struct netbuf *
|
||||
netconn_recv(struct netconn *conn)
|
||||
err_t
|
||||
netconn_recv(struct netconn *conn, struct netbuf **new_buf)
|
||||
{
|
||||
struct api_msg msg;
|
||||
struct netbuf *buf = NULL;
|
||||
struct pbuf *p;
|
||||
u16_t len;
|
||||
|
||||
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return NULL;);
|
||||
|
||||
if (conn->recvmbox == SYS_MBOX_NULL) {
|
||||
/* @todo: should calling netconn_recv on a TCP listen conn be fatal (ERR_CONN)?? */
|
||||
/* TCP listen conns don't have a recvmbox! */
|
||||
conn->err = ERR_CONN;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ERR_IS_FATAL(conn->err)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (conn->type == NETCONN_TCP) {
|
||||
#if LWIP_TCP
|
||||
if (conn->state == NETCONN_LISTEN) {
|
||||
/* @todo: should calling netconn_recv on a TCP listen conn be fatal?? */
|
||||
conn->err = ERR_CONN;
|
||||
return NULL;
|
||||
}
|
||||
struct netbuf *buf = NULL;
|
||||
err_t err;
|
||||
#endif /* LWIP_TCP */
|
||||
|
||||
buf = memp_malloc(MEMP_NETBUF);
|
||||
LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
|
||||
*new_buf = NULL;
|
||||
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
|
||||
|
||||
#if LWIP_TCP
|
||||
if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
|
||||
struct pbuf *p = NULL;
|
||||
/* This is not a listening netconn, since recvmbox is set */
|
||||
|
||||
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
|
||||
if (buf == NULL) {
|
||||
conn->err = ERR_MEM;
|
||||
return NULL;
|
||||
NETCONN_SET_SAFE_ERR(conn, ERR_MEM);
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
|
||||
conn->err = ERR_TIMEOUT;
|
||||
p = NULL;
|
||||
}
|
||||
#else
|
||||
sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, 0);
|
||||
#endif /* LWIP_SO_RCVTIMEO*/
|
||||
|
||||
if (p != NULL) {
|
||||
len = p->tot_len;
|
||||
SYS_ARCH_DEC(conn->recv_avail, len);
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
/* Register event with callback */
|
||||
API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
|
||||
|
||||
/* If we are closed, we indicate that we no longer wish to use the socket */
|
||||
if (p == NULL) {
|
||||
err = netconn_recv_data(conn, (void **)&p);
|
||||
if (err != ERR_OK) {
|
||||
memp_free(MEMP_NETBUF, buf);
|
||||
/* Avoid to lose any previous error code */
|
||||
if (conn->err == ERR_OK) {
|
||||
conn->err = ERR_CLSD;
|
||||
}
|
||||
return NULL;
|
||||
return err;
|
||||
}
|
||||
LWIP_ASSERT("p != NULL", p != NULL);
|
||||
|
||||
buf->p = p;
|
||||
buf->ptr = p;
|
||||
buf->port = 0;
|
||||
buf->addr = NULL;
|
||||
|
||||
/* Let the stack know that we have taken the data. */
|
||||
msg.function = do_recv;
|
||||
msg.msg.conn = conn;
|
||||
if (buf != NULL) {
|
||||
msg.msg.msg.r.len = buf->p->tot_len;
|
||||
} else {
|
||||
msg.msg.msg.r.len = 1;
|
||||
}
|
||||
TCPIP_APIMSG(&msg);
|
||||
ipX_addr_set_any(LWIP_IPV6, &buf->addr);
|
||||
*new_buf = buf;
|
||||
/* don't set conn->last_err: it's only ERR_OK, anyway */
|
||||
return ERR_OK;
|
||||
} else
|
||||
#endif /* LWIP_TCP */
|
||||
} else {
|
||||
{
|
||||
#if (LWIP_UDP || LWIP_RAW)
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
|
||||
buf = NULL;
|
||||
}
|
||||
#else
|
||||
sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, 0);
|
||||
#endif /* LWIP_SO_RCVTIMEO*/
|
||||
if (buf!=NULL) {
|
||||
SYS_ARCH_DEC(conn->recv_avail, buf->p->tot_len);
|
||||
/* Register event with callback */
|
||||
API_EVENT(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len);
|
||||
}
|
||||
return netconn_recv_data(conn, (void **)new_buf);
|
||||
#endif /* (LWIP_UDP || LWIP_RAW) */
|
||||
}
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err));
|
||||
|
||||
return buf;
|
||||
/**
|
||||
* TCP: update the receive window: by calling this, the application
|
||||
* tells the stack that it has processed data and is able to accept
|
||||
* new data.
|
||||
* ATTENTION: use with care, this is mainly used for sockets!
|
||||
* Can only be used when calling netconn_set_noautorecved(conn, 1) before.
|
||||
*
|
||||
* @param conn the netconn for which to update the receive window
|
||||
* @param length amount of data processed (ATTENTION: this must be accurate!)
|
||||
*/
|
||||
void
|
||||
netconn_recved(struct netconn *conn, u32_t length)
|
||||
{
|
||||
#if LWIP_TCP
|
||||
if ((conn != NULL) && (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) &&
|
||||
(netconn_get_noautorecved(conn))) {
|
||||
struct api_msg msg;
|
||||
/* Let the stack know that we have taken the data. */
|
||||
/* TODO: Speedup: Don't block and wait for the answer here
|
||||
(to prevent multiple thread-switches). */
|
||||
msg.function = do_recv;
|
||||
msg.msg.conn = conn;
|
||||
msg.msg.msg.r.len = length;
|
||||
/* don't care for the return value of do_recv */
|
||||
TCPIP_APIMSG(&msg);
|
||||
}
|
||||
#else /* LWIP_TCP */
|
||||
LWIP_UNUSED_ARG(conn);
|
||||
LWIP_UNUSED_ARG(length);
|
||||
#endif /* LWIP_TCP */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -415,10 +537,10 @@ netconn_recv(struct netconn *conn)
|
||||
* @return ERR_OK if data was sent, any other err_t on error
|
||||
*/
|
||||
err_t
|
||||
netconn_sendto(struct netconn *conn, struct netbuf *buf, struct ip_addr *addr, u16_t port)
|
||||
netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
if (buf != NULL) {
|
||||
buf->addr = addr;
|
||||
ipX_addr_set_ipaddr(PCB_ISIPV6(conn->pcb.ip), &buf->addr, addr);
|
||||
buf->port = port;
|
||||
return netconn_send(conn, buf);
|
||||
}
|
||||
@@ -436,15 +558,18 @@ err_t
|
||||
netconn_send(struct netconn *conn, struct netbuf *buf)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len));
|
||||
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
|
||||
msg.function = do_send;
|
||||
msg.msg.conn = conn;
|
||||
msg.msg.msg.b = buf;
|
||||
TCPIP_APIMSG(&msg);
|
||||
return conn->err;
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,18 +579,25 @@ netconn_send(struct netconn *conn, struct netbuf *buf)
|
||||
* @param dataptr pointer to the application buffer that contains the data to send
|
||||
* @param size size of the application data to send
|
||||
* @param apiflags combination of following flags :
|
||||
* - NETCONN_COPY (0x01) data will be copied into memory belonging to the stack
|
||||
* - NETCONN_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent
|
||||
* - NETCONN_COPY: data will be copied into memory belonging to the stack
|
||||
* - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
|
||||
* - NETCONN_DONTBLOCK: only write the data if all dat can be written at once
|
||||
* @return ERR_OK if data was sent, any other err_t on error
|
||||
*/
|
||||
err_t
|
||||
netconn_write(struct netconn *conn, const void *dataptr, int size, u8_t apiflags)
|
||||
netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;);
|
||||
LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;);
|
||||
if (size == 0) {
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* @todo: for non-blocking write, check if 'size' would ever fit into
|
||||
snd_queue or snd_buf */
|
||||
msg.function = do_write;
|
||||
msg.msg.conn = conn;
|
||||
msg.msg.msg.w.dataptr = dataptr;
|
||||
@@ -474,8 +606,37 @@ netconn_write(struct netconn *conn, const void *dataptr, int size, u8_t apiflags
|
||||
/* For locking the core: this _can_ be delayed on low memory/low send buffer,
|
||||
but if it is, this is done inside api_msg.c:do_write(), so we can use the
|
||||
non-blocking version here. */
|
||||
TCPIP_APIMSG(&msg);
|
||||
return conn->err;
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close ot shutdown a TCP netconn (doesn't delete it).
|
||||
*
|
||||
* @param conn the TCP netconn to close or shutdown
|
||||
* @param how fully close or only shutdown one side?
|
||||
* @return ERR_OK if the netconn was closed, any other err_t on error
|
||||
*/
|
||||
static err_t
|
||||
netconn_close_shutdown(struct netconn *conn, u8_t how)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
msg.function = do_close;
|
||||
msg.msg.conn = conn;
|
||||
/* shutting down both ends is the same as closing */
|
||||
msg.msg.msg.sd.shut = how;
|
||||
/* because of the LWIP_TCPIP_CORE_LOCKING implementation of do_close,
|
||||
don't use TCPIP_APIMSG here */
|
||||
err = tcpip_apimsg(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -487,60 +648,69 @@ netconn_write(struct netconn *conn, const void *dataptr, int size, u8_t apiflags
|
||||
err_t
|
||||
netconn_close(struct netconn *conn)
|
||||
{
|
||||
struct api_msg msg;
|
||||
|
||||
LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
msg.function = do_close;
|
||||
msg.msg.conn = conn;
|
||||
tcpip_apimsg(&msg);
|
||||
return conn->err;
|
||||
/* shutting down both ends is the same as closing */
|
||||
return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
|
||||
}
|
||||
|
||||
#if LWIP_IGMP
|
||||
/**
|
||||
* Shut down one or both sides of a TCP netconn (doesn't delete it).
|
||||
*
|
||||
* @param conn the TCP netconn to shut down
|
||||
* @return ERR_OK if the netconn was closed, any other err_t on error
|
||||
*/
|
||||
err_t
|
||||
netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
|
||||
{
|
||||
return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
|
||||
}
|
||||
|
||||
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
|
||||
/**
|
||||
* Join multicast groups for UDP netconns.
|
||||
*
|
||||
* @param conn the UDP netconn for which to change multicast addresses
|
||||
* @param multiaddr IP address of the multicast group to join or leave
|
||||
* @param interface the IP address of the network interface on which to send
|
||||
* @param netif_addr the IP address of the network interface on which to send
|
||||
* the igmp message
|
||||
* @param join_or_leave flag whether to send a join- or leave-message
|
||||
* @return ERR_OK if the action was taken, any err_t on error
|
||||
*/
|
||||
err_t
|
||||
netconn_join_leave_group(struct netconn *conn,
|
||||
struct ip_addr *multiaddr,
|
||||
struct ip_addr *interface,
|
||||
ip_addr_t *multiaddr,
|
||||
ip_addr_t *netif_addr,
|
||||
enum netconn_igmp join_or_leave)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
msg.function = do_join_leave_group;
|
||||
msg.msg.conn = conn;
|
||||
msg.msg.msg.jl.multiaddr = multiaddr;
|
||||
msg.msg.msg.jl.interface = interface;
|
||||
msg.msg.msg.jl.multiaddr = ip_2_ipX(multiaddr);
|
||||
msg.msg.msg.jl.netif_addr = ip_2_ipX(netif_addr);
|
||||
msg.msg.msg.jl.join_or_leave = join_or_leave;
|
||||
TCPIP_APIMSG(&msg);
|
||||
return conn->err;
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
|
||||
|
||||
#if LWIP_DNS
|
||||
/**
|
||||
* Execute a DNS query, only one IP address is returned
|
||||
*
|
||||
* @param name a string representation of the DNS host name to query
|
||||
* @param addr a preallocated struct ip_addr where to store the resolved IP address
|
||||
* @param addr a preallocated ip_addr_t where to store the resolved IP address
|
||||
* @return ERR_OK: resolving succeeded
|
||||
* ERR_MEM: memory error, try again later
|
||||
* ERR_ARG: dns client not initialized or invalid hostname
|
||||
* ERR_VAL: dns server response was invalid
|
||||
*/
|
||||
err_t
|
||||
netconn_gethostbyname(const char *name, struct ip_addr *addr)
|
||||
netconn_gethostbyname(const char *name, ip_addr_t *addr)
|
||||
{
|
||||
struct dns_api_msg msg;
|
||||
err_t err;
|
||||
@@ -549,19 +719,19 @@ netconn_gethostbyname(const char *name, struct ip_addr *addr)
|
||||
LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
|
||||
|
||||
sem = sys_sem_new(0);
|
||||
if (sem == SYS_SEM_NULL) {
|
||||
return ERR_MEM;
|
||||
err = sys_sem_new(&sem, 0);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
msg.name = name;
|
||||
msg.addr = addr;
|
||||
msg.err = &err;
|
||||
msg.sem = sem;
|
||||
msg.sem = &sem;
|
||||
|
||||
tcpip_callback(do_gethostbyname, &msg);
|
||||
sys_sem_wait(sem);
|
||||
sys_sem_free(sem);
|
||||
sys_sem_wait(&sem);
|
||||
sys_sem_free(&sem);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
1007
src/api/api_msg.c
1007
src/api/api_msg.c
File diff suppressed because it is too large
Load Diff
@@ -44,18 +44,19 @@ static const char *err_strerr[] = {
|
||||
"Ok.", /* ERR_OK 0 */
|
||||
"Out of memory error.", /* ERR_MEM -1 */
|
||||
"Buffer error.", /* ERR_BUF -2 */
|
||||
"Routing problem.", /* ERR_RTE -3 */
|
||||
"Connection aborted.", /* ERR_ABRT -4 */
|
||||
"Connection reset.", /* ERR_RST -5 */
|
||||
"Connection closed.", /* ERR_CLSD -6 */
|
||||
"Not connected.", /* ERR_CONN -7 */
|
||||
"Illegal value.", /* ERR_VAL -8 */
|
||||
"Illegal argument.", /* ERR_ARG -9 */
|
||||
"Address in use.", /* ERR_USE -10 */
|
||||
"Low-level netif error.", /* ERR_IF -11 */
|
||||
"Already connected.", /* ERR_ISCONN -12 */
|
||||
"Timeout.", /* ERR_TIMEOUT -13 */
|
||||
"Operation in progress." /* ERR_INPROGRESS -14 */
|
||||
"Timeout.", /* ERR_TIMEOUT -3 */
|
||||
"Routing problem.", /* ERR_RTE -4 */
|
||||
"Operation in progress.", /* ERR_INPROGRESS -5 */
|
||||
"Illegal value.", /* ERR_VAL -6 */
|
||||
"Operation would block.", /* ERR_WOULDBLOCK -7 */
|
||||
"Address in use.", /* ERR_USE -8 */
|
||||
"Already connected.", /* ERR_ISCONN -9 */
|
||||
"Connection aborted.", /* ERR_ABRT -10 */
|
||||
"Connection reset.", /* ERR_RST -11 */
|
||||
"Connection closed.", /* ERR_CLSD -12 */
|
||||
"Not connected.", /* ERR_CONN -13 */
|
||||
"Illegal argument.", /* ERR_ARG -14 */
|
||||
"Low-level netif error.", /* ERR_IF -15 */
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -57,11 +57,21 @@ netbuf *netbuf_new(void)
|
||||
{
|
||||
struct netbuf *buf;
|
||||
|
||||
buf = memp_malloc(MEMP_NETBUF);
|
||||
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
|
||||
if (buf != NULL) {
|
||||
buf->p = NULL;
|
||||
buf->ptr = NULL;
|
||||
buf->addr = NULL;
|
||||
ipX_addr_set_any(LWIP_IPV6, &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
|
||||
ipX_addr_set_any(LWIP_IPV6, &buf->toaddr);
|
||||
#endif /* LWIP_NETBUF_RECVINFO */
|
||||
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
|
||||
return buf;
|
||||
} else {
|
||||
return NULL;
|
||||
@@ -158,14 +168,14 @@ netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
|
||||
* Chain one netbuf to another (@see pbuf_chain)
|
||||
*
|
||||
* @param head the first netbuf
|
||||
* @param tail netbuf to chain after head
|
||||
* @param tail netbuf to chain after head, freed by this function, may not be reference after returning
|
||||
*/
|
||||
void
|
||||
netbuf_chain(struct netbuf *head, struct netbuf *tail)
|
||||
{
|
||||
LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);
|
||||
LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);
|
||||
pbuf_chain(head->p, tail->p);
|
||||
pbuf_cat(head->p, tail->p);
|
||||
head->ptr = head->p;
|
||||
memp_free(MEMP_NETBUF, tail);
|
||||
}
|
||||
|
||||
@@ -39,13 +39,18 @@
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/api.h"
|
||||
#include "lwip/dns.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/** helper struct for gethostbyname_r to access the char* buffer */
|
||||
struct gethostbyname_r_helper {
|
||||
struct ip_addr *addrs;
|
||||
struct ip_addr addr;
|
||||
ip_addr_t *addrs;
|
||||
ip_addr_t addr;
|
||||
char *aliases;
|
||||
};
|
||||
|
||||
@@ -80,13 +85,13 @@ struct hostent*
|
||||
lwip_gethostbyname(const char *name)
|
||||
{
|
||||
err_t err;
|
||||
struct ip_addr addr;
|
||||
ip_addr_t addr;
|
||||
|
||||
/* buffer variables for lwip_gethostbyname() */
|
||||
HOSTENT_STORAGE struct hostent s_hostent;
|
||||
HOSTENT_STORAGE char *s_aliases;
|
||||
HOSTENT_STORAGE struct ip_addr s_hostent_addr;
|
||||
HOSTENT_STORAGE struct ip_addr *s_phostent_addr;
|
||||
HOSTENT_STORAGE ip_addr_t s_hostent_addr;
|
||||
HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2];
|
||||
|
||||
/* query host IP address */
|
||||
err = netconn_gethostbyname(name, &addr);
|
||||
@@ -98,32 +103,33 @@ lwip_gethostbyname(const char *name)
|
||||
|
||||
/* fill hostent */
|
||||
s_hostent_addr = addr;
|
||||
s_phostent_addr = &s_hostent_addr;
|
||||
s_phostent_addr[0] = &s_hostent_addr;
|
||||
s_phostent_addr[1] = NULL;
|
||||
s_hostent.h_name = (char*)name;
|
||||
s_hostent.h_aliases = &s_aliases;
|
||||
s_hostent.h_addrtype = AF_INET;
|
||||
s_hostent.h_length = sizeof(struct ip_addr);
|
||||
s_hostent.h_length = sizeof(ip_addr_t);
|
||||
s_hostent.h_addr_list = (char**)&s_phostent_addr;
|
||||
|
||||
#if DNS_DEBUG
|
||||
/* dump hostent */
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == 0x%08lX\n",(u32_t)(s_hostent.h_aliases)));
|
||||
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]-> == 0x%08lX\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[%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_addrtype == %lu\n", (u32_t)(s_hostent.h_addrtype)));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %lu\n", (u32_t)(s_hostent.h_length)));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == 0x%08lX\n", s_hostent.h_addr_list));
|
||||
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));
|
||||
if (s_hostent.h_addr_list != NULL) {
|
||||
u8_t idx;
|
||||
for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == 0x%08lX\n", idx, s_hostent.h_addr_list[idx]));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, inet_ntoa(*((struct in_addr*)(s_hostent.h_addr_list[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])));
|
||||
}
|
||||
}
|
||||
#endif /* DNS_DEBUG */
|
||||
@@ -208,7 +214,7 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
|
||||
ret->h_name = (char*)hostname;
|
||||
ret->h_aliases = &(h->aliases);
|
||||
ret->h_addrtype = AF_INET;
|
||||
ret->h_length = sizeof(struct ip_addr);
|
||||
ret->h_length = sizeof(ip_addr_t);
|
||||
ret->h_addr_list = (char**)&(h->addrs);
|
||||
|
||||
/* set result != NULL */
|
||||
@@ -231,14 +237,8 @@ lwip_freeaddrinfo(struct addrinfo *ai)
|
||||
struct addrinfo *next;
|
||||
|
||||
while (ai != NULL) {
|
||||
if (ai->ai_addr != NULL) {
|
||||
mem_free(ai->ai_addr);
|
||||
}
|
||||
if (ai->ai_canonname != NULL) {
|
||||
mem_free(ai->ai_canonname);
|
||||
}
|
||||
next = ai->ai_next;
|
||||
mem_free(ai);
|
||||
memp_free(MEMP_NETDB, ai);
|
||||
ai = next;
|
||||
}
|
||||
}
|
||||
@@ -267,10 +267,12 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res)
|
||||
{
|
||||
err_t err;
|
||||
struct ip_addr addr;
|
||||
ip_addr_t addr;
|
||||
struct addrinfo *ai;
|
||||
struct sockaddr_in *sa = NULL;
|
||||
int port_nr = 0;
|
||||
size_t total_size;
|
||||
size_t namelen = 0;
|
||||
|
||||
if (res == NULL) {
|
||||
return EAI_FAIL;
|
||||
@@ -297,24 +299,29 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
}
|
||||
} else {
|
||||
/* service location specified, use loopback address */
|
||||
addr.addr = INADDR_LOOPBACK;
|
||||
ip_addr_set_loopback(&addr);
|
||||
}
|
||||
|
||||
ai = mem_malloc(sizeof(struct addrinfo));
|
||||
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
|
||||
if (nodename != NULL) {
|
||||
namelen = strlen(nodename);
|
||||
LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
|
||||
total_size += namelen + 1;
|
||||
}
|
||||
/* If this fails, please report to lwip-devel! :-) */
|
||||
LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!",
|
||||
total_size <= NETDB_ELEM_SIZE);
|
||||
ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
|
||||
if (ai == NULL) {
|
||||
goto memerr;
|
||||
}
|
||||
memset(ai, 0, sizeof(struct addrinfo));
|
||||
sa = mem_malloc(sizeof(struct sockaddr_in));
|
||||
if (sa == NULL) {
|
||||
goto memerr;
|
||||
}
|
||||
memset(sa, 0, sizeof(struct sockaddr_in));
|
||||
memset(ai, 0, total_size);
|
||||
sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo));
|
||||
/* set up sockaddr */
|
||||
sa->sin_addr.s_addr = addr.addr;
|
||||
inet_addr_from_ipaddr(&sa->sin_addr, &addr);
|
||||
sa->sin_family = AF_INET;
|
||||
sa->sin_len = sizeof(struct sockaddr_in);
|
||||
sa->sin_port = htons(port_nr);
|
||||
sa->sin_port = htons((u16_t)port_nr);
|
||||
|
||||
/* set up addrinfo */
|
||||
ai->ai_family = AF_INET;
|
||||
@@ -325,11 +332,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
}
|
||||
if (nodename != NULL) {
|
||||
/* copy nodename to canonname if specified */
|
||||
size_t namelen = strlen(nodename);
|
||||
ai->ai_canonname = mem_malloc(namelen + 1);
|
||||
if (ai->ai_canonname == NULL) {
|
||||
goto memerr;
|
||||
}
|
||||
ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
|
||||
MEMCPY(ai->ai_canonname, nodename, namelen);
|
||||
ai->ai_canonname[namelen] = 0;
|
||||
}
|
||||
@@ -341,10 +344,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
return 0;
|
||||
memerr:
|
||||
if (ai != NULL) {
|
||||
mem_free(ai);
|
||||
}
|
||||
if (sa != NULL) {
|
||||
mem_free(sa);
|
||||
memp_free(MEMP_NETDB, ai);
|
||||
}
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
* Call netif_add() inside the tcpip_thread context.
|
||||
*/
|
||||
void
|
||||
do_netifapi_netif_add( struct netifapi_msg_msg *msg)
|
||||
do_netifapi_netif_add(struct netifapi_msg_msg *msg)
|
||||
{
|
||||
if (!netif_add( msg->netif,
|
||||
msg->msg.add.ipaddr,
|
||||
@@ -58,16 +58,29 @@ do_netifapi_netif_add( struct netifapi_msg_msg *msg)
|
||||
TCPIP_NETIFAPI_ACK(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call netif_set_addr() inside the tcpip_thread context.
|
||||
*/
|
||||
void
|
||||
do_netifapi_netif_set_addr(struct netifapi_msg_msg *msg)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
do_netifapi_netif_common(struct netifapi_msg_msg *msg)
|
||||
{
|
||||
if (msg->msg.common.errtfunc!=NULL) {
|
||||
msg->err =
|
||||
msg->msg.common.errtfunc(msg->netif);
|
||||
if (msg->msg.common.errtfunc != NULL) {
|
||||
msg->err = msg->msg.common.errtfunc(msg->netif);
|
||||
} else {
|
||||
msg->err = ERR_OK;
|
||||
msg->msg.common.voidfunc(msg->netif);
|
||||
@@ -83,12 +96,12 @@ do_netifapi_netif_common( struct netifapi_msg_msg *msg)
|
||||
*/
|
||||
err_t
|
||||
netifapi_netif_add(struct netif *netif,
|
||||
struct ip_addr *ipaddr,
|
||||
struct ip_addr *netmask,
|
||||
struct ip_addr *gw,
|
||||
ip_addr_t *ipaddr,
|
||||
ip_addr_t *netmask,
|
||||
ip_addr_t *gw,
|
||||
void *state,
|
||||
err_t (* init)(struct netif *netif),
|
||||
err_t (* input)(struct pbuf *p, struct netif *netif))
|
||||
netif_init_fn init,
|
||||
netif_input_fn input)
|
||||
{
|
||||
struct netifapi_msg msg;
|
||||
msg.function = do_netifapi_netif_add;
|
||||
@@ -103,6 +116,28 @@ netifapi_netif_add(struct netif *netif,
|
||||
return msg.msg.err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call netif_set_addr() in a thread-safe way by running that function inside the
|
||||
* tcpip_thread context.
|
||||
*
|
||||
* @note for params @see netif_set_addr()
|
||||
*/
|
||||
err_t
|
||||
netifapi_netif_set_addr(struct netif *netif,
|
||||
ip_addr_t *ipaddr,
|
||||
ip_addr_t *netmask,
|
||||
ip_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;
|
||||
}
|
||||
|
||||
/**
|
||||
* call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe
|
||||
* way by running that function inside the tcpip_thread context.
|
||||
@@ -110,9 +145,8 @@ netifapi_netif_add(struct netif *netif,
|
||||
* @note use only for functions where there is only "netif" parameter.
|
||||
*/
|
||||
err_t
|
||||
netifapi_netif_common( struct netif *netif,
|
||||
void (* voidfunc)(struct netif *netif),
|
||||
err_t (* errtfunc)(struct netif *netif) )
|
||||
netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,
|
||||
netifapi_errt_fn errtfunc)
|
||||
{
|
||||
struct netifapi_msg msg;
|
||||
msg.function = do_netifapi_netif_common;
|
||||
|
||||
1518
src/api/sockets.c
1518
src/api/sockets.c
File diff suppressed because it is too large
Load Diff
471
src/api/tcpip.c
471
src/api/tcpip.c
@@ -42,182 +42,23 @@
|
||||
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_frag.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/autoip.h"
|
||||
#include "lwip/dhcp.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "lwip/init.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "netif/ppp_oe.h"
|
||||
|
||||
/* global variables */
|
||||
static void (* tcpip_init_done)(void *arg);
|
||||
static tcpip_init_done_fn tcpip_init_done;
|
||||
static void *tcpip_init_done_arg;
|
||||
static sys_mbox_t mbox = SYS_MBOX_NULL;
|
||||
static sys_mbox_t mbox;
|
||||
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
/** The global semaphore to lock the stack. */
|
||||
sys_sem_t lock_tcpip_core;
|
||||
sys_mutex_t lock_tcpip_core;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
|
||||
#if LWIP_TCP
|
||||
/* global variable that shows if the tcp timer is currently scheduled or not */
|
||||
static int tcpip_tcp_timer_active;
|
||||
|
||||
/**
|
||||
* Timer callback function that calls tcp_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
tcpip_tcp_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
/* call TCP timer handler */
|
||||
tcp_tmr();
|
||||
/* timer still needed? */
|
||||
if (tcp_active_pcbs || tcp_tw_pcbs) {
|
||||
/* restart timer */
|
||||
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
|
||||
} else {
|
||||
/* disable timer */
|
||||
tcpip_tcp_timer_active = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if !NO_SYS
|
||||
/**
|
||||
* Called from TCP_REG when registering a new PCB:
|
||||
* the reason is to have the TCP timer only running when
|
||||
* there are active (or time-wait) PCBs.
|
||||
*/
|
||||
void
|
||||
tcp_timer_needed(void)
|
||||
{
|
||||
/* timer is off but needed again? */
|
||||
if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
|
||||
/* enable and start timer */
|
||||
tcpip_tcp_timer_active = 1;
|
||||
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
|
||||
}
|
||||
}
|
||||
#endif /* !NO_SYS */
|
||||
#endif /* LWIP_TCP */
|
||||
|
||||
#if IP_REASSEMBLY
|
||||
/**
|
||||
* Timer callback function that calls ip_reass_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
ip_reass_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n"));
|
||||
ip_reass_tmr();
|
||||
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
|
||||
}
|
||||
#endif /* IP_REASSEMBLY */
|
||||
|
||||
#if LWIP_ARP
|
||||
/**
|
||||
* Timer callback function that calls etharp_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
arp_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: etharp_tmr()\n"));
|
||||
etharp_tmr();
|
||||
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_ARP */
|
||||
|
||||
#if LWIP_DHCP
|
||||
/**
|
||||
* Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
dhcp_timer_coarse(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
|
||||
dhcp_coarse_tmr();
|
||||
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
dhcp_timer_fine(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
|
||||
dhcp_fine_tmr();
|
||||
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
|
||||
}
|
||||
#endif /* LWIP_DHCP */
|
||||
|
||||
#if LWIP_AUTOIP
|
||||
/**
|
||||
* Timer callback function that calls autoip_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
autoip_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: autoip_tmr()\n"));
|
||||
autoip_tmr();
|
||||
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_AUTOIP */
|
||||
|
||||
#if LWIP_IGMP
|
||||
/**
|
||||
* Timer callback function that calls igmp_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
igmp_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: igmp_tmr()\n"));
|
||||
igmp_tmr();
|
||||
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
|
||||
#if LWIP_DNS
|
||||
/**
|
||||
* Timer callback function that calls dns_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
dns_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dns_tmr()\n"));
|
||||
dns_tmr();
|
||||
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_DNS */
|
||||
|
||||
/**
|
||||
* The main lwIP thread. This thread has exclusive access to lwIP core functions
|
||||
@@ -235,33 +76,17 @@ tcpip_thread(void *arg)
|
||||
struct tcpip_msg *msg;
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
#if IP_REASSEMBLY
|
||||
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
|
||||
#endif /* IP_REASSEMBLY */
|
||||
#if LWIP_ARP
|
||||
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
||||
#endif /* LWIP_ARP */
|
||||
#if LWIP_DHCP
|
||||
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
|
||||
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
|
||||
#endif /* LWIP_DHCP */
|
||||
#if LWIP_AUTOIP
|
||||
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
|
||||
#endif /* LWIP_AUTOIP */
|
||||
#if LWIP_IGMP
|
||||
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
|
||||
#endif /* LWIP_IGMP */
|
||||
#if LWIP_DNS
|
||||
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
|
||||
#endif /* LWIP_DNS */
|
||||
|
||||
if (tcpip_init_done != NULL) {
|
||||
tcpip_init_done(tcpip_init_done_arg);
|
||||
}
|
||||
|
||||
LOCK_TCPIP_CORE();
|
||||
while (1) { /* MAIN Loop */
|
||||
sys_mbox_fetch(mbox, (void *)&msg);
|
||||
UNLOCK_TCPIP_CORE();
|
||||
LWIP_TCPIP_THREAD_ALIVE();
|
||||
/* wait for a message, timeouts are processed while waiting */
|
||||
sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
|
||||
LOCK_TCPIP_CORE();
|
||||
switch (msg->type) {
|
||||
#if LWIP_NETCONN
|
||||
case TCPIP_MSG_API:
|
||||
@@ -270,17 +95,25 @@ tcpip_thread(void *arg)
|
||||
break;
|
||||
#endif /* LWIP_NETCONN */
|
||||
|
||||
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||
case TCPIP_MSG_INPKT:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
|
||||
#if LWIP_ARP
|
||||
if (msg->msg.inp.netif->flags & NETIF_FLAG_ETHARP) {
|
||||
#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_ARP */
|
||||
{ ip_input(msg->msg.inp.p, msg->msg.inp.netif);
|
||||
#endif /* LWIP_ETHERNET */
|
||||
#if LWIP_IPV6
|
||||
if ((*((unsigned char *)(msg->msg.inp.p->payload)) & 0xf0) == 0x60) {
|
||||
ip6_input(msg->msg.inp.p, msg->msg.inp.netif);
|
||||
} else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
ip_input(msg->msg.inp.p, msg->msg.inp.netif);
|
||||
}
|
||||
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
|
||||
break;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||
|
||||
#if LWIP_NETIF_API
|
||||
case TCPIP_MSG_NETIFAPI:
|
||||
@@ -289,23 +122,33 @@ tcpip_thread(void *arg)
|
||||
break;
|
||||
#endif /* LWIP_NETIF_API */
|
||||
|
||||
#if LWIP_TCPIP_TIMEOUT
|
||||
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);
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
break;
|
||||
case TCPIP_MSG_UNTIMEOUT:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
|
||||
sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
break;
|
||||
#endif /* LWIP_TCPIP_TIMEOUT */
|
||||
|
||||
case TCPIP_MSG_CALLBACK:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
|
||||
msg->msg.cb.f(msg->msg.cb.ctx);
|
||||
msg->msg.cb.function(msg->msg.cb.ctx);
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
break;
|
||||
|
||||
case TCPIP_MSG_TIMEOUT:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
|
||||
|
||||
if(msg->msg.tmo.msecs != 0xffffffff)
|
||||
sys_timeout (msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
|
||||
else
|
||||
sys_untimeout (msg->msg.tmo.h, msg->msg.tmo.arg);
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
case TCPIP_MSG_CALLBACK_STATIC:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
|
||||
msg->msg.cb.function(msg->msg.cb.ctx);
|
||||
break;
|
||||
|
||||
default:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
|
||||
LWIP_ASSERT("tcpip_thread: invalid message", 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -315,30 +158,47 @@ tcpip_thread(void *arg)
|
||||
* Pass a received packet to tcpip_thread for input processing
|
||||
*
|
||||
* @param p the received packet, p->payload pointing to the Ethernet header or
|
||||
* to an IP header (if netif doesn't got NETIF_FLAG_ETHARP flag)
|
||||
* to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or
|
||||
* NETIF_FLAG_ETHERNET flags)
|
||||
* @param inp the network interface on which the packet was received
|
||||
*/
|
||||
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);
|
||||
} 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 (mbox != SYS_MBOX_NULL) {
|
||||
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;
|
||||
if (!sys_mbox_valid(&mbox)) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
return ERR_VAL;
|
||||
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;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -353,23 +213,23 @@ tcpip_input(struct pbuf *p, struct netif *inp)
|
||||
* @return ERR_OK if the function was called, another err_t if not
|
||||
*/
|
||||
err_t
|
||||
tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block)
|
||||
tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
|
||||
{
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
if (mbox != SYS_MBOX_NULL) {
|
||||
msg = memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (sys_mbox_valid(&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.f = f;
|
||||
msg->msg.cb.function = function;
|
||||
msg->msg.cb.ctx = ctx;
|
||||
if (block) {
|
||||
sys_mbox_post(mbox, msg);
|
||||
sys_mbox_post(&mbox, msg);
|
||||
} else {
|
||||
if (sys_mbox_trypost(mbox, msg) != ERR_OK) {
|
||||
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
return ERR_MEM;
|
||||
}
|
||||
@@ -379,13 +239,22 @@ tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block)
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
#if LWIP_TCPIP_TIMEOUT
|
||||
/**
|
||||
* call sys_timeout 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
|
||||
*/
|
||||
err_t
|
||||
tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
||||
{
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
if (mbox != SYS_MBOX_NULL) {
|
||||
msg = memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (sys_mbox_valid(&mbox)) {
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
@@ -394,12 +263,41 @@ tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
||||
msg->msg.tmo.msecs = msecs;
|
||||
msg->msg.tmo.h = h;
|
||||
msg->msg.tmo.arg = arg;
|
||||
sys_mbox_post(mbox, msg);
|
||||
sys_mbox_post(&mbox, msg);
|
||||
return ERR_OK;
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
err_t
|
||||
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;
|
||||
}
|
||||
|
||||
msg->type = TCPIP_MSG_UNTIMEOUT;
|
||||
msg->msg.tmo.h = h;
|
||||
msg->msg.tmo.arg = arg;
|
||||
sys_mbox_post(&mbox, msg);
|
||||
return ERR_OK;
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
#endif /* LWIP_TCPIP_TIMEOUT */
|
||||
|
||||
#if LWIP_NETCONN
|
||||
/**
|
||||
* Call the lower part of a netconn_* function
|
||||
@@ -413,13 +311,17 @@ err_t
|
||||
tcpip_apimsg(struct api_msg *apimsg)
|
||||
{
|
||||
struct tcpip_msg msg;
|
||||
#ifdef LWIP_DEBUG
|
||||
/* catch functions that don't set err */
|
||||
apimsg->msg.err = ERR_VAL;
|
||||
#endif
|
||||
|
||||
if (mbox != SYS_MBOX_NULL) {
|
||||
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 ERR_OK;
|
||||
sys_mbox_post(&mbox, &msg);
|
||||
sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0);
|
||||
return apimsg->msg.err;
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
@@ -436,10 +338,15 @@ tcpip_apimsg(struct api_msg *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
|
||||
|
||||
LOCK_TCPIP_CORE();
|
||||
apimsg->function(&(apimsg->msg));
|
||||
UNLOCK_TCPIP_CORE();
|
||||
return ERR_OK;
|
||||
return apimsg->msg.err;
|
||||
|
||||
}
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
@@ -459,18 +366,18 @@ tcpip_netifapi(struct netifapi_msg* netifapimsg)
|
||||
{
|
||||
struct tcpip_msg msg;
|
||||
|
||||
if (mbox != SYS_MBOX_NULL) {
|
||||
netifapimsg->msg.sem = sys_sem_new(0);
|
||||
if (netifapimsg->msg.sem == SYS_SEM_NULL) {
|
||||
netifapimsg->msg.err = ERR_MEM;
|
||||
return netifapimsg->msg.err;
|
||||
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);
|
||||
sys_mbox_post(&mbox, &msg);
|
||||
sys_sem_wait(&netifapimsg->msg.sem);
|
||||
sys_sem_free(&netifapimsg->msg.sem);
|
||||
return netifapimsg->msg.err;
|
||||
}
|
||||
return ERR_VAL;
|
||||
@@ -495,6 +402,52 @@ tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
|
||||
#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;
|
||||
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)
|
||||
{
|
||||
if (!sys_mbox_valid(&mbox)) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
return sys_mbox_trypost(&mbox, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this module:
|
||||
* - initialize all sub modules
|
||||
@@ -504,18 +457,60 @@ tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
|
||||
* @param arg argument to pass to initfunc
|
||||
*/
|
||||
void
|
||||
tcpip_init(void (* initfunc)(void *), void *arg)
|
||||
tcpip_init(tcpip_init_done_fn initfunc, void *arg)
|
||||
{
|
||||
lwip_init();
|
||||
|
||||
tcpip_init_done = initfunc;
|
||||
tcpip_init_done_arg = arg;
|
||||
mbox = sys_mbox_new(TCPIP_MBOX_SIZE);
|
||||
if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
|
||||
LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
|
||||
}
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
lock_tcpip_core = sys_sem_new(1);
|
||||
if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
|
||||
LWIP_ASSERT("failed to create lock_tcpip_core", 0);
|
||||
}
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
|
||||
sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple callback function used with tcpip_callback to free a pbuf
|
||||
* (pbuf_free has a wrong signature for tcpip_callback)
|
||||
*
|
||||
* @param p The pbuf (chain) to be dereferenced.
|
||||
*/
|
||||
static void
|
||||
pbuf_free_int(void *p)
|
||||
{
|
||||
struct pbuf *q = (struct pbuf *)p;
|
||||
pbuf_free(q);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple wrapper function that allows you to free a pbuf from interrupt context.
|
||||
*
|
||||
* @param p The pbuf (chain) to be dereferenced.
|
||||
* @return ERR_OK if callback could be enqueued, an err_t if not
|
||||
*/
|
||||
err_t
|
||||
pbuf_free_callback(struct pbuf *p)
|
||||
{
|
||||
return tcpip_callback_with_block(pbuf_free_int, p, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple wrapper function that allows you to free heap memory from
|
||||
* interrupt context.
|
||||
*
|
||||
* @param m the heap memory to free
|
||||
* @return ERR_OK if callback could be enqueued, an err_t if not
|
||||
*/
|
||||
err_t
|
||||
mem_free_callback(void *m)
|
||||
{
|
||||
return tcpip_callback_with_block(mem_free, m, 0);
|
||||
}
|
||||
|
||||
#endif /* !NO_SYS */
|
||||
|
||||
108
src/core/def.c
Normal file
108
src/core/def.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @file
|
||||
* Common functions used throughout the stack.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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: Simon Goldschmidt
|
||||
*
|
||||
*/
|
||||
|
||||
#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.
|
||||
*/
|
||||
|
||||
#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
|
||||
/**
|
||||
* Convert an u16_t from host- to network byte order.
|
||||
*
|
||||
* @param n u16_t in host byte order
|
||||
* @return n in network byte order
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an u32_t from host- to network byte order.
|
||||
*
|
||||
* @param n u32_t in host byte order
|
||||
* @return n in network byte order
|
||||
*/
|
||||
u32_t
|
||||
lwip_htonl(u32_t n)
|
||||
{
|
||||
return ((n & 0xff) << 24) |
|
||||
((n & 0xff00) << 8) |
|
||||
((n & 0xff0000UL) >> 8) |
|
||||
((n & 0xff000000UL) >> 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an u32_t from network- to host byte order.
|
||||
*
|
||||
* @param n u32_t in network byte order
|
||||
* @return n in host byte order
|
||||
*/
|
||||
u32_t
|
||||
lwip_ntohl(u32_t n)
|
||||
{
|
||||
return lwip_htonl(n);
|
||||
}
|
||||
|
||||
#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */
|
||||
1199
src/core/dhcp.c
1199
src/core/dhcp.c
File diff suppressed because it is too large
Load Diff
370
src/core/dns.c
370
src/core/dns.c
@@ -78,13 +78,14 @@
|
||||
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/dns.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/** DNS server IP address */
|
||||
#ifndef DNS_SERVER_ADDRESS
|
||||
#define DNS_SERVER_ADDRESS inet_addr("208.67.222.222") /* resolver1.opendns.com */
|
||||
#define DNS_SERVER_ADDRESS(ipaddr) (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */
|
||||
#endif
|
||||
|
||||
/** DNS server port address */
|
||||
@@ -127,52 +128,41 @@
|
||||
PACK_STRUCT_BEGIN
|
||||
/** DNS message header */
|
||||
struct dns_hdr {
|
||||
u16_t id;
|
||||
u8_t flags1;
|
||||
u8_t flags2;
|
||||
u16_t numquestions;
|
||||
u16_t numanswers;
|
||||
u16_t numauthrr;
|
||||
u16_t numextrarr;
|
||||
PACK_STRUCT_FIELD(u16_t id);
|
||||
PACK_STRUCT_FIELD(u8_t flags1);
|
||||
PACK_STRUCT_FIELD(u8_t flags2);
|
||||
PACK_STRUCT_FIELD(u16_t numquestions);
|
||||
PACK_STRUCT_FIELD(u16_t numanswers);
|
||||
PACK_STRUCT_FIELD(u16_t numauthrr);
|
||||
PACK_STRUCT_FIELD(u16_t numextrarr);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
#define SIZEOF_DNS_HDR 12
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
/** DNS query message structure */
|
||||
/** DNS query message structure.
|
||||
No packing needed: only used locally on the stack. */
|
||||
struct dns_query {
|
||||
/* DNS query record starts with either a domain name or a pointer
|
||||
to a name already present somewhere in the packet. */
|
||||
u16_t type;
|
||||
u16_t class;
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
u16_t cls;
|
||||
};
|
||||
#define SIZEOF_DNS_QUERY 4
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
/** DNS answer message structure */
|
||||
/** DNS answer message structure.
|
||||
No packing needed: only used locally on the stack. */
|
||||
struct dns_answer {
|
||||
/* DNS answer record starts with either a domain name or a pointer
|
||||
to a name already present somewhere in the packet. */
|
||||
u16_t type;
|
||||
u16_t class;
|
||||
u16_t cls;
|
||||
u32_t ttl;
|
||||
u16_t len;
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
};
|
||||
#define SIZEOF_DNS_ANSWER 10
|
||||
|
||||
/** DNS table entry */
|
||||
struct dns_table_entry {
|
||||
@@ -184,15 +174,41 @@ struct dns_table_entry {
|
||||
u8_t err;
|
||||
u32_t ttl;
|
||||
char name[DNS_MAX_NAME_LENGTH];
|
||||
struct ip_addr ipaddr;
|
||||
ip_addr_t ipaddr;
|
||||
/* pointer to callback on DNS query done */
|
||||
dns_found_callback found;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
#if DNS_LOCAL_HOSTLIST
|
||||
|
||||
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
||||
/** Local host-list. For hostnames in this list, no
|
||||
* external name resolution is performed */
|
||||
static struct local_hostlist_entry *local_hostlist_dynamic;
|
||||
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||
|
||||
/** Defining this allows the local_hostlist_static to be placed in a different
|
||||
* linker section (e.g. FLASH) */
|
||||
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
|
||||
#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
|
||||
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
|
||||
/** Defining this allows the local_hostlist_static to be placed in a different
|
||||
* linker section (e.g. FLASH) */
|
||||
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
|
||||
#define DNS_LOCAL_HOSTLIST_STORAGE_POST
|
||||
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
|
||||
DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
|
||||
DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
|
||||
|
||||
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||
|
||||
static void dns_init_local();
|
||||
#endif /* DNS_LOCAL_HOSTLIST */
|
||||
|
||||
|
||||
/* forward declarations */
|
||||
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
|
||||
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
|
||||
static void dns_check_entries(void);
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
@@ -203,11 +219,10 @@ static void dns_check_entries(void);
|
||||
static struct udp_pcb *dns_pcb;
|
||||
static u8_t dns_seqno;
|
||||
static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
|
||||
static struct ip_addr dns_servers[DNS_MAX_SERVERS];
|
||||
|
||||
#if (DNS_USES_STATIC_BUF == 1)
|
||||
static u8_t dns_payload[DNS_MSG_SIZE];
|
||||
#endif /* (DNS_USES_STATIC_BUF == 1) */
|
||||
static ip_addr_t dns_servers[DNS_MAX_SERVERS];
|
||||
/** Contiguous buffer for processing responses */
|
||||
static u8_t dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)];
|
||||
static u8_t* dns_payload;
|
||||
|
||||
/**
|
||||
* Initialize the resolver: set up the UDP pcb and configure the default server
|
||||
@@ -216,10 +231,12 @@ static u8_t dns_payload[DNS_MSG_SIZE];
|
||||
void
|
||||
dns_init()
|
||||
{
|
||||
struct ip_addr dnsserver;
|
||||
ip_addr_t dnsserver;
|
||||
|
||||
dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);
|
||||
|
||||
/* initialize default DNS server address */
|
||||
dnsserver.addr = DNS_SERVER_ADDRESS;
|
||||
DNS_SERVER_ADDRESS(&dnsserver);
|
||||
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
|
||||
|
||||
@@ -241,6 +258,9 @@ dns_init()
|
||||
dns_setserver(0, &dnsserver);
|
||||
}
|
||||
}
|
||||
#if DNS_LOCAL_HOSTLIST
|
||||
dns_init_local();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,10 +270,10 @@ dns_init()
|
||||
* @param dnsserver IP address of the DNS server to set
|
||||
*/
|
||||
void
|
||||
dns_setserver(u8_t numdns, struct ip_addr *dnsserver)
|
||||
dns_setserver(u8_t numdns, ip_addr_t *dnsserver)
|
||||
{
|
||||
if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
|
||||
(dnsserver != NULL) && (dnsserver->addr !=0 )) {
|
||||
(dnsserver != NULL) && !ip_addr_isany(dnsserver)) {
|
||||
dns_servers[numdns] = (*dnsserver);
|
||||
}
|
||||
}
|
||||
@@ -265,7 +285,7 @@ dns_setserver(u8_t numdns, struct ip_addr *dnsserver)
|
||||
* @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
|
||||
* server has not been configured.
|
||||
*/
|
||||
struct ip_addr
|
||||
ip_addr_t
|
||||
dns_getserver(u8_t numdns)
|
||||
{
|
||||
if (numdns < DNS_MAX_SERVERS) {
|
||||
@@ -288,6 +308,131 @@ dns_tmr(void)
|
||||
}
|
||||
}
|
||||
|
||||
#if DNS_LOCAL_HOSTLIST
|
||||
static void
|
||||
dns_init_local()
|
||||
{
|
||||
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
|
||||
int i;
|
||||
struct local_hostlist_entry *entry;
|
||||
/* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
|
||||
struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
|
||||
size_t namelen;
|
||||
for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
|
||||
struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
|
||||
LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL);
|
||||
namelen = strlen(init_entry->name);
|
||||
LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
|
||||
entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
|
||||
LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
|
||||
if (entry != NULL) {
|
||||
entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
|
||||
MEMCPY((char*)entry->name, init_entry->name, namelen);
|
||||
((char*)entry->name)[namelen] = 0;
|
||||
entry->addr = init_entry->addr;
|
||||
entry->next = local_hostlist_dynamic;
|
||||
local_hostlist_dynamic = entry;
|
||||
}
|
||||
}
|
||||
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the local host-list for a hostname.
|
||||
*
|
||||
* @param hostname Hostname to look for in the local host-list
|
||||
* @return The first IP address for the hostname in the local host-list or
|
||||
* IPADDR_NONE if not found.
|
||||
*/
|
||||
static u32_t
|
||||
dns_lookup_local(const char *hostname)
|
||||
{
|
||||
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
||||
struct local_hostlist_entry *entry = local_hostlist_dynamic;
|
||||
while(entry != NULL) {
|
||||
if(strcmp(entry->name, hostname) == 0) {
|
||||
return ip4_addr_get_u32(&entry->addr);
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||
int i;
|
||||
for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
|
||||
if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
|
||||
return ip4_addr_get_u32(&local_hostlist_static[i].addr);
|
||||
}
|
||||
}
|
||||
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||
return IPADDR_NONE;
|
||||
}
|
||||
|
||||
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
||||
/** Remove all entries from the local host-list for a specific hostname
|
||||
* and/or IP addess
|
||||
*
|
||||
* @param hostname hostname for which entries shall be removed from the local
|
||||
* host-list
|
||||
* @param addr address for which entries shall be removed from the local host-list
|
||||
* @return the number of removed entries
|
||||
*/
|
||||
int
|
||||
dns_local_removehost(const char *hostname, const ip_addr_t *addr)
|
||||
{
|
||||
int removed = 0;
|
||||
struct local_hostlist_entry *entry = local_hostlist_dynamic;
|
||||
struct local_hostlist_entry *last_entry = NULL;
|
||||
while (entry != NULL) {
|
||||
if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&
|
||||
((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
|
||||
struct local_hostlist_entry *free_entry;
|
||||
if (last_entry != NULL) {
|
||||
last_entry->next = entry->next;
|
||||
} else {
|
||||
local_hostlist_dynamic = entry->next;
|
||||
}
|
||||
free_entry = entry;
|
||||
entry = entry->next;
|
||||
memp_free(MEMP_LOCALHOSTLIST, free_entry);
|
||||
removed++;
|
||||
} else {
|
||||
last_entry = entry;
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a hostname/IP address pair to the local host-list.
|
||||
* Duplicates are not checked.
|
||||
*
|
||||
* @param hostname hostname of the new entry
|
||||
* @param addr IP address of the new entry
|
||||
* @return ERR_OK if succeeded or ERR_MEM on memory error
|
||||
*/
|
||||
err_t
|
||||
dns_local_addhost(const char *hostname, const ip_addr_t *addr)
|
||||
{
|
||||
struct local_hostlist_entry *entry;
|
||||
size_t namelen;
|
||||
LWIP_ASSERT("invalid host name (NULL)", hostname != NULL);
|
||||
namelen = strlen(hostname);
|
||||
LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
|
||||
entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
|
||||
if (entry == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
|
||||
MEMCPY((char*)entry->name, hostname, namelen);
|
||||
((char*)entry->name)[namelen] = 0;
|
||||
ip_addr_copy(entry->addr, *addr);
|
||||
entry->next = local_hostlist_dynamic;
|
||||
local_hostlist_dynamic = entry;
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
|
||||
#endif /* DNS_LOCAL_HOSTLIST */
|
||||
|
||||
/**
|
||||
* Look up a hostname in the array of known hostnames.
|
||||
*
|
||||
@@ -297,14 +442,27 @@ dns_tmr(void)
|
||||
* for a hostname.
|
||||
*
|
||||
* @param name the hostname to look up
|
||||
* @return the hostname's IP address, as u32_t (instead of struct ip_addr to
|
||||
* better check for failure: != 0) or 0 if the hostname was not found
|
||||
* in the cached dns_table.
|
||||
* @return the hostname's IP address, as u32_t (instead of ip_addr_t to
|
||||
* better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname
|
||||
* was not found in the cached dns_table.
|
||||
*/
|
||||
static u32_t
|
||||
dns_lookup(const char *name)
|
||||
{
|
||||
u8_t i;
|
||||
#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
|
||||
u32_t addr;
|
||||
#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
|
||||
#if DNS_LOCAL_HOSTLIST
|
||||
if ((addr = dns_lookup_local(name)) != IPADDR_NONE) {
|
||||
return addr;
|
||||
}
|
||||
#endif /* DNS_LOCAL_HOSTLIST */
|
||||
#ifdef DNS_LOOKUP_LOCAL_EXTERN
|
||||
if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) {
|
||||
return addr;
|
||||
}
|
||||
#endif /* DNS_LOOKUP_LOCAL_EXTERN */
|
||||
|
||||
/* Walk through name list, return entry if found. If not, return NULL. */
|
||||
for (i = 0; i < DNS_TABLE_SIZE; ++i) {
|
||||
@@ -313,11 +471,11 @@ dns_lookup(const char *name)
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
|
||||
ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("\n"));
|
||||
return dns_table[i].ipaddr.addr;
|
||||
return ip4_addr_get_u32(&dns_table[i].ipaddr);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return IPADDR_NONE;
|
||||
}
|
||||
|
||||
#if DNS_DOES_NAME_CHECK
|
||||
@@ -412,20 +570,20 @@ dns_send(u8_t numdns, const char* name, u8_t id)
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
|
||||
(u16_t)(numdns), name));
|
||||
LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);
|
||||
LWIP_ASSERT("dns server has no IP address set", dns_servers[numdns].addr != 0);
|
||||
LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns]));
|
||||
|
||||
/* if here, we have either a new query or a retry on a previous query to process */
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dns_hdr) + DNS_MAX_NAME_LENGTH +
|
||||
sizeof(struct dns_query), PBUF_RAM);
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
|
||||
SIZEOF_DNS_QUERY, PBUF_RAM);
|
||||
if (p != NULL) {
|
||||
LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
|
||||
/* fill dns header */
|
||||
hdr = (struct dns_hdr*)p->payload;
|
||||
memset(hdr, 0, sizeof(struct dns_hdr));
|
||||
memset(hdr, 0, SIZEOF_DNS_HDR);
|
||||
hdr->id = htons(id);
|
||||
hdr->flags1 = DNS_FLAG1_RD;
|
||||
hdr->numquestions = htons(1);
|
||||
query = (char*)hdr + sizeof(struct dns_hdr);
|
||||
hdr->numquestions = PP_HTONS(1);
|
||||
query = (char*)hdr + SIZEOF_DNS_HDR;
|
||||
pHostname = name;
|
||||
--pHostname;
|
||||
|
||||
@@ -444,12 +602,12 @@ dns_send(u8_t numdns, const char* name, u8_t id)
|
||||
*query++='\0';
|
||||
|
||||
/* fill dns query */
|
||||
qry.type = htons(DNS_RRTYPE_A);
|
||||
qry.class = htons(DNS_RRCLASS_IN);
|
||||
MEMCPY( query, &qry, sizeof(struct dns_query));
|
||||
qry.type = PP_HTONS(DNS_RRTYPE_A);
|
||||
qry.cls = PP_HTONS(DNS_RRCLASS_IN);
|
||||
SMEMCPY(query, &qry, SIZEOF_DNS_QUERY);
|
||||
|
||||
/* resize pbuf to the exact dns query */
|
||||
pbuf_realloc(p, (query + sizeof(struct dns_query)) - ((char*)(p->payload)));
|
||||
pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))));
|
||||
|
||||
/* connect to the server for faster receiving */
|
||||
udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
|
||||
@@ -477,6 +635,7 @@ dns_send(u8_t numdns, const char* name, u8_t id)
|
||||
static void
|
||||
dns_check_entry(u8_t i)
|
||||
{
|
||||
err_t err;
|
||||
struct dns_table_entry *pEntry = &dns_table[i];
|
||||
|
||||
LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
|
||||
@@ -491,14 +650,18 @@ dns_check_entry(u8_t i)
|
||||
pEntry->retries = 0;
|
||||
|
||||
/* send DNS packet for this entry */
|
||||
dns_send(pEntry->numdns, pEntry->name, i);
|
||||
err = dns_send(pEntry->numdns, pEntry->name, i);
|
||||
if (err != ERR_OK) {
|
||||
LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
|
||||
("dns_send returned error: %s\n", lwip_strerr(err)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DNS_STATE_ASKING: {
|
||||
if (--pEntry->tmr == 0) {
|
||||
if (++pEntry->retries == DNS_MAX_RETRIES) {
|
||||
if ((pEntry->numdns+1<DNS_MAX_SERVERS) && (dns_servers[pEntry->numdns+1].addr!=0)) {
|
||||
if ((pEntry->numdns+1<DNS_MAX_SERVERS) && !ip_addr_isany(&dns_servers[pEntry->numdns+1])) {
|
||||
/* change of server */
|
||||
pEntry->numdns++;
|
||||
pEntry->tmr = 1;
|
||||
@@ -520,7 +683,11 @@ dns_check_entry(u8_t i)
|
||||
pEntry->tmr = pEntry->retries;
|
||||
|
||||
/* send DNS packet for this entry */
|
||||
dns_send(pEntry->numdns, pEntry->name, i);
|
||||
err = dns_send(pEntry->numdns, pEntry->name, i);
|
||||
if (err != ERR_OK) {
|
||||
LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
|
||||
("dns_send returned error: %s\n", lwip_strerr(err)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -563,20 +730,14 @@ dns_check_entries(void)
|
||||
* @params see udp.h
|
||||
*/
|
||||
static void
|
||||
dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
|
||||
dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
u8_t i;
|
||||
u16_t i;
|
||||
char *pHostname;
|
||||
struct dns_hdr *hdr;
|
||||
struct dns_answer ans;
|
||||
struct dns_table_entry *pEntry;
|
||||
u8_t nquestions, nanswers;
|
||||
#if (DNS_USES_STATIC_BUF == 0)
|
||||
u8_t dns_payload[DNS_MSG_SIZE];
|
||||
#endif /* (DNS_USES_STATIC_BUF == 0) */
|
||||
#if (DNS_USES_STATIC_BUF == 2)
|
||||
u8_t* dns_payload;
|
||||
#endif /* (DNS_USES_STATIC_BUF == 2) */
|
||||
u16_t nquestions, nanswers;
|
||||
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_UNUSED_ARG(pcb);
|
||||
@@ -587,25 +748,16 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
|
||||
if (p->tot_len > DNS_MSG_SIZE) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
|
||||
/* free pbuf and return */
|
||||
goto memerr1;
|
||||
goto memerr;
|
||||
}
|
||||
|
||||
/* is the dns message big enough ? */
|
||||
if (p->tot_len < (sizeof(struct dns_hdr) + sizeof(struct dns_query) + sizeof(struct dns_answer))) {
|
||||
if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
|
||||
/* free pbuf and return */
|
||||
goto memerr1;
|
||||
goto memerr;
|
||||
}
|
||||
|
||||
#if (DNS_USES_STATIC_BUF == 2)
|
||||
dns_payload = mem_malloc(p->tot_len);
|
||||
if (dns_payload == NULL) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: mem_malloc error\n"));
|
||||
/* free pbuf and return */
|
||||
goto memerr1;
|
||||
}
|
||||
#endif /* (DNS_USES_STATIC_BUF == 2) */
|
||||
|
||||
/* copy dns payload inside static buffer for processing */
|
||||
if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
|
||||
/* The ID in the DNS header should be our entry into the name table. */
|
||||
@@ -632,7 +784,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
|
||||
|
||||
#if DNS_DOES_NAME_CHECK
|
||||
/* Check if the name in the "question" part match with the name in the entry. */
|
||||
if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + sizeof(struct dns_hdr)) != 0) {
|
||||
if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
|
||||
/* call callback to indicate error, clean up memory and return */
|
||||
goto responseerr;
|
||||
@@ -640,22 +792,23 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
|
||||
#endif /* DNS_DOES_NAME_CHECK */
|
||||
|
||||
/* Skip the name in the "question" part */
|
||||
pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + sizeof(struct dns_hdr)) + sizeof(struct dns_query);
|
||||
pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;
|
||||
|
||||
while(nanswers > 0) {
|
||||
while (nanswers > 0) {
|
||||
/* skip answer resource record's host name */
|
||||
pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
|
||||
|
||||
/* Check for IP address type and Internet class. Others are discarded. */
|
||||
MEMCPY(&ans, pHostname, sizeof(struct dns_answer));
|
||||
if((ntohs(ans.type) == DNS_RRTYPE_A) && (ntohs(ans.class) == DNS_RRCLASS_IN) && (ntohs(ans.len) == sizeof(struct ip_addr)) ) {
|
||||
SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
|
||||
if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) &&
|
||||
(ans.len == PP_HTONS(sizeof(ip_addr_t))) ) {
|
||||
/* read the answer resource record's TTL, and maximize it if needed */
|
||||
pEntry->ttl = ntohl(ans.ttl);
|
||||
if (pEntry->ttl > DNS_MAX_TTL) {
|
||||
pEntry->ttl = DNS_MAX_TTL;
|
||||
}
|
||||
/* read the IP address after answer resource record's header */
|
||||
MEMCPY( &(pEntry->ipaddr), (pHostname+sizeof(struct dns_answer)), sizeof(struct ip_addr));
|
||||
SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
|
||||
ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("\n"));
|
||||
@@ -664,9 +817,9 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
|
||||
(*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
|
||||
}
|
||||
/* deallocate memory and return */
|
||||
goto memerr2;
|
||||
goto memerr;
|
||||
} else {
|
||||
pHostname = pHostname + sizeof(struct dns_answer) + htons(ans.len);
|
||||
pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
|
||||
}
|
||||
--nanswers;
|
||||
}
|
||||
@@ -678,7 +831,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
|
||||
}
|
||||
|
||||
/* deallocate memory and return */
|
||||
goto memerr2;
|
||||
goto memerr;
|
||||
|
||||
responseerr:
|
||||
/* ERROR: call specified callback function with NULL as name to indicate an error */
|
||||
@@ -689,13 +842,7 @@ responseerr:
|
||||
pEntry->state = DNS_STATE_UNUSED;
|
||||
pEntry->found = NULL;
|
||||
|
||||
memerr2:
|
||||
#if (DNS_USES_STATIC_BUF == 2)
|
||||
/* free dns buffer */
|
||||
mem_free(dns_payload);
|
||||
#endif /* (DNS_USES_STATIC_BUF == 2) */
|
||||
|
||||
memerr1:
|
||||
memerr:
|
||||
/* free pbuf */
|
||||
pbuf_free(p);
|
||||
return;
|
||||
@@ -715,6 +862,7 @@ dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
|
||||
u8_t i;
|
||||
u8_t lseq, lseqi;
|
||||
struct dns_table_entry *pEntry = NULL;
|
||||
size_t namelen;
|
||||
|
||||
/* search an unused entry, or the oldest one */
|
||||
lseq = lseqi = 0;
|
||||
@@ -754,7 +902,9 @@ dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
|
||||
pEntry->seqno = dns_seqno++;
|
||||
pEntry->found = found;
|
||||
pEntry->arg = callback_arg;
|
||||
strcpy(pEntry->name, name);
|
||||
namelen = LWIP_MIN(strlen(name), DNS_MAX_NAME_LENGTH-1);
|
||||
MEMCPY(pEntry->name, name, namelen);
|
||||
pEntry->name[namelen] = 0;
|
||||
|
||||
/* force to send query without waiting timer */
|
||||
dns_check_entry(i);
|
||||
@@ -772,9 +922,10 @@ dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
|
||||
* name is already in the local names table.
|
||||
* - ERR_INPROGRESS enqueue a request to be sent to the DNS server
|
||||
* for resolution if no errors are present.
|
||||
* - ERR_ARG: dns client not initialized or invalid hostname
|
||||
*
|
||||
* @param hostname the hostname that is to be queried
|
||||
* @param addr pointer to a struct ip_addr where to store the address if it is already
|
||||
* @param addr pointer to a ip_addr_t where to store the address if it is already
|
||||
* cached in the dns_table (only valid if ERR_OK is returned!)
|
||||
* @param found a callback function to be called on success, failure or timeout (only if
|
||||
* ERR_INPROGRESS is returned!)
|
||||
@@ -782,28 +933,33 @@ dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
|
||||
* @return a err_t return code.
|
||||
*/
|
||||
err_t
|
||||
dns_gethostbyname(const char *hostname, struct ip_addr *addr, dns_found_callback found,
|
||||
dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,
|
||||
void *callback_arg)
|
||||
{
|
||||
u32_t ipaddr;
|
||||
/* not initialized or no valid server yet, or invalid addr pointer
|
||||
* or invalid hostname or invalid hostname length */
|
||||
if ((dns_pcb == NULL) || (addr == NULL) ||
|
||||
(!hostname) || (!hostname[0]) ||
|
||||
(strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
|
||||
return ERR_VAL;
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
#if LWIP_HAVE_LOOPIF
|
||||
if (strcmp(hostname,"localhost")==0) {
|
||||
addr->addr = INADDR_LOOPBACK;
|
||||
if (strcmp(hostname, "localhost")==0) {
|
||||
ip_addr_set_loopback(addr);
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* LWIP_HAVE_LOOPIF */
|
||||
|
||||
/* host name already in octet notation? set ip addr and return ERR_OK
|
||||
* already have this address cached? */
|
||||
if (((addr->addr = inet_addr(hostname)) != INADDR_NONE) ||
|
||||
((addr->addr = dns_lookup(hostname)) != 0)) {
|
||||
/* host name already in octet notation? set ip addr and return ERR_OK */
|
||||
ipaddr = ipaddr_addr(hostname);
|
||||
if (ipaddr == IPADDR_NONE) {
|
||||
/* already have this address cached? */
|
||||
ipaddr = dns_lookup(hostname);
|
||||
}
|
||||
if (ipaddr != IPADDR_NONE) {
|
||||
ip4_addr_set_u32(addr, ipaddr);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,8 +39,9 @@
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
/* These are some reference implementations of the checksum algorithm, with the
|
||||
@@ -57,8 +58,9 @@
|
||||
#ifndef LWIP_CHKSUM
|
||||
# define LWIP_CHKSUM lwip_standard_chksum
|
||||
# ifndef LWIP_CHKSUM_ALGORITHM
|
||||
# define LWIP_CHKSUM_ALGORITHM 1
|
||||
# define LWIP_CHKSUM_ALGORITHM 2
|
||||
# endif
|
||||
u16_t lwip_standard_chksum(void *dataptr, int len);
|
||||
#endif
|
||||
/* If none set: */
|
||||
#ifndef LWIP_CHKSUM_ALGORITHM
|
||||
@@ -76,7 +78,7 @@
|
||||
* @note accumulator size limits summable length to 64k
|
||||
* @note host endianess is irrelevant (p3 RFC1071)
|
||||
*/
|
||||
static u16_t
|
||||
u16_t
|
||||
lwip_standard_chksum(void *dataptr, u16_t len)
|
||||
{
|
||||
u32_t acc;
|
||||
@@ -86,8 +88,7 @@ lwip_standard_chksum(void *dataptr, u16_t len)
|
||||
acc = 0;
|
||||
/* dataptr may be at odd or even addresses */
|
||||
octetptr = (u8_t*)dataptr;
|
||||
while (len > 1)
|
||||
{
|
||||
while (len > 1) {
|
||||
/* declare first octet as most significant
|
||||
thus assume network order, ignoring host order */
|
||||
src = (*octetptr) << 8;
|
||||
@@ -98,15 +99,14 @@ lwip_standard_chksum(void *dataptr, u16_t len)
|
||||
acc += src;
|
||||
len -= 2;
|
||||
}
|
||||
if (len > 0)
|
||||
{
|
||||
if (len > 0) {
|
||||
/* accumulate remaining octet */
|
||||
src = (*octetptr) << 8;
|
||||
acc += src;
|
||||
}
|
||||
/* add deferred carry bits */
|
||||
acc = (acc >> 16) + (acc & 0x0000ffffUL);
|
||||
if ((acc & 0xffff0000) != 0) {
|
||||
if ((acc & 0xffff0000UL) != 0) {
|
||||
acc = (acc >> 16) + (acc & 0x0000ffffUL);
|
||||
}
|
||||
/* This maybe a little confusing: reorder sum using htons()
|
||||
@@ -132,13 +132,13 @@ lwip_standard_chksum(void *dataptr, u16_t len)
|
||||
* @return host order (!) lwip checksum (non-inverted Internet sum)
|
||||
*/
|
||||
|
||||
static u16_t
|
||||
u16_t
|
||||
lwip_standard_chksum(void *dataptr, int len)
|
||||
{
|
||||
u8_t *pb = dataptr;
|
||||
u8_t *pb = (u8_t *)dataptr;
|
||||
u16_t *ps, t = 0;
|
||||
u32_t sum = 0;
|
||||
int odd = ((u32_t)pb & 1);
|
||||
int odd = ((mem_ptr_t)pb & 1);
|
||||
|
||||
/* Get aligned to u16_t */
|
||||
if (odd && len > 0) {
|
||||
@@ -147,28 +147,31 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
}
|
||||
|
||||
/* Add the bulk of the data */
|
||||
ps = (u16_t *)pb;
|
||||
ps = (u16_t *)(void *)pb;
|
||||
while (len > 1) {
|
||||
sum += *ps++;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
/* Consume left-over byte, if any */
|
||||
if (len > 0)
|
||||
((u8_t *)&t)[0] = *(u8_t *)ps;;
|
||||
if (len > 0) {
|
||||
((u8_t *)&t)[0] = *(u8_t *)ps;
|
||||
}
|
||||
|
||||
/* Add end bytes */
|
||||
sum += t;
|
||||
|
||||
/* Fold 32-bit sum to 16 bits */
|
||||
while ((sum >> 16) != 0)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
/* Fold 32-bit sum to 16 bits
|
||||
calling this twice is propably faster than if statements... */
|
||||
sum = FOLD_U32T(sum);
|
||||
sum = FOLD_U32T(sum);
|
||||
|
||||
/* Swap if alignment was odd */
|
||||
if (odd)
|
||||
sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);
|
||||
if (odd) {
|
||||
sum = SWAP_BYTES_IN_WORD(sum);
|
||||
}
|
||||
|
||||
return sum;
|
||||
return (u16_t)sum;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -185,15 +188,15 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
* by Curt McDowell, Broadcom Corp. December 8th, 2005
|
||||
*/
|
||||
|
||||
static u16_t
|
||||
u16_t
|
||||
lwip_standard_chksum(void *dataptr, int len)
|
||||
{
|
||||
u8_t *pb = dataptr;
|
||||
u8_t *pb = (u8_t *)dataptr;
|
||||
u16_t *ps, t = 0;
|
||||
u32_t *pl;
|
||||
u32_t sum = 0, tmp;
|
||||
/* starts at odd byte address? */
|
||||
int odd = ((u32_t)pb & 1);
|
||||
int odd = ((mem_ptr_t)pb & 1);
|
||||
|
||||
if (odd && len > 0) {
|
||||
((u8_t *)&t)[1] = *pb++;
|
||||
@@ -202,7 +205,7 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
|
||||
ps = (u16_t *)pb;
|
||||
|
||||
if (((u32_t)ps & 3) && len > 1) {
|
||||
if (((mem_ptr_t)ps & 3) && len > 1) {
|
||||
sum += *ps++;
|
||||
len -= 2;
|
||||
}
|
||||
@@ -211,18 +214,20 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
|
||||
while (len > 7) {
|
||||
tmp = sum + *pl++; /* ping */
|
||||
if (tmp < sum)
|
||||
if (tmp < sum) {
|
||||
tmp++; /* add back carry */
|
||||
}
|
||||
|
||||
sum = tmp + *pl++; /* pong */
|
||||
if (sum < tmp)
|
||||
if (sum < tmp) {
|
||||
sum++; /* add back carry */
|
||||
}
|
||||
|
||||
len -= 8;
|
||||
}
|
||||
|
||||
/* make room in upper bits */
|
||||
sum = (sum >> 16) + (sum & 0xffff);
|
||||
sum = FOLD_U32T(sum);
|
||||
|
||||
ps = (u16_t *)pl;
|
||||
|
||||
@@ -233,73 +238,59 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
}
|
||||
|
||||
/* dangling tail byte remaining? */
|
||||
if (len > 0) /* include odd byte */
|
||||
if (len > 0) { /* include odd byte */
|
||||
((u8_t *)&t)[0] = *(u8_t *)ps;
|
||||
}
|
||||
|
||||
sum += t; /* add end bytes */
|
||||
|
||||
while ((sum >> 16) != 0) /* combine halves */
|
||||
sum = (sum >> 16) + (sum & 0xffff);
|
||||
/* Fold 32-bit sum to 16 bits
|
||||
calling this twice is propably faster than if statements... */
|
||||
sum = FOLD_U32T(sum);
|
||||
sum = FOLD_U32T(sum);
|
||||
|
||||
if (odd)
|
||||
sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);
|
||||
if (odd) {
|
||||
sum = SWAP_BYTES_IN_WORD(sum);
|
||||
}
|
||||
|
||||
return sum;
|
||||
return (u16_t)sum;
|
||||
}
|
||||
#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,
|
||||
struct ip_addr *src, struct ip_addr *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;
|
||||
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) {
|
||||
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);
|
||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||
while ((acc >> 16) != 0) {
|
||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
||||
}
|
||||
/* just executing this next line is probably faster that the if statement needed
|
||||
to check whether we really need to execute it, and does no harm */
|
||||
acc = FOLD_U32T(acc);
|
||||
if (q->len % 2 != 0) {
|
||||
swapped = 1 - swapped;
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
|
||||
acc = SWAP_BYTES_IN_WORD(acc);
|
||||
}
|
||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||
}
|
||||
|
||||
if (swapped) {
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
|
||||
acc = SWAP_BYTES_IN_WORD(acc);
|
||||
}
|
||||
acc += (src->addr & 0xffffUL);
|
||||
acc += ((src->addr >> 16) & 0xffffUL);
|
||||
acc += (dest->addr & 0xffffUL);
|
||||
acc += ((dest->addr >> 16) & 0xffffUL);
|
||||
|
||||
acc += (u32_t)htons((u16_t)proto);
|
||||
acc += (u32_t)htons(proto_len);
|
||||
|
||||
while ((acc >> 16) != 0) {
|
||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
||||
}
|
||||
/* Fold 32-bit sum to 16 bits
|
||||
calling this twice is propably 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);
|
||||
}
|
||||
@@ -317,17 +308,69 @@ 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,
|
||||
struct ip_addr *src, struct ip_addr *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,
|
||||
ip_addr_t *src, ip_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);
|
||||
}
|
||||
#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 src source ipv6 address (used for checksum of pseudo header)
|
||||
* @param dst destination ipv6 address (used for checksum of pseudo header)
|
||||
* @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)
|
||||
* @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,
|
||||
ip6_addr_t *src, 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 */
|
||||
|
||||
/** 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) {
|
||||
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
|
||||
@@ -340,33 +383,100 @@ inet_chksum_pseudo_partial(struct pbuf *p,
|
||||
chksum_len -= chklen;
|
||||
LWIP_ASSERT("delete me", chksum_len < 0x7fff);
|
||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||
while ((acc >> 16) != 0) {
|
||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
||||
}
|
||||
/* fold the upper bit down */
|
||||
acc = FOLD_U32T(acc);
|
||||
if (q->len % 2 != 0) {
|
||||
swapped = 1 - swapped;
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
|
||||
acc = SWAP_BYTES_IN_WORD(acc);
|
||||
}
|
||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||
}
|
||||
|
||||
if (swapped) {
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
|
||||
acc = SWAP_BYTES_IN_WORD(acc);
|
||||
}
|
||||
acc += (src->addr & 0xffffUL);
|
||||
acc += ((src->addr >> 16) & 0xffffUL);
|
||||
acc += (dest->addr & 0xffffUL);
|
||||
acc += ((dest->addr >> 16) & 0xffffUL);
|
||||
|
||||
acc += (u32_t)htons((u16_t)proto);
|
||||
acc += (u32_t)htons(proto_len);
|
||||
|
||||
while ((acc >> 16) != 0) {
|
||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
||||
}
|
||||
/* Fold 32-bit sum to 16 bits
|
||||
calling this twice is propably 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);
|
||||
}
|
||||
|
||||
/* inet_chksum_pseudo_partial:
|
||||
*
|
||||
* 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_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
|
||||
u16_t chksum_len, ip_addr_t *src, ip_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);
|
||||
}
|
||||
|
||||
#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 src source ipv6 address (used for checksum of pseudo header)
|
||||
* @param dst destination ipv6 address (used for checksum of pseudo header)
|
||||
* @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
|
||||
* @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, ip6_addr_t *src, 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 */
|
||||
|
||||
/* inet_chksum:
|
||||
*
|
||||
* Calculates the Internet checksum over a portion of memory. Used primarily for IP
|
||||
@@ -380,13 +490,7 @@ inet_chksum_pseudo_partial(struct pbuf *p,
|
||||
u16_t
|
||||
inet_chksum(void *dataptr, u16_t len)
|
||||
{
|
||||
u32_t acc;
|
||||
|
||||
acc = LWIP_CHKSUM(dataptr, len);
|
||||
while ((acc >> 16) != 0) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
return (u16_t)~(acc & 0xffff);
|
||||
return ~LWIP_CHKSUM(dataptr, len);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -407,17 +511,35 @@ inet_chksum_pbuf(struct pbuf *p)
|
||||
swapped = 0;
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
acc += LWIP_CHKSUM(q->payload, q->len);
|
||||
while ((acc >> 16) != 0) {
|
||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
||||
}
|
||||
acc = FOLD_U32T(acc);
|
||||
if (q->len % 2 != 0) {
|
||||
swapped = 1 - swapped;
|
||||
acc = (acc & 0x00ffUL << 8) | (acc & 0xff00UL >> 8);
|
||||
acc = SWAP_BYTES_IN_WORD(acc);
|
||||
}
|
||||
}
|
||||
|
||||
if (swapped) {
|
||||
acc = ((acc & 0x00ffUL) << 8) | ((acc & 0xff00UL) >> 8);
|
||||
acc = SWAP_BYTES_IN_WORD(acc);
|
||||
}
|
||||
return (u16_t)~(acc & 0xffffUL);
|
||||
}
|
||||
|
||||
/* These are some implementations for LWIP_CHKSUM_COPY, which copies data
|
||||
* like MEMCPY but generates a checksum at the same time. Since this is a
|
||||
* performance-sensitive function, you might want to create your own version
|
||||
* in assembly targeted at your hardware by defining it in lwipopts.h:
|
||||
* #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len)
|
||||
*/
|
||||
|
||||
#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */
|
||||
/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM.
|
||||
* For architectures with big caches, data might still be in cache when
|
||||
* generating the checksum after copying.
|
||||
*/
|
||||
u16_t
|
||||
lwip_chksum_copy(void *dst, const void *src, u16_t len)
|
||||
{
|
||||
MEMCPY(dst, src, len);
|
||||
return LWIP_CHKSUM(dst, len);
|
||||
}
|
||||
#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */
|
||||
@@ -49,11 +49,16 @@
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/raw.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/tcp_impl.h"
|
||||
#include "lwip/snmp_msg.h"
|
||||
#include "lwip/autoip.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/timers.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/nd6.h"
|
||||
#include "lwip/mld6.h"
|
||||
|
||||
/* Compile-time sanity checks for configuration errors.
|
||||
* These can be done independently of LWIP_DEBUG, without penalty.
|
||||
@@ -61,6 +66,9 @@
|
||||
#ifndef BYTE_ORDER
|
||||
#error "BYTE_ORDER is not defined, you have to define it in your cc.h"
|
||||
#endif
|
||||
#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
|
||||
@@ -76,12 +84,12 @@
|
||||
#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"
|
||||
#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 (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))
|
||||
#error "If you want to use ARP, ARP_TABLE_SIZE must fit in an s8_t, so, you have to reduce it in your lwipopts.h"
|
||||
#endif
|
||||
#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
|
||||
@@ -100,6 +108,9 @@
|
||||
#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
|
||||
#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2))
|
||||
#error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work"
|
||||
#endif
|
||||
#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
|
||||
@@ -109,9 +120,6 @@
|
||||
#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 (PPP_SUPPORT && (NO_SYS==1))
|
||||
#error "If you want to use PPP, you have to define NO_SYS=0 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
|
||||
@@ -143,7 +151,7 @@
|
||||
#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 ((NO_SYS==0) && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT)))
|
||||
#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))
|
||||
@@ -155,6 +163,33 @@
|
||||
#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS)
|
||||
#error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h"
|
||||
#endif
|
||||
#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"
|
||||
#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 || LWIP_IPV6) && !defined(LWIP_RAND)
|
||||
#error "When using IGMP or IPv6, 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"
|
||||
#endif
|
||||
|
||||
|
||||
/* Compile-time checks for deprecated options.
|
||||
@@ -177,11 +212,6 @@
|
||||
#ifdef ETHARP_ALWAYS_INSERT
|
||||
#error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h."
|
||||
#endif
|
||||
#if SO_REUSE
|
||||
/* I removed the lot since this was an ugly hack. It broke the raw-API.
|
||||
It also came with many ugly goto's, Christiaan Simons. */
|
||||
#error "SO_REUSE currently unavailable, this was a hack"
|
||||
#endif
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
static void
|
||||
@@ -195,15 +225,32 @@ lwip_sanity_check(void)
|
||||
#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 or equal to TCP_SND_BUF.\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"));
|
||||
#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()
|
||||
@@ -220,7 +267,9 @@ lwip_init(void)
|
||||
|
||||
/* Modules initialization */
|
||||
stats_init();
|
||||
#if !NO_SYS
|
||||
sys_init();
|
||||
#endif /* !NO_SYS */
|
||||
mem_init();
|
||||
memp_init();
|
||||
pbuf_init();
|
||||
@@ -241,6 +290,9 @@ 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 */
|
||||
@@ -250,4 +302,15 @@ lwip_init(void)
|
||||
#if LWIP_DNS
|
||||
dns_init();
|
||||
#endif /* LWIP_DNS */
|
||||
#if LWIP_IPV6
|
||||
ip6_init();
|
||||
nd6_init();
|
||||
#if LWIP_IPV6_MLD
|
||||
mld6_init();
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#if LWIP_TIMERS
|
||||
sys_timeouts_init();
|
||||
#endif /* LWIP_TIMERS */
|
||||
}
|
||||
|
||||
@@ -76,7 +76,15 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Pseudo random macro based on netif informations.
|
||||
/* 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
|
||||
#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \
|
||||
@@ -86,11 +94,24 @@
|
||||
(netif->autoip?netif->autoip->tried_llipaddr:0))
|
||||
#endif /* LWIP_AUTOIP_RAND */
|
||||
|
||||
/**
|
||||
* Macro that generates the initial IP address to be tried by AUTOIP.
|
||||
* If you want to override this, define it to something else in lwipopts.h.
|
||||
*/
|
||||
#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
|
||||
#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
|
||||
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 random LL IP-Address for a network interface */
|
||||
static void autoip_create_rand_addr(struct netif *netif, struct ip_addr *RandomIPAddr);
|
||||
/* 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);
|
||||
@@ -98,13 +119,38 @@ 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);
|
||||
|
||||
/**
|
||||
* Initialize this module
|
||||
/* start sending probes for llipaddr */
|
||||
static void autoip_start_probing(struct netif *netif);
|
||||
|
||||
|
||||
/** 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
|
||||
*/
|
||||
void
|
||||
autoip_init(void)
|
||||
autoip_set_struct(struct netif *netif, struct autoip *autoip)
|
||||
{
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_init()\n"));
|
||||
LWIP_ASSERT("netif != NULL", netif != NULL);
|
||||
LWIP_ASSERT("autoip != NULL", autoip != NULL);
|
||||
LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL);
|
||||
|
||||
/* clear data structure */
|
||||
memset(autoip, 0, sizeof(struct autoip));
|
||||
/* autoip->state = AUTOIP_STATE_OFF; */
|
||||
netif->autoip = autoip;
|
||||
}
|
||||
|
||||
/** Restart AutoIP client and check the next address (conflict detected)
|
||||
*
|
||||
* @param netif The netif under AutoIP control
|
||||
*/
|
||||
static void
|
||||
autoip_restart(struct netif *netif)
|
||||
{
|
||||
netif->autoip->tried_llipaddr++;
|
||||
autoip_start(netif);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,27 +162,27 @@ autoip_handle_arp_conflict(struct netif *netif)
|
||||
/* Somehow detect if we are defending or retreating */
|
||||
unsigned char defend = 1; /* tbd */
|
||||
|
||||
if(defend) {
|
||||
if(netif->autoip->lastconflict > 0) {
|
||||
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 | 1,
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
|
||||
|
||||
/* TODO: close all TCP sessions */
|
||||
autoip_start(netif);
|
||||
autoip_restart(netif);
|
||||
} else {
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
|
||||
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_start(netif);
|
||||
autoip_restart(netif);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,30 +190,47 @@ autoip_handle_arp_conflict(struct netif *netif)
|
||||
* Create an IP-Address out of range 169.254.1.0 to 169.254.254.255
|
||||
*
|
||||
* @param netif network interface on which create the IP-Address
|
||||
* @param RandomIPAddr ip address to initialize
|
||||
* @param ipaddr ip address to initialize
|
||||
*/
|
||||
static void
|
||||
autoip_create_rand_addr(struct netif *netif, struct ip_addr *RandomIPAddr)
|
||||
autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr)
|
||||
{
|
||||
/* 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
|
||||
*/
|
||||
|
||||
RandomIPAddr->addr = (0xA9FE0100 + ((u32_t)(((u8_t)(netif->hwaddr[4])) |
|
||||
((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)) + netif->autoip->tried_llipaddr);
|
||||
* We have 254 * 256 possibilities */
|
||||
|
||||
if (RandomIPAddr->addr>0xA9FEFEFF) {
|
||||
RandomIPAddr->addr = (0xA9FE0100 + (RandomIPAddr->addr-0xA9FEFEFF));
|
||||
u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
|
||||
addr += netif->autoip->tried_llipaddr;
|
||||
addr = AUTOIP_NET | (addr & 0xffff);
|
||||
/* Now, 169.254.0.0 <= addr <= 169.254.255.255 */
|
||||
|
||||
if (addr < AUTOIP_RANGE_START) {
|
||||
addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
|
||||
}
|
||||
if (RandomIPAddr->addr<0xA9FE0100) {
|
||||
RandomIPAddr->addr = (0xA9FEFEFF - (0xA9FE0100-RandomIPAddr->addr));
|
||||
if (addr > AUTOIP_RANGE_END) {
|
||||
addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
|
||||
}
|
||||
RandomIPAddr->addr = htonl(RandomIPAddr->addr);
|
||||
LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
|
||||
(addr <= AUTOIP_RANGE_END));
|
||||
ip4_addr_set_u32(ipaddr, htonl(addr));
|
||||
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
|
||||
("autoip_create_rand_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n",
|
||||
(u16_t)(netif->autoip->tried_llipaddr), (u32_t)(RandomIPAddr->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),
|
||||
ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an ARP probe from a network interface
|
||||
*
|
||||
* @param netif network interface used to send the probe
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,11 +255,13 @@ static err_t
|
||||
autoip_bind(struct netif *netif)
|
||||
{
|
||||
struct autoip *autoip = netif->autoip;
|
||||
struct ip_addr sn_mask, gw_addr;
|
||||
ip_addr_t sn_mask, gw_addr;
|
||||
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,
|
||||
("autoip_bind(netif=%p) %c%c%"U16_F" 0x%08"X32_F"\n",
|
||||
(void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, autoip->llipaddr.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",
|
||||
(void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num,
|
||||
ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
|
||||
ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
|
||||
|
||||
IP4_ADDR(&sn_mask, 255, 255, 0, 0);
|
||||
IP4_ADDR(&gw_addr, 0, 0, 0, 0);
|
||||
@@ -222,31 +287,31 @@ autoip_start(struct netif *netif)
|
||||
struct autoip *autoip = netif->autoip;
|
||||
err_t result = ERR_OK;
|
||||
|
||||
if(netif_is_up(netif)) {
|
||||
if (netif_is_up(netif)) {
|
||||
netif_set_down(netif);
|
||||
}
|
||||
|
||||
/* Set IP-Address, Netmask and Gateway to 0 to make sure that
|
||||
* ARP Packets are formed correctly
|
||||
*/
|
||||
netif->ip_addr.addr = 0;
|
||||
netif->netmask.addr = 0;
|
||||
netif->gw.addr = 0;
|
||||
ip_addr_set_zero(&netif->ip_addr);
|
||||
ip_addr_set_zero(&netif->netmask);
|
||||
ip_addr_set_zero(&netif->gw);
|
||||
|
||||
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 = mem_malloc(sizeof(struct autoip));
|
||||
if(autoip == NULL) {
|
||||
autoip = (struct autoip *)mem_malloc(sizeof(struct autoip));
|
||||
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));
|
||||
memset(autoip, 0, sizeof(struct autoip));
|
||||
/* store this AutoIP client in the netif */
|
||||
netif->autoip = autoip;
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));
|
||||
@@ -254,14 +319,27 @@ autoip_start(struct netif *netif)
|
||||
autoip->state = AUTOIP_STATE_OFF;
|
||||
autoip->ttw = 0;
|
||||
autoip->sent_num = 0;
|
||||
memset(&autoip->llipaddr, 0, sizeof(struct ip_addr));
|
||||
ip_addr_set_zero(&autoip->llipaddr);
|
||||
autoip->lastconflict = 0;
|
||||
}
|
||||
|
||||
autoip_create_rand_addr(netif, &(autoip->llipaddr));
|
||||
autoip->tried_llipaddr++;
|
||||
autoip_create_addr(netif, &(autoip->llipaddr));
|
||||
autoip_start_probing(netif);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
autoip_start_probing(struct netif *netif)
|
||||
{
|
||||
struct autoip *autoip = netif->autoip;
|
||||
|
||||
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)));
|
||||
|
||||
/* time to wait to first probe, this is randomly
|
||||
* choosen out of 0 to PROBE_WAIT seconds.
|
||||
@@ -274,12 +352,24 @@ autoip_start(struct netif *netif)
|
||||
* accquiring 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;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
/**
|
||||
* Handle a possible change in the network configuration.
|
||||
*
|
||||
* If there is an AutoIP address configured, take the interface down
|
||||
* and begin probing with the same address.
|
||||
*/
|
||||
void
|
||||
autoip_network_changed(struct netif *netif)
|
||||
{
|
||||
if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {
|
||||
netif_set_down(netif);
|
||||
autoip_start_probing(netif);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -306,7 +396,7 @@ autoip_tmr()
|
||||
while (netif != NULL) {
|
||||
/* only act on AutoIP configured interfaces */
|
||||
if (netif->autoip != NULL) {
|
||||
if(netif->autoip->lastconflict > 0) {
|
||||
if (netif->autoip->lastconflict > 0) {
|
||||
netif->autoip->lastconflict--;
|
||||
}
|
||||
|
||||
@@ -316,16 +406,20 @@ autoip_tmr()
|
||||
|
||||
switch(netif->autoip->state) {
|
||||
case AUTOIP_STATE_PROBING:
|
||||
if(netif->autoip->ttw > 0) {
|
||||
if (netif->autoip->ttw > 0) {
|
||||
netif->autoip->ttw--;
|
||||
} else {
|
||||
if(netif->autoip->sent_num == PROBE_NUM) {
|
||||
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;
|
||||
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)));
|
||||
} else {
|
||||
etharp_request(netif, &(netif->autoip->llipaddr));
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,
|
||||
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 */
|
||||
@@ -337,26 +431,33 @@ autoip_tmr()
|
||||
break;
|
||||
|
||||
case AUTOIP_STATE_ANNOUNCING:
|
||||
if(netif->autoip->ttw > 0) {
|
||||
if (netif->autoip->ttw > 0) {
|
||||
netif->autoip->ttw--;
|
||||
} else {
|
||||
if(netif->autoip->sent_num == 0) {
|
||||
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
|
||||
* 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);
|
||||
}
|
||||
|
||||
if(netif->autoip->sent_num == ANNOUNCE_NUM) {
|
||||
netif->autoip->state = AUTOIP_STATE_BOUND;
|
||||
netif->autoip->sent_num = 0;
|
||||
netif->autoip->ttw = 0;
|
||||
} else {
|
||||
autoip_arp_announce(netif);
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
||||
("autoip_tmr() ANNOUNCING Sent Announce\n"));
|
||||
netif->autoip->sent_num++;
|
||||
netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||
}
|
||||
netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
||||
netif->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;
|
||||
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)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -376,27 +477,22 @@ autoip_tmr()
|
||||
void
|
||||
autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
|
||||
{
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_arp_reply()\n"));
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n"));
|
||||
if ((netif->autoip != NULL) && (netif->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
|
||||
*/
|
||||
struct ip_addr sipaddr, dipaddr;
|
||||
ip_addr_t sipaddr, dipaddr;
|
||||
struct eth_addr netifaddr;
|
||||
netifaddr.addr[0] = netif->hwaddr[0];
|
||||
netifaddr.addr[1] = netif->hwaddr[1];
|
||||
netifaddr.addr[2] = netif->hwaddr[2];
|
||||
netifaddr.addr[3] = netif->hwaddr[3];
|
||||
netifaddr.addr[4] = netif->hwaddr[4];
|
||||
netifaddr.addr[5] = netif->hwaddr[5];
|
||||
ETHADDR16_COPY(netifaddr.addr, netif->hwaddr);
|
||||
|
||||
/* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
|
||||
* structure packing (not using structure copy which breaks strict-aliasing rules).
|
||||
*/
|
||||
MEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));
|
||||
MEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));
|
||||
IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
|
||||
IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
|
||||
|
||||
if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||
|
||||
((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&
|
||||
@@ -410,9 +506,9 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
|
||||
if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||
|
||||
(ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) &&
|
||||
!eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
|
||||
("autoip_arp_reply(): Probe Conflict detected\n"));
|
||||
autoip_start(netif);
|
||||
autoip_restart(netif);
|
||||
}
|
||||
} else {
|
||||
/* RFC 3927 Section 2.5:
|
||||
@@ -421,7 +517,7 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
|
||||
*/
|
||||
if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&
|
||||
!eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
|
||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
|
||||
("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
|
||||
autoip_handle_arp_conflict(netif);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/def.h"
|
||||
@@ -53,16 +52,25 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/** 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) */
|
||||
#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
||||
#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1
|
||||
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
|
||||
|
||||
/* The amount of data from the original packet to return in a dest-unreachable */
|
||||
#define ICMP_DEST_UNREACH_DATASIZE 8
|
||||
|
||||
static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
|
||||
|
||||
/**
|
||||
* Processes ICMP input packets, called from ip_input().
|
||||
*
|
||||
* 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
|
||||
@@ -74,16 +82,14 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
#endif /* LWIP_DEBUG */
|
||||
struct icmp_echo_hdr *iecho;
|
||||
struct ip_hdr *iphdr;
|
||||
struct ip_addr tmpaddr;
|
||||
s16_t hlen;
|
||||
|
||||
ICMP_STATS_INC(icmp.recv);
|
||||
snmp_inc_icmpinmsgs();
|
||||
|
||||
|
||||
iphdr = p->payload;
|
||||
iphdr = (struct ip_hdr *)ip_current_header();
|
||||
hlen = IPH_HL(iphdr) * 4;
|
||||
if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
|
||||
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;
|
||||
}
|
||||
@@ -93,14 +99,35 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
code = *(((u8_t *)p->payload)+1);
|
||||
#endif /* LWIP_DEBUG */
|
||||
switch (type) {
|
||||
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;
|
||||
case ICMP_ECHO:
|
||||
/* broadcast or multicast destination address? */
|
||||
if (ip_addr_isbroadcast(&iphdr->dest, inp) || ip_addr_ismulticast(&iphdr->dest)) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
|
||||
ICMP_STATS_INC(icmp.err);
|
||||
pbuf_free(p);
|
||||
return;
|
||||
#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
|
||||
{
|
||||
int accepted = 1;
|
||||
#if !LWIP_MULTICAST_PING
|
||||
/* multicast destination address? */
|
||||
if (ip_addr_ismulticast(ip_current_dest_addr())) {
|
||||
accepted = 0;
|
||||
}
|
||||
#endif /* LWIP_MULTICAST_PING */
|
||||
#if !LWIP_BROADCAST_PING
|
||||
/* broadcast destination address? */
|
||||
if (ip_addr_isbroadcast(ip_current_dest_addr(), 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 */
|
||||
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"));
|
||||
@@ -113,6 +140,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
snmp_inc_icmpinerrors();
|
||||
return;
|
||||
}
|
||||
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
||||
if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
|
||||
/* p is not big enough to contain link headers
|
||||
* allocate a new one and copy p into it
|
||||
@@ -136,7 +164,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
|
||||
goto memerr;
|
||||
}
|
||||
iphdr = r->payload;
|
||||
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);
|
||||
@@ -153,19 +181,19 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
goto memerr;
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
|
||||
/* At this point, all checks are OK. */
|
||||
/* We generate an answer by switching the dest and src ip addresses,
|
||||
* setting the icmp type to ECHO_RESPONSE and updating the checksum. */
|
||||
iecho = p->payload;
|
||||
tmpaddr.addr = iphdr->src.addr;
|
||||
iphdr->src.addr = iphdr->dest.addr;
|
||||
iphdr->dest.addr = tmpaddr.addr;
|
||||
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 >= htons(0xffff - (ICMP_ECHO << 8))) {
|
||||
iecho->chksum += htons(ICMP_ECHO << 8) + 1;
|
||||
if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) {
|
||||
iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
|
||||
} else {
|
||||
iecho->chksum += htons(ICMP_ECHO << 8);
|
||||
iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
|
||||
}
|
||||
|
||||
/* Set the correct TTL and recalculate the header checksum. */
|
||||
@@ -185,7 +213,8 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
LWIP_ASSERT("Can't move over header in packet", 0);
|
||||
} else {
|
||||
err_t ret;
|
||||
ret = ip_output_if(p, &(iphdr->src), IP_HDRINCL,
|
||||
/* 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,
|
||||
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));
|
||||
@@ -205,11 +234,13 @@ lenerr:
|
||||
ICMP_STATS_INC(icmp.lenerr);
|
||||
snmp_inc_icmpinerrors();
|
||||
return;
|
||||
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
||||
memerr:
|
||||
pbuf_free(p);
|
||||
ICMP_STATS_INC(icmp.err);
|
||||
snmp_inc_icmpinerrors();
|
||||
return;
|
||||
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,40 +255,7 @@ memerr:
|
||||
void
|
||||
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
|
||||
{
|
||||
struct pbuf *q;
|
||||
struct ip_hdr *iphdr;
|
||||
struct icmp_dur_hdr *idur;
|
||||
|
||||
/* ICMP header + IP header + 8 bytes of data */
|
||||
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
|
||||
PBUF_RAM);
|
||||
if (q == NULL) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
|
||||
return;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold icmp message",
|
||||
(q->len >= (sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
|
||||
|
||||
iphdr = p->payload;
|
||||
|
||||
idur = q->payload;
|
||||
ICMPH_TYPE_SET(idur, ICMP_DUR);
|
||||
ICMPH_CODE_SET(idur, t);
|
||||
|
||||
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_dur_hdr), p->payload,
|
||||
IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
|
||||
|
||||
/* calculate checksum */
|
||||
idur->chksum = 0;
|
||||
idur->chksum = inet_chksum(idur, 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_icmpoutdestunreachs();
|
||||
|
||||
ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);
|
||||
pbuf_free(q);
|
||||
icmp_send_response(p, ICMP_DUR, t);
|
||||
}
|
||||
|
||||
#if IP_FORWARD || IP_REASSEMBLY
|
||||
@@ -270,48 +268,67 @@ icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
|
||||
*/
|
||||
void
|
||||
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
|
||||
{
|
||||
icmp_send_response(p, ICMP_TE, t);
|
||||
}
|
||||
|
||||
#endif /* IP_FORWARD || IP_REASSEMBLY */
|
||||
|
||||
/**
|
||||
* Send an icmp packet in response to an incoming packet.
|
||||
*
|
||||
* @param p the input packet for which the 'unreachable' should be sent,
|
||||
* p->payload pointing to the IP header
|
||||
* @param type Type of the ICMP header
|
||||
* @param code Code of the ICMP header
|
||||
*/
|
||||
static void
|
||||
icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
|
||||
{
|
||||
struct pbuf *q;
|
||||
struct ip_hdr *iphdr;
|
||||
struct icmp_te_hdr *tehdr;
|
||||
/* we can use the echo header here */
|
||||
struct icmp_echo_hdr *icmphdr;
|
||||
ip_addr_t iphdr_src;
|
||||
|
||||
/* ICMP header + IP header + 8 bytes of data */
|
||||
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
|
||||
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"));
|
||||
return;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold icmp message",
|
||||
(q->len >= (sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
|
||||
(q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
|
||||
|
||||
iphdr = p->payload;
|
||||
iphdr = (struct ip_hdr *)p->payload;
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
|
||||
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
|
||||
LWIP_DEBUGF(ICMP_DEBUG, (" to "));
|
||||
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
|
||||
|
||||
tehdr = q->payload;
|
||||
ICMPH_TYPE_SET(tehdr, ICMP_TE);
|
||||
ICMPH_CODE_SET(tehdr, t);
|
||||
icmphdr = (struct icmp_echo_hdr *)q->payload;
|
||||
icmphdr->type = type;
|
||||
icmphdr->code = code;
|
||||
icmphdr->id = 0;
|
||||
icmphdr->seqno = 0;
|
||||
|
||||
/* copy fields from original packet */
|
||||
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_dur_hdr), (u8_t *)p->payload,
|
||||
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
|
||||
IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
|
||||
|
||||
/* calculate checksum */
|
||||
tehdr->chksum = 0;
|
||||
tehdr->chksum = inet_chksum(tehdr, q->len);
|
||||
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_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);
|
||||
ip_addr_copy(iphdr_src, iphdr->src);
|
||||
ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);
|
||||
pbuf_free(q);
|
||||
}
|
||||
|
||||
#endif /* IP_FORWARD */
|
||||
|
||||
#endif /* LWIP_ICMP */
|
||||
|
||||
@@ -86,7 +86,6 @@ Steve Reynolds
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/icmp.h"
|
||||
@@ -96,13 +95,59 @@ Steve Reynolds
|
||||
|
||||
#include "string.h"
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Globales
|
||||
*----------------------------------------------------------------------------*/
|
||||
/*
|
||||
* IGMP constants
|
||||
*/
|
||||
#define IGMP_TTL 1
|
||||
#define IGMP_MINLEN 8
|
||||
#define ROUTER_ALERT 0x9404U
|
||||
#define ROUTER_ALERTLEN 4
|
||||
|
||||
/*
|
||||
* IGMP message types, including version number.
|
||||
*/
|
||||
#define IGMP_MEMB_QUERY 0x11 /* Membership query */
|
||||
#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */
|
||||
#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */
|
||||
#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */
|
||||
|
||||
/* Group membership states */
|
||||
#define IGMP_GROUP_NON_MEMBER 0
|
||||
#define IGMP_GROUP_DELAYING_MEMBER 1
|
||||
#define IGMP_GROUP_IDLE_MEMBER 2
|
||||
|
||||
/**
|
||||
* IGMP packet format.
|
||||
*/
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct igmp_msg {
|
||||
PACK_STRUCT_FIELD(u8_t igmp_msgtype);
|
||||
PACK_STRUCT_FIELD(u8_t igmp_maxresp);
|
||||
PACK_STRUCT_FIELD(u16_t igmp_checksum);
|
||||
PACK_STRUCT_FIELD(ip_addr_p_t igmp_group_address);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
|
||||
static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr);
|
||||
static err_t igmp_remove_group(struct igmp_group *group);
|
||||
static void igmp_timeout( struct igmp_group *group);
|
||||
static void igmp_start_timer(struct igmp_group *group, u8_t max_time);
|
||||
static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
|
||||
static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif);
|
||||
static void igmp_send(struct igmp_group *group, u8_t type);
|
||||
|
||||
|
||||
static struct igmp_group* igmp_group_list;
|
||||
static struct ip_addr allsystems;
|
||||
static struct ip_addr allrouters;
|
||||
static ip_addr_t allsystems;
|
||||
static ip_addr_t allrouters;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the IGMP module
|
||||
@@ -128,7 +173,7 @@ igmp_dump_group_list()
|
||||
while (group != NULL) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) group->interface));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
|
||||
group = group->next;
|
||||
}
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
|
||||
@@ -147,7 +192,7 @@ igmp_start(struct netif *netif)
|
||||
{
|
||||
struct igmp_group* group;
|
||||
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %x\n", (int) netif));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
|
||||
|
||||
group = igmp_lookup_group(netif, &allsystems);
|
||||
|
||||
@@ -159,8 +204,8 @@ igmp_start(struct netif *netif)
|
||||
if (netif->igmp_mac_filter != NULL) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &allsystems);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
|
||||
netif->igmp_mac_filter( netif, &allsystems, IGMP_ADD_MAC_FILTER);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
||||
netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
@@ -185,7 +230,7 @@ igmp_stop(struct netif *netif)
|
||||
while (group != NULL) {
|
||||
next = group->next;
|
||||
/* is it a group joined on this interface? */
|
||||
if (group->interface == netif) {
|
||||
if (group->netif == netif) {
|
||||
/* is it the first group of the list? */
|
||||
if (group == igmp_group_list) {
|
||||
igmp_group_list = next;
|
||||
@@ -198,7 +243,7 @@ igmp_stop(struct netif *netif)
|
||||
if (netif->igmp_mac_filter != NULL) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
||||
netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
|
||||
}
|
||||
/* free group */
|
||||
@@ -219,15 +264,15 @@ igmp_stop(struct netif *netif)
|
||||
* @param netif network interface on which report IGMP memberships
|
||||
*/
|
||||
void
|
||||
igmp_report_groups( struct netif *netif)
|
||||
igmp_report_groups(struct netif *netif)
|
||||
{
|
||||
struct igmp_group *group = igmp_group_list;
|
||||
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %x\n", (int) netif));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
|
||||
|
||||
while (group != NULL) {
|
||||
if (group->interface == netif) {
|
||||
igmp_delaying_member( group, IGMP_JOIN_DELAYING_MEMBER_TMR);
|
||||
if (group->netif == netif) {
|
||||
igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
|
||||
}
|
||||
group = group->next;
|
||||
}
|
||||
@@ -242,12 +287,12 @@ igmp_report_groups( struct netif *netif)
|
||||
* NULL if the group wasn't found.
|
||||
*/
|
||||
struct igmp_group *
|
||||
igmp_lookfor_group(struct netif *ifp, struct ip_addr *addr)
|
||||
igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)
|
||||
{
|
||||
struct igmp_group *group = igmp_group_list;
|
||||
|
||||
while (group != NULL) {
|
||||
if ((group->interface == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
|
||||
if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
|
||||
return group;
|
||||
}
|
||||
group = group->next;
|
||||
@@ -268,7 +313,7 @@ igmp_lookfor_group(struct netif *ifp, struct ip_addr *addr)
|
||||
* NULL on memory error.
|
||||
*/
|
||||
struct igmp_group *
|
||||
igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)
|
||||
igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)
|
||||
{
|
||||
struct igmp_group *group = igmp_group_list;
|
||||
|
||||
@@ -280,9 +325,9 @@ igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)
|
||||
}
|
||||
|
||||
/* Group doesn't exist yet, create a new one */
|
||||
group = memp_malloc(MEMP_IGMP_GROUP);
|
||||
group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
|
||||
if (group != NULL) {
|
||||
group->interface = ifp;
|
||||
group->netif = ifp;
|
||||
ip_addr_set(&(group->group_address), addr);
|
||||
group->timer = 0; /* Not running */
|
||||
group->group_state = IGMP_GROUP_NON_MEMBER;
|
||||
@@ -295,7 +340,7 @@ igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)
|
||||
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
|
||||
ip_addr_debug_print(IGMP_DEBUG, addr);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) ifp));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
|
||||
|
||||
return group;
|
||||
}
|
||||
@@ -306,7 +351,7 @@ igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)
|
||||
* @param group the group to remove from the global igmp_group_list
|
||||
* @return ERR_OK if group was removed from the list, an err_t otherwise
|
||||
*/
|
||||
err_t
|
||||
static err_t
|
||||
igmp_remove_group(struct igmp_group *group)
|
||||
{
|
||||
err_t err = ERR_OK;
|
||||
@@ -336,21 +381,21 @@ igmp_remove_group(struct igmp_group *group)
|
||||
/**
|
||||
* Called from ip_input() if a new IGMP packet is received.
|
||||
*
|
||||
* @param p received igmp packet, p->payload pointing to the ip header
|
||||
* @param p received igmp packet, p->payload pointing to the igmp header
|
||||
* @param inp network interface on which the packet was received
|
||||
* @param dest destination ip address of the igmp packet
|
||||
*/
|
||||
void
|
||||
igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
|
||||
igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
|
||||
{
|
||||
struct ip_hdr * iphdr;
|
||||
struct igmp_msg* igmp;
|
||||
struct igmp_group* group;
|
||||
struct igmp_group* groupref;
|
||||
|
||||
IGMP_STATS_INC(igmp.recv);
|
||||
|
||||
/* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
|
||||
iphdr = p->payload;
|
||||
if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
|
||||
if (p->len < IGMP_MINLEN) {
|
||||
pbuf_free(p);
|
||||
IGMP_STATS_INC(igmp.lenerr);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
|
||||
@@ -358,10 +403,10 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->src));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) inp));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->dest));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
|
||||
|
||||
/* Now calculate and check the checksum */
|
||||
igmp = (struct igmp_msg *)p->payload;
|
||||
@@ -373,11 +418,12 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
|
||||
}
|
||||
|
||||
/* Packet is ok so find an existing group */
|
||||
group = igmp_lookfor_group(inp, dest); /* use the incoming IP address! */
|
||||
group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */
|
||||
|
||||
/* If group can be found or create... */
|
||||
if (!group) {
|
||||
pbuf_free(p);
|
||||
IGMP_STATS_INC(igmp.drop);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
|
||||
return;
|
||||
}
|
||||
@@ -386,50 +432,56 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
|
||||
switch (igmp->igmp_msgtype) {
|
||||
case IGMP_MEMB_QUERY: {
|
||||
/* IGMP_MEMB_QUERY to the "all systems" address ? */
|
||||
if ((ip_addr_cmp(dest, &allsystems)) && (igmp->igmp_group_address.addr == 0)) {
|
||||
if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) {
|
||||
/* THIS IS THE GENERAL QUERY */
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
|
||||
|
||||
if (igmp->igmp_maxresp == 0) {
|
||||
IGMP_STATS_INC(igmp.v1_rxed);
|
||||
IGMP_STATS_INC(igmp.rx_v1);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
|
||||
igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
|
||||
} else {
|
||||
IGMP_STATS_INC(igmp.rx_general);
|
||||
}
|
||||
|
||||
IGMP_STATS_INC(igmp.group_query_rxed);
|
||||
groupref = igmp_group_list;
|
||||
while (groupref) {
|
||||
/* Do not send messages on the all systems group address! */
|
||||
if ((groupref->interface == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
|
||||
igmp_delaying_member( groupref, igmp->igmp_maxresp);
|
||||
if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
|
||||
igmp_delaying_member(groupref, igmp->igmp_maxresp);
|
||||
}
|
||||
groupref = groupref->next;
|
||||
}
|
||||
} else {
|
||||
/* IGMP_MEMB_QUERY to a specific group ? */
|
||||
if (group->group_address.addr != 0) {
|
||||
if (!ip_addr_isany(&igmp->igmp_group_address)) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
|
||||
if (ip_addr_cmp (dest, &allsystems)) {
|
||||
ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);
|
||||
if (ip_addr_cmp(dest, &allsystems)) {
|
||||
ip_addr_t groupaddr;
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
|
||||
/* we first need to re-lookfor the group since we used dest last time */
|
||||
group = igmp_lookfor_group(inp, &igmp->igmp_group_address);
|
||||
/* we first need to re-look for the group since we used dest last time */
|
||||
ip_addr_copy(groupaddr, igmp->igmp_group_address);
|
||||
group = igmp_lookfor_group(inp, &groupaddr);
|
||||
} else {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
|
||||
}
|
||||
|
||||
if (group != NULL) {
|
||||
IGMP_STATS_INC(igmp.unicast_query);
|
||||
igmp_delaying_member( group, igmp->igmp_maxresp);
|
||||
IGMP_STATS_INC(igmp.rx_group);
|
||||
igmp_delaying_member(group, igmp->igmp_maxresp);
|
||||
} else {
|
||||
IGMP_STATS_INC(igmp.drop);
|
||||
}
|
||||
} else {
|
||||
IGMP_STATS_INC(igmp.proterr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IGMP_V2_MEMB_REPORT: {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
|
||||
|
||||
IGMP_STATS_INC(igmp.report_rxed);
|
||||
IGMP_STATS_INC(igmp.rx_report);
|
||||
if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
|
||||
/* This is on a specific group we have already looked up */
|
||||
group->timer = 0; /* stopped */
|
||||
@@ -439,7 +491,9 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %x in state %x on group %x on if %x\n", (int) igmp->igmp_msgtype, (int) group->group_state, (int) &group, (int) group->interface));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
|
||||
igmp->igmp_msgtype, group->group_state, &group, group->netif));
|
||||
IGMP_STATS_INC(igmp.proterr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -456,7 +510,7 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
|
||||
* @return ERR_OK if group was joined on the netif(s), an err_t otherwise
|
||||
*/
|
||||
err_t
|
||||
igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
|
||||
igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
|
||||
{
|
||||
err_t err = ERR_VAL; /* no matching interface */
|
||||
struct igmp_group *group;
|
||||
@@ -488,11 +542,11 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
|
||||
if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
||||
netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
|
||||
}
|
||||
|
||||
IGMP_STATS_INC(igmp.join_sent);
|
||||
IGMP_STATS_INC(igmp.tx_join);
|
||||
igmp_send(group, IGMP_V2_MEMB_REPORT);
|
||||
|
||||
igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
|
||||
@@ -526,7 +580,7 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
|
||||
* @return ERR_OK if group was left on the netif(s), an err_t otherwise
|
||||
*/
|
||||
err_t
|
||||
igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
|
||||
igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
|
||||
{
|
||||
err_t err = ERR_VAL; /* no matching interface */
|
||||
struct igmp_group *group;
|
||||
@@ -555,7 +609,7 @@ igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
|
||||
/* If we are the last reporter for this group */
|
||||
if (group->last_reporter_flag) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
|
||||
IGMP_STATS_INC(igmp.leave_sent);
|
||||
IGMP_STATS_INC(igmp.tx_leave);
|
||||
igmp_send(group, IGMP_LEAVE_GROUP);
|
||||
}
|
||||
|
||||
@@ -563,7 +617,7 @@ igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
|
||||
if (netif->igmp_mac_filter != NULL) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
||||
netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
|
||||
}
|
||||
|
||||
@@ -601,8 +655,8 @@ igmp_tmr(void)
|
||||
struct igmp_group *group = igmp_group_list;
|
||||
|
||||
while (group != NULL) {
|
||||
if (group->timer != 0) {
|
||||
group->timer -= 1;
|
||||
if (group->timer > 0) {
|
||||
group->timer--;
|
||||
if (group->timer == 0) {
|
||||
igmp_timeout(group);
|
||||
}
|
||||
@@ -617,15 +671,16 @@ igmp_tmr(void)
|
||||
*
|
||||
* @param group an igmp_group for which a timeout is reached
|
||||
*/
|
||||
void
|
||||
static void
|
||||
igmp_timeout(struct igmp_group *group)
|
||||
{
|
||||
/* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */
|
||||
if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) group->interface));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
|
||||
|
||||
IGMP_STATS_INC(igmp.tx_report);
|
||||
igmp_send(group, IGMP_V2_MEMB_REPORT);
|
||||
}
|
||||
}
|
||||
@@ -637,24 +692,15 @@ igmp_timeout(struct igmp_group *group)
|
||||
* @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with
|
||||
* every call to igmp_tmr())
|
||||
*/
|
||||
void
|
||||
static void
|
||||
igmp_start_timer(struct igmp_group *group, u8_t max_time)
|
||||
{
|
||||
/**
|
||||
* @todo Important !! this should be random 0 -> max_time. Find out how to do this
|
||||
*/
|
||||
group->timer = max_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a timer for an igmp_group
|
||||
*
|
||||
* @param group the igmp_group for which to stop the timer
|
||||
*/
|
||||
void
|
||||
igmp_stop_timer(struct igmp_group *group)
|
||||
{
|
||||
group->timer = 0;
|
||||
/* ensure the input value is > 0 */
|
||||
if (max_time == 0) {
|
||||
max_time = 1;
|
||||
}
|
||||
/* ensure the random value is > 0 */
|
||||
group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -663,11 +709,13 @@ igmp_stop_timer(struct igmp_group *group)
|
||||
* @param group the igmp_group for which "delaying" membership report
|
||||
* @param maxresp query delay
|
||||
*/
|
||||
void
|
||||
igmp_delaying_member( struct igmp_group *group, u8_t maxresp)
|
||||
static void
|
||||
igmp_delaying_member(struct igmp_group *group, u8_t maxresp)
|
||||
{
|
||||
if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) {
|
||||
igmp_start_timer(group, (maxresp)/2);
|
||||
if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
|
||||
((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
|
||||
((group->timer == 0) || (maxresp < group->timer)))) {
|
||||
igmp_start_timer(group, maxresp);
|
||||
group->group_state = IGMP_GROUP_DELAYING_MEMBER;
|
||||
}
|
||||
}
|
||||
@@ -691,68 +739,15 @@ igmp_delaying_member( struct igmp_group *group, u8_t maxresp)
|
||||
* ERR_BUF if p doesn't have enough space for IP/LINK headers
|
||||
* returns errors returned by netif->output
|
||||
*/
|
||||
err_t
|
||||
igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl, u8_t proto, struct netif *netif)
|
||||
static err_t
|
||||
igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)
|
||||
{
|
||||
static u16_t ip_id = 0;
|
||||
struct ip_hdr * iphdr = NULL;
|
||||
u16_t * ra = NULL;
|
||||
|
||||
/* First write in the "router alert" */
|
||||
if (pbuf_header(p, ROUTER_ALERTLEN)) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n"));
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
/* This is the "router alert" option */
|
||||
ra = p->payload;
|
||||
ra[0] = htons (ROUTER_ALERT);
|
||||
u16_t ra[2];
|
||||
ra[0] = PP_HTONS(ROUTER_ALERT);
|
||||
ra[1] = 0x0000; /* Router shall examine packet */
|
||||
|
||||
/* now the normal ip header */
|
||||
if (pbuf_header(p, IP_HLEN)) {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n"));
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
iphdr = p->payload;
|
||||
|
||||
/* Should the IP header be generated or is it already included in p? */
|
||||
if (dest != IP_HDRINCL) {
|
||||
/** @todo should be shared with ip.c - ip_output_if */
|
||||
IPH_TTL_SET(iphdr, ttl);
|
||||
IPH_PROTO_SET(iphdr, proto);
|
||||
|
||||
ip_addr_set(&(iphdr->dest), dest);
|
||||
|
||||
IPH_VHLTOS_SET(iphdr, 4, ((IP_HLEN + ROUTER_ALERTLEN) / 4), 0/*tos*/);
|
||||
IPH_LEN_SET(iphdr, htons(p->tot_len));
|
||||
IPH_OFFSET_SET(iphdr, 0);
|
||||
IPH_ID_SET(iphdr, htons(ip_id));
|
||||
++ip_id;
|
||||
|
||||
if (ip_addr_isany(src)) {
|
||||
ip_addr_set(&(iphdr->src), &(netif->ip_addr));
|
||||
} else {
|
||||
ip_addr_set(&(iphdr->src), src);
|
||||
}
|
||||
|
||||
IPH_CHKSUM_SET(iphdr, 0);
|
||||
#if CHECKSUM_GEN_IP
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, (IP_HLEN + ROUTER_ALERTLEN)));
|
||||
#endif
|
||||
} else {
|
||||
dest = &(iphdr->dest);
|
||||
}
|
||||
|
||||
#if IP_DEBUG
|
||||
ip_debug_print(p);
|
||||
#endif
|
||||
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: sending to if %x\n", (int) netif));
|
||||
|
||||
return netif->output(netif, p, dest);
|
||||
IGMP_STATS_INC(igmp.xmit);
|
||||
return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -761,32 +756,31 @@ igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
* @param group the group to which to send the packet
|
||||
* @param type the type of igmp packet to send
|
||||
*/
|
||||
void
|
||||
static void
|
||||
igmp_send(struct igmp_group *group, u8_t type)
|
||||
{
|
||||
struct pbuf* p = NULL;
|
||||
struct igmp_msg* igmp = NULL;
|
||||
struct ip_addr src = {0};
|
||||
struct ip_addr* dest = NULL;
|
||||
ip_addr_t src = *IP_ADDR_ANY;
|
||||
ip_addr_t* dest = NULL;
|
||||
|
||||
/* IP header + "router alert" option + IGMP header */
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
|
||||
|
||||
if (p) {
|
||||
igmp = p->payload;
|
||||
igmp = (struct igmp_msg *)p->payload;
|
||||
LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
|
||||
(p->len >= sizeof(struct igmp_msg)));
|
||||
ip_addr_set(&src, &((group->interface)->ip_addr));
|
||||
ip_addr_copy(src, group->netif->ip_addr);
|
||||
|
||||
if (type == IGMP_V2_MEMB_REPORT) {
|
||||
dest = &(group->group_address);
|
||||
IGMP_STATS_INC(igmp.report_sent);
|
||||
ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));
|
||||
ip_addr_copy(igmp->igmp_group_address, group->group_address);
|
||||
group->last_reporter_flag = 1; /* Remember we were the last to report */
|
||||
} else {
|
||||
if (type == IGMP_LEAVE_GROUP) {
|
||||
dest = &allrouters;
|
||||
ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));
|
||||
ip_addr_copy(igmp->igmp_group_address, group->group_address);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -794,14 +788,15 @@ igmp_send(struct igmp_group *group, u8_t type)
|
||||
igmp->igmp_msgtype = type;
|
||||
igmp->igmp_maxresp = 0;
|
||||
igmp->igmp_checksum = 0;
|
||||
igmp->igmp_checksum = inet_chksum( igmp, IGMP_MINLEN);
|
||||
igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
|
||||
|
||||
igmp_ip_output_if( p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface);
|
||||
igmp_ip_output_if(p, &src, dest, group->netif);
|
||||
}
|
||||
|
||||
pbuf_free (p);
|
||||
pbuf_free(p);
|
||||
} else {
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
|
||||
IGMP_STATS_INC(igmp.memerr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,19 +43,62 @@
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/ip_frag.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/raw.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/tcp_impl.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/dhcp.h"
|
||||
#include "lwip/autoip.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "arch/perf.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/** Set this to 0 in the rare case of wanting to call an extra function to
|
||||
* generate the IP checksum (in contrast to calculating it on-the-fly). */
|
||||
#ifndef LWIP_INLINE_IP_CHKSUM
|
||||
#define LWIP_INLINE_IP_CHKSUM 1
|
||||
#endif
|
||||
#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP
|
||||
#define CHECKSUM_GEN_IP_INLINE 1
|
||||
#else
|
||||
#define CHECKSUM_GEN_IP_INLINE 0
|
||||
#endif
|
||||
|
||||
#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT)
|
||||
#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1
|
||||
|
||||
/** Some defines for DHCP to let link-layer-addressed packets through while the
|
||||
* netif is down.
|
||||
* To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT
|
||||
* to return 1 if the port is accepted and 0 if the port is not accepted.
|
||||
*/
|
||||
#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT)
|
||||
/* accept DHCP client port and custom port */
|
||||
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \
|
||||
|| (LWIP_IP_ACCEPT_UDP_PORT(port)))
|
||||
#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
|
||||
/* accept custom port only */
|
||||
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port))
|
||||
#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
|
||||
/* accept DHCP client port only */
|
||||
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT))
|
||||
#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
|
||||
|
||||
#else /* LWIP_DHCP */
|
||||
#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0
|
||||
#endif /* LWIP_DHCP */
|
||||
|
||||
/** Global data for both IPv4 and IPv6 */
|
||||
struct ip_globals ip_data;
|
||||
|
||||
/** The IP header ID of the next outgoing IP packet */
|
||||
static u16_t ip_id;
|
||||
|
||||
/**
|
||||
* Finds the appropriate network interface for a given IP address. It
|
||||
* searches the list of network interfaces linearly. A match is found
|
||||
@@ -66,7 +109,7 @@
|
||||
* @return the netif on which to send to reach dest
|
||||
*/
|
||||
struct netif *
|
||||
ip_route(struct ip_addr *dest)
|
||||
ip_route(ip_addr_t *dest)
|
||||
{
|
||||
struct netif *netif;
|
||||
|
||||
@@ -81,7 +124,8 @@ ip_route(struct ip_addr *dest)
|
||||
}
|
||||
}
|
||||
if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("ip_route: No route to 0x%"X32_F"\n", dest->addr));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
|
||||
IP_STATS_INC(ip.rterr);
|
||||
snmp_inc_ipoutnoroutes();
|
||||
return NULL;
|
||||
@@ -99,28 +143,35 @@ ip_route(struct ip_addr *dest)
|
||||
* @param p the packet to forward (p->payload points to IP header)
|
||||
* @param iphdr the IP header of the input packet
|
||||
* @param inp the netif on which this packet was received
|
||||
* @return the netif on which the packet was sent (NULL if it wasn't sent)
|
||||
*/
|
||||
static struct netif *
|
||||
static void
|
||||
ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
|
||||
{
|
||||
struct netif *netif;
|
||||
|
||||
PERF_START;
|
||||
|
||||
/* RFC3927 2.7: do not forward link-local addresses */
|
||||
if (ip_addr_islinklocal(ip_current_dest_addr())) {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()),
|
||||
ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr())));
|
||||
goto return_noroute;
|
||||
}
|
||||
|
||||
/* Find network interface where to forward this IP packet to. */
|
||||
netif = ip_route((struct ip_addr *)&(iphdr->dest));
|
||||
netif = ip_route(ip_current_dest_addr());
|
||||
if (netif == NULL) {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%"X32_F" found\n",
|
||||
iphdr->dest.addr));
|
||||
snmp_inc_ipoutnoroutes();
|
||||
return (struct netif *)NULL;
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n",
|
||||
ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()),
|
||||
ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr())));
|
||||
goto return_noroute;
|
||||
}
|
||||
/* Do not forward packets onto the same network interface on which
|
||||
* they arrived. */
|
||||
if (netif == inp) {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
|
||||
snmp_inc_ipoutnoroutes();
|
||||
return (struct netif *)NULL;
|
||||
goto return_noroute;
|
||||
}
|
||||
|
||||
/* decrement TTL */
|
||||
@@ -134,18 +185,19 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
|
||||
icmp_time_exceeded(p, ICMP_TE_TTL);
|
||||
}
|
||||
#endif /* LWIP_ICMP */
|
||||
return (struct netif *)NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Incrementally update the IP checksum. */
|
||||
if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) {
|
||||
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1);
|
||||
if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) {
|
||||
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1);
|
||||
} else {
|
||||
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100));
|
||||
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100));
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%"X32_F"\n",
|
||||
iphdr->dest.addr));
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()),
|
||||
ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr())));
|
||||
|
||||
IP_STATS_INC(ip.fw);
|
||||
IP_STATS_INC(ip.xmit);
|
||||
@@ -153,8 +205,10 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
|
||||
|
||||
PERF_STOP("ip_forward");
|
||||
/* transmit pbuf on chosen interface */
|
||||
netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));
|
||||
return netif;
|
||||
netif->output(netif, p, ip_current_dest_addr());
|
||||
return;
|
||||
return_noroute:
|
||||
snmp_inc_ipoutnoroutes();
|
||||
}
|
||||
#endif /* IP_FORWARD */
|
||||
|
||||
@@ -179,17 +233,17 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
struct netif *netif;
|
||||
u16_t iphdr_hlen;
|
||||
u16_t iphdr_len;
|
||||
#if LWIP_DHCP
|
||||
#if IP_ACCEPT_LINK_LAYER_ADDRESSING
|
||||
int check_ip_src=1;
|
||||
#endif /* LWIP_DHCP */
|
||||
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
|
||||
|
||||
IP_STATS_INC(ip.recv);
|
||||
snmp_inc_ipinreceives();
|
||||
|
||||
/* identify the IP header */
|
||||
iphdr = p->payload;
|
||||
iphdr = (struct ip_hdr *)p->payload;
|
||||
if (IPH_V(iphdr) != 4) {
|
||||
LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
|
||||
ip_debug_print(p);
|
||||
pbuf_free(p);
|
||||
IP_STATS_INC(ip.err);
|
||||
@@ -207,13 +261,16 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
|
||||
/* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
|
||||
if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
|
||||
if (iphdr_hlen > p->len)
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
|
||||
iphdr_hlen, p->len));
|
||||
if (iphdr_len > p->tot_len)
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), "
|
||||
"IP packet dropped.\n",
|
||||
iphdr_len, p->tot_len));
|
||||
if (iphdr_hlen > p->len) {
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
|
||||
iphdr_hlen, p->len));
|
||||
}
|
||||
if (iphdr_len > p->tot_len) {
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
|
||||
iphdr_len, p->tot_len));
|
||||
}
|
||||
/* free (drop) packet pbufs */
|
||||
pbuf_free(p);
|
||||
IP_STATS_INC(ip.lenerr);
|
||||
@@ -226,7 +283,8 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
#if CHECKSUM_CHECK_IP
|
||||
if (inet_chksum(iphdr, iphdr_hlen) != 0) {
|
||||
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
|
||||
ip_debug_print(p);
|
||||
pbuf_free(p);
|
||||
IP_STATS_INC(ip.chkerr);
|
||||
@@ -240,10 +298,14 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
* but we'll do it anyway just to be sure that its done. */
|
||||
pbuf_realloc(p, iphdr_len);
|
||||
|
||||
/* copy IP addresses to aligned ip_addr_t */
|
||||
ip_addr_copy(*ipX_2_ip(&ip_data.current_iphdr_dest), iphdr->dest);
|
||||
ip_addr_copy(*ipX_2_ip(&ip_data.current_iphdr_src), iphdr->src);
|
||||
|
||||
/* match packet against an interface, i.e. is this packet for us? */
|
||||
#if LWIP_IGMP
|
||||
if (ip_addr_ismulticast(&(iphdr->dest))) {
|
||||
if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(iphdr->dest)))) {
|
||||
if (ip_addr_ismulticast(ip_current_dest_addr())) {
|
||||
if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ip_current_dest_addr()))) {
|
||||
netif = inp;
|
||||
} else {
|
||||
netif = NULL;
|
||||
@@ -258,22 +320,33 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
netif = inp;
|
||||
do {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",
|
||||
iphdr->dest.addr, netif->ip_addr.addr,
|
||||
iphdr->dest.addr & netif->netmask.addr,
|
||||
netif->ip_addr.addr & netif->netmask.addr,
|
||||
iphdr->dest.addr & ~(netif->netmask.addr)));
|
||||
ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr),
|
||||
ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask),
|
||||
ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask),
|
||||
ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask)));
|
||||
|
||||
/* interface is up and configured? */
|
||||
if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {
|
||||
/* unicast to this interface address? */
|
||||
if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||
|
||||
if (ip_addr_cmp(ip_current_dest_addr(), &(netif->ip_addr)) ||
|
||||
/* or broadcast on this interface network address? */
|
||||
ip_addr_isbroadcast(&(iphdr->dest), netif)) {
|
||||
ip_addr_isbroadcast(ip_current_dest_addr(), netif)) {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
|
||||
netif->name[0], netif->name[1]));
|
||||
/* break out of for loop */
|
||||
break;
|
||||
}
|
||||
#if LWIP_AUTOIP
|
||||
/* connections to link-local addresses must persist after changing
|
||||
the netif's address (RFC3927 ch. 1.9) */
|
||||
if ((netif->autoip != NULL) &&
|
||||
ip_addr_cmp(ip_current_dest_addr(), &(netif->autoip->llipaddr))) {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n",
|
||||
netif->name[0], netif->name[1]));
|
||||
/* break out of for loop */
|
||||
break;
|
||||
}
|
||||
#endif /* LWIP_AUTOIP */
|
||||
}
|
||||
if (first) {
|
||||
first = 0;
|
||||
@@ -287,33 +360,40 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
} while(netif != NULL);
|
||||
}
|
||||
|
||||
#if LWIP_DHCP
|
||||
#if IP_ACCEPT_LINK_LAYER_ADDRESSING
|
||||
/* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
|
||||
* using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
|
||||
* According to RFC 1542 section 3.1.1, referred by RFC 2131).
|
||||
*
|
||||
* If you want to accept private broadcast communication while a netif is down,
|
||||
* define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.:
|
||||
*
|
||||
* #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345))
|
||||
*/
|
||||
if (netif == NULL) {
|
||||
/* remote port is DHCP server? */
|
||||
if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
|
||||
ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest)));
|
||||
if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) {
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n"));
|
||||
struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen);
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
|
||||
ntohs(udphdr->dest)));
|
||||
if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) {
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n"));
|
||||
netif = inp;
|
||||
check_ip_src = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_DHCP */
|
||||
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
|
||||
|
||||
/* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
|
||||
#if LWIP_DHCP
|
||||
if (check_ip_src)
|
||||
#endif /* LWIP_DHCP */
|
||||
{ if ((ip_addr_isbroadcast(&(iphdr->src), inp)) ||
|
||||
(ip_addr_ismulticast(&(iphdr->src)))) {
|
||||
#if IP_ACCEPT_LINK_LAYER_ADDRESSING
|
||||
/* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
|
||||
if (check_ip_src && !ip_addr_isany(ip_current_src_addr()))
|
||||
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
|
||||
{ if ((ip_addr_isbroadcast(ip_current_src_addr(), inp)) ||
|
||||
(ip_addr_ismulticast(ip_current_src_addr()))) {
|
||||
/* packet source is not valid */
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet source is not valid.\n"));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
|
||||
/* free (drop) packet pbufs */
|
||||
pbuf_free(p);
|
||||
IP_STATS_INC(ip.drop);
|
||||
@@ -326,10 +406,10 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
/* packet not for us? */
|
||||
if (netif == NULL) {
|
||||
/* packet not for us, route or discard */
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet not for us.\n"));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n"));
|
||||
#if IP_FORWARD
|
||||
/* non-broadcast packet? */
|
||||
if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {
|
||||
if (!ip_addr_isbroadcast(ip_current_dest_addr(), inp)) {
|
||||
/* try to forward IP packet on (other) interfaces */
|
||||
ip_forward(p, iphdr, inp);
|
||||
} else
|
||||
@@ -342,20 +422,20 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
return ERR_OK;
|
||||
}
|
||||
/* packet consists of multiple fragments? */
|
||||
if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
|
||||
if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) {
|
||||
#if IP_REASSEMBLY /* packet fragment reassembly code present? */
|
||||
LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n",
|
||||
ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
|
||||
ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
|
||||
/* reassemble the packet*/
|
||||
p = ip_reass(p);
|
||||
/* packet not fully reassembled yet? */
|
||||
if (p == NULL) {
|
||||
return ERR_OK;
|
||||
}
|
||||
iphdr = p->payload;
|
||||
iphdr = (struct ip_hdr *)p->payload;
|
||||
#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
|
||||
pbuf_free(p);
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
|
||||
ntohs(IPH_OFFSET(iphdr))));
|
||||
IP_STATS_INC(ip.opterr);
|
||||
IP_STATS_INC(ip.drop);
|
||||
@@ -369,11 +449,11 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
|
||||
#if LWIP_IGMP
|
||||
/* there is an extra "router alert" option in IGMP messages which we allow for but do not police */
|
||||
if((iphdr_hlen > IP_HLEN && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
|
||||
if((iphdr_hlen > IP_HLEN) && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
|
||||
#else
|
||||
if (iphdr_hlen > IP_HLEN) {
|
||||
#endif /* LWIP_IGMP */
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
|
||||
pbuf_free(p);
|
||||
IP_STATS_INC(ip.opterr);
|
||||
IP_STATS_INC(ip.drop);
|
||||
@@ -388,11 +468,16 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
ip_debug_print(p);
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
|
||||
|
||||
ip_data.current_netif = inp;
|
||||
ip_data.current_ip4_header = iphdr;
|
||||
ip_data.current_ip_header_tot_len = IPH_HL(iphdr) * 4;
|
||||
|
||||
#if LWIP_RAW
|
||||
/* raw input did not eat the packet? */
|
||||
if (raw_input(p, inp) == 0)
|
||||
#endif /* LWIP_RAW */
|
||||
{
|
||||
pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */
|
||||
|
||||
switch (IPH_PROTO(iphdr)) {
|
||||
#if LWIP_UDP
|
||||
@@ -418,21 +503,22 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
#endif /* LWIP_ICMP */
|
||||
#if LWIP_IGMP
|
||||
case IP_PROTO_IGMP:
|
||||
igmp_input(p,inp,&(iphdr->dest));
|
||||
igmp_input(p, inp, ip_current_dest_addr());
|
||||
break;
|
||||
#endif /* LWIP_IGMP */
|
||||
default:
|
||||
#if LWIP_ICMP
|
||||
/* send ICMP destination protocol unreachable unless is was a broadcast */
|
||||
if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&
|
||||
!ip_addr_ismulticast(&(iphdr->dest))) {
|
||||
if (!ip_addr_isbroadcast(ip_current_dest_addr(), inp) &&
|
||||
!ip_addr_ismulticast(ip_current_dest_addr())) {
|
||||
pbuf_header(p, iphdr_hlen); /* Move to ip header, no check necessary. */
|
||||
p->payload = iphdr;
|
||||
icmp_dest_unreach(p, ICMP_DUR_PROTO);
|
||||
}
|
||||
#endif /* LWIP_ICMP */
|
||||
pbuf_free(p);
|
||||
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
|
||||
|
||||
IP_STATS_INC(ip.proterr);
|
||||
IP_STATS_INC(ip.drop);
|
||||
@@ -440,6 +526,13 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
}
|
||||
}
|
||||
|
||||
/* @todo: this is not really necessary... */
|
||||
ip_data.current_netif = NULL;
|
||||
ip_data.current_ip4_header = NULL;
|
||||
ip_data.current_ip_header_tot_len = 0;
|
||||
ip_addr_set_any(ip_current_src_addr());
|
||||
ip_addr_set_any(ip_current_dest_addr());
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -469,70 +562,161 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
* unique identifiers independent of destination"
|
||||
*/
|
||||
err_t
|
||||
ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
|
||||
u8_t ttl, u8_t tos,
|
||||
u8_t proto, struct netif *netif)
|
||||
{
|
||||
#if IP_OPTIONS_SEND
|
||||
return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as ip_output_if() but with the possibility to include IP options:
|
||||
*
|
||||
* @ param ip_options pointer to the IP options, copied into the IP header
|
||||
* @ param optlen length of ip_options
|
||||
*/
|
||||
err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
|
||||
u16_t optlen)
|
||||
{
|
||||
#endif /* IP_OPTIONS_SEND */
|
||||
struct ip_hdr *iphdr;
|
||||
static u16_t ip_id = 0;
|
||||
ip_addr_t dest_addr;
|
||||
#if CHECKSUM_GEN_IP_INLINE
|
||||
u32_t chk_sum = 0;
|
||||
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||
|
||||
/* pbufs passed to IP must have a ref-count of 1 as their payload pointer
|
||||
gets altered as the packet is passed down the stack */
|
||||
LWIP_ASSERT("p->ref == 1", p->ref == 1);
|
||||
|
||||
snmp_inc_ipoutrequests();
|
||||
|
||||
/* Should the IP header be generated or is it already included in p? */
|
||||
if (dest != IP_HDRINCL) {
|
||||
u16_t ip_hlen = IP_HLEN;
|
||||
#if IP_OPTIONS_SEND
|
||||
u16_t optlen_aligned = 0;
|
||||
if (optlen != 0) {
|
||||
#if CHECKSUM_GEN_IP_INLINE
|
||||
int i;
|
||||
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||
/* round up to a multiple of 4 */
|
||||
optlen_aligned = ((optlen + 3) & ~3);
|
||||
ip_hlen += optlen_aligned;
|
||||
/* First write in the IP options */
|
||||
if (pbuf_header(p, optlen_aligned)) {
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n"));
|
||||
IP_STATS_INC(ip.err);
|
||||
snmp_inc_ipoutdiscards();
|
||||
return ERR_BUF;
|
||||
}
|
||||
MEMCPY(p->payload, ip_options, optlen);
|
||||
if (optlen < optlen_aligned) {
|
||||
/* zero the remaining bytes */
|
||||
memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
|
||||
}
|
||||
#if CHECKSUM_GEN_IP_INLINE
|
||||
for (i = 0; i < optlen_aligned/2; i++) {
|
||||
chk_sum += ((u16_t*)p->payload)[i];
|
||||
}
|
||||
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||
}
|
||||
#endif /* IP_OPTIONS_SEND */
|
||||
/* generate IP header */
|
||||
if (pbuf_header(p, IP_HLEN)) {
|
||||
LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n"));
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n"));
|
||||
|
||||
IP_STATS_INC(ip.err);
|
||||
snmp_inc_ipoutdiscards();
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
iphdr = p->payload;
|
||||
iphdr = (struct ip_hdr *)p->payload;
|
||||
LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",
|
||||
(p->len >= sizeof(struct ip_hdr)));
|
||||
|
||||
IPH_TTL_SET(iphdr, ttl);
|
||||
IPH_PROTO_SET(iphdr, proto);
|
||||
#if CHECKSUM_GEN_IP_INLINE
|
||||
chk_sum += LWIP_MAKE_U16(proto, ttl);
|
||||
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||
|
||||
ip_addr_set(&(iphdr->dest), dest);
|
||||
/* dest cannot be NULL here */
|
||||
ip_addr_copy(iphdr->dest, *dest);
|
||||
#if CHECKSUM_GEN_IP_INLINE
|
||||
chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF;
|
||||
chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16;
|
||||
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||
|
||||
IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos);
|
||||
IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos);
|
||||
#if CHECKSUM_GEN_IP_INLINE
|
||||
chk_sum += iphdr->_v_hl_tos;
|
||||
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||
IPH_LEN_SET(iphdr, htons(p->tot_len));
|
||||
#if CHECKSUM_GEN_IP_INLINE
|
||||
chk_sum += iphdr->_len;
|
||||
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||
IPH_OFFSET_SET(iphdr, 0);
|
||||
IPH_ID_SET(iphdr, htons(ip_id));
|
||||
#if CHECKSUM_GEN_IP_INLINE
|
||||
chk_sum += iphdr->_id;
|
||||
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||
++ip_id;
|
||||
|
||||
if (ip_addr_isany(src)) {
|
||||
ip_addr_set(&(iphdr->src), &(netif->ip_addr));
|
||||
ip_addr_copy(iphdr->src, netif->ip_addr);
|
||||
} else {
|
||||
ip_addr_set(&(iphdr->src), src);
|
||||
/* src cannot be NULL here */
|
||||
ip_addr_copy(iphdr->src, *src);
|
||||
}
|
||||
|
||||
#if CHECKSUM_GEN_IP_INLINE
|
||||
chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF;
|
||||
chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16;
|
||||
chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF);
|
||||
chk_sum = (chk_sum >> 16) + chk_sum;
|
||||
chk_sum = ~chk_sum;
|
||||
iphdr->_chksum = chk_sum; /* network order */
|
||||
#else /* CHECKSUM_GEN_IP_INLINE */
|
||||
IPH_CHKSUM_SET(iphdr, 0);
|
||||
#if CHECKSUM_GEN_IP
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));
|
||||
#endif
|
||||
#endif /* CHECKSUM_GEN_IP_INLINE */
|
||||
} else {
|
||||
/* IP header already included in p */
|
||||
iphdr = p->payload;
|
||||
dest = &(iphdr->dest);
|
||||
iphdr = (struct ip_hdr *)p->payload;
|
||||
ip_addr_copy(dest_addr, iphdr->dest);
|
||||
dest = &dest_addr;
|
||||
}
|
||||
|
||||
#if IP_FRAG
|
||||
/* don't fragment if interface has mtu set to 0 [loopif] */
|
||||
if (netif->mtu && (p->tot_len > netif->mtu))
|
||||
return ip_frag(p,netif,dest);
|
||||
#endif
|
||||
|
||||
IP_STATS_INC(ip.xmit);
|
||||
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
|
||||
ip_debug_print(p);
|
||||
|
||||
LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
|
||||
#if ENABLE_LOOPBACK
|
||||
if (ip_addr_cmp(dest, &netif->ip_addr)) {
|
||||
/* Packet to self, enqueue it for loopback */
|
||||
LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
|
||||
return netif_loop_output(netif, p, dest);
|
||||
}
|
||||
#if LWIP_IGMP
|
||||
if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) {
|
||||
netif_loop_output(netif, p, dest);
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
#if IP_FRAG
|
||||
/* don't fragment if interface has mtu set to 0 [loopif] */
|
||||
if (netif->mtu && (p->tot_len > netif->mtu)) {
|
||||
return ip_frag(p, netif, dest);
|
||||
}
|
||||
#endif /* IP_FRAG */
|
||||
|
||||
LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
|
||||
return netif->output(netif, p, dest);
|
||||
}
|
||||
|
||||
@@ -554,18 +738,70 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
* see ip_output_if() for more return values
|
||||
*/
|
||||
err_t
|
||||
ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto)
|
||||
{
|
||||
struct netif *netif;
|
||||
|
||||
/* pbufs passed to IP must have a ref-count of 1 as their payload pointer
|
||||
gets altered as the packet is passed down the stack */
|
||||
LWIP_ASSERT("p->ref == 1", p->ref == 1);
|
||||
|
||||
if ((netif = ip_route(dest)) == NULL) {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
|
||||
IP_STATS_INC(ip.rterr);
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
||||
return ip_output_if(p, src, dest, ttl, tos, proto, netif);
|
||||
}
|
||||
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
|
||||
* before calling ip_output_if.
|
||||
*
|
||||
* @param p the packet to send (p->payload points to the data, e.g. next
|
||||
protocol header; if dest == IP_HDRINCL, p already includes an IP
|
||||
header and p->payload points to that IP header)
|
||||
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
|
||||
* IP address of the netif used to send is used as source address)
|
||||
* @param dest the destination IP address to send the packet to
|
||||
* @param ttl the TTL value to be set in the IP header
|
||||
* @param tos the TOS value to be set in the IP header
|
||||
* @param proto the PROTOCOL to be set in the IP header
|
||||
* @param addr_hint address hint pointer set to netif->addr_hint before
|
||||
* calling ip_output_if()
|
||||
*
|
||||
* @return ERR_RTE if no route is found
|
||||
* see ip_output_if() for more return values
|
||||
*/
|
||||
err_t
|
||||
ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
|
||||
{
|
||||
struct netif *netif;
|
||||
err_t err;
|
||||
|
||||
/* pbufs passed to IP must have a ref-count of 1 as their payload pointer
|
||||
gets altered as the packet is passed down the stack */
|
||||
LWIP_ASSERT("p->ref == 1", p->ref == 1);
|
||||
|
||||
if ((netif = ip_route(dest)) == NULL) {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
|
||||
IP_STATS_INC(ip.rterr);
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
||||
NETIF_SET_HWADDRHINT(netif, addr_hint);
|
||||
err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
|
||||
NETIF_SET_HWADDRHINT(netif, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
|
||||
#if IP_DEBUG
|
||||
/* Print an IP header by using LWIP_DEBUGF
|
||||
* @param p an IP packet, p->payload pointing to the IP header
|
||||
@@ -573,7 +809,7 @@ ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
void
|
||||
ip_debug_print(struct pbuf *p)
|
||||
{
|
||||
struct ip_hdr *iphdr = p->payload;
|
||||
struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
|
||||
u8_t *payload;
|
||||
|
||||
payload = (u8_t *)iphdr + IP_HLEN;
|
||||
@@ -599,16 +835,16 @@ ip_debug_print(struct pbuf *p)
|
||||
ntohs(IPH_CHKSUM(iphdr))));
|
||||
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n",
|
||||
ip4_addr1(&iphdr->src),
|
||||
ip4_addr2(&iphdr->src),
|
||||
ip4_addr3(&iphdr->src),
|
||||
ip4_addr4(&iphdr->src)));
|
||||
ip4_addr1_16(&iphdr->src),
|
||||
ip4_addr2_16(&iphdr->src),
|
||||
ip4_addr3_16(&iphdr->src),
|
||||
ip4_addr4_16(&iphdr->src)));
|
||||
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n",
|
||||
ip4_addr1(&iphdr->dest),
|
||||
ip4_addr2(&iphdr->dest),
|
||||
ip4_addr3(&iphdr->dest),
|
||||
ip4_addr4(&iphdr->dest)));
|
||||
ip4_addr1_16(&iphdr->dest),
|
||||
ip4_addr2_16(&iphdr->dest),
|
||||
ip4_addr3_16(&iphdr->dest),
|
||||
ip4_addr4_16(&iphdr->dest)));
|
||||
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||
}
|
||||
#endif /* IP_DEBUG */
|
||||
@@ -1,14 +1,14 @@
|
||||
/**
|
||||
* @file
|
||||
* Functions common to all TCP/IPv4 modules, such as the byte order functions.
|
||||
* This is the IPv4 address tools 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,
|
||||
* 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,28 +17,97 @@
|
||||
* 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"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#include "lwip/inet.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 };
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
ip_addr_t ipaddr;
|
||||
ip4_addr_set_u32(&ipaddr, addr);
|
||||
|
||||
/* all ones (broadcast) or all zeroes (old skool broadcast) */
|
||||
if ((~addr == IPADDR_ANY) ||
|
||||
(addr == IPADDR_ANY)) {
|
||||
return 1;
|
||||
/* no broadcast support on this network interface? */
|
||||
} else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) {
|
||||
/* the given address cannot be a broadcast address
|
||||
* 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)) {
|
||||
return 0;
|
||||
/* on the same (sub) network... */
|
||||
} else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask))
|
||||
/* ...and host identifier bits are all ones? =>... */
|
||||
&& ((addr & ~ip4_addr_get_u32(&netif->netmask)) ==
|
||||
(IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) {
|
||||
/* => network broadcast address */
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks if a netmask is valid (starting with ones, then only zeros)
|
||||
*
|
||||
* @param netmask the IPv4 netmask to check (in network byte order!)
|
||||
* @return 1 if the netmask is valid, 0 if it is not
|
||||
*/
|
||||
u8_t
|
||||
ip4_addr_netmask_valid(u32_t netmask)
|
||||
{
|
||||
u32_t mask;
|
||||
u32_t nm_hostorder = lwip_htonl(netmask);
|
||||
|
||||
/* first, check for the first zero */
|
||||
for (mask = 1UL << 31 ; mask != 0; mask >>= 1) {
|
||||
if ((nm_hostorder & mask) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* then check that there is no one */
|
||||
for (; mask != 0; mask >>= 1) {
|
||||
if ((nm_hostorder & mask) != 0) {
|
||||
/* there is a one after the first zero -> invalid */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* no one after the first zero -> valid */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Here for now until needed in other places in lwIP */
|
||||
#ifndef isprint
|
||||
@@ -48,8 +117,8 @@
|
||||
#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')
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Ascii internet address interpretation routine.
|
||||
* The value returned is in network order.
|
||||
@@ -58,14 +127,14 @@
|
||||
* @return ip address in network order
|
||||
*/
|
||||
u32_t
|
||||
inet_addr(const char *cp)
|
||||
ipaddr_addr(const char *cp)
|
||||
{
|
||||
struct in_addr val;
|
||||
ip_addr_t val;
|
||||
|
||||
if (inet_aton(cp, &val)) {
|
||||
return (val.s_addr);
|
||||
if (ipaddr_aton(cp, &val)) {
|
||||
return ip4_addr_get_u32(&val);
|
||||
}
|
||||
return (INADDR_NONE);
|
||||
return (IPADDR_NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,10 +149,11 @@ inet_addr(const char *cp)
|
||||
* @return 1 if cp could be converted to addr, 0 on failure
|
||||
*/
|
||||
int
|
||||
inet_aton(const char *cp, struct in_addr *addr)
|
||||
ipaddr_aton(const char *cp, ip_addr_t *addr)
|
||||
{
|
||||
u32_t val;
|
||||
int base, n, c;
|
||||
u8_t base;
|
||||
char c;
|
||||
u32_t parts[4];
|
||||
u32_t *pp = parts;
|
||||
|
||||
@@ -123,8 +193,9 @@ inet_aton(const char *cp, struct in_addr *addr)
|
||||
* a.b.c (with c treated as 16 bits)
|
||||
* a.b (with b treated as 24 bits)
|
||||
*/
|
||||
if (pp >= parts + 3)
|
||||
if (pp >= parts + 3) {
|
||||
return (0);
|
||||
}
|
||||
*pp++ = val;
|
||||
c = *++cp;
|
||||
} else
|
||||
@@ -133,14 +204,14 @@ inet_aton(const char *cp, struct in_addr *addr)
|
||||
/*
|
||||
* Check for trailing characters.
|
||||
*/
|
||||
if (c != '\0' && (!isprint(c) || !isspace(c)))
|
||||
if (c != '\0' && !isspace(c)) {
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* Concoct the address according to
|
||||
* the number of parts specified.
|
||||
*/
|
||||
n = pp - parts + 1;
|
||||
switch (n) {
|
||||
switch (pp - parts + 1) {
|
||||
|
||||
case 0:
|
||||
return (0); /* initial nondigit */
|
||||
@@ -149,25 +220,32 @@ inet_aton(const char *cp, struct in_addr *addr)
|
||||
break;
|
||||
|
||||
case 2: /* a.b -- 8.24 bits */
|
||||
if (val > 0xffffffUL)
|
||||
if (val > 0xffffffUL) {
|
||||
return (0);
|
||||
}
|
||||
val |= parts[0] << 24;
|
||||
break;
|
||||
|
||||
case 3: /* a.b.c -- 8.8.16 bits */
|
||||
if (val > 0xffff)
|
||||
if (val > 0xffff) {
|
||||
return (0);
|
||||
}
|
||||
val |= (parts[0] << 24) | (parts[1] << 16);
|
||||
break;
|
||||
|
||||
case 4: /* a.b.c.d -- 8.8.8.8 bits */
|
||||
if (val > 0xff)
|
||||
if (val > 0xff) {
|
||||
return (0);
|
||||
}
|
||||
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
|
||||
break;
|
||||
default:
|
||||
LWIP_ASSERT("unhandled", 0);
|
||||
break;
|
||||
}
|
||||
if (addr) {
|
||||
ip4_addr_set_u32(addr, htonl(val));
|
||||
}
|
||||
if (addr)
|
||||
addr->s_addr = htonl(val);
|
||||
return (1);
|
||||
}
|
||||
|
||||
@@ -180,18 +258,35 @@ inet_aton(const char *cp, struct in_addr *addr)
|
||||
* represenation of addr
|
||||
*/
|
||||
char *
|
||||
inet_ntoa(struct in_addr addr)
|
||||
ipaddr_ntoa(const ip_addr_t *addr)
|
||||
{
|
||||
static char str[16];
|
||||
u32_t s_addr = addr.s_addr;
|
||||
return ipaddr_ntoa_r(addr, str, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
|
||||
*
|
||||
* @param addr ip 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 *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)
|
||||
{
|
||||
u32_t s_addr;
|
||||
char inv[3];
|
||||
char *rp;
|
||||
u8_t *ap;
|
||||
u8_t rem;
|
||||
u8_t n;
|
||||
u8_t i;
|
||||
int len = 0;
|
||||
|
||||
rp = str;
|
||||
s_addr = ip4_addr_get_u32(addr);
|
||||
|
||||
rp = buf;
|
||||
ap = (u8_t *)&s_addr;
|
||||
for(n = 0; n < 4; n++) {
|
||||
i = 0;
|
||||
@@ -200,79 +295,18 @@ inet_ntoa(struct in_addr addr)
|
||||
*ap /= (u8_t)10;
|
||||
inv[i++] = '0' + rem;
|
||||
} while(*ap);
|
||||
while(i--)
|
||||
while(i--) {
|
||||
if (len++ >= buflen) {
|
||||
return NULL;
|
||||
}
|
||||
*rp++ = inv[i];
|
||||
}
|
||||
if (len++ >= buflen) {
|
||||
return NULL;
|
||||
}
|
||||
*rp++ = '.';
|
||||
ap++;
|
||||
}
|
||||
*--rp = 0;
|
||||
return str;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
|
||||
/**
|
||||
* Convert an u16_t from host- to network byte order.
|
||||
*
|
||||
* @param n u16_t in host byte order
|
||||
* @return n in network byte order
|
||||
*/
|
||||
u16_t
|
||||
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
|
||||
ntohs(u16_t n)
|
||||
{
|
||||
return htons(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an u32_t from host- to network byte order.
|
||||
*
|
||||
* @param n u32_t in host byte order
|
||||
* @return n in network byte order
|
||||
*/
|
||||
u32_t
|
||||
htonl(u32_t n)
|
||||
{
|
||||
return ((n & 0xff) << 24) |
|
||||
((n & 0xff00) << 8) |
|
||||
((n & 0xff0000UL) >> 8) |
|
||||
((n & 0xff000000UL) >> 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an u32_t from network- to host byte order.
|
||||
*
|
||||
* @param n u32_t in network byte order
|
||||
* @return n in host byte order
|
||||
*/
|
||||
u32_t
|
||||
ntohl(u32_t n)
|
||||
{
|
||||
return htonl(n);
|
||||
}
|
||||
|
||||
#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */
|
||||
@@ -1,84 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* This is the IPv4 address tools 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: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#define IP_ADDR_ANY_VALUE 0x00000000UL
|
||||
#define IP_ADDR_BROADCAST_VALUE 0xffffffffUL
|
||||
|
||||
/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
|
||||
const struct ip_addr ip_addr_any = { IP_ADDR_ANY_VALUE };
|
||||
const struct ip_addr ip_addr_broadcast = { IP_ADDR_BROADCAST_VALUE };
|
||||
|
||||
/**
|
||||
* 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 ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif)
|
||||
{
|
||||
u32_t addr2test;
|
||||
|
||||
addr2test = addr->addr;
|
||||
/* all ones (broadcast) or all zeroes (old skool broadcast) */
|
||||
if ((~addr2test == IP_ADDR_ANY_VALUE) ||
|
||||
(addr2test == IP_ADDR_ANY_VALUE))
|
||||
return 1;
|
||||
/* no broadcast support on this network interface? */
|
||||
else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0)
|
||||
/* the given address cannot be a broadcast address
|
||||
* nor can we check against any broadcast addresses */
|
||||
return 0;
|
||||
/* address matches network interface address exactly? => no broadcast */
|
||||
else if (addr2test == netif->ip_addr.addr)
|
||||
return 0;
|
||||
/* on the same (sub) network... */
|
||||
else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask))
|
||||
/* ...and host identifier bits are all ones? =>... */
|
||||
&& ((addr2test & ~netif->netmask.addr) ==
|
||||
(IP_ADDR_BROADCAST_VALUE & ~netif->netmask.addr)))
|
||||
/* => network broadcast address */
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
@@ -40,8 +40,7 @@
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/ip_frag.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/snmp.h"
|
||||
@@ -81,12 +80,24 @@
|
||||
/** 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 IP header, since it replaces
|
||||
* the IP header in memory in incoming fragments (after copying it) to keep
|
||||
* track of the various fragments. (-> If the IP header doesn't need packing,
|
||||
* this struct doesn't need packing, too.)
|
||||
*/
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip_reass_helper {
|
||||
struct pbuf *next_pbuf;
|
||||
u16_t start;
|
||||
u16_t end;
|
||||
};
|
||||
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
|
||||
|
||||
#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \
|
||||
(ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
|
||||
@@ -146,7 +157,8 @@ ip_reass_tmr(void)
|
||||
static int
|
||||
ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
|
||||
{
|
||||
int pbufs_freed = 0;
|
||||
u16_t pbufs_freed = 0;
|
||||
u8_t clen;
|
||||
struct pbuf *p;
|
||||
struct ip_reass_helper *iprh;
|
||||
|
||||
@@ -166,7 +178,9 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p
|
||||
/* Then, copy the original header into it. */
|
||||
SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);
|
||||
icmp_time_exceeded(p, ICMP_TE_FRAG);
|
||||
pbufs_freed += pbuf_clen(p);
|
||||
clen = pbuf_clen(p);
|
||||
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
|
||||
pbufs_freed += clen;
|
||||
pbuf_free(p);
|
||||
}
|
||||
#endif /* LWIP_ICMP */
|
||||
@@ -180,8 +194,10 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p
|
||||
pcur = p;
|
||||
/* get the next pointer before freeing */
|
||||
p = iprh->next_pbuf;
|
||||
pbufs_freed += pbuf_clen(pcur);
|
||||
pbuf_free(pcur);
|
||||
clen = pbuf_clen(pcur);
|
||||
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
|
||||
pbufs_freed += clen;
|
||||
pbuf_free(pcur);
|
||||
}
|
||||
/* Then, unchain the struct ip_reassdata from the list and free it. */
|
||||
ip_reass_dequeue_datagram(ipr, prev);
|
||||
@@ -254,11 +270,11 @@ ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)
|
||||
{
|
||||
struct ip_reassdata* ipr;
|
||||
/* No matching previous fragment found, allocate a new reassdata struct */
|
||||
ipr = memp_malloc(MEMP_REASSDATA);
|
||||
ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
|
||||
if (ipr == NULL) {
|
||||
#if IP_REASS_FREE_OLDEST
|
||||
if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) {
|
||||
ipr = memp_malloc(MEMP_REASSDATA);
|
||||
ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
|
||||
}
|
||||
if (ipr == NULL)
|
||||
#endif /* IP_REASS_FREE_OLDEST */
|
||||
@@ -539,7 +555,7 @@ ip_reass(struct pbuf *p)
|
||||
* to an existing one */
|
||||
|
||||
/* check for 'no more fragments', and update queue entry*/
|
||||
if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {
|
||||
if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) {
|
||||
ipr->flags |= IP_REASS_FLAG_LASTFRAG;
|
||||
ipr->datagram_len = offset + len;
|
||||
LWIP_DEBUGF(IP_REASS_DEBUG,
|
||||
@@ -599,7 +615,39 @@ nullreturn:
|
||||
|
||||
#if IP_FRAG
|
||||
#if IP_FRAG_USES_STATIC_BUF
|
||||
static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU)];
|
||||
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*
|
||||
ip_frag_alloc_pbuf_custom_ref(void)
|
||||
{
|
||||
return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
|
||||
}
|
||||
|
||||
/** Free a struct pbuf_custom_ref */
|
||||
static void
|
||||
ip_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
|
||||
ipfrag_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);
|
||||
}
|
||||
ip_frag_free_pbuf_custom_ref(pcr);
|
||||
}
|
||||
#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
|
||||
#endif /* IP_FRAG_USES_STATIC_BUF */
|
||||
|
||||
/**
|
||||
@@ -616,13 +664,15 @@ static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU)];
|
||||
* @return ERR_OK if sent successfully, err_t otherwise
|
||||
*/
|
||||
err_t
|
||||
ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
|
||||
ip_frag(struct pbuf *p, struct netif *netif, ip_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;
|
||||
@@ -633,7 +683,7 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
|
||||
u16_t last;
|
||||
u16_t poff = IP_HLEN;
|
||||
u16_t tmp;
|
||||
#if !IP_FRAG_USES_STATIC_BUF
|
||||
#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
|
||||
u16_t newpbuflen = 0;
|
||||
u16_t left_to_copy;
|
||||
#endif
|
||||
@@ -653,10 +703,10 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
|
||||
rambuf->payload = LWIP_MEM_ALIGN((void *)buf);
|
||||
|
||||
/* Copy the IP header in it */
|
||||
iphdr = rambuf->payload;
|
||||
iphdr = (struct ip_hdr *)rambuf->payload;
|
||||
SMEMCPY(iphdr, p->payload, IP_HLEN);
|
||||
#else /* IP_FRAG_USES_STATIC_BUF */
|
||||
original_iphdr = p->payload;
|
||||
original_iphdr = (struct ip_hdr *)p->payload;
|
||||
iphdr = original_iphdr;
|
||||
#endif /* IP_FRAG_USES_STATIC_BUF */
|
||||
|
||||
@@ -674,8 +724,9 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
|
||||
|
||||
/* Set new offset and MF flag */
|
||||
tmp = omf | (IP_OFFMASK & (ofo));
|
||||
if (!last)
|
||||
if (!last) {
|
||||
tmp = tmp | IP_MF;
|
||||
}
|
||||
|
||||
/* Fill this fragment */
|
||||
cop = last ? left : nfb * 8;
|
||||
@@ -683,6 +734,23 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
|
||||
#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);
|
||||
if (rambuf == NULL) {
|
||||
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, rambuf->payload, cop, poff);
|
||||
/* make room for the IP header */
|
||||
if(pbuf_header(rambuf, IP_HLEN)) {
|
||||
pbuf_free(rambuf);
|
||||
return ERR_MEM;
|
||||
}
|
||||
/* fill in the IP header */
|
||||
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
|
||||
iphdr = 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.
|
||||
* The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
|
||||
@@ -695,7 +763,7 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
|
||||
LWIP_ASSERT("this needs a pbuf in one piece!",
|
||||
(p->len >= (IP_HLEN)));
|
||||
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
|
||||
iphdr = rambuf->payload;
|
||||
iphdr = (struct ip_hdr *)rambuf->payload;
|
||||
|
||||
/* Can just adjust p directly for needed offset. */
|
||||
p->payload = (u8_t *)p->payload + poff;
|
||||
@@ -703,29 +771,40 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
|
||||
|
||||
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;
|
||||
}
|
||||
newpbuf = pbuf_alloc(PBUF_RAW, 0, PBUF_REF);
|
||||
if (newpbuf == NULL) {
|
||||
pcr = ip_frag_alloc_pbuf_custom_ref();
|
||||
if (pcr == NULL) {
|
||||
pbuf_free(rambuf);
|
||||
return ERR_MEM;
|
||||
}
|
||||
/* Mirror this pbuf, although we might not need all of it. */
|
||||
newpbuf->payload = p->payload;
|
||||
newpbuf->len = newpbuf->tot_len = newpbuflen;
|
||||
newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
|
||||
if (newpbuf == NULL) {
|
||||
ip_frag_free_pbuf_custom_ref(pcr);
|
||||
pbuf_free(rambuf);
|
||||
return ERR_MEM;
|
||||
}
|
||||
pbuf_ref(p);
|
||||
pcr->original = p;
|
||||
pcr->pc.custom_free_function = ipfrag_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)
|
||||
if (left_to_copy) {
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
poff = newpbuflen;
|
||||
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
|
||||
#endif /* IP_FRAG_USES_STATIC_BUF */
|
||||
|
||||
/* Correct header */
|
||||
@@ -735,8 +814,9 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
||||
|
||||
#if IP_FRAG_USES_STATIC_BUF
|
||||
if (last)
|
||||
if (last) {
|
||||
pbuf_realloc(rambuf, left + IP_HLEN);
|
||||
}
|
||||
|
||||
/* This part is ugly: we alloc a RAM based pbuf for
|
||||
* the link level header for each chunk and then
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* DHCPv6.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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,42 +17,34 @@
|
||||
* 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>
|
||||
*/
|
||||
#ifndef __NETIF_LOOPIF_H__
|
||||
#define __NETIF_LOOPIF_H__
|
||||
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#if LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#if !LWIP_LOOPIF_MULTITHREADING
|
||||
void loopif_poll(struct netif *netif);
|
||||
#endif
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
err_t loopif_init(struct netif *netif);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __NETIF_LOOPIF_H__ */
|
||||
#endif /* LWIP_IPV6_DHCP6 */
|
||||
195
src/core/ipv6/ethip6.c
Normal file
195
src/core/ipv6/ethip6.c
Normal file
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* @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 <string.h>
|
||||
|
||||
#define ETHTYPE_IPV6 0x86DD
|
||||
|
||||
/** The ethernet address */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct eth_addr {
|
||||
PACK_STRUCT_FIELD(u8_t addr[6]);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** Ethernet header */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct eth_hdr {
|
||||
#if ETH_PAD_SIZE
|
||||
PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);
|
||||
#endif
|
||||
PACK_STRUCT_FIELD(struct eth_addr dest);
|
||||
PACK_STRUCT_FIELD(struct eth_addr src);
|
||||
PACK_STRUCT_FIELD(u16_t type);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)
|
||||
|
||||
/**
|
||||
* Send an IPv6 packet on the network using netif->linkoutput
|
||||
* The ethernet header is filled in before sending.
|
||||
*
|
||||
* @params netif the lwIP network interface on which to send the packet
|
||||
* @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header
|
||||
* @params src the source MAC address to be copied into the ethernet header
|
||||
* @params dst the destination MAC address to be copied into the ethernet header
|
||||
* @return ERR_OK if the packet was sent, any other err_t on failure
|
||||
*/
|
||||
static err_t
|
||||
ethip6_send(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst)
|
||||
{
|
||||
struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload;
|
||||
|
||||
LWIP_ASSERT("netif->hwaddr_len must be 6 for ethip6!",
|
||||
(netif->hwaddr_len == 6));
|
||||
SMEMCPY(ðhdr->dest, dst, 6);
|
||||
SMEMCPY(ðhdr->src, src, 6);
|
||||
ethhdr->type = PP_HTONS(ETHTYPE_IPV6);
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethip6_send: sending packet %p\n", (void *)p));
|
||||
/* send the packet */
|
||||
return netif->linkoutput(netif, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, ...
|
||||
*
|
||||
* @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_RTE No route to destination (no gateway to external networks),
|
||||
* or the return type of either etharp_query() or etharp_send_ip().
|
||||
*/
|
||||
err_t
|
||||
ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr)
|
||||
{
|
||||
struct eth_addr dest;
|
||||
s8_t i;
|
||||
|
||||
/* make room for Ethernet header - should not fail */
|
||||
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
|
||||
/* bail out */
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("etharp_output: could not allocate room for header.\n"));
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
/* 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] = ((u8_t *)(&(ip6addr->addr[3])))[0];
|
||||
dest.addr[3] = ((u8_t *)(&(ip6addr->addr[3])))[1];
|
||||
dest.addr[4] = ((u8_t *)(&(ip6addr->addr[3])))[2];
|
||||
dest.addr[5] = ((u8_t *)(&(ip6addr->addr[3])))[3];
|
||||
|
||||
/* Send out. */
|
||||
return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest);
|
||||
}
|
||||
|
||||
/* We have a unicast destination IP address */
|
||||
/* TODO anycast? */
|
||||
/* Get next hop record. */
|
||||
i = nd6_get_next_hop_entry(ip6addr, netif);
|
||||
if (i < 0) {
|
||||
/* failed to get a next hop neighbor record. */
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
/* Now that we have a destination record, send or queue the packet. */
|
||||
if (neighbor_cache[i].state == ND6_STALE) {
|
||||
/* Switch to delay state. */
|
||||
neighbor_cache[i].state = ND6_DELAY;
|
||||
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME;
|
||||
}
|
||||
/* TODO should we send or queue if PROBE? send for now, to let unicast NS pass. */
|
||||
if ((neighbor_cache[i].state == ND6_REACHABLE) ||
|
||||
(neighbor_cache[i].state == ND6_DELAY) ||
|
||||
(neighbor_cache[i].state == ND6_PROBE)) {
|
||||
|
||||
/* Send out. */
|
||||
SMEMCPY(dest.addr, neighbor_cache[i].lladdr, 6);
|
||||
return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest);
|
||||
}
|
||||
|
||||
/* We should queue packet on this interface. */
|
||||
pbuf_header(q, -(s16_t)SIZEOF_ETH_HDR);
|
||||
nd6_queue_packet(i, q);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#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,270 @@
|
||||
*
|
||||
* 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/ip.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/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/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;
|
||||
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];
|
||||
icmp6hdr = (struct icmp6_hdr *)p->payload;
|
||||
|
||||
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"));
|
||||
#if LWIP_ICMP6_CHECKSUM_CHECK
|
||||
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);
|
||||
ICMP6_STATS_INC(icmp6.chkerr);
|
||||
ICMP6_STATS_INC(icmp6.drop);
|
||||
return;
|
||||
}
|
||||
#endif /* LWIP_ICMP6_CHECKSUM_CHECK */
|
||||
|
||||
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);
|
||||
ICMP_STATS_INC(icmp.lenerr);
|
||||
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 /* 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. */
|
||||
reply_src = 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;
|
||||
}
|
||||
|
||||
/* Set fields in reply. */
|
||||
((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP;
|
||||
((struct icmp6_echo_hdr *)(r->payload))->chksum = 0;
|
||||
((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r,
|
||||
IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr());
|
||||
|
||||
/* 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;
|
||||
ip6_addr_t * reply_src;
|
||||
|
||||
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);
|
||||
|
||||
/* Select an address to use as source. */
|
||||
reply_src = ip6_select_source_address(ip_current_netif(), ip6_current_src_addr());
|
||||
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;
|
||||
icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len,
|
||||
reply_src, ip6_current_src_addr());
|
||||
|
||||
ICMP6_STATS_INC(icmp6.xmit);
|
||||
ip6_output(q, reply_src, ip6_current_src_addr(), LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6);
|
||||
pbuf_free(q);
|
||||
}
|
||||
|
||||
#endif /* LWIP_ICMP */
|
||||
#endif /* LWIP_ICMP6 && LWIP_IPV6 */
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/**
|
||||
* @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.
|
||||
* Copyright (c) 2010 Inico Technologies Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -33,131 +32,20 @@
|
||||
*
|
||||
* 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"
|
||||
#include "lwip/inet6.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.
|
||||
*/
|
||||
/** @see ip6_addr.c for implementation of functions. */
|
||||
|
||||
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 */
|
||||
|
||||
1121
src/core/ipv6/ip6.c
1121
src/core/ipv6/ip6.c
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,11 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* IPv6 addresses.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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,47 +32,210 @@
|
||||
*
|
||||
* 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"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/inet.h"
|
||||
|
||||
u8_t
|
||||
ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
|
||||
struct ip_addr *mask)
|
||||
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
/* used by IP6_ADDR_ANY in ip6_addr.h */
|
||||
const ip6_addr_t ip6_addr_any = { { 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 represenation (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 (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] == ':') {
|
||||
s++;
|
||||
/* "::" found, set zeros */
|
||||
while (zero_blocks-- > 0) {
|
||||
if (current_block_index & 0x1) {
|
||||
addr_index++;
|
||||
}
|
||||
else {
|
||||
addr->addr[addr_index] = 0;
|
||||
}
|
||||
current_block_index++;
|
||||
}
|
||||
}
|
||||
} else if (isxdigit(*s)) {
|
||||
/* add current digit */
|
||||
current_block_value = (current_block_value << 4) +
|
||||
(isdigit(*s) ? *s - '0' :
|
||||
10 + (islower(*s) ? *s - 'a' : *s - 'A'));
|
||||
} else {
|
||||
/* unexpected digit, space? CRLF? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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. */
|
||||
for (addr_index = 0; addr_index < 4; addr_index++) {
|
||||
addr->addr[addr_index] = 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
|
||||
* represenation 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;
|
||||
s32_t zero_flag, i;
|
||||
|
||||
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);
|
||||
i = 0;
|
||||
zero_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 = htonl(addr->addr[current_block_index >> 1]);
|
||||
if ((current_block_index & 0x1) == 0) {
|
||||
current_block_value = current_block_value >> 16;
|
||||
}
|
||||
current_block_value &= 0xffff;
|
||||
|
||||
if (current_block_value == 0) {
|
||||
/* generate empty block "::" */
|
||||
if (!zero_flag) {
|
||||
if (current_block_index > 0) {
|
||||
zero_flag = 1;
|
||||
buf[i++] = ':';
|
||||
if (i >= buflen) return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
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));
|
||||
if (i >= buflen) return NULL;
|
||||
}
|
||||
|
||||
if (((current_block_value & 0xf00) == 0) && (zero_flag)) {
|
||||
/* do nothing */
|
||||
}
|
||||
else {
|
||||
buf[i++] = xchar(((current_block_value & 0xf00) >> 8));
|
||||
if (i >= buflen) return NULL;
|
||||
}
|
||||
|
||||
if (((current_block_value & 0xf0) == 0) && (zero_flag)) {
|
||||
/* do nothing */
|
||||
}
|
||||
else {
|
||||
buf[i++] = xchar(((current_block_value & 0xf0) >> 4));
|
||||
if (i >= buflen) return NULL;
|
||||
}
|
||||
|
||||
buf[i++] = xchar((current_block_value & 0xf));
|
||||
if (i >= buflen) return NULL;
|
||||
|
||||
zero_flag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
buf[i] = 0;
|
||||
|
||||
return buf;
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
689
src/core/ipv6/ip6_frag.c
Normal file
689
src/core/ipv6/ip6_frag.c
Normal file
@@ -0,0 +1,689 @@
|
||||
/**
|
||||
* @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/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 */
|
||||
|
||||
#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;
|
||||
|
||||
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;
|
||||
u8_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 header (we are now pointing to Fragment header). */
|
||||
pbuf_header(p, (u8_t*)p->payload - (u8_t*)ipr->iphdr);
|
||||
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 != 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
|
||||
* @param len the length of the payload (after 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;
|
||||
u8_t clen, valid = 1;
|
||||
struct pbuf *q;
|
||||
|
||||
IP6_FRAG_STATS_INC(ip6_frag.recv);
|
||||
|
||||
frag_hdr = (struct ip6_frag_hdr *) p->payload;
|
||||
|
||||
clen = pbuf_clen(p);
|
||||
|
||||
offset = 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 = ntohs(ip6_current_header()->_plen);
|
||||
len -= ((u8_t*)p->payload - (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(), &(ipr->iphdr->src)) &&
|
||||
ip6_addr_cmp(ip6_current_dest_addr(), &(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)
|
||||
#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). */
|
||||
ipr->iphdr = (struct ip6_hdr *)ip6_current_header();
|
||||
|
||||
/* 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)
|
||||
#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. */
|
||||
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) {
|
||||
ipr->iphdr = (struct ip6_hdr *)ip6_current_header();
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
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 */
|
||||
|
||||
/* chain together the pbufs contained within the ip6_reassdata list. */
|
||||
iprh = (struct ip6_reass_helper*) ipr->p->payload;
|
||||
while(iprh != NULL) {
|
||||
|
||||
if (iprh->next_pbuf != NULL) {
|
||||
/* Save next helper struct (will be hidden in next step). */
|
||||
iprh_tmp = (struct ip6_reass_helper*) iprh->next_pbuf->payload;
|
||||
|
||||
/* hide the fragment header for every succeding fragment */
|
||||
pbuf_header(iprh->next_pbuf, -IP6_FRAG_HLEN);
|
||||
pbuf_cat(ipr->p, iprh->next_pbuf);
|
||||
}
|
||||
else {
|
||||
iprh_tmp = NULL;
|
||||
}
|
||||
|
||||
iprh = iprh_tmp;
|
||||
}
|
||||
|
||||
/* Adjust datagram length by adding header lengths. */
|
||||
ipr->datagram_len += ((u8_t*)ipr->p->payload - (u8_t*)ipr->iphdr)
|
||||
+ IP6_FRAG_HLEN
|
||||
- IP6_HLEN ;
|
||||
|
||||
/* Set payload length in ip header. */
|
||||
ipr->iphdr->_plen = htons(ipr->datagram_len);
|
||||
|
||||
/* Get the furst 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;
|
||||
|
||||
/* Move pbuf back to IPv6 header. */
|
||||
pbuf_header(p, (u8_t*)p->payload - (u8_t*)ipr->iphdr);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* and adjust the number of pbufs currently queued for reassembly. */
|
||||
ip6_reass_pbufcount -= pbuf_clen(p);
|
||||
|
||||
/* 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
|
||||
|
||||
/** 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, ip6_addr_t *dest)
|
||||
{
|
||||
struct ip6_hdr *original_ip6hdr;
|
||||
struct ip6_hdr *ip6hdr;
|
||||
struct ip6_frag_hdr * frag_hdr;
|
||||
struct pbuf *rambuf;
|
||||
struct pbuf *newpbuf;
|
||||
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;
|
||||
u16_t newpbuflen = 0;
|
||||
u16_t left_to_copy;
|
||||
|
||||
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;
|
||||
|
||||
/* 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 + IP6_FRAG_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;
|
||||
|
||||
/* Set headers */
|
||||
frag_hdr->_nexth = original_ip6hdr->_nexth;
|
||||
frag_hdr->reserved = 0;
|
||||
frag_hdr->_fragment_offset = htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG));
|
||||
frag_hdr->_identification = 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 */
|
||||
578
src/core/ipv6/mld6.c
Normal file
578
src/core/ipv6/mld6.c
Normal file
@@ -0,0 +1,578 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710.
|
||||
* No support for MLDv2.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/mld6.h"
|
||||
#include "lwip/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/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
|
||||
|
||||
|
||||
/* The list of joined groups. */
|
||||
static struct mld_group* mld_group_list;
|
||||
|
||||
|
||||
/* Forward declarations. */
|
||||
static struct mld_group * mld6_new_group(struct netif *ifp, ip6_addr_t *addr);
|
||||
static err_t mld6_free_group(struct mld_group *group);
|
||||
static void mld6_delayed_report(struct mld_group *group, u16_t maxresp);
|
||||
static void mld6_send(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 = mld_group_list;
|
||||
struct mld_group *prev = NULL;
|
||||
struct mld_group *next;
|
||||
|
||||
/* look for groups joined on this interface further down the list */
|
||||
while (group != NULL) {
|
||||
next = group->next;
|
||||
/* is it a group joined on this interface? */
|
||||
if (group->netif == netif) {
|
||||
/* is it the first group of the list? */
|
||||
if (group == mld_group_list) {
|
||||
mld_group_list = next;
|
||||
}
|
||||
/* is there a "previous" group defined? */
|
||||
if (prev != NULL) {
|
||||
prev->next = next;
|
||||
}
|
||||
/* disable the group at the MAC level */
|
||||
if (netif->mld_mac_filter != NULL) {
|
||||
netif->mld_mac_filter(netif, &(group->group_address), MLD6_DEL_MAC_FILTER);
|
||||
}
|
||||
/* free group */
|
||||
memp_free(MEMP_MLD6_GROUP, group);
|
||||
} else {
|
||||
/* change the "previous" */
|
||||
prev = 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 = mld_group_list;
|
||||
|
||||
while (group != NULL) {
|
||||
if (group->netif == netif) {
|
||||
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, ip6_addr_t *addr)
|
||||
{
|
||||
struct mld_group *group = mld_group_list;
|
||||
|
||||
while (group != NULL) {
|
||||
if ((group->netif == ifp) && (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, ip6_addr_t *addr)
|
||||
{
|
||||
struct mld_group *group;
|
||||
|
||||
group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP);
|
||||
if (group != NULL) {
|
||||
group->netif = ifp;
|
||||
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 = mld_group_list;
|
||||
|
||||
mld_group_list = group;
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a group in the mld_group_list and free
|
||||
*
|
||||
* @param group the group to remove
|
||||
* @return ERR_OK if group was removed from the list, an err_t otherwise
|
||||
*/
|
||||
static err_t
|
||||
mld6_free_group(struct mld_group *group)
|
||||
{
|
||||
err_t err = ERR_OK;
|
||||
|
||||
/* Is it the first group? */
|
||||
if (mld_group_list == group) {
|
||||
mld_group_list = group->next;
|
||||
} else {
|
||||
/* look for group further down the list */
|
||||
struct mld_group *tmpGroup;
|
||||
for (tmpGroup = mld_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
|
||||
if (tmpGroup->next == group) {
|
||||
tmpGroup->next = group->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Group not find group */
|
||||
if (tmpGroup == NULL)
|
||||
err = ERR_ARG;
|
||||
}
|
||||
/* free group */
|
||||
memp_free(MEMP_MLD6_GROUP, group);
|
||||
|
||||
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 = mld_group_list;
|
||||
while (group != NULL) {
|
||||
if ((group->netif == inp) &&
|
||||
(!(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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr)
|
||||
{
|
||||
err_t err = ERR_VAL; /* no matching interface */
|
||||
struct mld_group *group;
|
||||
struct netif *netif;
|
||||
u8_t match;
|
||||
u8_t i;
|
||||
|
||||
/* loop through netif's */
|
||||
netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
/* Should we join this interface ? */
|
||||
match = 0;
|
||||
if (ip6_addr_isany(srcaddr)) {
|
||||
match = 1;
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
|
||||
if (ip6_addr_cmp(srcaddr, netif_ip6_addr(netif, i))) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
/* 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, MLD6_ADD_MAC_FILTER);
|
||||
}
|
||||
|
||||
/* Report our membership. */
|
||||
MLD6_STATS_INC(mld6.tx_report);
|
||||
mld6_send(group, ICMP6_TYPE_MLR);
|
||||
mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
|
||||
}
|
||||
|
||||
/* Increment group use */
|
||||
group->use++;
|
||||
err = ERR_OK;
|
||||
}
|
||||
|
||||
/* proceed to next network interface */
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr)
|
||||
{
|
||||
err_t err = ERR_VAL; /* no matching interface */
|
||||
struct mld_group *group;
|
||||
struct netif *netif;
|
||||
u8_t match;
|
||||
u8_t i;
|
||||
|
||||
/* loop through netif's */
|
||||
netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
/* Should we leave this interface ? */
|
||||
match = 0;
|
||||
if (ip6_addr_isany(srcaddr)) {
|
||||
match = 1;
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
|
||||
if (ip6_addr_cmp(srcaddr, netif_ip6_addr(netif, i))) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
/* 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) {
|
||||
/* If we are the last reporter for this group */
|
||||
if (group->last_reporter_flag) {
|
||||
MLD6_STATS_INC(mld6.tx_leave);
|
||||
mld6_send(group, ICMP6_TYPE_MLD);
|
||||
}
|
||||
|
||||
/* Disable the group at the MAC level */
|
||||
if (netif->mld_mac_filter != NULL) {
|
||||
netif->mld_mac_filter(netif, groupaddr, MLD6_DEL_MAC_FILTER);
|
||||
}
|
||||
|
||||
/* Free the group */
|
||||
mld6_free_group(group);
|
||||
} else {
|
||||
/* Decrement group use */
|
||||
group->use--;
|
||||
}
|
||||
/* Leave on this interface */
|
||||
err = ERR_OK;
|
||||
}
|
||||
}
|
||||
/* proceed to next network interface */
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 mld_group *group = mld_group_list;
|
||||
|
||||
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(group, ICMP6_TYPE_MLR);
|
||||
group->group_state = MLD6_GROUP_IDLE_MEMBER;
|
||||
}
|
||||
}
|
||||
}
|
||||
group = group->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;
|
||||
}
|
||||
|
||||
/* Randomize maxresp. */
|
||||
maxresp = (LWIP_RAND() % (maxresp - 1)) + 1;
|
||||
|
||||
/* 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 mld_group *group, u8_t type)
|
||||
{
|
||||
struct mld_header * mld_hdr;
|
||||
struct pbuf * p;
|
||||
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) || (p->len < (sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr)))) {
|
||||
/* We couldn't allocate a suitable pbuf. drop it. */
|
||||
if (p != NULL) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
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(group->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_ANY;
|
||||
} else {
|
||||
/* Use link-local address as source address. */
|
||||
src_addr = netif_ip6_addr(group->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));
|
||||
|
||||
mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len,
|
||||
src_addr, &(group->group_address));
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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, group->netif);
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* LWIP_IPV6 */
|
||||
1730
src/core/ipv6/nd6.c
Normal file
1730
src/core/ipv6/nd6.c
Normal file
File diff suppressed because it is too large
Load Diff
368
src/core/mem.c
368
src/core/mem.c
@@ -61,20 +61,13 @@
|
||||
#include "lwip/mem.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 */
|
||||
|
||||
/**
|
||||
* This structure is used to save the pool one element came from.
|
||||
*/
|
||||
struct mem_helper
|
||||
{
|
||||
memp_t poolnr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocate memory: determine the smallest pool that is big enough
|
||||
* to contain an element of 'size' and get an element from that pool.
|
||||
@@ -85,13 +78,18 @@ struct mem_helper
|
||||
void *
|
||||
mem_malloc(mem_size_t size)
|
||||
{
|
||||
struct mem_helper *element;
|
||||
void *ret;
|
||||
struct memp_malloc_helper *element;
|
||||
memp_t poolnr;
|
||||
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++) {
|
||||
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 mem_helper that saves the pool this element came from? */
|
||||
if ((size + sizeof(struct mem_helper)) <= memp_sizes[poolnr]) {
|
||||
plus a struct memp_malloc_helper that saves the pool this element came from? */
|
||||
if (required_size <= memp_sizes[poolnr]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -99,20 +97,26 @@ mem_malloc(mem_size_t size)
|
||||
LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
|
||||
return NULL;
|
||||
}
|
||||
element = (struct mem_helper*)memp_malloc(poolnr);
|
||||
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 */
|
||||
/** @todo: we could try a bigger pool if this one is empty! */
|
||||
#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 */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* save the pool number this element came from */
|
||||
element->poolnr = poolnr;
|
||||
/* and return a pointer to the memory directly after the struct mem_helper */
|
||||
element++;
|
||||
/* and return a pointer to the memory directly after the struct memp_malloc_helper */
|
||||
ret = (u8_t*)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));
|
||||
|
||||
return element;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,13 +129,13 @@ mem_malloc(mem_size_t size)
|
||||
void
|
||||
mem_free(void *rmem)
|
||||
{
|
||||
struct mem_helper *hmem = (struct mem_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 mem_helper */
|
||||
hmem--;
|
||||
/* get the original struct memp_malloc_helper */
|
||||
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)));
|
||||
@@ -152,7 +156,7 @@ mem_free(void *rmem)
|
||||
struct mem {
|
||||
/** index (-> ram[next]) of the next struct */
|
||||
mem_size_t next;
|
||||
/** index (-> ram[next]) of the next struct */
|
||||
/** index (-> ram[prev]) of the previous struct */
|
||||
mem_size_t prev;
|
||||
/** 1: this area is used; 0: this area is unused */
|
||||
u8_t used;
|
||||
@@ -169,16 +173,53 @@ struct mem {
|
||||
#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))
|
||||
#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE)
|
||||
|
||||
/** If you want to relocate the heap to external memory, simply define
|
||||
* LWIP_RAM_HEAP_POINTER as a void-pointer to that location.
|
||||
* If so, make sure the memory at that location is big enough (see below on
|
||||
* 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 */
|
||||
static u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];
|
||||
u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];
|
||||
#define LWIP_RAM_HEAP_POINTER ram_heap
|
||||
#endif /* LWIP_RAM_HEAP_POINTER */
|
||||
|
||||
/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */
|
||||
static u8_t *ram;
|
||||
/** the last entry, always unused! */
|
||||
static struct mem *ram_end;
|
||||
/** pointer to the lowest free block, this is used for faster search */
|
||||
static struct mem *lfree;
|
||||
|
||||
/** concurrent access protection */
|
||||
static sys_sem_t mem_sem;
|
||||
#if !NO_SYS
|
||||
static sys_mutex_t mem_mutex;
|
||||
#endif
|
||||
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
|
||||
static volatile u8_t mem_free_count;
|
||||
|
||||
/* Allow mem_free from other (e.g. interrupt) context */
|
||||
#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free)
|
||||
#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free)
|
||||
#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free)
|
||||
#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc)
|
||||
#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc)
|
||||
#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc)
|
||||
|
||||
#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
|
||||
/* Protect the heap only by using a semaphore */
|
||||
#define LWIP_MEM_FREE_DECL_PROTECT()
|
||||
#define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex)
|
||||
#define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex)
|
||||
/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */
|
||||
#define LWIP_MEM_ALLOC_DECL_PROTECT()
|
||||
#define LWIP_MEM_ALLOC_PROTECT()
|
||||
#define LWIP_MEM_ALLOC_UNPROTECT()
|
||||
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
|
||||
|
||||
/**
|
||||
* "Plug holes" by combining adjacent empty struct mems.
|
||||
@@ -186,7 +227,7 @@ static sys_sem_t mem_sem;
|
||||
* one empty struct mem pointing to another empty struct mem.
|
||||
*
|
||||
* @param mem this points to a struct mem which just has been freed
|
||||
* @internal this function is only called by mem_free() and mem_realloc()
|
||||
* @internal this function is only called by mem_free() and mem_trim()
|
||||
*
|
||||
* This assumes access to the heap is protected by the calling function
|
||||
* already.
|
||||
@@ -204,25 +245,25 @@ plug_holes(struct mem *mem)
|
||||
/* plug hole forward */
|
||||
LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED);
|
||||
|
||||
nmem = (struct mem *)&ram[mem->next];
|
||||
nmem = (struct mem *)(void *)&ram[mem->next];
|
||||
if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
|
||||
/* if mem->next is unused and not end of ram, combine mem and mem->next */
|
||||
if (lfree == nmem) {
|
||||
lfree = mem;
|
||||
}
|
||||
mem->next = nmem->next;
|
||||
((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;
|
||||
((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram);
|
||||
}
|
||||
|
||||
/* plug hole backward */
|
||||
pmem = (struct mem *)&ram[mem->prev];
|
||||
pmem = (struct mem *)(void *)&ram[mem->prev];
|
||||
if (pmem != mem && pmem->used == 0) {
|
||||
/* if mem->prev is unused, combine mem and mem->prev */
|
||||
if (lfree == mem) {
|
||||
lfree = pmem;
|
||||
}
|
||||
pmem->next = mem->next;
|
||||
((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;
|
||||
((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,26 +279,26 @@ mem_init(void)
|
||||
(SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0);
|
||||
|
||||
/* align the heap */
|
||||
ram = LWIP_MEM_ALIGN(ram_heap);
|
||||
ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER);
|
||||
/* initialize the start of the heap */
|
||||
mem = (struct mem *)ram;
|
||||
mem = (struct mem *)(void *)ram;
|
||||
mem->next = MEM_SIZE_ALIGNED;
|
||||
mem->prev = 0;
|
||||
mem->used = 0;
|
||||
/* initialize the end of the heap */
|
||||
ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED];
|
||||
ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED];
|
||||
ram_end->used = 1;
|
||||
ram_end->next = MEM_SIZE_ALIGNED;
|
||||
ram_end->prev = MEM_SIZE_ALIGNED;
|
||||
|
||||
mem_sem = sys_sem_new(1);
|
||||
|
||||
/* initialize the lowest-free pointer to the start of the heap */
|
||||
lfree = (struct mem *)ram;
|
||||
lfree = (struct mem *)(void *)ram;
|
||||
|
||||
#if MEM_STATS
|
||||
lwip_stats.mem.avail = MEM_SIZE_ALIGNED;
|
||||
#endif /* MEM_STATS */
|
||||
MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
|
||||
|
||||
if(sys_mutex_new(&mem_mutex) != ERR_OK) {
|
||||
LWIP_ASSERT("failed to create mem_mutex", 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,29 +311,30 @@ void
|
||||
mem_free(void *rmem)
|
||||
{
|
||||
struct mem *mem;
|
||||
LWIP_MEM_FREE_DECL_PROTECT();
|
||||
|
||||
if (rmem == NULL) {
|
||||
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n"));
|
||||
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n"));
|
||||
return;
|
||||
}
|
||||
LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0);
|
||||
|
||||
/* protect the heap from concurrent access */
|
||||
sys_arch_sem_wait(mem_sem, 0);
|
||||
|
||||
LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
|
||||
(u8_t *)rmem < (u8_t *)ram_end);
|
||||
|
||||
if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
|
||||
LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n"));
|
||||
#if MEM_STATS
|
||||
++lwip_stats.mem.err;
|
||||
#endif /* MEM_STATS */
|
||||
sys_sem_signal(mem_sem);
|
||||
SYS_ARCH_DECL_PROTECT(lev);
|
||||
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n"));
|
||||
/* protect mem stats from concurrent access */
|
||||
SYS_ARCH_PROTECT(lev);
|
||||
MEM_STATS_INC(illegal);
|
||||
SYS_ARCH_UNPROTECT(lev);
|
||||
return;
|
||||
}
|
||||
/* protect the heap from concurrent access */
|
||||
LWIP_MEM_FREE_PROTECT();
|
||||
/* Get the corresponding struct mem ... */
|
||||
mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
|
||||
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);
|
||||
/* ... and is now unused. */
|
||||
@@ -303,31 +345,34 @@ mem_free(void *rmem)
|
||||
lfree = mem;
|
||||
}
|
||||
|
||||
#if MEM_STATS
|
||||
lwip_stats.mem.used -= mem->next - ((u8_t *)mem - ram);
|
||||
#endif /* MEM_STATS */
|
||||
MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram)));
|
||||
|
||||
/* finally, see if prev or next are free also */
|
||||
plug_holes(mem);
|
||||
sys_sem_signal(mem_sem);
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
mem_free_count = 1;
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
LWIP_MEM_FREE_UNPROTECT();
|
||||
}
|
||||
|
||||
/**
|
||||
* In contrast to its name, mem_realloc can only shrink memory, not expand it.
|
||||
* Since the only use (for now) is in pbuf_realloc (which also can only shrink),
|
||||
* this shouldn't be a problem!
|
||||
* Shrink memory returned by mem_malloc().
|
||||
*
|
||||
* @param rmem pointer to memory allocated by mem_malloc the is to be shrinked
|
||||
* @param newsize required size after shrinking (needs to be smaller than or
|
||||
* equal to the previous size)
|
||||
* @return for compatibility reasons: is always == rmem, at the moment
|
||||
* or NULL if newsize is > old size, in which case rmem is NOT touched
|
||||
* or freed!
|
||||
*/
|
||||
void *
|
||||
mem_realloc(void *rmem, mem_size_t newsize)
|
||||
mem_trim(void *rmem, mem_size_t newsize)
|
||||
{
|
||||
mem_size_t size;
|
||||
mem_size_t ptr, ptr2;
|
||||
struct mem *mem, *mem2;
|
||||
/* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */
|
||||
LWIP_MEM_FREE_DECL_PROTECT();
|
||||
|
||||
/* Expand the size of the allocated memory region so that we can
|
||||
adjust for alignment. */
|
||||
@@ -342,20 +387,25 @@ mem_realloc(void *rmem, mem_size_t newsize)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LWIP_ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
|
||||
LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
|
||||
(u8_t *)rmem < (u8_t *)ram_end);
|
||||
|
||||
if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
|
||||
LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n"));
|
||||
SYS_ARCH_DECL_PROTECT(lev);
|
||||
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n"));
|
||||
/* protect mem stats from concurrent access */
|
||||
SYS_ARCH_PROTECT(lev);
|
||||
MEM_STATS_INC(illegal);
|
||||
SYS_ARCH_UNPROTECT(lev);
|
||||
return rmem;
|
||||
}
|
||||
/* Get the corresponding struct mem ... */
|
||||
mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
|
||||
mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
|
||||
/* ... and its offset pointer */
|
||||
ptr = (u8_t *)mem - ram;
|
||||
ptr = (mem_size_t)((u8_t *)mem - ram);
|
||||
|
||||
size = mem->next - ptr - SIZEOF_STRUCT_MEM;
|
||||
LWIP_ASSERT("mem_realloc can only shrink memory", newsize <= size);
|
||||
LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size);
|
||||
if (newsize > size) {
|
||||
/* not supported */
|
||||
return NULL;
|
||||
@@ -366,13 +416,9 @@ mem_realloc(void *rmem, mem_size_t newsize)
|
||||
}
|
||||
|
||||
/* protect the heap from concurrent access */
|
||||
sys_arch_sem_wait(mem_sem, 0);
|
||||
LWIP_MEM_FREE_PROTECT();
|
||||
|
||||
#if MEM_STATS
|
||||
lwip_stats.mem.used -= (size - newsize);
|
||||
#endif /* MEM_STATS */
|
||||
|
||||
mem2 = (struct mem *)&ram[mem->next];
|
||||
mem2 = (struct mem *)(void *)&ram[mem->next];
|
||||
if(mem2->used == 0) {
|
||||
/* The next struct is unused, we can simply move it at little */
|
||||
mem_size_t next;
|
||||
@@ -381,9 +427,9 @@ mem_realloc(void *rmem, mem_size_t newsize)
|
||||
/* create new struct mem which is moved directly after the shrinked mem */
|
||||
ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
|
||||
if (lfree == mem2) {
|
||||
lfree = (struct mem *)&ram[ptr2];
|
||||
lfree = (struct mem *)(void *)&ram[ptr2];
|
||||
}
|
||||
mem2 = (struct mem *)&ram[ptr2];
|
||||
mem2 = (struct mem *)(void *)&ram[ptr2];
|
||||
mem2->used = 0;
|
||||
/* restore the next pointer */
|
||||
mem2->next = next;
|
||||
@@ -395,8 +441,9 @@ mem_realloc(void *rmem, mem_size_t newsize)
|
||||
* let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not
|
||||
* the end of the heap */
|
||||
if (mem2->next != MEM_SIZE_ALIGNED) {
|
||||
((struct mem *)&ram[mem2->next])->prev = ptr2;
|
||||
((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
|
||||
}
|
||||
MEM_STATS_DEC_USED(used, (size - newsize));
|
||||
/* no need to plug holes, we've already done that */
|
||||
} else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {
|
||||
/* Next struct is used but there's room for another struct mem with
|
||||
@@ -407,7 +454,7 @@ mem_realloc(void *rmem, mem_size_t newsize)
|
||||
* region that couldn't hold data, but when mem->next gets freed,
|
||||
* the 2 regions would be combined, resulting in more free memory */
|
||||
ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
|
||||
mem2 = (struct mem *)&ram[ptr2];
|
||||
mem2 = (struct mem *)(void *)&ram[ptr2];
|
||||
if (mem2 < lfree) {
|
||||
lfree = mem2;
|
||||
}
|
||||
@@ -416,8 +463,9 @@ mem_realloc(void *rmem, mem_size_t newsize)
|
||||
mem2->prev = ptr;
|
||||
mem->next = ptr2;
|
||||
if (mem2->next != MEM_SIZE_ALIGNED) {
|
||||
((struct mem *)&ram[mem2->next])->prev = ptr2;
|
||||
((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
|
||||
}
|
||||
MEM_STATS_DEC_USED(used, (size - newsize));
|
||||
/* the original mem->next is used, so no need to plug holes! */
|
||||
}
|
||||
/* else {
|
||||
@@ -426,7 +474,10 @@ mem_realloc(void *rmem, mem_size_t newsize)
|
||||
-> don't do anyhting.
|
||||
-> the remaining space stays unused since it is too small
|
||||
} */
|
||||
sys_sem_signal(mem_sem);
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
mem_free_count = 1;
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
LWIP_MEM_FREE_UNPROTECT();
|
||||
return rmem;
|
||||
}
|
||||
|
||||
@@ -444,6 +495,10 @@ mem_malloc(mem_size_t size)
|
||||
{
|
||||
mem_size_t ptr, ptr2;
|
||||
struct mem *mem, *mem2;
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
u8_t local_mem_free_count = 0;
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
LWIP_MEM_ALLOC_DECL_PROTECT();
|
||||
|
||||
if (size == 0) {
|
||||
return NULL;
|
||||
@@ -463,90 +518,103 @@ mem_malloc(mem_size_t size)
|
||||
}
|
||||
|
||||
/* protect the heap from concurrent access */
|
||||
sys_arch_sem_wait(mem_sem, 0);
|
||||
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 */
|
||||
do {
|
||||
local_mem_free_count = 0;
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
|
||||
/* Scan through the heap searching for a free block that is big enough,
|
||||
* beginning with the lowest free block.
|
||||
*/
|
||||
for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;
|
||||
ptr = ((struct mem *)&ram[ptr])->next) {
|
||||
mem = (struct mem *)&ram[ptr];
|
||||
|
||||
if ((!mem->used) &&
|
||||
(mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
|
||||
/* mem is not used and at least perfect fit is possible:
|
||||
* mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
|
||||
|
||||
if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
|
||||
/* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
|
||||
* at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
|
||||
* -> split large block, create empty remainder,
|
||||
* remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
|
||||
* mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
|
||||
* struct mem would fit in but no data between mem2 and mem2->next
|
||||
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
|
||||
* region that couldn't hold data, but when mem->next gets freed,
|
||||
* the 2 regions would be combined, resulting in more free memory
|
||||
*/
|
||||
ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
|
||||
/* create mem2 struct */
|
||||
mem2 = (struct mem *)&ram[ptr2];
|
||||
mem2->used = 0;
|
||||
mem2->next = mem->next;
|
||||
mem2->prev = ptr;
|
||||
/* and insert it between mem and mem->next */
|
||||
mem->next = ptr2;
|
||||
mem->used = 1;
|
||||
|
||||
if (mem2->next != MEM_SIZE_ALIGNED) {
|
||||
((struct mem *)&ram[mem2->next])->prev = ptr2;
|
||||
}
|
||||
#if MEM_STATS
|
||||
lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM);
|
||||
if (lwip_stats.mem.max < lwip_stats.mem.used) {
|
||||
lwip_stats.mem.max = lwip_stats.mem.used;
|
||||
}
|
||||
#endif /* MEM_STATS */
|
||||
} else {
|
||||
/* (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
|
||||
* also can't move mem->next directly behind mem, since mem->next
|
||||
* will always be used at this point!
|
||||
*/
|
||||
mem->used = 1;
|
||||
#if MEM_STATS
|
||||
lwip_stats.mem.used += mem->next - ((u8_t *)mem - ram);
|
||||
if (lwip_stats.mem.max < lwip_stats.mem.used) {
|
||||
lwip_stats.mem.max = lwip_stats.mem.used;
|
||||
}
|
||||
#endif /* MEM_STATS */
|
||||
/* Scan through the heap searching for a free block that is big enough,
|
||||
* beginning with the lowest free block.
|
||||
*/
|
||||
for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size;
|
||||
ptr = ((struct mem *)(void *)&ram[ptr])->next) {
|
||||
mem = (struct mem *)(void *)&ram[ptr];
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
mem_free_count = 0;
|
||||
LWIP_MEM_ALLOC_UNPROTECT();
|
||||
/* allow mem_free to run */
|
||||
LWIP_MEM_ALLOC_PROTECT();
|
||||
if (mem_free_count != 0) {
|
||||
local_mem_free_count = mem_free_count;
|
||||
}
|
||||
mem_free_count = 0;
|
||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
||||
|
||||
if (mem == lfree) {
|
||||
/* Find next free block after mem and update lowest free pointer */
|
||||
while (lfree->used && lfree != ram_end) {
|
||||
lfree = (struct mem *)&ram[lfree->next];
|
||||
if ((!mem->used) &&
|
||||
(mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
|
||||
/* mem is not used and at least perfect fit is possible:
|
||||
* mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
|
||||
|
||||
if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
|
||||
/* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
|
||||
* at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
|
||||
* -> split large block, create empty remainder,
|
||||
* remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
|
||||
* mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
|
||||
* struct mem would fit in but no data between mem2 and mem2->next
|
||||
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
|
||||
* region that couldn't hold data, but when mem->next gets freed,
|
||||
* the 2 regions would be combined, resulting in more free memory
|
||||
*/
|
||||
ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
|
||||
/* create mem2 struct */
|
||||
mem2 = (struct mem *)(void *)&ram[ptr2];
|
||||
mem2->used = 0;
|
||||
mem2->next = mem->next;
|
||||
mem2->prev = ptr;
|
||||
/* and insert it between mem and mem->next */
|
||||
mem->next = ptr2;
|
||||
mem->used = 1;
|
||||
|
||||
if (mem2->next != MEM_SIZE_ALIGNED) {
|
||||
((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
|
||||
}
|
||||
MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));
|
||||
} else {
|
||||
/* (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
|
||||
* 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));
|
||||
}
|
||||
LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
|
||||
}
|
||||
sys_sem_signal(mem_sem);
|
||||
LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
|
||||
(mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
|
||||
LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
|
||||
(unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
|
||||
LWIP_ASSERT("mem_malloc: sanity check alignment",
|
||||
(((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);
|
||||
|
||||
return (u8_t *)mem + SIZEOF_STRUCT_MEM;
|
||||
if (mem == lfree) {
|
||||
/* Find next free block after mem and update lowest free pointer */
|
||||
while (lfree->used && lfree != ram_end) {
|
||||
LWIP_MEM_ALLOC_UNPROTECT();
|
||||
/* prevent high interrupt latency... */
|
||||
LWIP_MEM_ALLOC_PROTECT();
|
||||
lfree = (struct mem *)(void *)&ram[lfree->next];
|
||||
}
|
||||
LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
|
||||
}
|
||||
LWIP_MEM_ALLOC_UNPROTECT();
|
||||
sys_mutex_unlock(&mem_mutex);
|
||||
LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
|
||||
(mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
|
||||
LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
|
||||
((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
|
||||
LWIP_ASSERT("mem_malloc: sanity check alignment",
|
||||
(((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);
|
||||
|
||||
return (u8_t *)mem + SIZEOF_STRUCT_MEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
|
||||
#if MEM_STATS
|
||||
++lwip_stats.mem.err;
|
||||
#endif /* MEM_STATS */
|
||||
sys_sem_signal(mem_sem);
|
||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
||||
/* if we got interrupted by a mem_free, try again */
|
||||
} 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);
|
||||
LWIP_MEM_ALLOC_UNPROTECT();
|
||||
sys_mutex_unlock(&mem_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
182
src/core/memp.c
182
src/core/memp.c
@@ -44,18 +44,28 @@
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/raw.h"
|
||||
#include "lwip/tcp.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 "lwip/nd6.h"
|
||||
#include "lwip/ip6_frag.h"
|
||||
#include "lwip/mld6.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
struct memp {
|
||||
struct memp *next;
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
@@ -109,15 +119,23 @@ struct memp {
|
||||
* 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
|
||||
#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
|
||||
static
|
||||
#endif
|
||||
const u16_t memp_sizes[MEMP_MAX] = {
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) MEMP_ALIGN_SIZE(size),
|
||||
#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 */
|
||||
|
||||
/** 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),
|
||||
@@ -132,12 +150,33 @@ static const char *memp_desc[MEMP_MAX] = {
|
||||
};
|
||||
#endif /* LWIP_DEBUG */
|
||||
|
||||
/** This is the actual memory used by the pools. */
|
||||
#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
|
||||
/**
|
||||
* Check that memp-lists don't form a circle
|
||||
@@ -162,15 +201,55 @@ memp_sanity(void)
|
||||
}
|
||||
#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
|
||||
|
||||
/**
|
||||
* 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_size the element size of the pool p comes from
|
||||
* @param memp_type the pool p comes from
|
||||
*/
|
||||
static void
|
||||
memp_overflow_check_element(struct memp *p, u16_t memp_size)
|
||||
memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type)
|
||||
{
|
||||
u16_t k;
|
||||
u8_t *m;
|
||||
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
|
||||
m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type];
|
||||
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
|
||||
LWIP_ASSERT(errstr, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a memp element was victim of an underflow
|
||||
* (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
|
||||
*/
|
||||
static void
|
||||
memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type)
|
||||
{
|
||||
u16_t k;
|
||||
u8_t *m;
|
||||
@@ -178,15 +257,18 @@ memp_overflow_check_element(struct memp *p, u16_t memp_size)
|
||||
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) {
|
||||
LWIP_ASSERT("detected memp underflow!", 0);
|
||||
}
|
||||
}
|
||||
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
|
||||
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
|
||||
m = (u8_t*)p + MEMP_SIZE + memp_size - MEMP_SANITY_REGION_AFTER_ALIGNED;
|
||||
for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
|
||||
if (m[k] != 0xcd) {
|
||||
LWIP_ASSERT("detected memp overflow!", 0);
|
||||
LWIP_ASSERT(errstr, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -203,12 +285,20 @@ memp_overflow_check_all(void)
|
||||
u16_t i, j;
|
||||
struct memp *p;
|
||||
|
||||
p = LWIP_MEM_ALIGN(memp_memory);
|
||||
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(p, memp_sizes[i]);
|
||||
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i]);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,7 +313,7 @@ memp_overflow_init(void)
|
||||
struct memp *p;
|
||||
u8_t *m;
|
||||
|
||||
p = LWIP_MEM_ALIGN(memp_memory);
|
||||
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) {
|
||||
@@ -232,10 +322,10 @@ memp_overflow_init(void)
|
||||
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] - MEMP_SANITY_REGION_AFTER_ALIGNED;
|
||||
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]);
|
||||
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,23 +342,31 @@ memp_init(void)
|
||||
struct memp *memp;
|
||||
u16_t i, j;
|
||||
|
||||
#if MEMP_STATS
|
||||
for (i = 0; i < MEMP_MAX; ++i) {
|
||||
lwip_stats.memp[i].used = lwip_stats.memp[i].max =
|
||||
lwip_stats.memp[i].err = 0;
|
||||
lwip_stats.memp[i].avail = memp_num[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]);
|
||||
}
|
||||
#endif /* MEMP_STATS */
|
||||
|
||||
memp = LWIP_MEM_ALIGN(memp_memory);
|
||||
#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 *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]);
|
||||
memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
+ MEMP_SANITY_REGION_AFTER_ALIGNED
|
||||
#endif
|
||||
);
|
||||
}
|
||||
}
|
||||
#if MEMP_OVERFLOW_CHECK
|
||||
@@ -308,27 +406,20 @@ memp_malloc_fn(memp_t type, const char* file, const int line)
|
||||
|
||||
memp = memp_tab[type];
|
||||
|
||||
if (memp != NULL) {
|
||||
memp_tab[type] = memp->next;
|
||||
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 */
|
||||
#if MEMP_STATS
|
||||
++lwip_stats.memp[type].used;
|
||||
if (lwip_stats.memp[type].used > lwip_stats.memp[type].max) {
|
||||
lwip_stats.memp[type].max = lwip_stats.memp[type].used;
|
||||
}
|
||||
#endif /* MEMP_STATS */
|
||||
MEMP_STATS_INC_USED(used, type);
|
||||
LWIP_ASSERT("memp_malloc: memp properly aligned",
|
||||
((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
|
||||
memp = (struct memp*)((u8_t*)memp + MEMP_SIZE);
|
||||
memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE);
|
||||
} else {
|
||||
LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
|
||||
#if MEMP_STATS
|
||||
++lwip_stats.memp[type].err;
|
||||
#endif /* MEMP_STATS */
|
||||
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);
|
||||
@@ -354,20 +445,19 @@ memp_free(memp_t type, void *mem)
|
||||
LWIP_ASSERT("memp_free: mem properly aligned",
|
||||
((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);
|
||||
|
||||
memp = (struct memp *)((u8_t*)mem - MEMP_SIZE);
|
||||
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(memp, memp_sizes[type]);
|
||||
memp_overflow_check_element_overflow(memp, type);
|
||||
memp_overflow_check_element_underflow(memp, type);
|
||||
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
|
||||
#endif /* MEMP_OVERFLOW_CHECK */
|
||||
|
||||
#if MEMP_STATS
|
||||
lwip_stats.memp[type].used--;
|
||||
#endif /* MEMP_STATS */
|
||||
MEMP_STATS_DEC(used, type);
|
||||
|
||||
memp->next = memp_tab[type];
|
||||
memp_tab[type] = memp;
|
||||
@@ -378,3 +468,5 @@ memp_free(memp_t type, void *mem)
|
||||
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
}
|
||||
|
||||
#endif /* MEMP_MEM_MALLOC */
|
||||
|
||||
595
src/core/netif.c
595
src/core/netif.c
@@ -40,27 +40,94 @@
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/tcp_impl.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "lwip/stats.h"
|
||||
#if ENABLE_LOOPBACK
|
||||
#include "lwip/sys.h"
|
||||
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
|
||||
#include "lwip/tcpip.h"
|
||||
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
|
||||
#if LWIP_AUTOIP
|
||||
#include "lwip/autoip.h"
|
||||
#endif /* LWIP_AUTOIP */
|
||||
#if LWIP_DHCP
|
||||
#include "lwip/dhcp.h"
|
||||
#endif /* LWIP_DHCP */
|
||||
#if LWIP_IPV6_DHCP6
|
||||
#include "lwip/dhcp6.h"
|
||||
#endif /* LWIP_IPV6_DHCP6 */
|
||||
#if LWIP_IPV6_MLD
|
||||
#include "lwip/mld6.h"
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
|
||||
#if LWIP_NETIF_STATUS_CALLBACK
|
||||
#define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); }
|
||||
#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0)
|
||||
#else
|
||||
#define NETIF_STATUS_CALLBACK(n) { /* NOP */ }
|
||||
#define NETIF_STATUS_CALLBACK(n)
|
||||
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
||||
|
||||
#if LWIP_NETIF_LINK_CALLBACK
|
||||
#define NETIF_LINK_CALLBACK(n) { if (n->link_callback) (n->link_callback)(n); }
|
||||
#define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0)
|
||||
#else
|
||||
#define NETIF_LINK_CALLBACK(n) { /* NOP */ }
|
||||
#define NETIF_LINK_CALLBACK(n)
|
||||
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
||||
|
||||
struct netif *netif_list;
|
||||
struct netif *netif_default;
|
||||
|
||||
static u8_t netif_num;
|
||||
|
||||
#if LWIP_HAVE_LOOPIF
|
||||
static struct netif loop_netif;
|
||||
|
||||
/**
|
||||
* Initialize a lwip network interface structure for a loopback interface
|
||||
*
|
||||
* @param netif the lwip network interface structure for this loopif
|
||||
* @return ERR_OK if the loopif is initialized
|
||||
* ERR_MEM if private data couldn't be allocated
|
||||
*/
|
||||
static err_t
|
||||
netif_loopif_init(struct netif *netif)
|
||||
{
|
||||
/* initialize the snmp variables and counters inside the struct netif
|
||||
* ifSpeed: no assumption can be made!
|
||||
*/
|
||||
NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0);
|
||||
|
||||
netif->name[0] = 'l';
|
||||
netif->name[1] = 'o';
|
||||
netif->output = netif_loop_output;
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* LWIP_HAVE_LOOPIF */
|
||||
|
||||
void
|
||||
netif_init(void)
|
||||
{
|
||||
#if LWIP_HAVE_LOOPIF
|
||||
ip_addr_t loop_ipaddr, loop_netmask, loop_gw;
|
||||
IP4_ADDR(&loop_gw, 127,0,0,1);
|
||||
IP4_ADDR(&loop_ipaddr, 127,0,0,1);
|
||||
IP4_ADDR(&loop_netmask, 255,0,0,0);
|
||||
|
||||
#if NO_SYS
|
||||
netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input);
|
||||
#else /* NO_SYS */
|
||||
netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input);
|
||||
#endif /* NO_SYS */
|
||||
netif_set_up(&loop_netif);
|
||||
|
||||
#endif /* LWIP_HAVE_LOOPIF */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a network interface to the list of lwIP netifs.
|
||||
*
|
||||
@@ -76,18 +143,25 @@ struct netif *netif_default;
|
||||
* @return netif, or NULL if failed.
|
||||
*/
|
||||
struct netif *
|
||||
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, ip_addr_t *ipaddr, ip_addr_t *netmask,
|
||||
ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
|
||||
{
|
||||
static u8_t netifnum = 0;
|
||||
#if LWIP_IPV6
|
||||
u32_t i;
|
||||
#endif
|
||||
|
||||
LWIP_ASSERT("No init function given", init != NULL);
|
||||
|
||||
/* reset new interface configuration state */
|
||||
netif->ip_addr.addr = 0;
|
||||
netif->netmask.addr = 0;
|
||||
netif->gw.addr = 0;
|
||||
ip_addr_set_zero(&netif->ip_addr);
|
||||
ip_addr_set_zero(&netif->netmask);
|
||||
ip_addr_set_zero(&netif->gw);
|
||||
#if LWIP_IPV6
|
||||
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
|
||||
ip6_addr_set_zero(&netif->ip6_addr[i]);
|
||||
netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID);
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
netif->flags = 0;
|
||||
#if LWIP_DHCP
|
||||
/* netif not under DHCP control by default */
|
||||
@@ -97,6 +171,17 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
|
||||
/* netif not under AutoIP control by default */
|
||||
netif->autoip = NULL;
|
||||
#endif /* LWIP_AUTOIP */
|
||||
#if LWIP_IPV6_AUTOCONFIG
|
||||
/* IPv6 address autoconfiguration not enabled by default */
|
||||
netif->ip6_autoconfig_enabled = 0;
|
||||
#endif /* LWIP_IPV6_AUTOCONFIG */
|
||||
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
|
||||
netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT;
|
||||
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
|
||||
#if LWIP_IPV6_DHCP6
|
||||
/* netif not under DHCPv6 control by default */
|
||||
netif->dhcp6 = NULL;
|
||||
#endif /* LWIP_IPV6_DHCP6 */
|
||||
#if LWIP_NETIF_STATUS_CALLBACK
|
||||
netif->status_callback = NULL;
|
||||
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
||||
@@ -106,14 +191,22 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
|
||||
#if LWIP_IGMP
|
||||
netif->igmp_mac_filter = NULL;
|
||||
#endif /* LWIP_IGMP */
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
netif->mld_mac_filter = NULL;
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
|
||||
#if ENABLE_LOOPBACK
|
||||
netif->loop_first = NULL;
|
||||
netif->loop_last = NULL;
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
|
||||
/* remember netif specific state information data */
|
||||
netif->state = state;
|
||||
netif->num = netifnum++;
|
||||
netif->num = netif_num++;
|
||||
netif->input = input;
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = NULL;
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
NETIF_SET_HWADDRHINT(netif, NULL);
|
||||
#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
|
||||
netif->loop_cnt_current = 0;
|
||||
#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
|
||||
|
||||
netif_set_addr(netif, ipaddr, netmask, gw);
|
||||
|
||||
@@ -130,7 +223,7 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
|
||||
#if LWIP_IGMP
|
||||
/* start IGMP processing */
|
||||
if (netif->flags & NETIF_FLAG_IGMP) {
|
||||
igmp_start( netif);
|
||||
igmp_start(netif);
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
|
||||
@@ -155,8 +248,8 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
|
||||
* @param gw the new default gateway
|
||||
*/
|
||||
void
|
||||
netif_set_addr(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
|
||||
struct ip_addr *gw)
|
||||
netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
|
||||
ip_addr_t *gw)
|
||||
{
|
||||
netif_set_ipaddr(netif, ipaddr);
|
||||
netif_set_netmask(netif, netmask);
|
||||
@@ -168,41 +261,51 @@ netif_set_addr(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netm
|
||||
*
|
||||
* @param netif the network interface to remove
|
||||
*/
|
||||
void netif_remove(struct netif * netif)
|
||||
void
|
||||
netif_remove(struct netif *netif)
|
||||
{
|
||||
if ( netif == NULL ) return;
|
||||
if (netif == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if LWIP_IGMP
|
||||
/* stop IGMP processing */
|
||||
if (netif->flags & NETIF_FLAG_IGMP) {
|
||||
igmp_stop( netif);
|
||||
igmp_stop(netif);
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
/* stop MLD processing */
|
||||
mld6_stop(netif);
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
|
||||
if (netif_is_up(netif)) {
|
||||
/* set netif down before removing (call callback function) */
|
||||
netif_set_down(netif);
|
||||
}
|
||||
|
||||
snmp_delete_ipaddridx_tree(netif);
|
||||
|
||||
/* is it the first netif? */
|
||||
if (netif_list == netif) {
|
||||
netif_list = netif->next;
|
||||
snmp_dec_iflist();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/* look for netif further down the list */
|
||||
struct netif * tmpNetif;
|
||||
for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {
|
||||
if (tmpNetif->next == netif) {
|
||||
tmpNetif->next = netif->next;
|
||||
snmp_dec_iflist();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tmpNetif == NULL)
|
||||
return; /* we didn't find any netif today */
|
||||
}
|
||||
snmp_dec_iflist();
|
||||
/* this netif is default? */
|
||||
if (netif_default == netif)
|
||||
if (netif_default == netif) {
|
||||
/* reset default netif */
|
||||
netif_set_default(NULL);
|
||||
}
|
||||
LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
|
||||
}
|
||||
|
||||
@@ -246,7 +349,7 @@ netif_find(char *name)
|
||||
* default gateway
|
||||
*/
|
||||
void
|
||||
netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
|
||||
netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
|
||||
{
|
||||
/* TODO: Handling of obsolete pcbs */
|
||||
/* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */
|
||||
@@ -255,17 +358,21 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
|
||||
struct tcp_pcb_listen *lpcb;
|
||||
|
||||
/* address is actually being changed? */
|
||||
if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0)
|
||||
{
|
||||
if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {
|
||||
/* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
|
||||
LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: netif address being changed\n"));
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
|
||||
pcb = tcp_active_pcbs;
|
||||
while (pcb != NULL) {
|
||||
/* PCB bound to current local interface address? */
|
||||
if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
|
||||
if (ip_addr_cmp(ipX_2_ip(&pcb->local_ip), &(netif->ip_addr))
|
||||
#if LWIP_AUTOIP
|
||||
/* connections to link-local addresses must persist (RFC3927 ch. 1.9) */
|
||||
&& !ip_addr_islinklocal(ipX_2_ip(&pcb->local_ip))
|
||||
#endif /* LWIP_AUTOIP */
|
||||
) {
|
||||
/* this connection must be aborted */
|
||||
struct tcp_pcb *next = pcb->next;
|
||||
LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
|
||||
tcp_abort(pcb);
|
||||
pcb = next;
|
||||
} else {
|
||||
@@ -274,11 +381,11 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
|
||||
}
|
||||
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
|
||||
/* PCB bound to current local interface address? */
|
||||
if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&
|
||||
(ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {
|
||||
if ((!(ip_addr_isany(ipX_2_ip(&lpcb->local_ip)))) &&
|
||||
(ip_addr_cmp(ipX_2_ip(&lpcb->local_ip), &(netif->ip_addr)))) {
|
||||
/* The PCB is listening to the old ipaddr and
|
||||
* is set to listen to the new one instead */
|
||||
ip_addr_set(&(lpcb->local_ip), ipaddr);
|
||||
ip_addr_set(ipX_2_ip(&lpcb->local_ip), ipaddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -290,12 +397,12 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
|
||||
snmp_insert_ipaddridx_tree(netif);
|
||||
snmp_insert_iprteidx_tree(0,netif);
|
||||
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
netif->name[0], netif->name[1],
|
||||
ip4_addr1(&netif->ip_addr),
|
||||
ip4_addr2(&netif->ip_addr),
|
||||
ip4_addr3(&netif->ip_addr),
|
||||
ip4_addr4(&netif->ip_addr)));
|
||||
ip4_addr1_16(&netif->ip_addr),
|
||||
ip4_addr2_16(&netif->ip_addr),
|
||||
ip4_addr3_16(&netif->ip_addr),
|
||||
ip4_addr4_16(&netif->ip_addr)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,15 +414,15 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
|
||||
* @note call netif_set_addr() if you also want to change ip address and netmask
|
||||
*/
|
||||
void
|
||||
netif_set_gw(struct netif *netif, struct ip_addr *gw)
|
||||
netif_set_gw(struct netif *netif, ip_addr_t *gw)
|
||||
{
|
||||
ip_addr_set(&(netif->gw), gw);
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
netif->name[0], netif->name[1],
|
||||
ip4_addr1(&netif->gw),
|
||||
ip4_addr2(&netif->gw),
|
||||
ip4_addr3(&netif->gw),
|
||||
ip4_addr4(&netif->gw)));
|
||||
ip4_addr1_16(&netif->gw),
|
||||
ip4_addr2_16(&netif->gw),
|
||||
ip4_addr3_16(&netif->gw),
|
||||
ip4_addr4_16(&netif->gw)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -328,18 +435,18 @@ netif_set_gw(struct netif *netif, struct ip_addr *gw)
|
||||
* default gateway
|
||||
*/
|
||||
void
|
||||
netif_set_netmask(struct netif *netif, struct ip_addr *netmask)
|
||||
netif_set_netmask(struct netif *netif, ip_addr_t *netmask)
|
||||
{
|
||||
snmp_delete_iprteidx_tree(0, netif);
|
||||
/* set new netmask to netif */
|
||||
ip_addr_set(&(netif->netmask), netmask);
|
||||
snmp_insert_iprteidx_tree(0, netif);
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
netif->name[0], netif->name[1],
|
||||
ip4_addr1(&netif->netmask),
|
||||
ip4_addr2(&netif->netmask),
|
||||
ip4_addr3(&netif->netmask),
|
||||
ip4_addr4(&netif->netmask)));
|
||||
ip4_addr1_16(&netif->netmask),
|
||||
ip4_addr2_16(&netif->netmask),
|
||||
ip4_addr3_16(&netif->netmask),
|
||||
ip4_addr4_16(&netif->netmask)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -351,13 +458,10 @@ netif_set_netmask(struct netif *netif, struct ip_addr *netmask)
|
||||
void
|
||||
netif_set_default(struct netif *netif)
|
||||
{
|
||||
if (netif == NULL)
|
||||
{
|
||||
if (netif == NULL) {
|
||||
/* remove default route */
|
||||
snmp_delete_iprteidx_tree(1, netif);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* install default route */
|
||||
snmp_insert_iprteidx_tree(1, netif);
|
||||
}
|
||||
@@ -377,27 +481,40 @@ netif_set_default(struct netif *netif)
|
||||
*/
|
||||
void netif_set_up(struct netif *netif)
|
||||
{
|
||||
if ( !(netif->flags & NETIF_FLAG_UP )) {
|
||||
if (!(netif->flags & NETIF_FLAG_UP)) {
|
||||
netif->flags |= NETIF_FLAG_UP;
|
||||
|
||||
#if LWIP_SNMP
|
||||
snmp_get_sysuptime(&netif->ts);
|
||||
#endif /* LWIP_SNMP */
|
||||
|
||||
NETIF_LINK_CALLBACK(netif);
|
||||
NETIF_STATUS_CALLBACK(netif);
|
||||
|
||||
if (netif->flags & NETIF_FLAG_LINK_UP) {
|
||||
#if LWIP_ARP
|
||||
/** For Ethernet network interfaces, we would like to send a
|
||||
* "gratuitous ARP"; this is an ARP packet sent by a node in order
|
||||
* to spontaneously cause other nodes to update an entry in their
|
||||
* ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6.
|
||||
*/
|
||||
if (netif->flags & NETIF_FLAG_ETHARP) {
|
||||
etharp_query(netif, &(netif->ip_addr), NULL);
|
||||
}
|
||||
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
|
||||
if (netif->flags & (NETIF_FLAG_ETHARP)) {
|
||||
etharp_gratuitous(netif);
|
||||
}
|
||||
#endif /* LWIP_ARP */
|
||||
|
||||
|
||||
#if LWIP_IGMP
|
||||
/* resend IGMP memberships */
|
||||
if (netif->flags & NETIF_FLAG_IGMP) {
|
||||
igmp_report_groups( netif);
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
/* send mld memberships */
|
||||
mld6_report_groups( netif);
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
|
||||
|
||||
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
|
||||
/* Send Router Solicitation messages. */
|
||||
netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT;
|
||||
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,64 +528,69 @@ void netif_set_up(struct netif *netif)
|
||||
*/
|
||||
void netif_set_down(struct netif *netif)
|
||||
{
|
||||
if ( netif->flags & NETIF_FLAG_UP )
|
||||
{
|
||||
netif->flags &= ~NETIF_FLAG_UP;
|
||||
if (netif->flags & NETIF_FLAG_UP) {
|
||||
netif->flags &= ~NETIF_FLAG_UP;
|
||||
#if LWIP_SNMP
|
||||
snmp_get_sysuptime(&netif->ts);
|
||||
snmp_get_sysuptime(&netif->ts);
|
||||
#endif
|
||||
|
||||
NETIF_LINK_CALLBACK(netif);
|
||||
NETIF_STATUS_CALLBACK(netif);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask if an interface is up
|
||||
*/
|
||||
u8_t netif_is_up(struct netif *netif)
|
||||
{
|
||||
return (netif->flags & NETIF_FLAG_UP)?1:0;
|
||||
NETIF_STATUS_CALLBACK(netif);
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_NETIF_STATUS_CALLBACK
|
||||
/**
|
||||
* Set callback to be called when interface is brought up/down
|
||||
*/
|
||||
void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif ))
|
||||
void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)
|
||||
{
|
||||
if ( netif )
|
||||
netif->status_callback = status_callback;
|
||||
if (netif) {
|
||||
netif->status_callback = status_callback;
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
||||
|
||||
#if LWIP_NETIF_LINK_CALLBACK
|
||||
/**
|
||||
* Called by a driver when its link goes up
|
||||
*/
|
||||
void netif_set_link_up(struct netif *netif )
|
||||
{
|
||||
netif->flags |= NETIF_FLAG_LINK_UP;
|
||||
if (!(netif->flags & NETIF_FLAG_LINK_UP)) {
|
||||
netif->flags |= NETIF_FLAG_LINK_UP;
|
||||
|
||||
#if LWIP_DHCP
|
||||
if (netif->dhcp) {
|
||||
dhcp_network_changed(netif);
|
||||
}
|
||||
#endif /* LWIP_DHCP */
|
||||
|
||||
#if LWIP_AUTOIP
|
||||
if (netif->autoip) {
|
||||
autoip_network_changed(netif);
|
||||
}
|
||||
#endif /* LWIP_AUTOIP */
|
||||
|
||||
if (netif->flags & NETIF_FLAG_UP) {
|
||||
#if LWIP_ARP
|
||||
/** For Ethernet network interfaces, we would like to send a
|
||||
* "gratuitous ARP"; this is an ARP packet sent by a node in order
|
||||
* to spontaneously cause other nodes to update an entry in their
|
||||
* ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6.
|
||||
*/
|
||||
if (netif->flags & NETIF_FLAG_ETHARP) {
|
||||
etharp_query(netif, &(netif->ip_addr), NULL);
|
||||
}
|
||||
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
|
||||
if (netif->flags & NETIF_FLAG_ETHARP) {
|
||||
etharp_gratuitous(netif);
|
||||
}
|
||||
#endif /* LWIP_ARP */
|
||||
|
||||
#if LWIP_IGMP
|
||||
/* resend IGMP memberships */
|
||||
if (netif->flags & NETIF_FLAG_IGMP) {
|
||||
igmp_report_groups( netif);
|
||||
}
|
||||
/* resend IGMP memberships */
|
||||
if (netif->flags & NETIF_FLAG_IGMP) {
|
||||
igmp_report_groups( netif);
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
|
||||
NETIF_LINK_CALLBACK(netif);
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
/* send mld memberships */
|
||||
mld6_report_groups( netif);
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
|
||||
}
|
||||
NETIF_LINK_CALLBACK(netif);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -476,24 +598,261 @@ void netif_set_link_up(struct netif *netif )
|
||||
*/
|
||||
void netif_set_link_down(struct netif *netif )
|
||||
{
|
||||
netif->flags &= ~NETIF_FLAG_LINK_UP;
|
||||
NETIF_LINK_CALLBACK(netif);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask if a link is up
|
||||
*/
|
||||
u8_t netif_is_link_up(struct netif *netif)
|
||||
{
|
||||
return (netif->flags & NETIF_FLAG_LINK_UP) ? 1 : 0;
|
||||
if (netif->flags & NETIF_FLAG_LINK_UP) {
|
||||
netif->flags &= ~NETIF_FLAG_LINK_UP;
|
||||
NETIF_LINK_CALLBACK(netif);
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_NETIF_LINK_CALLBACK
|
||||
/**
|
||||
* Set callback to be called when link is brought up/down
|
||||
*/
|
||||
void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif ))
|
||||
void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback)
|
||||
{
|
||||
if ( netif )
|
||||
netif->link_callback = link_callback;
|
||||
if (netif) {
|
||||
netif->link_callback = link_callback;
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
||||
|
||||
#if ENABLE_LOOPBACK
|
||||
/**
|
||||
* Send an IP packet to be received on the same netif (loopif-like).
|
||||
* The pbuf is simply copied and handed back to netif->input.
|
||||
* In multithreaded mode, this is done directly since netif->input must put
|
||||
* the packet on a queue.
|
||||
* In callback mode, the packet is put on an internal queue and is fed to
|
||||
* netif->input by netif_poll().
|
||||
*
|
||||
* @param netif the lwip network interface structure
|
||||
* @param p the (IP) packet to 'send'
|
||||
* @param ipaddr the ip address to send the packet to (not used)
|
||||
* @return ERR_OK if the packet has been sent
|
||||
* ERR_MEM if the pbuf used to copy the packet couldn't be allocated
|
||||
*/
|
||||
err_t
|
||||
netif_loop_output(struct netif *netif, struct pbuf *p,
|
||||
ip_addr_t *ipaddr)
|
||||
{
|
||||
struct pbuf *r;
|
||||
err_t err;
|
||||
struct pbuf *last;
|
||||
#if LWIP_LOOPBACK_MAX_PBUFS
|
||||
u8_t clen = 0;
|
||||
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
|
||||
/* If we have a loopif, SNMP counters are adjusted for it,
|
||||
* if not they are adjusted for 'netif'. */
|
||||
#if LWIP_SNMP
|
||||
#if LWIP_HAVE_LOOPIF
|
||||
struct netif *stats_if = &loop_netif;
|
||||
#else /* LWIP_HAVE_LOOPIF */
|
||||
struct netif *stats_if = netif;
|
||||
#endif /* LWIP_HAVE_LOOPIF */
|
||||
#endif /* LWIP_SNMP */
|
||||
SYS_ARCH_DECL_PROTECT(lev);
|
||||
LWIP_UNUSED_ARG(ipaddr);
|
||||
|
||||
/* Allocate a new pbuf */
|
||||
r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
|
||||
if (r == NULL) {
|
||||
LINK_STATS_INC(link.memerr);
|
||||
LINK_STATS_INC(link.drop);
|
||||
snmp_inc_ifoutdiscards(stats_if);
|
||||
return ERR_MEM;
|
||||
}
|
||||
#if LWIP_LOOPBACK_MAX_PBUFS
|
||||
clen = pbuf_clen(r);
|
||||
/* check for overflow or too many pbuf on queue */
|
||||
if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) ||
|
||||
((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) {
|
||||
pbuf_free(r);
|
||||
LINK_STATS_INC(link.memerr);
|
||||
LINK_STATS_INC(link.drop);
|
||||
snmp_inc_ifoutdiscards(stats_if);
|
||||
return ERR_MEM;
|
||||
}
|
||||
netif->loop_cnt_current += clen;
|
||||
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
|
||||
|
||||
/* Copy the whole pbuf queue p into the single pbuf r */
|
||||
if ((err = pbuf_copy(r, p)) != ERR_OK) {
|
||||
pbuf_free(r);
|
||||
LINK_STATS_INC(link.memerr);
|
||||
LINK_STATS_INC(link.drop);
|
||||
snmp_inc_ifoutdiscards(stats_if);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Put the packet on a linked list which gets emptied through calling
|
||||
netif_poll(). */
|
||||
|
||||
/* let last point to the last pbuf in chain r */
|
||||
for (last = r; last->next != NULL; last = last->next);
|
||||
|
||||
SYS_ARCH_PROTECT(lev);
|
||||
if(netif->loop_first != NULL) {
|
||||
LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL);
|
||||
netif->loop_last->next = r;
|
||||
netif->loop_last = last;
|
||||
} else {
|
||||
netif->loop_first = r;
|
||||
netif->loop_last = last;
|
||||
}
|
||||
SYS_ARCH_UNPROTECT(lev);
|
||||
|
||||
LINK_STATS_INC(link.xmit);
|
||||
snmp_add_ifoutoctets(stats_if, p->tot_len);
|
||||
snmp_inc_ifoutucastpkts(stats_if);
|
||||
|
||||
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
|
||||
/* For multithreading environment, schedule a call to netif_poll */
|
||||
tcpip_callback((tcpip_callback_fn)netif_poll, netif);
|
||||
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call netif_poll() in the main loop of your application. This is to prevent
|
||||
* reentering non-reentrant functions like tcp_input(). Packets passed to
|
||||
* netif_loop_output() are put on a list that is passed to netif->input() by
|
||||
* netif_poll().
|
||||
*/
|
||||
void
|
||||
netif_poll(struct netif *netif)
|
||||
{
|
||||
struct pbuf *in;
|
||||
/* If we have a loopif, SNMP counters are adjusted for it,
|
||||
* if not they are adjusted for 'netif'. */
|
||||
#if LWIP_SNMP
|
||||
#if LWIP_HAVE_LOOPIF
|
||||
struct netif *stats_if = &loop_netif;
|
||||
#else /* LWIP_HAVE_LOOPIF */
|
||||
struct netif *stats_if = netif;
|
||||
#endif /* LWIP_HAVE_LOOPIF */
|
||||
#endif /* LWIP_SNMP */
|
||||
SYS_ARCH_DECL_PROTECT(lev);
|
||||
|
||||
do {
|
||||
/* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
|
||||
SYS_ARCH_PROTECT(lev);
|
||||
in = netif->loop_first;
|
||||
if (in != NULL) {
|
||||
struct pbuf *in_end = in;
|
||||
#if LWIP_LOOPBACK_MAX_PBUFS
|
||||
u8_t clen = pbuf_clen(in);
|
||||
/* adjust the number of pbufs on queue */
|
||||
LWIP_ASSERT("netif->loop_cnt_current underflow",
|
||||
((netif->loop_cnt_current - clen) < netif->loop_cnt_current));
|
||||
netif->loop_cnt_current -= clen;
|
||||
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
|
||||
while (in_end->len != in_end->tot_len) {
|
||||
LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
|
||||
in_end = in_end->next;
|
||||
}
|
||||
/* 'in_end' now points to the last pbuf from 'in' */
|
||||
if (in_end == netif->loop_last) {
|
||||
/* this was the last pbuf in the list */
|
||||
netif->loop_first = netif->loop_last = NULL;
|
||||
} else {
|
||||
/* pop the pbuf off the list */
|
||||
netif->loop_first = in_end->next;
|
||||
LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL);
|
||||
}
|
||||
/* De-queue the pbuf from its successors on the 'loop_' list. */
|
||||
in_end->next = NULL;
|
||||
}
|
||||
SYS_ARCH_UNPROTECT(lev);
|
||||
|
||||
if (in != NULL) {
|
||||
LINK_STATS_INC(link.recv);
|
||||
snmp_add_ifinoctets(stats_if, in->tot_len);
|
||||
snmp_inc_ifinucastpkts(stats_if);
|
||||
/* loopback packets are always IP packets! */
|
||||
if (ip_input(in, netif) != ERR_OK) {
|
||||
pbuf_free(in);
|
||||
}
|
||||
/* Don't reference the packet any more! */
|
||||
in = NULL;
|
||||
}
|
||||
/* go on while there is a packet on the list */
|
||||
} while (netif->loop_first != NULL);
|
||||
}
|
||||
|
||||
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
|
||||
/**
|
||||
* Calls netif_poll() for every netif on the netif_list.
|
||||
*/
|
||||
void
|
||||
netif_poll_all(void)
|
||||
{
|
||||
struct netif *netif = netif_list;
|
||||
/* loop through netifs */
|
||||
while (netif != NULL) {
|
||||
netif_poll(netif);
|
||||
/* proceed to next network interface */
|
||||
netif = netif->next;
|
||||
}
|
||||
}
|
||||
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
|
||||
#if LWIP_IPV6
|
||||
s8_t
|
||||
netif_matches_ip6_addr(struct netif * netif, ip6_addr_t * ip6addr)
|
||||
{
|
||||
s8_t i;
|
||||
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
|
||||
if (ip6_addr_cmp(netif_ip6_addr(netif, i), ip6addr)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit)
|
||||
{
|
||||
u8_t i, addr_index;
|
||||
|
||||
/* Link-local prefix. */
|
||||
netif->ip6_addr[0].addr[0] = PP_HTONL(0xfe800000ul);
|
||||
netif->ip6_addr[0].addr[1] = 0;
|
||||
|
||||
/* Generate interface ID. */
|
||||
if (from_mac_48bit) {
|
||||
/* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */
|
||||
netif->ip6_addr[0].addr[2] = htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) |
|
||||
((u32_t)(netif->hwaddr[1]) << 16) |
|
||||
((u32_t)(netif->hwaddr[2]) << 8) |
|
||||
(0xff));
|
||||
netif->ip6_addr[0].addr[3] = htonl((0xfeul << 24) |
|
||||
((u32_t)(netif->hwaddr[3]) << 16) |
|
||||
((u32_t)(netif->hwaddr[4]) << 8) |
|
||||
(netif->hwaddr[5]));
|
||||
}
|
||||
else {
|
||||
/* Use hwaddr directly as interface ID. */
|
||||
netif->ip6_addr[0].addr[2] = 0;
|
||||
netif->ip6_addr[0].addr[3] = 0;
|
||||
|
||||
addr_index = 3;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (i == 4) {
|
||||
addr_index--;
|
||||
}
|
||||
netif->ip6_addr[0].addr[addr_index] |= ((u32_t)(netif->hwaddr[netif->hwaddr_len - i - 1])) << (8 * (i & 0x03));
|
||||
}
|
||||
}
|
||||
|
||||
/* Set address state. */
|
||||
#if LWIP_IPV6_DUP_DETECT_ATTEMPTS
|
||||
/* Will perform duplicate address detection (DAD). */
|
||||
netif->ip6_addr_state[0] = IP6_ADDR_TENTATIVE;
|
||||
#else
|
||||
/* Consider address valid. */
|
||||
netif->ip6_addr_state[0] = IP6_ADDR_PREFERRED;
|
||||
#endif /* LWIP_IPV6_AUTOCONFIG */
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
469
src/core/pbuf.c
469
src/core/pbuf.c
@@ -70,6 +70,12 @@
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "arch/perf.h"
|
||||
#if TCP_QUEUE_OOSEQ
|
||||
#include "lwip/tcp_impl.h"
|
||||
#endif
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
#include "lwip/inet_chksum.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -78,6 +84,72 @@
|
||||
aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
|
||||
#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
|
||||
|
||||
#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS
|
||||
#define PBUF_POOL_IS_EMPTY()
|
||||
#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
|
||||
/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
|
||||
#ifndef PBUF_POOL_FREE_OOSEQ
|
||||
#define PBUF_POOL_FREE_OOSEQ 1
|
||||
#endif /* PBUF_POOL_FREE_OOSEQ */
|
||||
|
||||
#if PBUF_POOL_FREE_OOSEQ
|
||||
#include "lwip/tcpip.h"
|
||||
#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
|
||||
static u8_t pbuf_free_ooseq_queued;
|
||||
/**
|
||||
* Attempt to reclaim some memory from queued out-of-sequence TCP segments
|
||||
* if we run out of pool pbufs. It's better to give priority to new packets
|
||||
* if we're running out.
|
||||
*
|
||||
* This must be done in the correct thread context therefore this function
|
||||
* can only be used with NO_SYS=0 and through tcpip_callback.
|
||||
*/
|
||||
static void
|
||||
pbuf_free_ooseq(void* arg)
|
||||
{
|
||||
struct tcp_pcb* pcb;
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
pbuf_free_ooseq_queued = 0;
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
|
||||
for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
|
||||
if (NULL != pcb->ooseq) {
|
||||
/** Free the ooseq pbufs of one PCB only */
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n"));
|
||||
tcp_segs_free(pcb->ooseq);
|
||||
pcb->ooseq = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Queue a call to pbuf_free_ooseq if not already queued. */
|
||||
static void
|
||||
pbuf_pool_is_empty(void)
|
||||
{
|
||||
u8_t queued;
|
||||
SYS_ARCH_DECL_PROTECT(old_level);
|
||||
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
queued = pbuf_free_ooseq_queued;
|
||||
pbuf_free_ooseq_queued = 1;
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
|
||||
if(!queued) {
|
||||
/* queue a call to pbuf_free_ooseq if not already queued */
|
||||
if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) {
|
||||
SYS_ARCH_PROTECT(old_level);
|
||||
pbuf_free_ooseq_queued = 0;
|
||||
SYS_ARCH_UNPROTECT(old_level);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* PBUF_POOL_FREE_OOSEQ */
|
||||
#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
|
||||
|
||||
/**
|
||||
* Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
|
||||
*
|
||||
@@ -115,24 +187,24 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
||||
struct pbuf *p, *q, *r;
|
||||
u16_t offset;
|
||||
s32_t rem_len; /* remaining length */
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F")\n", length));
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
|
||||
|
||||
/* determine header offset */
|
||||
offset = 0;
|
||||
switch (layer) {
|
||||
case PBUF_TRANSPORT:
|
||||
/* add room for transport (often TCP) layer header */
|
||||
offset += PBUF_TRANSPORT_HLEN;
|
||||
/* FALLTHROUGH */
|
||||
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN;
|
||||
break;
|
||||
case PBUF_IP:
|
||||
/* add room for IP layer header */
|
||||
offset += PBUF_IP_HLEN;
|
||||
/* FALLTHROUGH */
|
||||
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN;
|
||||
break;
|
||||
case PBUF_LINK:
|
||||
/* add room for link layer header */
|
||||
offset += PBUF_LINK_HLEN;
|
||||
offset = PBUF_LINK_HLEN;
|
||||
break;
|
||||
case PBUF_RAW:
|
||||
offset = 0;
|
||||
break;
|
||||
default:
|
||||
LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
|
||||
@@ -142,9 +214,10 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
||||
switch (type) {
|
||||
case PBUF_POOL:
|
||||
/* allocate head of pbuf chain into p */
|
||||
p = memp_malloc(MEMP_PBUF_POOL);
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
|
||||
p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
|
||||
if (p == NULL) {
|
||||
PBUF_POOL_IS_EMPTY();
|
||||
return NULL;
|
||||
}
|
||||
p->type = type;
|
||||
@@ -161,6 +234,8 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
||||
LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
|
||||
((u8_t*)p->payload + p->len <=
|
||||
(u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
|
||||
LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT",
|
||||
(PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 );
|
||||
/* set reference count (needed here in case we fail) */
|
||||
p->ref = 1;
|
||||
|
||||
@@ -172,8 +247,9 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
||||
rem_len = length - p->len;
|
||||
/* any remaining pbufs to be allocated? */
|
||||
while (rem_len > 0) {
|
||||
q = memp_malloc(MEMP_PBUF_POOL);
|
||||
q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
|
||||
if (q == NULL) {
|
||||
PBUF_POOL_IS_EMPTY();
|
||||
/* free chain so far allocated */
|
||||
pbuf_free(p);
|
||||
/* bail out unsuccesfully */
|
||||
@@ -225,9 +301,10 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
||||
/* pbuf references existing (externally allocated) RAM payload? */
|
||||
case PBUF_REF:
|
||||
/* only allocate memory for the pbuf structure */
|
||||
p = memp_malloc(MEMP_PBUF);
|
||||
p = (struct pbuf *)memp_malloc(MEMP_PBUF);
|
||||
if (p == NULL) {
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
|
||||
(type == PBUF_ROM) ? "ROM" : "REF"));
|
||||
return NULL;
|
||||
}
|
||||
@@ -245,10 +322,71 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
||||
p->ref = 1;
|
||||
/* set flags */
|
||||
p->flags = 0;
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
|
||||
return p;
|
||||
}
|
||||
|
||||
#if LWIP_SUPPORT_CUSTOM_PBUF
|
||||
/** Initialize a custom pbuf (already allocated).
|
||||
*
|
||||
* @param layer flag to define header size
|
||||
* @param length size of the pbuf's payload
|
||||
* @param type type of the pbuf (only used to treat the pbuf accordingly, as
|
||||
* this function allocates no memory)
|
||||
* @param p pointer to the custom pbuf to initialize (already allocated)
|
||||
* @param payload_mem pointer to the buffer that is used for payload and headers,
|
||||
* must be at least big enough to hold 'length' plus the header size,
|
||||
* may be NULL if set later
|
||||
* @param payload_mem_len the size of the 'payload_mem' buffer, must be at least
|
||||
* big enough to hold 'length' plus the header size
|
||||
*/
|
||||
struct pbuf*
|
||||
pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p,
|
||||
void *payload_mem, u16_t payload_mem_len)
|
||||
{
|
||||
u16_t offset;
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length));
|
||||
|
||||
/* determine header offset */
|
||||
switch (l) {
|
||||
case PBUF_TRANSPORT:
|
||||
/* add room for transport (often TCP) layer header */
|
||||
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN;
|
||||
break;
|
||||
case PBUF_IP:
|
||||
/* add room for IP layer header */
|
||||
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN;
|
||||
break;
|
||||
case PBUF_LINK:
|
||||
/* add room for link layer header */
|
||||
offset = PBUF_LINK_HLEN;
|
||||
break;
|
||||
case PBUF_RAW:
|
||||
offset = 0;
|
||||
break;
|
||||
default:
|
||||
LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) {
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p->pbuf.next = NULL;
|
||||
if (payload_mem != NULL) {
|
||||
p->pbuf.payload = LWIP_MEM_ALIGN((void *)((u8_t *)payload_mem + offset));
|
||||
} else {
|
||||
p->pbuf.payload = NULL;
|
||||
}
|
||||
p->pbuf.flags = PBUF_FLAG_IS_CUSTOM;
|
||||
p->pbuf.len = p->pbuf.tot_len = length;
|
||||
p->pbuf.type = type;
|
||||
p->pbuf.ref = 1;
|
||||
return &p->pbuf;
|
||||
}
|
||||
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
|
||||
|
||||
/**
|
||||
* Shrink a pbuf chain to a desired length.
|
||||
@@ -272,6 +410,7 @@ pbuf_realloc(struct pbuf *p, u16_t new_len)
|
||||
u16_t rem_len; /* remaining length */
|
||||
s32_t grow;
|
||||
|
||||
LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
|
||||
LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
|
||||
p->type == PBUF_ROM ||
|
||||
p->type == PBUF_RAM ||
|
||||
@@ -299,6 +438,7 @@ pbuf_realloc(struct pbuf *p, u16_t new_len)
|
||||
q->tot_len += (u16_t)grow;
|
||||
/* proceed to next pbuf in chain */
|
||||
q = q->next;
|
||||
LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
|
||||
}
|
||||
/* we have now reached the new last pbuf (in q) */
|
||||
/* rem_len == desired length for pbuf q */
|
||||
@@ -307,8 +447,8 @@ pbuf_realloc(struct pbuf *p, u16_t new_len)
|
||||
/* (other types merely adjust their length fields */
|
||||
if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
|
||||
/* reallocate and adjust the length of the pbuf that will be split */
|
||||
q = mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);
|
||||
LWIP_ASSERT("mem_realloc give q == NULL", q != NULL);
|
||||
q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len);
|
||||
LWIP_ASSERT("mem_trim returned q == NULL", q != NULL);
|
||||
}
|
||||
/* adjust length fields for new last pbuf */
|
||||
q->len = rem_len;
|
||||
@@ -352,8 +492,9 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment)
|
||||
u16_t increment_magnitude;
|
||||
|
||||
LWIP_ASSERT("p != NULL", p != NULL);
|
||||
if ((header_size_increment == 0) || (p == NULL))
|
||||
if ((header_size_increment == 0) || (p == NULL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (header_size_increment < 0){
|
||||
increment_magnitude = -header_size_increment;
|
||||
@@ -383,9 +524,9 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment)
|
||||
p->payload = (u8_t *)p->payload - header_size_increment;
|
||||
/* boundary check fails? */
|
||||
if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {
|
||||
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
|
||||
(void *)p->payload,
|
||||
(void *)(p + 1)));\
|
||||
LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
|
||||
(void *)p->payload, (void *)(p + 1)));
|
||||
/* restore old payload pointer */
|
||||
p->payload = payload;
|
||||
/* bail out unsuccesfully */
|
||||
@@ -402,8 +543,7 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment)
|
||||
* bail out unsuccesfully */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/* Unknown type */
|
||||
LWIP_ASSERT("bad pbuf type", 0);
|
||||
return 1;
|
||||
@@ -412,7 +552,7 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment)
|
||||
p->len += header_size_increment;
|
||||
p->tot_len += header_size_increment;
|
||||
|
||||
LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n",
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n",
|
||||
(void *)payload, (void *)p->payload, header_size_increment));
|
||||
|
||||
return 0;
|
||||
@@ -461,10 +601,11 @@ pbuf_free(struct pbuf *p)
|
||||
if (p == NULL) {
|
||||
LWIP_ASSERT("p != NULL", p != NULL);
|
||||
/* if assertions are disabled, proceed with debug output */
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("pbuf_free(p == NULL) was called.\n"));
|
||||
return 0;
|
||||
}
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p));
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p));
|
||||
|
||||
PERF_START;
|
||||
|
||||
@@ -491,17 +632,27 @@ pbuf_free(struct pbuf *p)
|
||||
if (ref == 0) {
|
||||
/* remember next pbuf in chain for next iteration */
|
||||
q = p->next;
|
||||
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p));
|
||||
LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
|
||||
type = p->type;
|
||||
/* is this a pbuf from the pool? */
|
||||
if (type == PBUF_POOL) {
|
||||
memp_free(MEMP_PBUF_POOL, p);
|
||||
/* is this a ROM or RAM referencing pbuf? */
|
||||
} else if (type == PBUF_ROM || type == PBUF_REF) {
|
||||
memp_free(MEMP_PBUF, p);
|
||||
/* type == PBUF_RAM */
|
||||
} else {
|
||||
mem_free(p);
|
||||
#if LWIP_SUPPORT_CUSTOM_PBUF
|
||||
/* is this a custom pbuf? */
|
||||
if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) {
|
||||
struct pbuf_custom *pc = (struct pbuf_custom*)p;
|
||||
LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL);
|
||||
pc->custom_free_function(p);
|
||||
} else
|
||||
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
|
||||
{
|
||||
/* is this a pbuf from the pool? */
|
||||
if (type == PBUF_POOL) {
|
||||
memp_free(MEMP_PBUF_POOL, p);
|
||||
/* is this a ROM or RAM referencing pbuf? */
|
||||
} else if (type == PBUF_ROM || type == PBUF_REF) {
|
||||
memp_free(MEMP_PBUF, p);
|
||||
/* type == PBUF_RAM */
|
||||
} else {
|
||||
mem_free(p);
|
||||
}
|
||||
}
|
||||
count++;
|
||||
/* proceed to next pbuf */
|
||||
@@ -509,7 +660,7 @@ pbuf_free(struct pbuf *p)
|
||||
/* p->ref > 0, this pbuf is still referenced to */
|
||||
/* (and so the remaining pbufs in chain as well) */
|
||||
} else {
|
||||
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
|
||||
LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
|
||||
/* stop walking through the chain */
|
||||
p = NULL;
|
||||
}
|
||||
@@ -614,7 +765,7 @@ pbuf_chain(struct pbuf *h, struct pbuf *t)
|
||||
pbuf_cat(h, t);
|
||||
/* t is now referenced by h */
|
||||
pbuf_ref(t);
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -643,10 +794,10 @@ pbuf_dechain(struct pbuf *p)
|
||||
/* total length of pbuf p is its own length only */
|
||||
p->tot_len = p->len;
|
||||
/* q is no longer referenced by p, free it */
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
|
||||
tail_gone = pbuf_free(q);
|
||||
if (tail_gone > 0) {
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE,
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,
|
||||
("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
|
||||
}
|
||||
/* return remaining tail or NULL if deallocated */
|
||||
@@ -667,8 +818,8 @@ pbuf_dechain(struct pbuf *p)
|
||||
*
|
||||
* @note Only one packet is copied, no packet queue!
|
||||
*
|
||||
* @param p_to pbuf source of the copy
|
||||
* @param p_from pbuf destination of the copy
|
||||
* @param p_to pbuf destination of the copy
|
||||
* @param p_from pbuf source of the copy
|
||||
*
|
||||
* @return ERR_OK if pbuf was copied
|
||||
* ERR_ARG if one of the pbufs is NULL or p_to is not big
|
||||
@@ -679,7 +830,7 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
|
||||
{
|
||||
u16_t offset_to=0, offset_from=0, len;
|
||||
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_copy(%p, %p)\n",
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
|
||||
(void*)p_to, (void*)p_from));
|
||||
|
||||
/* is the target big enough to hold the source? */
|
||||
@@ -725,7 +876,7 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
|
||||
(p_to->next == NULL), return ERR_VAL;);
|
||||
}
|
||||
} while (p_from);
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 1, ("pbuf_copy: end of chain reached.\n"));
|
||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n"));
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -735,8 +886,10 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
|
||||
*
|
||||
* @param buf the pbuf from which to copy data
|
||||
* @param dataptr the application supplied buffer
|
||||
* @param len length of data to copy (dataptr must be big enough)
|
||||
* @param len length of data to copy (dataptr must be big enough). No more
|
||||
* than buf->tot_len will be copied, irrespective of len
|
||||
* @param offset offset into the packet buffer from where to begin copying len bytes
|
||||
* @return the number of bytes copied, or 0 on failure
|
||||
*/
|
||||
u16_t
|
||||
pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
|
||||
@@ -746,8 +899,8 @@ pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
|
||||
u16_t buf_copy_len;
|
||||
u16_t copied_total = 0;
|
||||
|
||||
LWIP_ERROR("netbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
|
||||
LWIP_ERROR("netbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
|
||||
LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
|
||||
LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
|
||||
|
||||
left = 0;
|
||||
|
||||
@@ -775,3 +928,229 @@ pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
|
||||
}
|
||||
return copied_total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy application supplied data into a pbuf.
|
||||
* This function can only be used to copy the equivalent of buf->tot_len data.
|
||||
*
|
||||
* @param buf pbuf to fill with data
|
||||
* @param dataptr application supplied data buffer
|
||||
* @param len length of the application supplied data buffer
|
||||
*
|
||||
* @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough
|
||||
*/
|
||||
err_t
|
||||
pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
|
||||
{
|
||||
struct pbuf *p;
|
||||
u16_t buf_copy_len;
|
||||
u16_t total_copy_len = len;
|
||||
u16_t copied_total = 0;
|
||||
|
||||
LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;);
|
||||
LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;);
|
||||
|
||||
if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
/* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
|
||||
for(p = buf; total_copy_len != 0; p = p->next) {
|
||||
LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);
|
||||
buf_copy_len = total_copy_len;
|
||||
if (buf_copy_len > p->len) {
|
||||
/* this pbuf cannot hold all remaining data */
|
||||
buf_copy_len = p->len;
|
||||
}
|
||||
/* copy the necessary parts of the buffer */
|
||||
MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);
|
||||
total_copy_len -= buf_copy_len;
|
||||
copied_total += buf_copy_len;
|
||||
}
|
||||
LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a single pbuf out of a queue of pbufs.
|
||||
*
|
||||
* @remark: Either the source pbuf 'p' is freed by this function or the original
|
||||
* pbuf 'p' is returned, therefore the caller has to check the result!
|
||||
*
|
||||
* @param p the source pbuf
|
||||
* @param layer pbuf_layer of the new pbuf
|
||||
*
|
||||
* @return a new, single pbuf (p->next is NULL)
|
||||
* or the old pbuf if allocation fails
|
||||
*/
|
||||
struct pbuf*
|
||||
pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
|
||||
{
|
||||
struct pbuf *q;
|
||||
err_t err;
|
||||
if (p->next == NULL) {
|
||||
return p;
|
||||
}
|
||||
q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);
|
||||
if (q == NULL) {
|
||||
/* @todo: what do we do now? */
|
||||
return p;
|
||||
}
|
||||
err = pbuf_copy(q, p);
|
||||
LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
|
||||
pbuf_free(p);
|
||||
return q;
|
||||
}
|
||||
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
/**
|
||||
* Copies data into a single pbuf (*not* into a pbuf queue!) and updates
|
||||
* the checksum while copying
|
||||
*
|
||||
* @param p the pbuf to copy data into
|
||||
* @param start_offset offset of p->payload where to copy the data to
|
||||
* @param dataptr data to copy into the pbuf
|
||||
* @param len length of data to copy into the pbuf
|
||||
* @param chksum pointer to the checksum which is updated
|
||||
* @return ERR_OK if successful, another error if the data does not fit
|
||||
* within the (first) pbuf (no pbuf queues!)
|
||||
*/
|
||||
err_t
|
||||
pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
|
||||
u16_t len, u16_t *chksum)
|
||||
{
|
||||
u32_t acc;
|
||||
u16_t copy_chksum;
|
||||
char *dst_ptr;
|
||||
LWIP_ASSERT("p != NULL", p != NULL);
|
||||
LWIP_ASSERT("dataptr != NULL", dataptr != NULL);
|
||||
LWIP_ASSERT("chksum != NULL", chksum != NULL);
|
||||
LWIP_ASSERT("len != 0", len != 0);
|
||||
|
||||
if ((start_offset >= p->len) || (start_offset + len > p->len)) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
dst_ptr = ((char*)p->payload) + start_offset;
|
||||
copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len);
|
||||
if ((start_offset & 1) != 0) {
|
||||
copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum);
|
||||
}
|
||||
acc = *chksum;
|
||||
acc += copy_chksum;
|
||||
*chksum = FOLD_U32T(acc);
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
|
||||
/** Get one byte from the specified position in a pbuf
|
||||
* WARNING: returns zero for offset >= p->tot_len
|
||||
*
|
||||
* @param p pbuf to parse
|
||||
* @param offset offset into p of the byte to return
|
||||
* @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len
|
||||
*/
|
||||
u8_t
|
||||
pbuf_get_at(struct pbuf* p, u16_t offset)
|
||||
{
|
||||
u16_t copy_from = offset;
|
||||
struct pbuf* q = p;
|
||||
|
||||
/* get the correct pbuf */
|
||||
while ((q != NULL) && (q->len <= copy_from)) {
|
||||
copy_from -= q->len;
|
||||
q = q->next;
|
||||
}
|
||||
/* return requested data if pbuf is OK */
|
||||
if ((q != NULL) && (q->len > copy_from)) {
|
||||
return ((u8_t*)q->payload)[copy_from];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Compare pbuf contents at specified offset with memory s2, both of length n
|
||||
*
|
||||
* @param p pbuf to compare
|
||||
* @param offset offset into p at wich to start comparing
|
||||
* @param s2 buffer to compare
|
||||
* @param n length of buffer to compare
|
||||
* @return zero if equal, nonzero otherwise
|
||||
* (0xffff if p is too short, diffoffset+1 otherwise)
|
||||
*/
|
||||
u16_t
|
||||
pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)
|
||||
{
|
||||
u16_t start = offset;
|
||||
struct pbuf* q = p;
|
||||
|
||||
/* get the correct pbuf */
|
||||
while ((q != NULL) && (q->len <= start)) {
|
||||
start -= q->len;
|
||||
q = q->next;
|
||||
}
|
||||
/* return requested data if pbuf is OK */
|
||||
if ((q != NULL) && (q->len > start)) {
|
||||
u16_t i;
|
||||
for(i = 0; i < n; i++) {
|
||||
u8_t a = pbuf_get_at(q, start + i);
|
||||
u8_t b = ((u8_t*)s2)[i];
|
||||
if (a != b) {
|
||||
return i+1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
/** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset
|
||||
* start_offset.
|
||||
*
|
||||
* @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
|
||||
* return value 'not found'
|
||||
* @param mem search for the contents of this buffer
|
||||
* @param mem_len length of 'mem'
|
||||
* @param start_offset offset into p at which to start searching
|
||||
* @return 0xFFFF if substr was not found in p or the index where it was found
|
||||
*/
|
||||
u16_t
|
||||
pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)
|
||||
{
|
||||
u16_t i;
|
||||
u16_t max = p->tot_len - mem_len;
|
||||
if (p->tot_len >= mem_len + start_offset) {
|
||||
for(i = start_offset; i <= max; ) {
|
||||
u16_t plus = pbuf_memcmp(p, i, mem, mem_len);
|
||||
if (plus == 0) {
|
||||
return i;
|
||||
} else {
|
||||
i += plus;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0xFFFF;
|
||||
}
|
||||
|
||||
/** Find occurrence of substr with length substr_len in pbuf p, start at offset
|
||||
* start_offset
|
||||
* WARNING: in contrast to strstr(), this one does not stop at the first \0 in
|
||||
* the pbuf/source string!
|
||||
*
|
||||
* @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
|
||||
* return value 'not found'
|
||||
* @param substr string to search for in p, maximum length is 0xFFFE
|
||||
* @return 0xFFFF if substr was not found in p or the index where it was found
|
||||
*/
|
||||
u16_t
|
||||
pbuf_strstr(struct pbuf* p, const char* substr)
|
||||
{
|
||||
size_t substr_len;
|
||||
if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) {
|
||||
return 0xFFFF;
|
||||
}
|
||||
substr_len = strlen(substr);
|
||||
if (substr_len >= 0xFFFF) {
|
||||
return 0xFFFF;
|
||||
}
|
||||
return pbuf_memfind(p, substr, (u16_t)substr_len, 0);
|
||||
}
|
||||
|
||||
191
src/core/raw.c
191
src/core/raw.c
@@ -44,13 +44,13 @@
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/raw.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "arch/perf.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -81,36 +81,61 @@ raw_input(struct pbuf *p, struct netif *inp)
|
||||
struct ip_hdr *iphdr;
|
||||
s16_t proto;
|
||||
u8_t eaten = 0;
|
||||
#if LWIP_IPV6
|
||||
struct ip6_hdr *ip6hdr;
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
|
||||
LWIP_UNUSED_ARG(inp);
|
||||
|
||||
iphdr = p->payload;
|
||||
proto = IPH_PROTO(iphdr);
|
||||
iphdr = (struct ip_hdr *)p->payload;
|
||||
#if LWIP_IPV6
|
||||
if (IPH_V(iphdr) == 6) {
|
||||
ip6hdr = (struct ip6_hdr *)p->payload;
|
||||
proto = IP6H_NEXTH(ip6hdr);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
proto = IPH_PROTO(iphdr);
|
||||
}
|
||||
|
||||
prev = NULL;
|
||||
pcb = raw_pcbs;
|
||||
/* loop through all raw pcbs until the packet is eaten by one */
|
||||
/* this allows multiple pcbs to match against the packet by design */
|
||||
while ((eaten == 0) && (pcb != NULL)) {
|
||||
if (pcb->protocol == proto) {
|
||||
/* receive callback function available? */
|
||||
if (pcb->recv != NULL) {
|
||||
/* the receive callback function did not eat the packet? */
|
||||
if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0)
|
||||
{
|
||||
/* receive function ate the packet */
|
||||
p = NULL;
|
||||
eaten = 1;
|
||||
if (prev != NULL) {
|
||||
/* move the pcb to the front of raw_pcbs so that is
|
||||
found faster next time */
|
||||
prev->next = pcb->next;
|
||||
pcb->next = raw_pcbs;
|
||||
raw_pcbs = pcb;
|
||||
if ((pcb->protocol == proto) && IP_PCB_IPVER_INPUT_MATCH(pcb) &&
|
||||
(ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip) ||
|
||||
ipX_addr_cmp(PCB_ISIPV6(pcb), &(pcb->local_ip), ipX_current_dest_addr()))) {
|
||||
#if IP_SOF_BROADCAST_RECV
|
||||
/* broadcast filter? */
|
||||
if (((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(ip_current_dest_addr(), inp))
|
||||
#if LWIP_IPV6
|
||||
&& !PCB_ISIPV6(pcb)
|
||||
#endif /* LWIP_IPV6 */
|
||||
)
|
||||
#endif /* IP_SOF_BROADCAST_RECV */
|
||||
{
|
||||
/* receive callback function available? */
|
||||
if (pcb->recv.ip4 != NULL) {
|
||||
/* the receive callback function did not eat the packet? */
|
||||
eaten = pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr());
|
||||
if (eaten != 0) {
|
||||
/* receive function ate the packet */
|
||||
p = NULL;
|
||||
eaten = 1;
|
||||
if (prev != NULL) {
|
||||
/* move the pcb to the front of raw_pcbs so that is
|
||||
found faster next time */
|
||||
prev->next = pcb->next;
|
||||
pcb->next = raw_pcbs;
|
||||
raw_pcbs = pcb;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* no receive callback function was set for this raw PCB */
|
||||
}
|
||||
/* no receive callback function was set for this raw PCB */
|
||||
/* drop the packet */
|
||||
}
|
||||
prev = pcb;
|
||||
@@ -134,9 +159,9 @@ raw_input(struct pbuf *p, struct netif *inp)
|
||||
* @see raw_disconnect()
|
||||
*/
|
||||
err_t
|
||||
raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr)
|
||||
raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
|
||||
{
|
||||
ip_addr_set(&pcb->local_ip, ipaddr);
|
||||
ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->local_ip, ipaddr);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -154,9 +179,9 @@ raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr)
|
||||
* @see raw_disconnect() and raw_sendto()
|
||||
*/
|
||||
err_t
|
||||
raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr)
|
||||
raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr)
|
||||
{
|
||||
ip_addr_set(&pcb->remote_ip, ipaddr);
|
||||
ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->remote_ip, ipaddr);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -175,13 +200,10 @@ raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr)
|
||||
* available for others.
|
||||
*/
|
||||
void
|
||||
raw_recv(struct raw_pcb *pcb,
|
||||
u8_t (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p,
|
||||
struct ip_addr *addr),
|
||||
void *recv_arg)
|
||||
raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
|
||||
{
|
||||
/* remember recv() callback and user data */
|
||||
pcb->recv = recv;
|
||||
pcb->recv.ip4 = recv;
|
||||
pcb->recv_arg = recv_arg;
|
||||
}
|
||||
|
||||
@@ -198,39 +220,51 @@ raw_recv(struct raw_pcb *pcb,
|
||||
*
|
||||
*/
|
||||
err_t
|
||||
raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
|
||||
raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
|
||||
{
|
||||
err_t err;
|
||||
struct netif *netif;
|
||||
struct ip_addr *src_ip;
|
||||
ipX_addr_t *src_ip;
|
||||
struct pbuf *q; /* q will be sent down the stack */
|
||||
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("raw_sendto\n"));
|
||||
|
||||
s16_t header_size;
|
||||
ipX_addr_t *dst_ip = ip_2_ipX(ipaddr);
|
||||
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
|
||||
|
||||
header_size = (
|
||||
#if LWIP_IPV6
|
||||
PCB_ISIPV6(pcb) ? IP6_HLEN :
|
||||
#endif /* LWIP_IPV6 */
|
||||
IP_HLEN);
|
||||
|
||||
/* not enough space to add an IP header to first pbuf in given p chain? */
|
||||
if (pbuf_header(p, IP_HLEN)) {
|
||||
if (pbuf_header(p, header_size)) {
|
||||
/* allocate header in new pbuf */
|
||||
q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
|
||||
/* new header pbuf could not be allocated? */
|
||||
if (q == NULL) {
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 2, ("raw_sendto: could not allocate header\n"));
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
|
||||
return ERR_MEM;
|
||||
}
|
||||
/* chain header q in front of given pbuf p */
|
||||
pbuf_chain(q, p);
|
||||
if (p->tot_len != 0) {
|
||||
/* chain header q in front of given pbuf p */
|
||||
pbuf_chain(q, p);
|
||||
}
|
||||
/* { first pbuf q points to header pbuf } */
|
||||
LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
|
||||
} else {
|
||||
/* first pbuf q equals given pbuf */
|
||||
q = p;
|
||||
if(pbuf_header(q, -IP_HLEN)) {
|
||||
if(pbuf_header(q, -header_size)) {
|
||||
LWIP_ASSERT("Can't restore header we just removed!", 0);
|
||||
return ERR_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
if ((netif = ip_route(ipaddr)) == NULL) {
|
||||
LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr));
|
||||
|
||||
netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip);
|
||||
if (netif == NULL) {
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to "));
|
||||
ipX_addr_debug_print(PCB_ISIPV6(pcb), RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip);
|
||||
/* free any temporary header pbuf allocated by pbuf_header() */
|
||||
if (q != p) {
|
||||
pbuf_free(q);
|
||||
@@ -238,21 +272,43 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
||||
if (ip_addr_isany(&pcb->local_ip)) {
|
||||
#if IP_SOF_BROADCAST
|
||||
#if LWIP_IPV6
|
||||
/* @todo: why does IPv6 not filter broadcast with SOF_BROADCAST enabled? */
|
||||
if (!PCB_ISIPV6(pcb))
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
/* broadcast filter? */
|
||||
if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) {
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
|
||||
/* free any temporary header pbuf allocated by pbuf_header() */
|
||||
if (q != p) {
|
||||
pbuf_free(q);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
}
|
||||
#endif /* IP_SOF_BROADCAST */
|
||||
|
||||
if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) {
|
||||
/* use outgoing network interface IP address as source address */
|
||||
src_ip = &(netif->ip_addr);
|
||||
src_ip = ipX_netif_get_local_ipX(PCB_ISIPV6(pcb), netif, dst_ip);
|
||||
#if LWIP_IPV6
|
||||
if (src_ip == NULL) {
|
||||
if (q != p) {
|
||||
pbuf_free(q);
|
||||
}
|
||||
return ERR_RTE;
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
} else {
|
||||
/* use RAW PCB local IP address as source address */
|
||||
src_ip = &(pcb->local_ip);
|
||||
src_ip = &pcb->local_ip;
|
||||
}
|
||||
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = &(pcb->addr_hint);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = NULL;
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
|
||||
err = ipX_output_if(PCB_ISIPV6(pcb), q, ipX_2_ip(src_ip), ipX_2_ip(dst_ip), pcb->ttl, pcb->tos, pcb->protocol, netif);
|
||||
NETIF_SET_HWADDRHINT(netif, NULL);
|
||||
|
||||
/* did we chain a header earlier? */
|
||||
if (q != p) {
|
||||
@@ -272,7 +328,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
|
||||
err_t
|
||||
raw_send(struct raw_pcb *pcb, struct pbuf *p)
|
||||
{
|
||||
return raw_sendto(pcb, p, &pcb->remote_ip);
|
||||
return raw_sendto(pcb, p, ipX_2_ip(&pcb->remote_ip));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,12 +371,13 @@ raw_remove(struct raw_pcb *pcb)
|
||||
* @see raw_remove()
|
||||
*/
|
||||
struct raw_pcb *
|
||||
raw_new(u8_t proto) {
|
||||
raw_new(u8_t proto)
|
||||
{
|
||||
struct raw_pcb *pcb;
|
||||
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("raw_new\n"));
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n"));
|
||||
|
||||
pcb = memp_malloc(MEMP_RAW_PCB);
|
||||
pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB);
|
||||
/* could allocate RAW PCB? */
|
||||
if (pcb != NULL) {
|
||||
/* initialize PCB to all zeroes */
|
||||
@@ -333,4 +390,26 @@ raw_new(u8_t proto) {
|
||||
return pcb;
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
/**
|
||||
* Create a RAW PCB for IPv6.
|
||||
*
|
||||
* @return The RAW PCB which was created. NULL if the PCB data structure
|
||||
* could not be allocated.
|
||||
*
|
||||
* @param proto the protocol number (next header) of the IPv6 packet payload
|
||||
* (e.g. IP6_NEXTH_ICMP6)
|
||||
*
|
||||
* @see raw_remove()
|
||||
*/
|
||||
struct raw_pcb *
|
||||
raw_new_ip6(u8_t proto)
|
||||
{
|
||||
struct raw_pcb *pcb;
|
||||
pcb = raw_new(proto);
|
||||
ip_set_v6(pcb, 1);
|
||||
return pcb;
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#endif /* LWIP_RAW */
|
||||
|
||||
@@ -61,7 +61,7 @@ snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)
|
||||
plen += p->len;
|
||||
if (ofs < plen)
|
||||
{
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
msg_ptr += ofs - base;
|
||||
*type = *msg_ptr;
|
||||
return ERR_OK;
|
||||
@@ -94,7 +94,7 @@ snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length
|
||||
plen += p->len;
|
||||
if (ofs < plen)
|
||||
{
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
msg_ptr += ofs - base;
|
||||
|
||||
if (*msg_ptr < 0x80)
|
||||
@@ -125,7 +125,7 @@ snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
@@ -160,7 +160,7 @@ snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -186,7 +186,7 @@ snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
@@ -249,7 +249,7 @@ snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
|
||||
plen += p->len;
|
||||
if (ofs < plen)
|
||||
{
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
msg_ptr += ofs - base;
|
||||
if ((len > 0) && (len < 6))
|
||||
{
|
||||
@@ -273,7 +273,7 @@ snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
@@ -295,7 +295,7 @@ snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
@@ -349,7 +349,7 @@ snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)
|
||||
plen += p->len;
|
||||
if (ofs < plen)
|
||||
{
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
msg_ptr += ofs - base;
|
||||
if ((len > 0) && (len < 5))
|
||||
{
|
||||
@@ -386,7 +386,7 @@ snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
@@ -439,7 +439,7 @@ snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
|
||||
plen += p->len;
|
||||
if (ofs < plen)
|
||||
{
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
msg_ptr += ofs - base;
|
||||
|
||||
oid->len = 0;
|
||||
@@ -493,7 +493,7 @@ snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
@@ -519,7 +519,7 @@ snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
@@ -551,7 +551,7 @@ snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
@@ -607,7 +607,7 @@ snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw
|
||||
plen += p->len;
|
||||
if (ofs < plen)
|
||||
{
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
msg_ptr += ofs - base;
|
||||
if (raw_len >= len)
|
||||
{
|
||||
@@ -623,7 +623,7 @@ snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -190,7 +190,7 @@ snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type)
|
||||
plen += p->len;
|
||||
if (ofs < plen)
|
||||
{
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
msg_ptr += ofs - base;
|
||||
*msg_ptr = type;
|
||||
return ERR_OK;
|
||||
@@ -222,12 +222,12 @@ snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
|
||||
plen += p->len;
|
||||
if (ofs < plen)
|
||||
{
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
msg_ptr += ofs - base;
|
||||
|
||||
if (length < 0x80)
|
||||
{
|
||||
*msg_ptr = length;
|
||||
*msg_ptr = (u8_t)length;
|
||||
return ERR_OK;
|
||||
}
|
||||
else if (length < 0x100)
|
||||
@@ -239,14 +239,14 @@ snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* next octet in same pbuf */
|
||||
msg_ptr++;
|
||||
}
|
||||
*msg_ptr = length;
|
||||
*msg_ptr = (u8_t)length;
|
||||
return ERR_OK;
|
||||
}
|
||||
else
|
||||
@@ -265,7 +265,7 @@ snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
@@ -276,12 +276,12 @@ snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
|
||||
if (i == 0)
|
||||
{
|
||||
/* least significant length octet */
|
||||
*msg_ptr = length;
|
||||
*msg_ptr = (u8_t)length;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* most significant length octet */
|
||||
*msg_ptr = length >> 8;
|
||||
*msg_ptr = (u8_t)(length >> 8);
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
@@ -305,7 +305,7 @@ snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
|
||||
* @see snmp_asn1_enc_u32t_cnt()
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)
|
||||
snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value)
|
||||
{
|
||||
u16_t plen, base;
|
||||
u8_t *msg_ptr;
|
||||
@@ -317,7 +317,7 @@ snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)
|
||||
plen += p->len;
|
||||
if (ofs < plen)
|
||||
{
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
msg_ptr += ofs - base;
|
||||
|
||||
if (octets_needed == 5)
|
||||
@@ -331,7 +331,7 @@ snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
@@ -343,14 +343,14 @@ snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)
|
||||
while (octets_needed > 1)
|
||||
{
|
||||
octets_needed--;
|
||||
*msg_ptr = value >> (octets_needed << 3);
|
||||
*msg_ptr = (u8_t)(value >> (octets_needed << 3));
|
||||
ofs += 1;
|
||||
if (ofs >= plen)
|
||||
{
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
@@ -360,7 +360,7 @@ snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)
|
||||
}
|
||||
}
|
||||
/* (only) one least significant octet */
|
||||
*msg_ptr = value;
|
||||
*msg_ptr = (u8_t)value;
|
||||
return ERR_OK;
|
||||
}
|
||||
p = p->next;
|
||||
@@ -381,7 +381,7 @@ snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)
|
||||
* @see snmp_asn1_enc_s32t_cnt()
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value)
|
||||
snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value)
|
||||
{
|
||||
u16_t plen, base;
|
||||
u8_t *msg_ptr;
|
||||
@@ -393,20 +393,20 @@ snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value)
|
||||
plen += p->len;
|
||||
if (ofs < plen)
|
||||
{
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
msg_ptr += ofs - base;
|
||||
|
||||
while (octets_needed > 1)
|
||||
{
|
||||
octets_needed--;
|
||||
*msg_ptr = value >> (octets_needed << 3);
|
||||
*msg_ptr = (u8_t)(value >> (octets_needed << 3));
|
||||
ofs += 1;
|
||||
if (ofs >= plen)
|
||||
{
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
@@ -416,7 +416,7 @@ snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value)
|
||||
}
|
||||
}
|
||||
/* (only) one least significant octet */
|
||||
*msg_ptr = value;
|
||||
*msg_ptr = (u8_t)value;
|
||||
return ERR_OK;
|
||||
}
|
||||
p = p->next;
|
||||
@@ -447,7 +447,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
|
||||
plen += p->len;
|
||||
if (ofs < plen)
|
||||
{
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
msg_ptr += ofs - base;
|
||||
|
||||
if (ident_len > 1)
|
||||
@@ -460,7 +460,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
|
||||
else
|
||||
{
|
||||
/* calculate prefix */
|
||||
*msg_ptr = (ident[0] * 40) + ident[1];
|
||||
*msg_ptr = (u8_t)((ident[0] * 40) + ident[1]);
|
||||
}
|
||||
ofs += 1;
|
||||
if (ofs >= plen)
|
||||
@@ -468,7 +468,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
@@ -498,7 +498,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
|
||||
{
|
||||
u8_t code;
|
||||
|
||||
code = sub_id >> shift;
|
||||
code = (u8_t)(sub_id >> shift);
|
||||
if ((code != 0) || (tail != 0))
|
||||
{
|
||||
tail = 1;
|
||||
@@ -509,7 +509,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
@@ -529,7 +529,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
@@ -559,7 +559,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
|
||||
* @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
|
||||
*/
|
||||
err_t
|
||||
snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw)
|
||||
snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw)
|
||||
{
|
||||
u16_t plen, base;
|
||||
u8_t *msg_ptr;
|
||||
@@ -571,7 +571,7 @@ snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw)
|
||||
plen += p->len;
|
||||
if (ofs < plen)
|
||||
{
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
msg_ptr += ofs - base;
|
||||
|
||||
while (raw_len > 1)
|
||||
@@ -586,7 +586,7 @@ snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw)
|
||||
/* next octet in next pbuf */
|
||||
p = p->next;
|
||||
if (p == NULL) { return ERR_ARG; }
|
||||
msg_ptr = p->payload;
|
||||
msg_ptr = (u8_t*)p->payload;
|
||||
plen += p->len;
|
||||
}
|
||||
else
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -37,7 +37,8 @@
|
||||
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/snmp_structs.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
/** .iso.org.dod.internet address prefix, @see snmp_iso_*() */
|
||||
const s32_t prefix[4] = {1, 3, 6, 1};
|
||||
@@ -94,7 +95,7 @@ void
|
||||
snmp_ifindextonetif(s32_t ifindex, struct netif **netif)
|
||||
{
|
||||
struct netif *nif = netif_list;
|
||||
u16_t i, ifidx;
|
||||
s32_t i, ifidx;
|
||||
|
||||
ifidx = ifindex - 1;
|
||||
i = 0;
|
||||
@@ -118,7 +119,7 @@ snmp_netiftoifindex(struct netif *netif, s32_t *ifidx)
|
||||
u16_t i;
|
||||
|
||||
i = 0;
|
||||
while (nif != netif)
|
||||
while ((nif != NULL) && (nif != netif))
|
||||
{
|
||||
nif = nif->next;
|
||||
i++;
|
||||
@@ -132,18 +133,9 @@ snmp_netiftoifindex(struct netif *netif, s32_t *ifidx)
|
||||
* @param ip points to output struct
|
||||
*/
|
||||
void
|
||||
snmp_oidtoip(s32_t *ident, struct ip_addr *ip)
|
||||
snmp_oidtoip(s32_t *ident, ip_addr_t *ip)
|
||||
{
|
||||
u32_t ipa;
|
||||
|
||||
ipa = ident[0];
|
||||
ipa <<= 8;
|
||||
ipa |= ident[1];
|
||||
ipa <<= 8;
|
||||
ipa |= ident[2];
|
||||
ipa <<= 8;
|
||||
ipa |= ident[3];
|
||||
ip->addr = ipa;
|
||||
IP4_ADDR(ip, ident[0], ident[1], ident[2], ident[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,15 +144,12 @@ snmp_oidtoip(s32_t *ident, struct ip_addr *ip)
|
||||
* @param ident points to s32_t ident[4] output
|
||||
*/
|
||||
void
|
||||
snmp_iptooid(struct ip_addr *ip, s32_t *ident)
|
||||
snmp_iptooid(ip_addr_t *ip, s32_t *ident)
|
||||
{
|
||||
u32_t ipa;
|
||||
|
||||
ipa = ip->addr;
|
||||
ident[0] = (ipa >> 24) & 0xff;
|
||||
ident[1] = (ipa >> 16) & 0xff;
|
||||
ident[2] = (ipa >> 8) & 0xff;
|
||||
ident[3] = ipa & 0xff;
|
||||
ident[0] = ip4_addr1(ip);
|
||||
ident[1] = ip4_addr2(ip);
|
||||
ident[2] = ip4_addr3(ip);
|
||||
ident[3] = ip4_addr4(ip);
|
||||
}
|
||||
|
||||
struct mib_list_node *
|
||||
@@ -168,7 +157,7 @@ snmp_mib_ln_alloc(s32_t id)
|
||||
{
|
||||
struct mib_list_node *ln;
|
||||
|
||||
ln = (struct mib_list_node *)mem_malloc(sizeof(struct mib_list_node));
|
||||
ln = (struct mib_list_node *)memp_malloc(MEMP_SNMP_NODE);
|
||||
if (ln != NULL)
|
||||
{
|
||||
ln->prev = NULL;
|
||||
@@ -182,7 +171,7 @@ snmp_mib_ln_alloc(s32_t id)
|
||||
void
|
||||
snmp_mib_ln_free(struct mib_list_node *ln)
|
||||
{
|
||||
mem_free(ln);
|
||||
memp_free(MEMP_SNMP_NODE, ln);
|
||||
}
|
||||
|
||||
struct mib_list_rootnode *
|
||||
@@ -190,7 +179,7 @@ snmp_mib_lrn_alloc(void)
|
||||
{
|
||||
struct mib_list_rootnode *lrn;
|
||||
|
||||
lrn = (struct mib_list_rootnode*)mem_malloc(sizeof(struct mib_list_rootnode));
|
||||
lrn = (struct mib_list_rootnode*)memp_malloc(MEMP_SNMP_ROOTNODE);
|
||||
if (lrn != NULL)
|
||||
{
|
||||
lrn->get_object_def = noleafs_get_object_def;
|
||||
@@ -209,7 +198,7 @@ snmp_mib_lrn_alloc(void)
|
||||
void
|
||||
snmp_mib_lrn_free(struct mib_list_rootnode *lrn)
|
||||
{
|
||||
mem_free(lrn);
|
||||
memp_free(MEMP_SNMP_ROOTNODE, lrn);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -456,7 +445,7 @@ snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n)
|
||||
* @param node points to the root of the tree ('.internet')
|
||||
* @param ident_len the length of the supplied object identifier
|
||||
* @param ident points to the array of sub identifiers
|
||||
* @param np points to the found object instance (rerurn)
|
||||
* @param np points to the found object instance (return)
|
||||
* @return pointer to the requested parent (!) node if success, NULL otherwise
|
||||
*/
|
||||
struct mib_node *
|
||||
@@ -753,7 +742,8 @@ snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snm
|
||||
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));
|
||||
/* non-leaf, store right child ptr and id */
|
||||
j = i + 1;
|
||||
LWIP_ASSERT("i < 0xff", i < 0xff);
|
||||
j = (u8_t)i + 1;
|
||||
while ((j < an->maxlength) && (empty_table(an->nptr[j])))
|
||||
{
|
||||
j++;
|
||||
@@ -995,7 +985,8 @@ snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snm
|
||||
|
||||
LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));
|
||||
/* non-leaf, store right child ptr and id */
|
||||
j = i + 1;
|
||||
LWIP_ASSERT("i < 0xff", i < 0xff);
|
||||
j = (u8_t)i + 1;
|
||||
if (j < len)
|
||||
{
|
||||
/* right node is the current external node */
|
||||
|
||||
@@ -36,14 +36,14 @@
|
||||
|
||||
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/snmp_asn1.h"
|
||||
#include "lwip/snmp_msg.h"
|
||||
#include "lwip/snmp_structs.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -58,7 +58,7 @@ struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS];
|
||||
/* UDP Protocol Control Block */
|
||||
struct udp_pcb *snmp1_pcb;
|
||||
|
||||
static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
|
||||
static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
|
||||
static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
|
||||
static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
|
||||
|
||||
@@ -88,6 +88,15 @@ snmp_init(void)
|
||||
msg_ps++;
|
||||
}
|
||||
trap_msg.pcb = snmp1_pcb;
|
||||
|
||||
#ifdef SNMP_PRIVATE_MIB_INIT
|
||||
/* If defined, rhis must be a function-like define to initialize the
|
||||
* private MIB after the stack has been initialized.
|
||||
* The private MIB can also be initialized in tcpip_callback (or after
|
||||
* the stack is initialized), this define is only for convenience. */
|
||||
SNMP_PRIVATE_MIB_INIT();
|
||||
#endif /* SNMP_PRIVATE_MIB_INIT */
|
||||
|
||||
/* The coldstart trap will only be output
|
||||
if our outgoing interface is up & configured */
|
||||
snmp_coldstart_trap();
|
||||
@@ -150,7 +159,8 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
|
||||
/* translate answer into a known lifeform */
|
||||
en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
|
||||
if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
|
||||
if ((msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) &&
|
||||
(msg_ps->ext_object_def.access & MIB_ACCESS_READ))
|
||||
{
|
||||
msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
|
||||
en->get_value_q(request_id, &msg_ps->ext_object_def);
|
||||
@@ -171,7 +181,7 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
en = msg_ps->ext_mib_node;
|
||||
|
||||
/* allocate output varbind */
|
||||
vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
|
||||
vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
|
||||
LWIP_ASSERT("vb != NULL",vb != NULL);
|
||||
if (vb != NULL)
|
||||
{
|
||||
@@ -186,10 +196,12 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
msg_ps->vb_ptr->ident_len = 0;
|
||||
|
||||
vb->value_type = msg_ps->ext_object_def.asn_type;
|
||||
vb->value_len = msg_ps->ext_object_def.v_len;
|
||||
LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff);
|
||||
vb->value_len = (u8_t)msg_ps->ext_object_def.v_len;
|
||||
if (vb->value_len > 0)
|
||||
{
|
||||
vb->value = mem_malloc(vb->value_len);
|
||||
LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE);
|
||||
vb->value = memp_malloc(MEMP_SNMP_VALUE);
|
||||
LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
|
||||
if (vb->value != NULL)
|
||||
{
|
||||
@@ -205,7 +217,7 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n"));
|
||||
msg_ps->vb_ptr->ident = vb->ident;
|
||||
msg_ps->vb_ptr->ident_len = vb->ident_len;
|
||||
mem_free(vb);
|
||||
memp_free(MEMP_SNMP_VARBIND, vb);
|
||||
snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
|
||||
}
|
||||
}
|
||||
@@ -268,7 +280,8 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
|
||||
msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
|
||||
mn->get_object_def(np.ident_len, np.ident, &object_def);
|
||||
if (object_def.instance != MIB_OBJECT_NONE)
|
||||
if ((object_def.instance != MIB_OBJECT_NONE) &&
|
||||
(object_def.access & MIB_ACCESS_READ))
|
||||
{
|
||||
mn = mn;
|
||||
}
|
||||
@@ -283,7 +296,7 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
|
||||
msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
|
||||
/* allocate output varbind */
|
||||
vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
|
||||
vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
|
||||
LWIP_ASSERT("vb != NULL",vb != NULL);
|
||||
if (vb != NULL)
|
||||
{
|
||||
@@ -298,10 +311,13 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
msg_ps->vb_ptr->ident_len = 0;
|
||||
|
||||
vb->value_type = object_def.asn_type;
|
||||
vb->value_len = object_def.v_len;
|
||||
LWIP_ASSERT("invalid length", object_def.v_len <= 0xff);
|
||||
vb->value_len = (u8_t)object_def.v_len;
|
||||
if (vb->value_len > 0)
|
||||
{
|
||||
vb->value = mem_malloc(vb->value_len);
|
||||
LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low",
|
||||
vb->value_len <= SNMP_MAX_VALUE_SIZE);
|
||||
vb->value = memp_malloc(MEMP_SNMP_VALUE);
|
||||
LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
|
||||
if (vb->value != NULL)
|
||||
{
|
||||
@@ -315,7 +331,7 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));
|
||||
msg_ps->vb_ptr->ident = vb->ident;
|
||||
msg_ps->vb_ptr->ident_len = vb->ident_len;
|
||||
mem_free(vb);
|
||||
memp_free(MEMP_SNMP_VARBIND, vb);
|
||||
snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
|
||||
}
|
||||
}
|
||||
@@ -394,9 +410,10 @@ snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
/* get_value() answer */
|
||||
en = msg_ps->ext_mib_node;
|
||||
|
||||
LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff);
|
||||
vb = snmp_varbind_alloc(&msg_ps->ext_oid,
|
||||
msg_ps->ext_object_def.asn_type,
|
||||
msg_ps->ext_object_def.v_len);
|
||||
(u8_t)msg_ps->ext_object_def.v_len);
|
||||
if (vb != NULL)
|
||||
{
|
||||
en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
|
||||
@@ -468,7 +485,8 @@ snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
|
||||
mn->get_object_def(1, &oid.id[oid.len - 1], &object_def);
|
||||
|
||||
vb = snmp_varbind_alloc(&oid, object_def.asn_type, object_def.v_len);
|
||||
LWIP_ASSERT("invalid length", object_def.v_len <= 0xff);
|
||||
vb = snmp_varbind_alloc(&oid, object_def.asn_type, (u8_t)object_def.v_len);
|
||||
if (vb != NULL)
|
||||
{
|
||||
msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
|
||||
@@ -538,7 +556,7 @@ snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
/* set_test() answer*/
|
||||
en = msg_ps->ext_mib_node;
|
||||
|
||||
if (msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE)
|
||||
if (msg_ps->ext_object_def.access & MIB_ACCESS_WRITE)
|
||||
{
|
||||
if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&
|
||||
(en->set_test_a(request_id,&msg_ps->ext_object_def,
|
||||
@@ -589,9 +607,10 @@ snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
{
|
||||
struct mib_external_node *en;
|
||||
|
||||
/** set_value_a() @todo: use reply value?? */
|
||||
/** set_value_a() */
|
||||
en = msg_ps->ext_mib_node;
|
||||
en->set_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);
|
||||
en->set_value_a(request_id, &msg_ps->ext_object_def,
|
||||
msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value);
|
||||
|
||||
/** @todo use set_value_pc() if toobig */
|
||||
msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
|
||||
@@ -652,7 +671,7 @@ snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
|
||||
{
|
||||
msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;
|
||||
|
||||
if (object_def.access == MIB_OBJECT_READ_WRITE)
|
||||
if (object_def.access & MIB_ACCESS_WRITE)
|
||||
{
|
||||
if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&
|
||||
(mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
|
||||
@@ -787,123 +806,85 @@ snmp_msg_event(u8_t request_id)
|
||||
|
||||
/* lwIP UDP receive callback function */
|
||||
static void
|
||||
snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
|
||||
snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
struct udp_hdr *udphdr;
|
||||
struct snmp_msg_pstat *msg_ps;
|
||||
u8_t req_idx;
|
||||
err_t err_ret;
|
||||
u16_t payload_len = p->tot_len;
|
||||
u16_t payload_ofs = 0;
|
||||
u16_t varbind_ofs = 0;
|
||||
|
||||
/* suppress unused argument warning */
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
/* peek in the UDP header (goto IP payload) */
|
||||
if(pbuf_header(p, UDP_HLEN)){
|
||||
LWIP_ASSERT("Can't move to UDP header", 0);
|
||||
|
||||
/* traverse input message process list, look for SNMP_MSG_EMPTY */
|
||||
msg_ps = &msg_input_list[0];
|
||||
req_idx = 0;
|
||||
while ((req_idx < SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
|
||||
{
|
||||
req_idx++;
|
||||
msg_ps++;
|
||||
}
|
||||
if (req_idx == SNMP_CONCURRENT_REQUESTS)
|
||||
{
|
||||
/* exceeding number of concurrent requests */
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
udphdr = p->payload;
|
||||
|
||||
/* check if datagram is really directed at us (including broadcast requests) */
|
||||
if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == SNMP_IN_PORT))
|
||||
/* accepting request */
|
||||
snmp_inc_snmpinpkts();
|
||||
/* record used 'protocol control block' */
|
||||
msg_ps->pcb = pcb;
|
||||
/* source address (network order) */
|
||||
msg_ps->sip = *addr;
|
||||
/* source port (host order (lwIP oddity)) */
|
||||
msg_ps->sp = port;
|
||||
|
||||
/* check total length, version, community, pdu type */
|
||||
err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
|
||||
/* Only accept requests and requests without error (be robust) */
|
||||
/* Reject response and trap headers or error requests as input! */
|
||||
if ((err_ret != ERR_OK) ||
|
||||
((msg_ps->rt != SNMP_ASN1_PDU_GET_REQ) &&
|
||||
(msg_ps->rt != SNMP_ASN1_PDU_GET_NEXT_REQ) &&
|
||||
(msg_ps->rt != SNMP_ASN1_PDU_SET_REQ)) ||
|
||||
((msg_ps->error_status != SNMP_ES_NOERROR) ||
|
||||
(msg_ps->error_index != 0)) )
|
||||
{
|
||||
struct snmp_msg_pstat *msg_ps;
|
||||
u8_t req_idx;
|
||||
|
||||
/* traverse input message process list, look for SNMP_MSG_EMPTY */
|
||||
msg_ps = &msg_input_list[0];
|
||||
req_idx = 0;
|
||||
while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
|
||||
{
|
||||
req_idx++;
|
||||
msg_ps++;
|
||||
}
|
||||
if (req_idx != SNMP_CONCURRENT_REQUESTS)
|
||||
{
|
||||
err_t err_ret;
|
||||
u16_t payload_len;
|
||||
u16_t payload_ofs;
|
||||
u16_t varbind_ofs = 0;
|
||||
|
||||
/* accepting request */
|
||||
snmp_inc_snmpinpkts();
|
||||
/* record used 'protocol control block' */
|
||||
msg_ps->pcb = pcb;
|
||||
/* source address (network order) */
|
||||
msg_ps->sip = *addr;
|
||||
/* source port (host order (lwIP oddity)) */
|
||||
msg_ps->sp = port;
|
||||
/* read UDP payload length from UDP header */
|
||||
payload_len = ntohs(udphdr->len) - UDP_HLEN;
|
||||
|
||||
/* adjust to UDP payload */
|
||||
payload_ofs = UDP_HLEN;
|
||||
|
||||
/* check total length, version, community, pdu type */
|
||||
err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
|
||||
if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) ||
|
||||
(msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) ||
|
||||
(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) &&
|
||||
((msg_ps->error_status == SNMP_ES_NOERROR) &&
|
||||
(msg_ps->error_index == 0)) )
|
||||
{
|
||||
/* Only accept requests and requests without error (be robust) */
|
||||
err_ret = err_ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reject response and trap headers or error requests as input! */
|
||||
err_ret = ERR_ARG;
|
||||
}
|
||||
if (err_ret == ERR_OK)
|
||||
{
|
||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
|
||||
|
||||
/* Builds a list of variable bindings. Copy the varbinds from the pbuf
|
||||
chain to glue them when these are divided over two or more pbuf's. */
|
||||
err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
|
||||
if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0))
|
||||
{
|
||||
/* we've decoded the incoming message, release input msg now */
|
||||
pbuf_free(p);
|
||||
|
||||
msg_ps->error_status = SNMP_ES_NOERROR;
|
||||
msg_ps->error_index = 0;
|
||||
/* find object for each variable binding */
|
||||
msg_ps->state = SNMP_MSG_SEARCH_OBJ;
|
||||
/* first variable binding from list to inspect */
|
||||
msg_ps->vb_idx = 0;
|
||||
|
||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
|
||||
|
||||
/* handle input event and as much objects as possible in one go */
|
||||
snmp_msg_event(req_idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* varbind-list decode failed, or varbind list empty.
|
||||
drop request silently, do not return error!
|
||||
(errors are only returned for a specific varbind failure) */
|
||||
pbuf_free(p);
|
||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* header check failed
|
||||
drop request silently, do not return error! */
|
||||
pbuf_free(p);
|
||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* exceeding number of concurrent requests */
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* datagram not for us */
|
||||
/* header check failed drop request silently, do not return error! */
|
||||
pbuf_free(p);
|
||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
|
||||
return;
|
||||
}
|
||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
|
||||
|
||||
/* Builds a list of variable bindings. Copy the varbinds from the pbuf
|
||||
chain to glue them when these are divided over two or more pbuf's. */
|
||||
err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
|
||||
/* we've decoded the incoming message, release input msg now */
|
||||
pbuf_free(p);
|
||||
if ((err_ret != ERR_OK) || (msg_ps->invb.count == 0))
|
||||
{
|
||||
/* varbind-list decode failed, or varbind list empty.
|
||||
drop request silently, do not return error!
|
||||
(errors are only returned for a specific varbind failure) */
|
||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
msg_ps->error_status = SNMP_ES_NOERROR;
|
||||
msg_ps->error_index = 0;
|
||||
/* find object for each variable binding */
|
||||
msg_ps->state = SNMP_MSG_SEARCH_OBJ;
|
||||
/* first variable binding from list to inspect */
|
||||
msg_ps->vb_idx = 0;
|
||||
|
||||
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
|
||||
|
||||
/* handle input event and as much objects as possible in one go */
|
||||
snmp_msg_event(req_idx);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -977,7 +958,7 @@ snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret,
|
||||
/* add zero terminator */
|
||||
len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN));
|
||||
m_stat->community[len] = 0;
|
||||
m_stat->com_strlen = len;
|
||||
m_stat->com_strlen = (u8_t)len;
|
||||
if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0)
|
||||
{
|
||||
/** @todo: move this if we need to check more names */
|
||||
@@ -1145,7 +1126,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_
|
||||
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
|
||||
if ((derr != ERR_OK) ||
|
||||
(type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||
|
||||
(len <= 0) || (len > vb_len))
|
||||
(len == 0) || (len > vb_len))
|
||||
{
|
||||
snmp_inc_snmpinasnparseerrs();
|
||||
/* free varbinds (if available) */
|
||||
@@ -1194,7 +1175,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_
|
||||
vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t));
|
||||
if (vb != NULL)
|
||||
{
|
||||
s32_t *vptr = vb->value;
|
||||
s32_t *vptr = (s32_t*)vb->value;
|
||||
|
||||
derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr);
|
||||
snmp_varbind_tail_add(&m_stat->invb, vb);
|
||||
@@ -1210,7 +1191,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_
|
||||
vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t));
|
||||
if (vb != NULL)
|
||||
{
|
||||
u32_t *vptr = vb->value;
|
||||
u32_t *vptr = (u32_t*)vb->value;
|
||||
|
||||
derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr);
|
||||
snmp_varbind_tail_add(&m_stat->invb, vb);
|
||||
@@ -1222,10 +1203,11 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_
|
||||
break;
|
||||
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
|
||||
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
|
||||
vb = snmp_varbind_alloc(&oid, type, len);
|
||||
LWIP_ASSERT("invalid length", len <= 0xff);
|
||||
vb = snmp_varbind_alloc(&oid, type, (u8_t)len);
|
||||
if (vb != NULL)
|
||||
{
|
||||
derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
|
||||
derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value);
|
||||
snmp_varbind_tail_add(&m_stat->invb, vb);
|
||||
}
|
||||
else
|
||||
@@ -1253,7 +1235,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_
|
||||
if (vb != NULL)
|
||||
{
|
||||
u8_t i = oid_value.len;
|
||||
s32_t *vptr = vb->value;
|
||||
s32_t *vptr = (s32_t*)vb->value;
|
||||
|
||||
while(i > 0)
|
||||
{
|
||||
@@ -1276,7 +1258,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_
|
||||
vb = snmp_varbind_alloc(&oid, type, 4);
|
||||
if (vb != NULL)
|
||||
{
|
||||
derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
|
||||
derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value);
|
||||
snmp_varbind_tail_add(&m_stat->invb, vb);
|
||||
}
|
||||
else
|
||||
@@ -1322,7 +1304,7 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
|
||||
{
|
||||
struct snmp_varbind *vb;
|
||||
|
||||
vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
|
||||
vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
|
||||
LWIP_ASSERT("vb != NULL",vb != NULL);
|
||||
if (vb != NULL)
|
||||
{
|
||||
@@ -1334,12 +1316,13 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
|
||||
vb->ident_len = i;
|
||||
if (i > 0)
|
||||
{
|
||||
LWIP_ASSERT("SNMP_MAX_TREE_DEPTH is configured too low", i <= SNMP_MAX_TREE_DEPTH);
|
||||
/* allocate array of s32_t for our object identifier */
|
||||
vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i);
|
||||
vb->ident = (s32_t*)memp_malloc(MEMP_SNMP_VALUE);
|
||||
LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL);
|
||||
if (vb->ident == NULL)
|
||||
{
|
||||
mem_free(vb);
|
||||
memp_free(MEMP_SNMP_VARBIND, vb);
|
||||
return NULL;
|
||||
}
|
||||
while(i > 0)
|
||||
@@ -1357,16 +1340,17 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
|
||||
vb->value_len = len;
|
||||
if (len > 0)
|
||||
{
|
||||
LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE);
|
||||
/* allocate raw bytes for our object value */
|
||||
vb->value = mem_malloc(len);
|
||||
vb->value = memp_malloc(MEMP_SNMP_VALUE);
|
||||
LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
|
||||
if (vb->value == NULL)
|
||||
{
|
||||
if (vb->ident != NULL)
|
||||
{
|
||||
mem_free(vb->ident);
|
||||
memp_free(MEMP_SNMP_VALUE, vb->ident);
|
||||
}
|
||||
mem_free(vb);
|
||||
memp_free(MEMP_SNMP_VARBIND, vb);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -1384,13 +1368,13 @@ snmp_varbind_free(struct snmp_varbind *vb)
|
||||
{
|
||||
if (vb->value != NULL )
|
||||
{
|
||||
mem_free(vb->value);
|
||||
memp_free(MEMP_SNMP_VALUE, vb->value);
|
||||
}
|
||||
if (vb->ident != NULL )
|
||||
{
|
||||
mem_free(vb->ident);
|
||||
memp_free(MEMP_SNMP_VALUE, vb->ident);
|
||||
}
|
||||
mem_free(vb);
|
||||
memp_free(MEMP_SNMP_VARBIND, vb);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
struct snmp_trap_dst
|
||||
{
|
||||
/* destination IP address in network order */
|
||||
struct ip_addr dip;
|
||||
ip_addr_t dip;
|
||||
/* set to 0 when disabled, >0 when enabled */
|
||||
u8_t enable;
|
||||
};
|
||||
@@ -92,11 +92,11 @@ snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)
|
||||
* @param dst IPv4 address in host order.
|
||||
*/
|
||||
void
|
||||
snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst)
|
||||
snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst)
|
||||
{
|
||||
if (dst_idx < SNMP_TRAP_DESTINATIONS)
|
||||
{
|
||||
trap_dst[dst_idx].dip.addr = htonl(dst->addr);
|
||||
ip_addr_set(&trap_dst[dst_idx].dip, dst);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,23 +221,24 @@ snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)
|
||||
{
|
||||
struct snmp_trap_dst *td;
|
||||
struct netif *dst_if;
|
||||
struct ip_addr dst_ip;
|
||||
ip_addr_t dst_ip;
|
||||
struct pbuf *p;
|
||||
u16_t i,tot_len;
|
||||
|
||||
for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++)
|
||||
{
|
||||
if ((td->enable != 0) && (td->dip.addr != 0))
|
||||
if ((td->enable != 0) && !ip_addr_isany(&td->dip))
|
||||
{
|
||||
/* network order trap destination */
|
||||
trap_msg.dip.addr = td->dip.addr;
|
||||
ip_addr_copy(trap_msg.dip, td->dip);
|
||||
/* lookup current source address for this dst */
|
||||
dst_if = ip_route(&td->dip);
|
||||
dst_ip.addr = ntohl(dst_if->ip_addr.addr);
|
||||
trap_msg.sip_raw[0] = dst_ip.addr >> 24;
|
||||
trap_msg.sip_raw[1] = dst_ip.addr >> 16;
|
||||
trap_msg.sip_raw[2] = dst_ip.addr >> 8;
|
||||
trap_msg.sip_raw[3] = dst_ip.addr;
|
||||
ip_addr_copy(dst_ip, dst_if->ip_addr);
|
||||
/* @todo: what about IPv6? */
|
||||
trap_msg.sip_raw[0] = ip4_addr1(&dst_ip);
|
||||
trap_msg.sip_raw[1] = ip4_addr2(&dst_ip);
|
||||
trap_msg.sip_raw[2] = ip4_addr3(&dst_ip);
|
||||
trap_msg.sip_raw[3] = ip4_addr4(&dst_ip);
|
||||
trap_msg.gen_trap = generic_trap;
|
||||
trap_msg.spc_trap = specific_trap;
|
||||
if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC)
|
||||
@@ -269,11 +270,8 @@ snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)
|
||||
snmp_inc_snmpouttraps();
|
||||
snmp_inc_snmpoutpkts();
|
||||
|
||||
/** connect to the TRAP destination */
|
||||
udp_connect(trap_msg.pcb, &trap_msg.dip, SNMP_TRAP_PORT);
|
||||
udp_send(trap_msg.pcb, p);
|
||||
/** disassociate remote address and port with this pcb */
|
||||
udp_disconnect(trap_msg.pcb);
|
||||
/** send to the TRAP destination */
|
||||
udp_sendto(trap_msg.pcb, p, &trap_msg.dip, SNMP_TRAP_PORT);
|
||||
|
||||
pbuf_free(p);
|
||||
}
|
||||
@@ -435,13 +433,13 @@ snmp_varbind_list_sum(struct snmp_varbind_root *root)
|
||||
switch (vb->value_type)
|
||||
{
|
||||
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
|
||||
sint_ptr = vb->value;
|
||||
sint_ptr = (s32_t*)vb->value;
|
||||
snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen);
|
||||
break;
|
||||
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
|
||||
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
|
||||
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
|
||||
uint_ptr = vb->value;
|
||||
uint_ptr = (u32_t*)vb->value;
|
||||
snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen);
|
||||
break;
|
||||
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
|
||||
@@ -451,7 +449,7 @@ snmp_varbind_list_sum(struct snmp_varbind_root *root)
|
||||
vb->vlen = vb->value_len;
|
||||
break;
|
||||
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
|
||||
sint_ptr = vb->value;
|
||||
sint_ptr = (s32_t*)vb->value;
|
||||
snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen);
|
||||
break;
|
||||
default:
|
||||
@@ -649,25 +647,25 @@ snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs)
|
||||
switch (vb->value_type)
|
||||
{
|
||||
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
|
||||
sint_ptr = vb->value;
|
||||
sint_ptr = (s32_t*)vb->value;
|
||||
snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr);
|
||||
break;
|
||||
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
|
||||
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
|
||||
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
|
||||
uint_ptr = vb->value;
|
||||
uint_ptr = (u32_t*)vb->value;
|
||||
snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr);
|
||||
break;
|
||||
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
|
||||
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
|
||||
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
|
||||
raw_ptr = vb->value;
|
||||
raw_ptr = (u8_t*)vb->value;
|
||||
snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr);
|
||||
break;
|
||||
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
|
||||
break;
|
||||
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
|
||||
sint_ptr = vb->value;
|
||||
sint_ptr = (s32_t*)vb->value;
|
||||
snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr);
|
||||
break;
|
||||
default:
|
||||
|
||||
137
src/core/stats.c
137
src/core/stats.c
@@ -48,13 +48,31 @@
|
||||
|
||||
struct stats_ lwip_stats;
|
||||
|
||||
void stats_init(void)
|
||||
{
|
||||
#ifdef LWIP_DEBUG
|
||||
#if MEMP_STATS
|
||||
const char * memp_names[] = {
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) desc,
|
||||
#include "lwip/memp_std.h"
|
||||
};
|
||||
int i;
|
||||
for (i = 0; i < MEMP_MAX; i++) {
|
||||
lwip_stats.memp[i].name = memp_names[i];
|
||||
}
|
||||
#endif /* MEMP_STATS */
|
||||
#if MEM_STATS
|
||||
lwip_stats.mem.name = "MEM";
|
||||
#endif /* MEM_STATS */
|
||||
#endif /* LWIP_DEBUG */
|
||||
}
|
||||
|
||||
#if LWIP_STATS_DISPLAY
|
||||
void
|
||||
stats_display_proto(struct stats_proto *proto, char *name)
|
||||
stats_display_proto(struct stats_proto *proto, const char *name)
|
||||
{
|
||||
LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
|
||||
LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit));
|
||||
LWIP_PLATFORM_DIAG(("rexmit: %"STAT_COUNTER_F"\n\t", proto->rexmit));
|
||||
LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv));
|
||||
LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw));
|
||||
LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop));
|
||||
@@ -68,23 +86,31 @@ stats_display_proto(struct stats_proto *proto, char *name)
|
||||
LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit));
|
||||
}
|
||||
|
||||
#if IGMP_STATS
|
||||
void
|
||||
stats_display_igmp(struct stats_igmp *igmp)
|
||||
stats_display_igmp(struct stats_igmp *igmp, const char *name)
|
||||
{
|
||||
LWIP_PLATFORM_DIAG(("\nIGMP\n\t"));
|
||||
LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr));
|
||||
LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
|
||||
LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit));
|
||||
LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv));
|
||||
LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop));
|
||||
LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr));
|
||||
LWIP_PLATFORM_DIAG(("v1_rxed: %"STAT_COUNTER_F"\n\t", igmp->v1_rxed));
|
||||
LWIP_PLATFORM_DIAG(("join_sent: %"STAT_COUNTER_F"\n\t", igmp->join_sent));
|
||||
LWIP_PLATFORM_DIAG(("leave_sent: %"STAT_COUNTER_F"\n\t", igmp->leave_sent));
|
||||
LWIP_PLATFORM_DIAG(("unicast_query: %"STAT_COUNTER_F"\n\t", igmp->unicast_query));
|
||||
LWIP_PLATFORM_DIAG(("report_sent: %"STAT_COUNTER_F"\n\t", igmp->report_sent));
|
||||
LWIP_PLATFORM_DIAG(("report_rxed: %"STAT_COUNTER_F"\n\t", igmp->report_rxed));
|
||||
LWIP_PLATFORM_DIAG(("group_query_rxed: %"STAT_COUNTER_F"\n", igmp->group_query_rxed));
|
||||
LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr));
|
||||
LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", igmp->memerr));
|
||||
LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", igmp->proterr));
|
||||
LWIP_PLATFORM_DIAG(("rx_v1: %"STAT_COUNTER_F"\n\t", igmp->rx_v1));
|
||||
LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n", igmp->rx_group));
|
||||
LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n", igmp->rx_general));
|
||||
LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report));
|
||||
LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join));
|
||||
LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave));
|
||||
LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n\t", igmp->tx_report));
|
||||
}
|
||||
#endif /* IGMP_STATS */
|
||||
|
||||
#if MEM_STATS || MEMP_STATS
|
||||
void
|
||||
stats_display_mem(struct stats_mem *mem, char *name)
|
||||
stats_display_mem(struct stats_mem *mem, const char *name)
|
||||
{
|
||||
LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name));
|
||||
LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail));
|
||||
@@ -93,48 +119,61 @@ stats_display_mem(struct stats_mem *mem, char *name)
|
||||
LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err));
|
||||
}
|
||||
|
||||
void
|
||||
stats_display(void)
|
||||
{
|
||||
#if MEMP_STATS
|
||||
s16_t i;
|
||||
void
|
||||
stats_display_memp(struct stats_mem *mem, int index)
|
||||
{
|
||||
char * memp_names[] = {
|
||||
#define LWIP_MEMPOOL(name,num,size,desc) desc,
|
||||
#include "lwip/memp_std.h"
|
||||
};
|
||||
#endif
|
||||
#if LINK_STATS
|
||||
stats_display_proto(&lwip_stats.link, "LINK");
|
||||
#endif
|
||||
#if ETHARP_STATS
|
||||
stats_display_proto(&lwip_stats.etharp, "ETHARP");
|
||||
#endif
|
||||
#if IPFRAG_STATS
|
||||
stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG");
|
||||
#endif
|
||||
#if IP_STATS
|
||||
stats_display_proto(&lwip_stats.ip, "IP");
|
||||
#endif
|
||||
#if ICMP_STATS
|
||||
stats_display_proto(&lwip_stats.icmp, "ICMP");
|
||||
#endif
|
||||
#if IGMP_STATS
|
||||
stats_display_igmp(&lwip_stats.igmp);
|
||||
#endif
|
||||
#if UDP_STATS
|
||||
stats_display_proto(&lwip_stats.udp, "UDP");
|
||||
#endif
|
||||
#if TCP_STATS
|
||||
stats_display_proto(&lwip_stats.tcp, "TCP");
|
||||
#endif
|
||||
#if MEM_STATS
|
||||
stats_display_mem(&lwip_stats.mem, "HEAP");
|
||||
#endif
|
||||
#if MEMP_STATS
|
||||
for (i = 0; i < MEMP_MAX; i++) {
|
||||
stats_display_mem(&lwip_stats.memp[i], memp_names[i]);
|
||||
if(index < MEMP_MAX) {
|
||||
stats_display_mem(mem, memp_names[index]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* MEMP_STATS */
|
||||
#endif /* MEM_STATS || MEMP_STATS */
|
||||
|
||||
#if SYS_STATS
|
||||
void
|
||||
stats_display_sys(struct stats_sys *sys)
|
||||
{
|
||||
LWIP_PLATFORM_DIAG(("\nSYS\n\t"));
|
||||
LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used));
|
||||
LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max));
|
||||
LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err));
|
||||
LWIP_PLATFORM_DIAG(("mutex.used: %"U32_F"\n\t", (u32_t)sys->mutex.used));
|
||||
LWIP_PLATFORM_DIAG(("mutex.max: %"U32_F"\n\t", (u32_t)sys->mutex.max));
|
||||
LWIP_PLATFORM_DIAG(("mutex.err: %"U32_F"\n\t", (u32_t)sys->mutex.err));
|
||||
LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used));
|
||||
LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max));
|
||||
LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err));
|
||||
}
|
||||
#endif /* SYS_STATS */
|
||||
|
||||
void
|
||||
stats_display(void)
|
||||
{
|
||||
s16_t i;
|
||||
|
||||
LINK_STATS_DISPLAY();
|
||||
ETHARP_STATS_DISPLAY();
|
||||
IPFRAG_STATS_DISPLAY();
|
||||
IP6_FRAG_STATS_DISPLAY();
|
||||
IP_STATS_DISPLAY();
|
||||
ND6_STATS_DISPLAY();
|
||||
IP6_STATS_DISPLAY();
|
||||
IGMP_STATS_DISPLAY();
|
||||
MLD6_STATS_DISPLAY();
|
||||
ICMP_STATS_DISPLAY();
|
||||
ICMP6_STATS_DISPLAY();
|
||||
UDP_STATS_DISPLAY();
|
||||
TCP_STATS_DISPLAY();
|
||||
MEM_STATS_DISPLAY();
|
||||
for (i = 0; i < MEMP_MAX; i++) {
|
||||
MEMP_STATS_DISPLAY(i);
|
||||
}
|
||||
SYS_STATS_DISPLAY();
|
||||
}
|
||||
#endif /* LWIP_STATS_DISPLAY */
|
||||
|
||||
|
||||
308
src/core/sys.c
308
src/core/sys.c
@@ -38,307 +38,29 @@
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/tcpip.h"
|
||||
|
||||
/* Most of the functions defined in sys.h must be implemented in the
|
||||
* architecture-dependent file sys_arch.c */
|
||||
|
||||
#if !NO_SYS
|
||||
|
||||
/**
|
||||
* Struct used for sys_sem_wait_timeout() to tell wether the time
|
||||
* has run out or the semaphore has really become available.
|
||||
*/
|
||||
struct sswt_cb
|
||||
{
|
||||
s16_t timeflag;
|
||||
sys_sem_t *psem;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wait (forever) for a message to arrive in an mbox.
|
||||
* While waiting, timeouts (for this thread) are processed.
|
||||
*
|
||||
* @param mbox the mbox to fetch the message from
|
||||
* @param msg the place to store the message
|
||||
*/
|
||||
void
|
||||
sys_mbox_fetch(sys_mbox_t mbox, void **msg)
|
||||
{
|
||||
u32_t time;
|
||||
struct sys_timeouts *timeouts;
|
||||
struct sys_timeo *tmptimeout;
|
||||
sys_timeout_handler h;
|
||||
void *arg;
|
||||
|
||||
again:
|
||||
timeouts = sys_arch_timeouts();
|
||||
|
||||
if (!timeouts || !timeouts->next) {
|
||||
UNLOCK_TCPIP_CORE();
|
||||
time = sys_arch_mbox_fetch(mbox, msg, 0);
|
||||
LOCK_TCPIP_CORE();
|
||||
} else {
|
||||
if (timeouts->next->time > 0) {
|
||||
UNLOCK_TCPIP_CORE();
|
||||
time = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);
|
||||
LOCK_TCPIP_CORE();
|
||||
} else {
|
||||
time = SYS_ARCH_TIMEOUT;
|
||||
}
|
||||
|
||||
if (time == SYS_ARCH_TIMEOUT) {
|
||||
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
|
||||
could be fetched. We should now call the timeout handler and
|
||||
deallocate the memory allocated for the timeout. */
|
||||
tmptimeout = timeouts->next;
|
||||
timeouts->next = tmptimeout->next;
|
||||
h = tmptimeout->h;
|
||||
arg = tmptimeout->arg;
|
||||
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
|
||||
if (h != NULL) {
|
||||
LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", (void*)&h, arg));
|
||||
h(arg);
|
||||
}
|
||||
|
||||
/* We try again to fetch a message from the mbox. */
|
||||
goto again;
|
||||
} else {
|
||||
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
|
||||
occured. The time variable is set to the number of
|
||||
milliseconds we waited for the message. */
|
||||
if (time < timeouts->next->time) {
|
||||
timeouts->next->time -= time;
|
||||
} else {
|
||||
timeouts->next->time = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait (forever) for a semaphore to become available.
|
||||
* While waiting, timeouts (for this thread) are processed.
|
||||
*
|
||||
* @param sem semaphore to wait for
|
||||
*/
|
||||
void
|
||||
sys_sem_wait(sys_sem_t sem)
|
||||
{
|
||||
u32_t time;
|
||||
struct sys_timeouts *timeouts;
|
||||
struct sys_timeo *tmptimeout;
|
||||
sys_timeout_handler h;
|
||||
void *arg;
|
||||
|
||||
again:
|
||||
|
||||
timeouts = sys_arch_timeouts();
|
||||
|
||||
if (!timeouts || !timeouts->next) {
|
||||
sys_arch_sem_wait(sem, 0);
|
||||
} else {
|
||||
if (timeouts->next->time > 0) {
|
||||
time = sys_arch_sem_wait(sem, timeouts->next->time);
|
||||
} else {
|
||||
time = SYS_ARCH_TIMEOUT;
|
||||
}
|
||||
|
||||
if (time == SYS_ARCH_TIMEOUT) {
|
||||
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
|
||||
could be fetched. We should now call the timeout handler and
|
||||
deallocate the memory allocated for the timeout. */
|
||||
tmptimeout = timeouts->next;
|
||||
timeouts->next = tmptimeout->next;
|
||||
h = tmptimeout->h;
|
||||
arg = tmptimeout->arg;
|
||||
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
|
||||
if (h != NULL) {
|
||||
LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", (void*)&h, (void *)arg));
|
||||
h(arg);
|
||||
}
|
||||
|
||||
/* We try again to fetch a message from the mbox. */
|
||||
goto again;
|
||||
} else {
|
||||
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
|
||||
occured. The time variable is set to the number of
|
||||
milliseconds we waited for the message. */
|
||||
if (time < timeouts->next->time) {
|
||||
timeouts->next->time -= time;
|
||||
} else {
|
||||
timeouts->next->time = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a one-shot timer (aka timeout). Timeouts are processed in the
|
||||
* following cases:
|
||||
* - while waiting for a message using sys_mbox_fetch()
|
||||
* - while waiting for a semaphore using sys_sem_wait() or sys_sem_wait_timeout()
|
||||
* - while sleeping using the inbuilt sys_msleep()
|
||||
*
|
||||
* @param msecs time in milliseconds after that the timer should expire
|
||||
* @param h callback function to call when msecs have elapsed
|
||||
* @param arg argument to pass to the callback function
|
||||
*/
|
||||
void
|
||||
sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
||||
{
|
||||
struct sys_timeouts *timeouts;
|
||||
struct sys_timeo *timeout, *t;
|
||||
|
||||
timeout = memp_malloc(MEMP_SYS_TIMEOUT);
|
||||
if (timeout == NULL) {
|
||||
LWIP_ASSERT("sys_timeout: timeout != NULL", timeout != NULL);
|
||||
return;
|
||||
}
|
||||
timeout->next = NULL;
|
||||
timeout->h = h;
|
||||
timeout->arg = arg;
|
||||
timeout->time = msecs;
|
||||
|
||||
timeouts = sys_arch_timeouts();
|
||||
|
||||
LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n",
|
||||
(void *)timeout, msecs, (void*)&h, (void *)arg));
|
||||
|
||||
if (timeouts == NULL) {
|
||||
LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (timeouts->next == NULL) {
|
||||
timeouts->next = timeout;
|
||||
return;
|
||||
}
|
||||
|
||||
if (timeouts->next->time > msecs) {
|
||||
timeouts->next->time -= msecs;
|
||||
timeout->next = timeouts->next;
|
||||
timeouts->next = timeout;
|
||||
} else {
|
||||
for(t = timeouts->next; t != NULL; t = t->next) {
|
||||
timeout->time -= t->time;
|
||||
if (t->next == NULL || t->next->time > timeout->time) {
|
||||
if (t->next != NULL) {
|
||||
t->next->time -= timeout->time;
|
||||
}
|
||||
timeout->next = t->next;
|
||||
t->next = timeout;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Go through timeout list (for this task only) and remove the first matching
|
||||
* entry, even though the timeout has not triggered yet.
|
||||
*
|
||||
* @note This function only works as expected if there is only one timeout
|
||||
* calling 'h' in the list of timeouts.
|
||||
*
|
||||
* @param h callback function that would be called by the timeout
|
||||
* @param arg callback argument that would be passed to h
|
||||
*/
|
||||
void
|
||||
sys_untimeout(sys_timeout_handler h, void *arg)
|
||||
{
|
||||
struct sys_timeouts *timeouts;
|
||||
struct sys_timeo *prev_t, *t;
|
||||
|
||||
timeouts = sys_arch_timeouts();
|
||||
|
||||
if (timeouts == NULL) {
|
||||
LWIP_ASSERT("sys_untimeout: timeouts != NULL", timeouts != NULL);
|
||||
return;
|
||||
}
|
||||
if (timeouts->next == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
|
||||
if ((t->h == h) && (t->arg == arg)) {
|
||||
/* We have a match */
|
||||
/* Unlink from previous in list */
|
||||
if (prev_t == NULL)
|
||||
timeouts->next = t->next;
|
||||
else
|
||||
prev_t->next = t->next;
|
||||
/* If not the last one, add time of this one back to next */
|
||||
if (t->next != NULL)
|
||||
t->next->time += t->time;
|
||||
memp_free(MEMP_SYS_TIMEOUT, t);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timeout handler function for sys_sem_wait_timeout()
|
||||
*
|
||||
* @param arg struct sswt_cb* used to signal a semaphore and end waiting.
|
||||
*/
|
||||
static void
|
||||
sswt_handler(void *arg)
|
||||
{
|
||||
struct sswt_cb *sswt_cb = (struct sswt_cb *) arg;
|
||||
|
||||
/* Timeout. Set flag to TRUE and signal semaphore */
|
||||
sswt_cb->timeflag = 1;
|
||||
sys_sem_signal(*(sswt_cb->psem));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for a semaphore with timeout (specified in ms)
|
||||
*
|
||||
* @param sem semaphore to wait
|
||||
* @param timeout timeout in ms (0: wait forever)
|
||||
* @return 0 on timeout, 1 otherwise
|
||||
*/
|
||||
int
|
||||
sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout)
|
||||
{
|
||||
struct sswt_cb sswt_cb;
|
||||
|
||||
sswt_cb.psem = &sem;
|
||||
sswt_cb.timeflag = 0;
|
||||
|
||||
/* If timeout is zero, then just wait forever */
|
||||
if (timeout > 0) {
|
||||
/* Create a timer and pass it the address of our flag */
|
||||
sys_timeout(timeout, sswt_handler, &sswt_cb);
|
||||
}
|
||||
sys_sem_wait(sem);
|
||||
/* Was it a timeout? */
|
||||
if (sswt_cb.timeflag) {
|
||||
/* timeout */
|
||||
return 0;
|
||||
} else {
|
||||
/* Not a timeout. Remove timeout entry */
|
||||
sys_untimeout(sswt_handler, &sswt_cb);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleep for some ms. Timeouts are processed while sleeping.
|
||||
* Sleep for some ms. Timeouts are NOT processed while sleeping.
|
||||
*
|
||||
* @param ms number of milliseconds to sleep
|
||||
*/
|
||||
void
|
||||
sys_msleep(u32_t ms)
|
||||
{
|
||||
sys_sem_t delaysem = sys_sem_new(0);
|
||||
|
||||
sys_sem_wait_timeout(delaysem, ms);
|
||||
|
||||
sys_sem_free(delaysem);
|
||||
if (ms > 0) {
|
||||
sys_sem_t delaysem;
|
||||
err_t err = sys_sem_new(&delaysem, 0);
|
||||
if (err == ERR_OK) {
|
||||
sys_arch_sem_wait(&delaysem, ms);
|
||||
sys_sem_free(&delaysem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* NO_SYS */
|
||||
#endif /* !NO_SYS */
|
||||
|
||||
828
src/core/tcp.c
828
src/core/tcp.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1417
src/core/tcp_out.c
1417
src/core/tcp_out.c
File diff suppressed because it is too large
Load Diff
542
src/core/timers.c
Normal file
542
src/core/timers.c
Normal file
@@ -0,0 +1,542 @@
|
||||
/**
|
||||
* @file
|
||||
* Stack-internal timers implementation.
|
||||
* This file includes timer callbacks for stack-internal timers as well as
|
||||
* functions to set up or stop timers and check for expired timers.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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>
|
||||
* Simon Goldschmidt
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/timers.h"
|
||||
#include "lwip/tcp_impl.h"
|
||||
|
||||
#if LWIP_TIMERS
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/tcpip.h"
|
||||
|
||||
#include "lwip/ip_frag.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "lwip/dhcp.h"
|
||||
#include "lwip/autoip.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/nd6.h"
|
||||
#include "lwip/ip6_frag.h"
|
||||
#include "lwip/mld6.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
/** The one and only timeout list */
|
||||
static struct sys_timeo *next_timeout;
|
||||
#if NO_SYS
|
||||
static u32_t timeouts_last_time;
|
||||
#endif /* NO_SYS */
|
||||
|
||||
#if LWIP_TCP
|
||||
/** global variable that shows if the tcp timer is currently scheduled or not */
|
||||
static int tcpip_tcp_timer_active;
|
||||
|
||||
/**
|
||||
* Timer callback function that calls tcp_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
tcpip_tcp_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
/* call TCP timer handler */
|
||||
tcp_tmr();
|
||||
/* timer still needed? */
|
||||
if (tcp_active_pcbs || tcp_tw_pcbs) {
|
||||
/* restart timer */
|
||||
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
|
||||
} else {
|
||||
/* disable timer */
|
||||
tcpip_tcp_timer_active = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from TCP_REG when registering a new PCB:
|
||||
* the reason is to have the TCP timer only running when
|
||||
* there are active (or time-wait) PCBs.
|
||||
*/
|
||||
void
|
||||
tcp_timer_needed(void)
|
||||
{
|
||||
/* timer is off but needed again? */
|
||||
if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
|
||||
/* enable and start timer */
|
||||
tcpip_tcp_timer_active = 1;
|
||||
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_TCP */
|
||||
|
||||
#if IP_REASSEMBLY
|
||||
/**
|
||||
* Timer callback function that calls ip_reass_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
ip_reass_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n"));
|
||||
ip_reass_tmr();
|
||||
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
|
||||
}
|
||||
#endif /* IP_REASSEMBLY */
|
||||
|
||||
#if LWIP_ARP
|
||||
/**
|
||||
* Timer callback function that calls etharp_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
arp_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n"));
|
||||
etharp_tmr();
|
||||
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_ARP */
|
||||
|
||||
#if LWIP_DHCP
|
||||
/**
|
||||
* Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
dhcp_timer_coarse(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
|
||||
dhcp_coarse_tmr();
|
||||
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
dhcp_timer_fine(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
|
||||
dhcp_fine_tmr();
|
||||
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
|
||||
}
|
||||
#endif /* LWIP_DHCP */
|
||||
|
||||
#if LWIP_AUTOIP
|
||||
/**
|
||||
* Timer callback function that calls autoip_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
autoip_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n"));
|
||||
autoip_tmr();
|
||||
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_AUTOIP */
|
||||
|
||||
#if LWIP_IGMP
|
||||
/**
|
||||
* Timer callback function that calls igmp_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
igmp_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n"));
|
||||
igmp_tmr();
|
||||
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
|
||||
#if LWIP_DNS
|
||||
/**
|
||||
* Timer callback function that calls dns_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
dns_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n"));
|
||||
dns_tmr();
|
||||
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_DNS */
|
||||
|
||||
#if LWIP_IPV6
|
||||
/**
|
||||
* Timer callback function that calls nd6_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
nd6_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: nd6_tmr()\n"));
|
||||
nd6_tmr();
|
||||
sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL);
|
||||
}
|
||||
|
||||
#if LWIP_IPV6_REASS
|
||||
/**
|
||||
* Timer callback function that calls ip6_reass_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
ip6_reass_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip6_reass_tmr()\n"));
|
||||
ip6_reass_tmr();
|
||||
sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_IPV6_REASS */
|
||||
|
||||
#if LWIP_IPV6_MLD
|
||||
/**
|
||||
* Timer callback function that calls mld6_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
mld6_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: mld6_tmr()\n"));
|
||||
mld6_tmr();
|
||||
sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
/** Initialize this module */
|
||||
void sys_timeouts_init(void)
|
||||
{
|
||||
#if IP_REASSEMBLY
|
||||
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
|
||||
#endif /* IP_REASSEMBLY */
|
||||
#if LWIP_ARP
|
||||
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
||||
#endif /* LWIP_ARP */
|
||||
#if LWIP_DHCP
|
||||
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
|
||||
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
|
||||
#endif /* LWIP_DHCP */
|
||||
#if LWIP_AUTOIP
|
||||
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
|
||||
#endif /* LWIP_AUTOIP */
|
||||
#if LWIP_IGMP
|
||||
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
|
||||
#endif /* LWIP_IGMP */
|
||||
#if LWIP_DNS
|
||||
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
|
||||
#endif /* LWIP_DNS */
|
||||
#if LWIP_IPV6
|
||||
sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL);
|
||||
#if LWIP_IPV6_REASS
|
||||
sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL);
|
||||
#endif /* LWIP_IPV6_REASS */
|
||||
#if LWIP_IPV6_MLD
|
||||
sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL);
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#if NO_SYS
|
||||
/* Initialise timestamp for sys_check_timeouts */
|
||||
timeouts_last_time = sys_now();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a one-shot timer (aka timeout). Timeouts are processed in the
|
||||
* following cases:
|
||||
* - while waiting for a message using sys_timeouts_mbox_fetch()
|
||||
* - by calling sys_check_timeouts() (NO_SYS==1 only)
|
||||
*
|
||||
* @param msecs time in milliseconds after that the timer should expire
|
||||
* @param handler callback function to call when msecs have elapsed
|
||||
* @param arg argument to pass to the callback function
|
||||
*/
|
||||
#if LWIP_DEBUG_TIMERNAMES
|
||||
void
|
||||
sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)
|
||||
#else /* LWIP_DEBUG_TIMERNAMES */
|
||||
void
|
||||
sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
|
||||
#endif /* LWIP_DEBUG_TIMERNAMES */
|
||||
{
|
||||
struct sys_timeo *timeout, *t;
|
||||
|
||||
timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT);
|
||||
if (timeout == NULL) {
|
||||
LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL);
|
||||
return;
|
||||
}
|
||||
timeout->next = NULL;
|
||||
timeout->h = handler;
|
||||
timeout->arg = arg;
|
||||
timeout->time = msecs;
|
||||
#if LWIP_DEBUG_TIMERNAMES
|
||||
timeout->handler_name = handler_name;
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n",
|
||||
(void *)timeout, msecs, handler_name, (void *)arg));
|
||||
#endif /* LWIP_DEBUG_TIMERNAMES */
|
||||
|
||||
if (next_timeout == NULL) {
|
||||
next_timeout = timeout;
|
||||
return;
|
||||
}
|
||||
|
||||
if (next_timeout->time > msecs) {
|
||||
next_timeout->time -= msecs;
|
||||
timeout->next = next_timeout;
|
||||
next_timeout = timeout;
|
||||
} else {
|
||||
for(t = next_timeout; t != NULL; t = t->next) {
|
||||
timeout->time -= t->time;
|
||||
if (t->next == NULL || t->next->time > timeout->time) {
|
||||
if (t->next != NULL) {
|
||||
t->next->time -= timeout->time;
|
||||
}
|
||||
timeout->next = t->next;
|
||||
t->next = timeout;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Go through timeout list (for this task only) and remove the first matching
|
||||
* entry, even though the timeout has not triggered yet.
|
||||
*
|
||||
* @note This function only works as expected if there is only one timeout
|
||||
* calling 'handler' in the list of timeouts.
|
||||
*
|
||||
* @param handler callback function that would be called by the timeout
|
||||
* @param arg callback argument that would be passed to handler
|
||||
*/
|
||||
void
|
||||
sys_untimeout(sys_timeout_handler handler, void *arg)
|
||||
{
|
||||
struct sys_timeo *prev_t, *t;
|
||||
|
||||
if (next_timeout == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
|
||||
if ((t->h == handler) && (t->arg == arg)) {
|
||||
/* We have a match */
|
||||
/* Unlink from previous in list */
|
||||
if (prev_t == NULL) {
|
||||
next_timeout = t->next;
|
||||
} else {
|
||||
prev_t->next = t->next;
|
||||
}
|
||||
/* If not the last one, add time of this one back to next */
|
||||
if (t->next != NULL) {
|
||||
t->next->time += t->time;
|
||||
}
|
||||
memp_free(MEMP_SYS_TIMEOUT, t);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#if NO_SYS
|
||||
|
||||
/** Handle timeouts for NO_SYS==1 (i.e. without using
|
||||
* tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout
|
||||
* handler functions when timeouts expire.
|
||||
*
|
||||
* Must be called periodically from your main loop.
|
||||
*/
|
||||
void
|
||||
sys_check_timeouts(void)
|
||||
{
|
||||
struct sys_timeo *tmptimeout;
|
||||
u32_t diff;
|
||||
sys_timeout_handler handler;
|
||||
void *arg;
|
||||
int had_one;
|
||||
u32_t now;
|
||||
|
||||
now = sys_now();
|
||||
if (next_timeout) {
|
||||
/* this cares for wraparounds */
|
||||
diff = LWIP_U32_DIFF(now, timeouts_last_time);
|
||||
do
|
||||
{
|
||||
had_one = 0;
|
||||
tmptimeout = next_timeout;
|
||||
if (tmptimeout->time <= diff) {
|
||||
/* timeout has expired */
|
||||
had_one = 1;
|
||||
timeouts_last_time = now;
|
||||
diff -= tmptimeout->time;
|
||||
next_timeout = tmptimeout->next;
|
||||
handler = tmptimeout->h;
|
||||
arg = tmptimeout->arg;
|
||||
#if LWIP_DEBUG_TIMERNAMES
|
||||
if (handler != NULL) {
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n",
|
||||
tmptimeout->handler_name, arg));
|
||||
}
|
||||
#endif /* LWIP_DEBUG_TIMERNAMES */
|
||||
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
|
||||
if (handler != NULL) {
|
||||
handler(arg);
|
||||
}
|
||||
}
|
||||
/* repeat until all expired timers have been called */
|
||||
}while(had_one);
|
||||
}
|
||||
}
|
||||
|
||||
/** Set back the timestamp of the last call to sys_check_timeouts()
|
||||
* This is necessary if sys_check_timeouts() hasn't been called for a long
|
||||
* time (e.g. while saving energy) to prevent all timer functions of that
|
||||
* period being called.
|
||||
*/
|
||||
void
|
||||
sys_restart_timeouts(void)
|
||||
{
|
||||
timeouts_last_time = sys_now();
|
||||
}
|
||||
|
||||
#else /* NO_SYS */
|
||||
|
||||
/**
|
||||
* Wait (forever) for a message to arrive in an mbox.
|
||||
* While waiting, timeouts are processed.
|
||||
*
|
||||
* @param mbox the mbox to fetch the message from
|
||||
* @param msg the place to store the message
|
||||
*/
|
||||
void
|
||||
sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
|
||||
{
|
||||
u32_t time_needed;
|
||||
struct sys_timeo *tmptimeout;
|
||||
sys_timeout_handler handler;
|
||||
void *arg;
|
||||
|
||||
again:
|
||||
if (!next_timeout) {
|
||||
time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
|
||||
} else {
|
||||
if (next_timeout->time > 0) {
|
||||
time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time);
|
||||
} else {
|
||||
time_needed = SYS_ARCH_TIMEOUT;
|
||||
}
|
||||
|
||||
if (time_needed == SYS_ARCH_TIMEOUT) {
|
||||
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
|
||||
could be fetched. We should now call the timeout handler and
|
||||
deallocate the memory allocated for the timeout. */
|
||||
tmptimeout = next_timeout;
|
||||
next_timeout = tmptimeout->next;
|
||||
handler = tmptimeout->h;
|
||||
arg = tmptimeout->arg;
|
||||
#if LWIP_DEBUG_TIMERNAMES
|
||||
if (handler != NULL) {
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n",
|
||||
tmptimeout->handler_name, arg));
|
||||
}
|
||||
#endif /* LWIP_DEBUG_TIMERNAMES */
|
||||
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
|
||||
if (handler != NULL) {
|
||||
/* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the
|
||||
timeout handler function. */
|
||||
LOCK_TCPIP_CORE();
|
||||
handler(arg);
|
||||
UNLOCK_TCPIP_CORE();
|
||||
}
|
||||
LWIP_TCPIP_THREAD_ALIVE();
|
||||
|
||||
/* We try again to fetch a message from the mbox. */
|
||||
goto again;
|
||||
} else {
|
||||
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
|
||||
occured. The time variable is set to the number of
|
||||
milliseconds we waited for the message. */
|
||||
if (time_needed < next_timeout->time) {
|
||||
next_timeout->time -= time_needed;
|
||||
} else {
|
||||
next_timeout->time = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* NO_SYS */
|
||||
|
||||
#else /* LWIP_TIMERS */
|
||||
/* Satisfy the TCP code which calls this function */
|
||||
void
|
||||
tcp_timer_needed(void)
|
||||
{
|
||||
}
|
||||
#endif /* LWIP_TIMERS */
|
||||
630
src/core/udp.c
630
src/core/udp.c
@@ -53,11 +53,14 @@
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/icmp6.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "arch/perf.h"
|
||||
@@ -77,7 +80,7 @@ struct udp_pcb *udp_pcbs;
|
||||
* recv function. If no pcb is found or the datagram is incorrect, the
|
||||
* pbuf is freed.
|
||||
*
|
||||
* @param p pbuf to be demultiplexed to a UDP PCB.
|
||||
* @param p pbuf to be demultiplexed to a UDP PCB (p->payload pointing to the UDP header)
|
||||
* @param inp network interface on which the datagram was received.
|
||||
*
|
||||
*/
|
||||
@@ -87,19 +90,17 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
struct udp_hdr *udphdr;
|
||||
struct udp_pcb *pcb, *prev;
|
||||
struct udp_pcb *uncon_pcb;
|
||||
struct ip_hdr *iphdr;
|
||||
u16_t src, dest;
|
||||
u8_t local_match;
|
||||
u8_t broadcast;
|
||||
u8_t for_us;
|
||||
|
||||
PERF_START;
|
||||
|
||||
UDP_STATS_INC(udp.recv);
|
||||
|
||||
iphdr = p->payload;
|
||||
|
||||
/* Check minimum length (IP header + UDP header)
|
||||
* and move payload pointer to UDP header */
|
||||
if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) {
|
||||
/* Check minimum length (UDP header) */
|
||||
if (p->len < UDP_HLEN) {
|
||||
/* drop short packets */
|
||||
LWIP_DEBUGF(UDP_DEBUG,
|
||||
("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len));
|
||||
@@ -112,6 +113,13 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
|
||||
udphdr = (struct udp_hdr *)p->payload;
|
||||
|
||||
/* is broadcast packet ? */
|
||||
#if LWIP_IPV6
|
||||
broadcast = !ip_current_is_v6() && ip_addr_isbroadcast(ip_current_dest_addr(), inp);
|
||||
#else /* LWIP_IPV6 */
|
||||
broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), inp);
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));
|
||||
|
||||
/* convert src and dest ports to host byte order */
|
||||
@@ -121,13 +129,11 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
udp_debug_print(udphdr);
|
||||
|
||||
/* print the UDP source and destination */
|
||||
LWIP_DEBUGF(UDP_DEBUG,
|
||||
("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- "
|
||||
"(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
|
||||
ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest),
|
||||
ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest),
|
||||
ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src),
|
||||
ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src)));
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp ("));
|
||||
ipX_addr_debug_print(ip_current_is_v6(), UDP_DEBUG, ipX_current_dest_addr());
|
||||
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", ntohs(udphdr->dest)));
|
||||
ipX_addr_debug_print(ip_current_is_v6(), UDP_DEBUG, ipX_current_src_addr());
|
||||
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", ntohs(udphdr->src)));
|
||||
|
||||
#if LWIP_DHCP
|
||||
pcb = NULL;
|
||||
@@ -139,9 +145,10 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) {
|
||||
/* accept the packe if
|
||||
(- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY!
|
||||
- inp->dhcp->pcb->remote == ANY or iphdr->src */
|
||||
if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) ||
|
||||
ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &(iphdr->src)))) {
|
||||
- inp->dhcp->pcb->remote == ANY or iphdr->src
|
||||
(no need to check for IPv6 since the dhcp struct always uses IPv4) */
|
||||
if (ipX_addr_isany(0, &inp->dhcp->pcb->remote_ip) ||
|
||||
ip_addr_cmp(ipX_2_ip(&(inp->dhcp->pcb->remote_ip)), ip_current_src_addr())) {
|
||||
pcb = inp->dhcp->pcb;
|
||||
}
|
||||
}
|
||||
@@ -159,34 +166,48 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
local_match = 0;
|
||||
/* print the PCB local and remote address */
|
||||
LWIP_DEBUGF(UDP_DEBUG,
|
||||
("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- "
|
||||
"(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
|
||||
ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),
|
||||
ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port,
|
||||
ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
|
||||
ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port));
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("pcb ("));
|
||||
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG, &pcb->local_ip);
|
||||
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port));
|
||||
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG, &pcb->remote_ip);
|
||||
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port));
|
||||
|
||||
/* compare PCB local addr+port to UDP destination addr+port */
|
||||
if ((pcb->local_port == dest) &&
|
||||
(ip_addr_isany(&pcb->local_ip) ||
|
||||
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) ||
|
||||
#if LWIP_IPV6
|
||||
((PCB_ISIPV6(pcb) && (ip_current_is_v6()) &&
|
||||
(ip6_addr_isany(ipX_2_ip6(&pcb->local_ip)) ||
|
||||
#if LWIP_IPV6_MLD
|
||||
ip6_addr_ismulticast(ip6_current_dest_addr()) ||
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
ip6_addr_cmp(ipX_2_ip6(&pcb->local_ip), ip6_current_dest_addr()))) ||
|
||||
(!PCB_ISIPV6(pcb) &&
|
||||
(ip_current_header() != NULL) &&
|
||||
#else /* LWIP_IPV6 */
|
||||
((
|
||||
#endif /* LWIP_IPV6 */
|
||||
((!broadcast && ipX_addr_isany(0, &pcb->local_ip)) ||
|
||||
ip_addr_cmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr()) ||
|
||||
#if LWIP_IGMP
|
||||
ip_addr_ismulticast(&(iphdr->dest)) ||
|
||||
ip_addr_ismulticast(ip_current_dest_addr()) ||
|
||||
#endif /* LWIP_IGMP */
|
||||
ip_addr_isbroadcast(&(iphdr->dest), inp))) {
|
||||
#if IP_SOF_BROADCAST_RECV
|
||||
(broadcast && (pcb->so_options & SOF_BROADCAST)))))) {
|
||||
#else /* IP_SOF_BROADCAST_RECV */
|
||||
(broadcast))))) {
|
||||
#endif /* IP_SOF_BROADCAST_RECV */
|
||||
local_match = 1;
|
||||
if ((uncon_pcb == NULL) &&
|
||||
((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
|
||||
/* the first unconnected matching PCB */
|
||||
/* the first unconnected matching PCB */
|
||||
uncon_pcb = pcb;
|
||||
}
|
||||
}
|
||||
/* compare PCB remote addr+port to UDP source addr+port */
|
||||
if ((local_match != 0) &&
|
||||
(pcb->remote_port == src) &&
|
||||
(ip_addr_isany(&pcb->remote_ip) ||
|
||||
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) {
|
||||
(pcb->remote_port == src) && IP_PCB_IPVER_INPUT_MATCH(pcb) &&
|
||||
(ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->remote_ip) ||
|
||||
ipX_addr_cmp(PCB_ISIPV6(pcb), &pcb->remote_ip, ipX_current_src_addr()))) {
|
||||
/* the first fully matching PCB */
|
||||
if (prev != NULL) {
|
||||
/* move the pcb to the front of udp_pcbs so that is
|
||||
@@ -208,12 +229,24 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
}
|
||||
|
||||
/* Check checksum if this is a match or if it was directed at us. */
|
||||
if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) {
|
||||
if (pcb != NULL) {
|
||||
for_us = 1;
|
||||
} else {
|
||||
#if LWIP_IPV6
|
||||
if (ip_current_is_v6()) {
|
||||
for_us = netif_matches_ip6_addr(inp, ip6_current_dest_addr());
|
||||
} else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
for_us = ip_addr_cmp(&inp->ip_addr, ip_current_dest_addr());
|
||||
}
|
||||
}
|
||||
if (for_us) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n"));
|
||||
#if LWIP_UDPLITE
|
||||
if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
|
||||
/* Do the UDP Lite checksum */
|
||||
#if CHECKSUM_CHECK_UDP
|
||||
#if LWIP_UDPLITE
|
||||
if (ip_current_header_proto() == IP_PROTO_UDPLITE) {
|
||||
/* Do the UDP Lite checksum */
|
||||
u16_t chklen = ntohs(udphdr->len);
|
||||
if (chklen < sizeof(struct udp_hdr)) {
|
||||
if (chklen == 0) {
|
||||
@@ -223,44 +256,26 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
} else {
|
||||
/* At least the UDP-Lite header must be covered by the
|
||||
checksum! (Again, see RFC 3828 chap. 3.1) */
|
||||
UDP_STATS_INC(udp.chkerr);
|
||||
UDP_STATS_INC(udp.drop);
|
||||
snmp_inc_udpinerrors();
|
||||
pbuf_free(p);
|
||||
goto end;
|
||||
goto chkerr;
|
||||
}
|
||||
}
|
||||
if (inet_chksum_pseudo_partial(p, (struct ip_addr *)&(iphdr->src),
|
||||
(struct ip_addr *)&(iphdr->dest),
|
||||
IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | 2,
|
||||
("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
|
||||
UDP_STATS_INC(udp.chkerr);
|
||||
UDP_STATS_INC(udp.drop);
|
||||
snmp_inc_udpinerrors();
|
||||
pbuf_free(p);
|
||||
goto end;
|
||||
if (ipX_chksum_pseudo_partial(ip_current_is_v6(), p, IP_PROTO_UDPLITE,
|
||||
p->tot_len, chklen,
|
||||
ipX_current_src_addr(), ipX_current_dest_addr()) != 0) {
|
||||
goto chkerr;
|
||||
}
|
||||
#endif /* CHECKSUM_CHECK_UDP */
|
||||
} else
|
||||
#endif /* LWIP_UDPLITE */
|
||||
{
|
||||
#if CHECKSUM_CHECK_UDP
|
||||
if (udphdr->chksum != 0) {
|
||||
if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
|
||||
(struct ip_addr *)&(iphdr->dest),
|
||||
IP_PROTO_UDP, p->tot_len) != 0) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | 2,
|
||||
("udp_input: UDP datagram discarded due to failing checksum\n"));
|
||||
UDP_STATS_INC(udp.chkerr);
|
||||
UDP_STATS_INC(udp.drop);
|
||||
snmp_inc_udpinerrors();
|
||||
pbuf_free(p);
|
||||
goto end;
|
||||
if (ipX_chksum_pseudo(ip_current_is_v6(), p, IP_PROTO_UDP, p->tot_len,
|
||||
ipX_current_src_addr(),
|
||||
ipX_current_dest_addr()) != 0) {
|
||||
goto chkerr;
|
||||
}
|
||||
}
|
||||
#endif /* CHECKSUM_CHECK_UDP */
|
||||
}
|
||||
#endif /* CHECKSUM_CHECK_UDP */
|
||||
if(pbuf_header(p, -UDP_HLEN)) {
|
||||
/* Can we cope with this failing? Just assert for now */
|
||||
LWIP_ASSERT("pbuf_header failed\n", 0);
|
||||
@@ -271,10 +286,87 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
}
|
||||
if (pcb != NULL) {
|
||||
snmp_inc_udpindatagrams();
|
||||
#if SO_REUSE && SO_REUSE_RXTOALL
|
||||
if ((broadcast ||
|
||||
#if LWIP_IPV6
|
||||
ip6_addr_ismulticast(ip6_current_dest_addr()) ||
|
||||
#endif /* LWIP_IPV6 */
|
||||
ip_addr_ismulticast(ip_current_dest_addr())) &&
|
||||
((pcb->so_options & SOF_REUSEADDR) != 0)) {
|
||||
/* pass broadcast- or multicast packets to all multicast pcbs
|
||||
if SOF_REUSEADDR is set on the first match */
|
||||
struct udp_pcb *mpcb;
|
||||
u8_t p_header_changed = 0;
|
||||
s16_t hdrs_len = (s16_t)(ip_current_header_tot_len() + UDP_HLEN);
|
||||
for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) {
|
||||
if (mpcb != pcb) {
|
||||
/* compare PCB local addr+port to UDP destination addr+port */
|
||||
if ((mpcb->local_port == dest) &&
|
||||
#if LWIP_IPV6
|
||||
((PCB_ISIPV6(mpcb) &&
|
||||
(ip6_addr_ismulticast(ip6_current_dest_addr()) ||
|
||||
ip6_addr_cmp(ipX_2_ip6(&mpcb->local_ip), ip6_current_dest_addr()))) ||
|
||||
(!PCB_ISIPV6(mpcb) &&
|
||||
#else /* LWIP_IPV6 */
|
||||
((
|
||||
#endif /* LWIP_IPV6 */
|
||||
((!broadcast && ipX_addr_isany(0, &mpcb->local_ip)) ||
|
||||
ip_addr_cmp(ipX_2_ip(&mpcb->local_ip), ip_current_dest_addr()) ||
|
||||
#if LWIP_IGMP
|
||||
ip_addr_ismulticast(ip_current_dest_addr()) ||
|
||||
#endif /* LWIP_IGMP */
|
||||
#if IP_SOF_BROADCAST_RECV
|
||||
(broadcast && (mpcb->so_options & SOF_BROADCAST)))))) {
|
||||
#else /* IP_SOF_BROADCAST_RECV */
|
||||
(broadcast))))) {
|
||||
#endif /* IP_SOF_BROADCAST_RECV */
|
||||
/* pass a copy of the packet to all local matches */
|
||||
if (mpcb->recv.ip4 != NULL) {
|
||||
struct pbuf *q;
|
||||
/* for that, move payload to IP header again */
|
||||
if (p_header_changed == 0) {
|
||||
pbuf_header(p, hdrs_len);
|
||||
p_header_changed = 1;
|
||||
}
|
||||
q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
|
||||
if (q != NULL) {
|
||||
err_t err = pbuf_copy(q, p);
|
||||
if (err == ERR_OK) {
|
||||
/* move payload to UDP data */
|
||||
pbuf_header(q, -hdrs_len);
|
||||
#if LWIP_IPV6
|
||||
if (PCB_ISIPV6(mpcb)) {
|
||||
mpcb->recv.ip6(mpcb->recv_arg, mpcb, q, ip6_current_src_addr(), src);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
mpcb->recv.ip4(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p_header_changed) {
|
||||
/* and move payload to UDP data again */
|
||||
pbuf_header(p, -hdrs_len);
|
||||
}
|
||||
}
|
||||
#endif /* SO_REUSE && SO_REUSE_RXTOALL */
|
||||
/* callback */
|
||||
if (pcb->recv != NULL) {
|
||||
if (pcb->recv.ip4 != NULL) {
|
||||
/* now the recv function is responsible for freeing p */
|
||||
pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src);
|
||||
#if LWIP_IPV6
|
||||
if (PCB_ISIPV6(pcb)) {
|
||||
pcb->recv.ip6(pcb->recv_arg, pcb, p, ip6_current_src_addr(), src);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr(), src);
|
||||
}
|
||||
} else {
|
||||
/* no recv function registered? then we have to free the pbuf! */
|
||||
pbuf_free(p);
|
||||
@@ -283,17 +375,19 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
} else {
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n"));
|
||||
|
||||
#if LWIP_ICMP
|
||||
#if LWIP_ICMP || LWIP_ICMP6
|
||||
/* No match was found, send ICMP destination port unreachable unless
|
||||
destination address was broadcast/multicast. */
|
||||
if (!ip_addr_isbroadcast(&iphdr->dest, inp) &&
|
||||
!ip_addr_ismulticast(&iphdr->dest)) {
|
||||
if (!broadcast &&
|
||||
#if LWIP_IPV6
|
||||
!ip6_addr_ismulticast(ip6_current_dest_addr()) &&
|
||||
#endif /* LWIP_IPV6 */
|
||||
!ip_addr_ismulticast(ip_current_dest_addr())) {
|
||||
/* move payload pointer back to ip header */
|
||||
pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN);
|
||||
LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr));
|
||||
icmp_dest_unreach(p, ICMP_DUR_PORT);
|
||||
pbuf_header(p, ip_current_header_tot_len() + UDP_HLEN);
|
||||
icmp_port_unreach(ip_current_is_v6(), p);
|
||||
}
|
||||
#endif /* LWIP_ICMP */
|
||||
#endif /* LWIP_ICMP || LWIP_ICMP6 */
|
||||
UDP_STATS_INC(udp.proterr);
|
||||
UDP_STATS_INC(udp.drop);
|
||||
snmp_inc_udpnoports();
|
||||
@@ -304,6 +398,15 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
}
|
||||
end:
|
||||
PERF_STOP("udp_input");
|
||||
return;
|
||||
chkerr:
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("udp_input: UDP (or UDP Lite) datagram discarded due to failing checksum\n"));
|
||||
UDP_STATS_INC(udp.chkerr);
|
||||
UDP_STATS_INC(udp.drop);
|
||||
snmp_inc_udpinerrors();
|
||||
pbuf_free(p);
|
||||
PERF_STOP("udp_input");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -328,9 +431,22 @@ err_t
|
||||
udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
||||
{
|
||||
/* send to the packet using remote ip and port stored in the pcb */
|
||||
return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);
|
||||
return udp_sendto(pcb, p, ipX_2_ip(&pcb->remote_ip), pcb->remote_port);
|
||||
}
|
||||
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
/** Same as udp_send() but with checksum
|
||||
*/
|
||||
err_t
|
||||
udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
|
||||
u8_t have_chksum, u16_t chksum)
|
||||
{
|
||||
/* send to the packet using remote ip and port stored in the pcb */
|
||||
return udp_sendto_chksum(pcb, p, ipX_2_ip(&pcb->remote_ip), pcb->remote_port,
|
||||
have_chksum, chksum);
|
||||
}
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
|
||||
/**
|
||||
* Send data to a specified address using UDP.
|
||||
*
|
||||
@@ -350,26 +466,55 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
||||
*/
|
||||
err_t
|
||||
udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
|
||||
struct ip_addr *dst_ip, u16_t dst_port)
|
||||
ip_addr_t *dst_ip, u16_t dst_port)
|
||||
{
|
||||
struct netif *netif;
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0);
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_send\n"));
|
||||
/** Same as udp_sendto(), but with checksum */
|
||||
err_t
|
||||
udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
|
||||
u16_t dst_port, u8_t have_chksum, u16_t chksum)
|
||||
{
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
struct netif *netif;
|
||||
ipX_addr_t *dst_ip_route = ip_2_ipX(dst_ip);
|
||||
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));
|
||||
|
||||
#if LWIP_IPV6 || LWIP_IGMP
|
||||
if (ipX_addr_ismulticast(PCB_ISIPV6(pcb), dst_ip_route)) {
|
||||
/* For multicast, find a netif based on source address. */
|
||||
#if LWIP_IPV6
|
||||
if (PCB_ISIPV6(pcb)) {
|
||||
dst_ip_route = &pcb->local_ip;
|
||||
} else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
#if LWIP_IGMP
|
||||
dst_ip_route = ip_2_ipX(&pcb->multicast_ip);
|
||||
#endif /* LWIP_IGMP */
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_IPV6 || LWIP_IGMP */
|
||||
|
||||
/* find the outgoing network interface for this packet */
|
||||
#if LWIP_IGMP
|
||||
netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));
|
||||
#else
|
||||
netif = ip_route(dst_ip);
|
||||
#endif /* LWIP_IGMP */
|
||||
netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip_route);
|
||||
|
||||
/* no outgoing network interface could be found? */
|
||||
if (netif == NULL) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%"X32_F"\n", dst_ip->addr));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to "));
|
||||
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ip_2_ipX(dst_ip));
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("\n"));
|
||||
UDP_STATS_INC(udp.rterr);
|
||||
return ERR_RTE;
|
||||
}
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum);
|
||||
#else /* LWIP_CHECKSUM_ON_COPY */
|
||||
return udp_sendto_if(pcb, p, dst_ip, dst_port, netif);
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -393,19 +538,44 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
|
||||
*/
|
||||
err_t
|
||||
udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
|
||||
struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif)
|
||||
ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif)
|
||||
{
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0);
|
||||
}
|
||||
|
||||
/** Same as udp_sendto_if(), but with checksum */
|
||||
err_t
|
||||
udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
|
||||
u16_t dst_port, struct netif *netif, u8_t have_chksum,
|
||||
u16_t chksum)
|
||||
{
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
struct udp_hdr *udphdr;
|
||||
struct ip_addr *src_ip;
|
||||
ip_addr_t *src_ip;
|
||||
err_t err;
|
||||
struct pbuf *q; /* q will be sent down the stack */
|
||||
u8_t ip_proto;
|
||||
|
||||
#if IP_SOF_BROADCAST
|
||||
/* broadcast filter? */
|
||||
if ( ((pcb->so_options & SOF_BROADCAST) == 0) &&
|
||||
#if LWIP_IPV6
|
||||
!PCB_ISIPV6(pcb) &&
|
||||
#endif /* LWIP_IPV6 */
|
||||
ip_addr_isbroadcast(dst_ip, netif) ) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
|
||||
return ERR_VAL;
|
||||
}
|
||||
#endif /* IP_SOF_BROADCAST */
|
||||
|
||||
/* if the PCB is not yet bound to a port, bind it here */
|
||||
if (pcb->local_port == 0) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n"));
|
||||
err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n"));
|
||||
err = udp_bind(pcb, ipX_2_ip(&pcb->local_ip), pcb->local_port);
|
||||
if (err != ERR_OK) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: forced port bind failed\n"));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n"));
|
||||
return err;
|
||||
}
|
||||
}
|
||||
@@ -416,11 +586,13 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
|
||||
q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
|
||||
/* new header pbuf could not be allocated? */
|
||||
if (q == NULL) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: could not allocate header\n"));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n"));
|
||||
return ERR_MEM;
|
||||
}
|
||||
/* chain header q in front of given pbuf p */
|
||||
pbuf_chain(q, p);
|
||||
if (p->tot_len != 0) {
|
||||
/* chain header q in front of given pbuf p (only if p contains data) */
|
||||
pbuf_chain(q, p);
|
||||
}
|
||||
/* first pbuf q points to header pbuf */
|
||||
LWIP_DEBUGF(UDP_DEBUG,
|
||||
("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
|
||||
@@ -433,20 +605,68 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
|
||||
LWIP_ASSERT("check that first pbuf can hold struct udp_hdr",
|
||||
(q->len >= sizeof(struct udp_hdr)));
|
||||
/* q now represents the packet to be sent */
|
||||
udphdr = q->payload;
|
||||
udphdr = (struct udp_hdr *)q->payload;
|
||||
udphdr->src = htons(pcb->local_port);
|
||||
udphdr->dest = htons(dst_port);
|
||||
/* in UDP, 0 checksum means 'no checksum' */
|
||||
udphdr->chksum = 0x0000;
|
||||
|
||||
/* Multicast Loop? */
|
||||
#if LWIP_IGMP
|
||||
if (((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) &&
|
||||
#if LWIP_IPV6
|
||||
(
|
||||
#if LWIP_IPV6_MLD
|
||||
(PCB_ISIPV6(pcb) &&
|
||||
ip6_addr_ismulticast(ip_2_ip6(dst_ip))) ||
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
(!PCB_ISIPV6(pcb) &&
|
||||
#else /* LWIP_IPV6 */
|
||||
((
|
||||
#endif /* LWIP_IPV6 */
|
||||
ip_addr_ismulticast(dst_ip)))) {
|
||||
q->flags |= PBUF_FLAG_MCASTLOOP;
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
|
||||
|
||||
/* PCB local address is IP_ANY_ADDR? */
|
||||
if (ip_addr_isany(&pcb->local_ip)) {
|
||||
#if LWIP_IPV6
|
||||
if (PCB_ISIPV6(pcb)) {
|
||||
if (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) {
|
||||
src_ip = ip6_2_ip(ip6_select_source_address(netif, ip_2_ip6(dst_ip)));
|
||||
if (src_ip == NULL) {
|
||||
/* No suitable source address was found. */
|
||||
if (q != p) {
|
||||
/* free the header pbuf */
|
||||
pbuf_free(q);
|
||||
/* p is still referenced by the caller, and will live on */
|
||||
}
|
||||
return ERR_RTE;
|
||||
}
|
||||
} else {
|
||||
/* use UDP PCB local IPv6 address as source address, if still valid. */
|
||||
if (netif_matches_ip6_addr(netif, ipX_2_ip6(&pcb->local_ip)) < 0) {
|
||||
/* Address isn't valid anymore. */
|
||||
if (q != p) {
|
||||
/* free the header pbuf */
|
||||
pbuf_free(q);
|
||||
/* p is still referenced by the caller, and will live on */
|
||||
}
|
||||
return ERR_RTE;
|
||||
}
|
||||
src_ip = ipX_2_ip(&pcb->local_ip);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
if (ip_addr_isany(ipX_2_ip(&pcb->local_ip))) {
|
||||
/* use outgoing network interface IP address as source address */
|
||||
src_ip = &(netif->ip_addr);
|
||||
} else {
|
||||
/* check if UDP PCB local IP address is correct
|
||||
* this could be an old address if netif->ip_addr has changed */
|
||||
if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
|
||||
if (!ip_addr_cmp(ipX_2_ip(&(pcb->local_ip)), &(netif->ip_addr))) {
|
||||
/* local_ip doesn't match, drop the packet */
|
||||
if (q != p) {
|
||||
/* free the header pbuf */
|
||||
@@ -457,7 +677,7 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
|
||||
return ERR_VAL;
|
||||
}
|
||||
/* use UDP PCB local IP address as source address */
|
||||
src_ip = &(pcb->local_ip);
|
||||
src_ip = ipX_2_ip(&(pcb->local_ip));
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));
|
||||
@@ -485,21 +705,28 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
|
||||
udphdr->len = htons(chklen_hdr);
|
||||
/* calculate checksum */
|
||||
#if CHECKSUM_GEN_UDP
|
||||
udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip,
|
||||
IP_PROTO_UDPLITE, q->tot_len, chklen);
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
if (have_chksum) {
|
||||
chklen = UDP_HLEN;
|
||||
}
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
udphdr->chksum = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), q, IP_PROTO_UDPLITE,
|
||||
q->tot_len, chklen, ip_2_ipX(src_ip), ip_2_ipX(dst_ip));
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
if (have_chksum) {
|
||||
u32_t acc;
|
||||
acc = udphdr->chksum + (u16_t)~(chksum);
|
||||
udphdr->chksum = FOLD_U32T(acc);
|
||||
}
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
|
||||
/* chksum zero must become 0xffff, as zero means 'no checksum' */
|
||||
if (udphdr->chksum == 0x0000)
|
||||
if (udphdr->chksum == 0x0000) {
|
||||
udphdr->chksum = 0xffff;
|
||||
#endif /* CHECKSUM_CHECK_UDP */
|
||||
/* output to IP */
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = &(pcb->addr_hint);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = NULL;
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
}
|
||||
#endif /* CHECKSUM_GEN_UDP */
|
||||
|
||||
ip_proto = IP_PROTO_UDPLITE;
|
||||
} else
|
||||
#endif /* LWIP_UDPLITE */
|
||||
{ /* UDP */
|
||||
@@ -507,23 +734,40 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
|
||||
udphdr->len = htons(q->tot_len);
|
||||
/* calculate checksum */
|
||||
#if CHECKSUM_GEN_UDP
|
||||
if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
|
||||
udphdr->chksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);
|
||||
/* Checksum is mandatory over IPv6. */
|
||||
if (PCB_ISIPV6(pcb) || (pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
|
||||
u16_t udpchksum;
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
if (have_chksum) {
|
||||
u32_t acc;
|
||||
udpchksum = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), q, IP_PROTO_UDP,
|
||||
q->tot_len, UDP_HLEN, ip_2_ipX(src_ip), ip_2_ipX(dst_ip));
|
||||
acc = udpchksum + (u16_t)~(chksum);
|
||||
udpchksum = FOLD_U32T(acc);
|
||||
} else
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
{
|
||||
udpchksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), q, IP_PROTO_UDP, q->tot_len,
|
||||
ip_2_ipX(src_ip), ip_2_ipX(dst_ip));
|
||||
}
|
||||
|
||||
/* chksum zero must become 0xffff, as zero means 'no checksum' */
|
||||
if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;
|
||||
if (udpchksum == 0x0000) {
|
||||
udpchksum = 0xffff;
|
||||
}
|
||||
udphdr->chksum = udpchksum;
|
||||
}
|
||||
#endif /* CHECKSUM_CHECK_UDP */
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));
|
||||
/* output to IP */
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = &(pcb->addr_hint);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
netif->addr_hint = NULL;
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
#endif /* CHECKSUM_GEN_UDP */
|
||||
ip_proto = IP_PROTO_UDP;
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,0x%02"X16_F",)\n", (u16_t)ip_proto));
|
||||
/* output to IP */
|
||||
NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint));
|
||||
err = ipX_output_if(PCB_ISIPV6(pcb), q, src_ip, dst_ip, pcb->ttl, pcb->tos, ip_proto, netif);
|
||||
NETIF_SET_HWADDRHINT(netif, NULL);
|
||||
|
||||
/* TODO: must this be increased even if error occured? */
|
||||
snmp_inc_udpoutdatagrams();
|
||||
|
||||
@@ -559,14 +803,14 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
|
||||
* @see udp_disconnect()
|
||||
*/
|
||||
err_t
|
||||
udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
|
||||
{
|
||||
struct udp_pcb *ipcb;
|
||||
u8_t rebind;
|
||||
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_bind(ipaddr = "));
|
||||
ip_addr_debug_print(UDP_DEBUG, ipaddr);
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, (", port = %"U16_F")\n", port));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = "));
|
||||
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE, ip_2_ipX(ipaddr));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port));
|
||||
|
||||
rebind = 0;
|
||||
/* Check for double bind and rebind of the same pcb */
|
||||
@@ -579,33 +823,38 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
rebind = 1;
|
||||
}
|
||||
|
||||
/* this code does not allow upper layer to share a UDP port for
|
||||
listening to broadcast or multicast traffic (See SO_REUSE_ADDR and
|
||||
SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR
|
||||
combine with implementation of UDP PCB flags. Leon Woestenberg. */
|
||||
#ifdef LWIP_UDP_TODO
|
||||
/* port matches that of PCB in list? */
|
||||
else
|
||||
if ((ipcb->local_port == port) &&
|
||||
/* By default, we don't allow to bind to a port that any other udp
|
||||
PCB is alread bound to, unless *all* PCBs with that port have tha
|
||||
REUSEADDR flag set. */
|
||||
#if SO_REUSE
|
||||
else if (((pcb->so_options & SOF_REUSEADDR) == 0) &&
|
||||
((ipcb->so_options & SOF_REUSEADDR) == 0)) {
|
||||
#else /* SO_REUSE */
|
||||
/* port matches that of PCB in list and REUSEADDR not set -> reject */
|
||||
else {
|
||||
#endif /* SO_REUSE */
|
||||
if ((ipcb->local_port == port) && IP_PCB_IPVER_EQ(pcb, ipcb) &&
|
||||
/* IP address matches, or one is IP_ADDR_ANY? */
|
||||
(ip_addr_isany(&(ipcb->local_ip)) ||
|
||||
ip_addr_isany(ipaddr) ||
|
||||
ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {
|
||||
(ipX_addr_isany(PCB_ISIPV6(ipcb), &(ipcb->local_ip)) ||
|
||||
ipX_addr_isany(PCB_ISIPV6(ipcb), ip_2_ipX(ipaddr)) ||
|
||||
ipX_addr_cmp(PCB_ISIPV6(ipcb), &(ipcb->local_ip), ip_2_ipX(ipaddr)))) {
|
||||
/* other PCB already binds to this local IP and port */
|
||||
LWIP_DEBUGF(UDP_DEBUG,
|
||||
("udp_bind: local port %"U16_F" already bound by another pcb\n", port));
|
||||
return ERR_USE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ip_addr_set(&pcb->local_ip, ipaddr);
|
||||
ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->local_ip, ipaddr);
|
||||
|
||||
/* no port specified? */
|
||||
if (port == 0) {
|
||||
#ifndef UDP_LOCAL_PORT_RANGE_START
|
||||
#define UDP_LOCAL_PORT_RANGE_START 4096
|
||||
#define UDP_LOCAL_PORT_RANGE_END 0x7fff
|
||||
/* From http://www.iana.org/assignments/port-numbers:
|
||||
"The Dynamic and/or Private Ports are those from 49152 through 65535" */
|
||||
#define UDP_LOCAL_PORT_RANGE_START 0xc000
|
||||
#define UDP_LOCAL_PORT_RANGE_END 0xffff
|
||||
#endif
|
||||
port = UDP_LOCAL_PORT_RANGE_START;
|
||||
ipcb = udp_pcbs;
|
||||
@@ -615,9 +864,10 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
port++;
|
||||
/* restart scanning all udp pcbs */
|
||||
ipcb = udp_pcbs;
|
||||
} else
|
||||
} else {
|
||||
/* go on with next udp pcb */
|
||||
ipcb = ipcb->next;
|
||||
}
|
||||
}
|
||||
if (ipcb != NULL) {
|
||||
/* no more ports available in local range */
|
||||
@@ -633,14 +883,12 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
pcb->next = udp_pcbs;
|
||||
udp_pcbs = pcb;
|
||||
}
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",
|
||||
(u16_t)(ntohl(pcb->local_ip.addr) >> 24 & 0xff),
|
||||
(u16_t)(ntohl(pcb->local_ip.addr) >> 16 & 0xff),
|
||||
(u16_t)(ntohl(pcb->local_ip.addr) >> 8 & 0xff),
|
||||
(u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_bind: bound to "));
|
||||
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->local_ip);
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->local_port));
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect an UDP PCB.
|
||||
*
|
||||
@@ -659,44 +907,49 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
* @see udp_disconnect()
|
||||
*/
|
||||
err_t
|
||||
udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
|
||||
{
|
||||
struct udp_pcb *ipcb;
|
||||
|
||||
if (pcb->local_port == 0) {
|
||||
err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
|
||||
if (err != ERR_OK)
|
||||
err_t err = udp_bind(pcb, ipX_2_ip(&pcb->local_ip), pcb->local_port);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
ip_addr_set(&pcb->remote_ip, ipaddr);
|
||||
ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->remote_ip, ipaddr);
|
||||
pcb->remote_port = port;
|
||||
pcb->flags |= UDP_FLAGS_CONNECTED;
|
||||
/** TODO: this functionality belongs in upper layers */
|
||||
#ifdef LWIP_UDP_TODO
|
||||
/* Nail down local IP for netconn_addr()/getsockname() */
|
||||
if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {
|
||||
struct netif *netif;
|
||||
#if LWIP_IPV6
|
||||
if (!PCB_ISIPV6(pcb))
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
/* Nail down local IP for netconn_addr()/getsockname() */
|
||||
if (ip_addr_isany(ipX_2_ip(&pcb->local_ip)) && !ip_addr_isany(ipX_2_ip(&pcb->remote_ip))) {
|
||||
struct netif *netif;
|
||||
|
||||
if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));
|
||||
UDP_STATS_INC(udp.rterr);
|
||||
return ERR_RTE;
|
||||
if ((netif = ip_route(ipX_2_ip(&pcb->remote_ip))) == NULL) {
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n",
|
||||
ip4_addr_get_u32(ipX_2_ip(&pcb->remote_ip))));
|
||||
UDP_STATS_INC(udp.rterr);
|
||||
return ERR_RTE;
|
||||
}
|
||||
/** TODO: this will bind the udp pcb locally, to the interface which
|
||||
is used to route output packets to the remote address. However, we
|
||||
might want to accept incoming packets on any interface! */
|
||||
ipX_addr_copy(0, pcb->local_ip, netif->ip_addr);
|
||||
} else if (ip_addr_isany(ipX_2_ip(&pcb->remote_ip))) {
|
||||
ipX_addr_set_any(0, &pcb->local_ip);
|
||||
}
|
||||
/** TODO: this will bind the udp pcb locally, to the interface which
|
||||
is used to route output packets to the remote address. However, we
|
||||
might want to accept incoming packets on any interface! */
|
||||
pcb->local_ip = netif->ip_addr;
|
||||
} else if (ip_addr_isany(&pcb->remote_ip)) {
|
||||
pcb->local_ip.addr = 0;
|
||||
}
|
||||
#endif
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",
|
||||
(u16_t)(ntohl(pcb->remote_ip.addr) >> 24 & 0xff),
|
||||
(u16_t)(ntohl(pcb->remote_ip.addr) >> 16 & 0xff),
|
||||
(u16_t)(ntohl(pcb->remote_ip.addr) >> 8 & 0xff),
|
||||
(u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to "));
|
||||
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
||||
&pcb->remote_ip);
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->remote_port));
|
||||
|
||||
/* Insert UDP PCB into the list of active UDP PCBs. */
|
||||
for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
|
||||
@@ -720,7 +973,7 @@ void
|
||||
udp_disconnect(struct udp_pcb *pcb)
|
||||
{
|
||||
/* reset remote address association */
|
||||
ip_addr_set(&pcb->remote_ip, IP_ADDR_ANY);
|
||||
ipX_addr_set_any(PCB_ISIPV6(pcb), &pcb->remote_ip);
|
||||
pcb->remote_port = 0;
|
||||
/* mark PCB as unconnected */
|
||||
pcb->flags &= ~UDP_FLAGS_CONNECTED;
|
||||
@@ -736,13 +989,10 @@ udp_disconnect(struct udp_pcb *pcb)
|
||||
* @param recv_arg additional argument to pass to the callback function
|
||||
*/
|
||||
void
|
||||
udp_recv(struct udp_pcb *pcb,
|
||||
void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p,
|
||||
struct ip_addr *addr, u16_t port),
|
||||
void *recv_arg)
|
||||
udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg)
|
||||
{
|
||||
/* remember recv() callback and user data */
|
||||
pcb->recv = recv;
|
||||
pcb->recv.ip4 = recv;
|
||||
pcb->recv_arg = recv_arg;
|
||||
}
|
||||
|
||||
@@ -765,7 +1015,7 @@ udp_remove(struct udp_pcb *pcb)
|
||||
/* make list start at 2nd pcb */
|
||||
udp_pcbs = udp_pcbs->next;
|
||||
/* pcb not 1st in list */
|
||||
} else
|
||||
} else {
|
||||
for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
|
||||
/* find pcb in udp_pcbs list */
|
||||
if (pcb2->next != NULL && pcb2->next == pcb) {
|
||||
@@ -773,6 +1023,7 @@ udp_remove(struct udp_pcb *pcb)
|
||||
pcb2->next = pcb->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
memp_free(MEMP_UDP_PCB, pcb);
|
||||
}
|
||||
|
||||
@@ -788,7 +1039,7 @@ struct udp_pcb *
|
||||
udp_new(void)
|
||||
{
|
||||
struct udp_pcb *pcb;
|
||||
pcb = memp_malloc(MEMP_UDP_PCB);
|
||||
pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB);
|
||||
/* could allocate UDP PCB? */
|
||||
if (pcb != NULL) {
|
||||
/* UDP Lite: by initializing to all zeroes, chksum_len is set to 0
|
||||
@@ -801,6 +1052,25 @@ udp_new(void)
|
||||
return pcb;
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
/**
|
||||
* Create a UDP PCB for IPv6.
|
||||
*
|
||||
* @return The UDP PCB which was created. NULL if the PCB data structure
|
||||
* could not be allocated.
|
||||
*
|
||||
* @see udp_remove()
|
||||
*/
|
||||
struct udp_pcb *
|
||||
udp_new_ip6(void)
|
||||
{
|
||||
struct udp_pcb *pcb;
|
||||
pcb = udp_new();
|
||||
ip_set_v6(pcb, 1);
|
||||
return pcb;
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#if UDP_DEBUG
|
||||
/**
|
||||
* Print UDP header information for debug purposes.
|
||||
|
||||
@@ -52,6 +52,10 @@
|
||||
#include "lwip/udp.h"
|
||||
#include "netif/etharp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* AutoIP Timing */
|
||||
#define AUTOIP_TMR_INTERVAL 100
|
||||
#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL)
|
||||
@@ -76,7 +80,7 @@
|
||||
|
||||
struct autoip
|
||||
{
|
||||
struct ip_addr llipaddr; /* the currently selected, probed, announced or used LL IP-Address */
|
||||
ip_addr_t llipaddr; /* the currently selected, probed, announced or used LL IP-Address */
|
||||
u8_t state; /* current AutoIP state machine state */
|
||||
u8_t sent_num; /* sent number of probes or announces, dependent on state */
|
||||
u16_t ttw; /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */
|
||||
@@ -85,8 +89,10 @@ struct autoip
|
||||
};
|
||||
|
||||
|
||||
/** Init srand, has to be called before entering mainloop */
|
||||
void autoip_init(void);
|
||||
#define autoip_init() /* Compatibility define, no init needed. */
|
||||
|
||||
/** Set a struct autoip allocated by the application to work with */
|
||||
void autoip_set_struct(struct netif *netif, struct autoip *autoip);
|
||||
|
||||
/** Start AutoIP client */
|
||||
err_t autoip_start(struct netif *netif);
|
||||
@@ -100,6 +106,13 @@ void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr);
|
||||
/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */
|
||||
void autoip_tmr(void);
|
||||
|
||||
/** Handle a possible change in the network configuration */
|
||||
void autoip_network_changed(struct netif *netif);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_AUTOIP */
|
||||
|
||||
#endif /* __LWIP_AUTOIP_H__ */
|
||||
|
||||
@@ -33,89 +33,93 @@
|
||||
#define __LWIP_ICMP_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#if LWIP_IPV6 && LWIP_ICMP6
|
||||
#include "lwip/icmp6.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ICMP_ER 0 /* echo reply */
|
||||
#define ICMP_DUR 3 /* destination unreachable */
|
||||
#define ICMP_SQ 4 /* source quench */
|
||||
#define ICMP_RD 5 /* redirect */
|
||||
#define ICMP_ER 0 /* echo reply */
|
||||
#define ICMP_DUR 3 /* destination unreachable */
|
||||
#define ICMP_SQ 4 /* source quench */
|
||||
#define ICMP_RD 5 /* redirect */
|
||||
#define ICMP_ECHO 8 /* echo */
|
||||
#define ICMP_TE 11 /* time exceeded */
|
||||
#define ICMP_PP 12 /* parameter problem */
|
||||
#define ICMP_TS 13 /* timestamp */
|
||||
#define ICMP_TE 11 /* time exceeded */
|
||||
#define ICMP_PP 12 /* parameter problem */
|
||||
#define ICMP_TS 13 /* timestamp */
|
||||
#define ICMP_TSR 14 /* timestamp reply */
|
||||
#define ICMP_IRQ 15 /* information request */
|
||||
#define ICMP_IR 16 /* information reply */
|
||||
#define ICMP_IR 16 /* information reply */
|
||||
|
||||
enum icmp_dur_type {
|
||||
ICMP_DUR_NET = 0, /* net unreachable */
|
||||
ICMP_DUR_HOST = 1, /* host unreachable */
|
||||
ICMP_DUR_NET = 0, /* net unreachable */
|
||||
ICMP_DUR_HOST = 1, /* host unreachable */
|
||||
ICMP_DUR_PROTO = 2, /* protocol unreachable */
|
||||
ICMP_DUR_PORT = 3, /* port unreachable */
|
||||
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
|
||||
ICMP_DUR_SR = 5 /* source route failed */
|
||||
ICMP_DUR_PORT = 3, /* port unreachable */
|
||||
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
|
||||
ICMP_DUR_SR = 5 /* source route failed */
|
||||
};
|
||||
|
||||
enum icmp_te_type {
|
||||
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
|
||||
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
|
||||
ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */
|
||||
};
|
||||
|
||||
void icmp_input(struct pbuf *p, struct netif *inp);
|
||||
|
||||
void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
|
||||
void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
/** This is the standard ICMP header only that the u32_t data
|
||||
* is splitted to two u16_t like ICMP echo needs it.
|
||||
* This header is also used for other ICMP types that do not
|
||||
* use the data part.
|
||||
*/
|
||||
PACK_STRUCT_BEGIN
|
||||
struct icmp_echo_hdr {
|
||||
PACK_STRUCT_FIELD(u16_t _type_code);
|
||||
PACK_STRUCT_FIELD(u8_t type);
|
||||
PACK_STRUCT_FIELD(u8_t code);
|
||||
PACK_STRUCT_FIELD(u16_t chksum);
|
||||
PACK_STRUCT_FIELD(u16_t id);
|
||||
PACK_STRUCT_FIELD(u16_t seqno);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
|
||||
PACK_STRUCT_BEGIN
|
||||
struct icmp_dur_hdr {
|
||||
PACK_STRUCT_FIELD(u16_t _type_code);
|
||||
PACK_STRUCT_FIELD(u16_t chksum);
|
||||
PACK_STRUCT_FIELD(u32_t unused);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
|
||||
PACK_STRUCT_BEGIN
|
||||
struct icmp_te_hdr {
|
||||
PACK_STRUCT_FIELD(u16_t _type_code);
|
||||
PACK_STRUCT_FIELD(u16_t chksum);
|
||||
PACK_STRUCT_FIELD(u32_t unused);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
#define ICMPH_TYPE(hdr) (ntohs((hdr)->_type_code) >> 8)
|
||||
#define ICMPH_CODE(hdr) (ntohs((hdr)->_type_code) & 0xff)
|
||||
#define ICMPH_TYPE(hdr) ((hdr)->type)
|
||||
#define ICMPH_CODE(hdr) ((hdr)->code)
|
||||
|
||||
#define ICMPH_TYPE_SET(hdr, type) ((hdr)->_type_code = htons(ICMPH_CODE(hdr) | ((type) << 8)))
|
||||
#define ICMPH_CODE_SET(hdr, code) ((hdr)->_type_code = htons((code) | (ICMPH_TYPE(hdr) << 8)))
|
||||
/** Combines type and code to an u16_t */
|
||||
#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t))
|
||||
#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c))
|
||||
|
||||
|
||||
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
void icmp_input(struct pbuf *p, struct netif *inp);
|
||||
void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
|
||||
void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
|
||||
|
||||
#endif /* LWIP_ICMP */
|
||||
|
||||
#if (LWIP_IPV6 && LWIP_ICMP6)
|
||||
#define icmp_port_unreach(isipv6, pbuf) ((isipv6) ? \
|
||||
icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT) : \
|
||||
icmp_dest_unreach(pbuf, ICMP_DUR_PORT))
|
||||
#elif LWIP_ICMP
|
||||
#define icmp_port_unreach(isipv6, pbuf) icmp_dest_unreach(pbuf, ICMP_DUR_PORT)
|
||||
#else /* (LWIP_IPV6 && LWIP_ICMP6) || LWIP_ICMP*/
|
||||
#define icmp_port_unreach(isipv6, pbuf)
|
||||
#endif /* (LWIP_IPV6 && LWIP_ICMP6) || LWIP_ICMP*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_ICMP */
|
||||
|
||||
#endif /* __LWIP_ICMP_H__ */
|
||||
|
||||
@@ -46,57 +46,20 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* IGMP constants
|
||||
*/
|
||||
#define IP_PROTO_IGMP 2
|
||||
#define IGMP_TTL 1
|
||||
#define IGMP_MINLEN 8
|
||||
#define ROUTER_ALERT 0x9404
|
||||
#define ROUTER_ALERTLEN 4
|
||||
|
||||
/*
|
||||
* IGMP message types, including version number.
|
||||
*/
|
||||
#define IGMP_MEMB_QUERY 0x11 /* Membership query */
|
||||
#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */
|
||||
#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */
|
||||
#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */
|
||||
|
||||
/* IGMP timer */
|
||||
#define IGMP_TMR_INTERVAL 100 /* Milliseconds */
|
||||
#define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL)
|
||||
#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL)
|
||||
|
||||
/* MAC Filter Actions */
|
||||
/* MAC Filter Actions, these are passed to a netif's
|
||||
* igmp_mac_filter callback function. */
|
||||
#define IGMP_DEL_MAC_FILTER 0
|
||||
#define IGMP_ADD_MAC_FILTER 1
|
||||
|
||||
/* Group membership states */
|
||||
#define IGMP_GROUP_NON_MEMBER 0
|
||||
#define IGMP_GROUP_DELAYING_MEMBER 1
|
||||
#define IGMP_GROUP_IDLE_MEMBER 2
|
||||
|
||||
/*
|
||||
* IGMP packet format.
|
||||
*/
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct igmp_msg {
|
||||
PACK_STRUCT_FIELD(u8_t igmp_msgtype);
|
||||
PACK_STRUCT_FIELD(u8_t igmp_maxresp);
|
||||
PACK_STRUCT_FIELD(u16_t igmp_checksum);
|
||||
PACK_STRUCT_FIELD(struct ip_addr igmp_group_address);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* now a group structure - there is
|
||||
/**
|
||||
* igmp group structure - there is
|
||||
* a list of groups for each interface
|
||||
* these should really be linked from the interface, but
|
||||
* if we keep them separate we will not affect the lwip original code
|
||||
@@ -106,53 +69,34 @@ PACK_STRUCT_END
|
||||
* will not run the state machine as it is used to kick off reports
|
||||
* from all the other groups
|
||||
*/
|
||||
|
||||
struct igmp_group {
|
||||
/** next link */
|
||||
struct igmp_group *next;
|
||||
struct netif *interface;
|
||||
struct ip_addr group_address;
|
||||
u8_t last_reporter_flag; /* signifies we were the last person to report */
|
||||
/** interface on which the group is active */
|
||||
struct netif *netif;
|
||||
/** multicast address */
|
||||
ip_addr_t group_address;
|
||||
/** signifies we were the last person to report */
|
||||
u8_t last_reporter_flag;
|
||||
/** current state of the group */
|
||||
u8_t group_state;
|
||||
/** timer for reporting, negative is OFF */
|
||||
u16_t timer;
|
||||
u8_t use; /* counter of simultaneous uses */
|
||||
/** counter of simultaneous uses */
|
||||
u8_t use;
|
||||
};
|
||||
|
||||
|
||||
/* Prototypes */
|
||||
void igmp_init(void);
|
||||
|
||||
err_t igmp_start( struct netif *netif);
|
||||
|
||||
err_t igmp_stop( struct netif *netif);
|
||||
|
||||
void igmp_report_groups( struct netif *netif);
|
||||
|
||||
struct igmp_group *igmp_lookfor_group( struct netif *ifp, struct ip_addr *addr);
|
||||
|
||||
struct igmp_group *igmp_lookup_group( struct netif *ifp, struct ip_addr *addr);
|
||||
|
||||
err_t igmp_remove_group( struct igmp_group *group);
|
||||
|
||||
void igmp_input( struct pbuf *p, struct netif *inp, struct ip_addr *dest);
|
||||
|
||||
err_t igmp_joingroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr);
|
||||
|
||||
err_t igmp_leavegroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr);
|
||||
|
||||
err_t igmp_start(struct netif *netif);
|
||||
err_t igmp_stop(struct netif *netif);
|
||||
void igmp_report_groups(struct netif *netif);
|
||||
struct igmp_group *igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr);
|
||||
void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest);
|
||||
err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr);
|
||||
err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr);
|
||||
void igmp_tmr(void);
|
||||
|
||||
void igmp_timeout( struct igmp_group *group);
|
||||
|
||||
void igmp_start_timer( struct igmp_group *group, u8_t max_time);
|
||||
|
||||
void igmp_stop_timer( struct igmp_group *group);
|
||||
|
||||
void igmp_delaying_member( struct igmp_group *group, u8_t maxresp);
|
||||
|
||||
err_t igmp_ip_output_if( struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t proto, struct netif *netif);
|
||||
|
||||
void igmp_send( struct igmp_group *group, u8_t type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -33,60 +33,72 @@
|
||||
#define __LWIP_INET_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
u32_t inet_addr(const char *cp);
|
||||
int inet_aton(const char *cp, struct in_addr *addr);
|
||||
char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */
|
||||
/** For compatibility with BSD code */
|
||||
struct in_addr {
|
||||
u32_t s_addr;
|
||||
};
|
||||
|
||||
#ifdef htons
|
||||
#undef htons
|
||||
#endif /* htons */
|
||||
#ifdef htonl
|
||||
#undef htonl
|
||||
#endif /* htonl */
|
||||
#ifdef ntohs
|
||||
#undef ntohs
|
||||
#endif /* ntohs */
|
||||
#ifdef ntohl
|
||||
#undef ntohl
|
||||
#endif /* ntohl */
|
||||
/** 255.255.255.255 */
|
||||
#define INADDR_NONE IPADDR_NONE
|
||||
/** 127.0.0.1 */
|
||||
#define INADDR_LOOPBACK IPADDR_LOOPBACK
|
||||
/** 0.0.0.0 */
|
||||
#define INADDR_ANY IPADDR_ANY
|
||||
/** 255.255.255.255 */
|
||||
#define INADDR_BROADCAST IPADDR_BROADCAST
|
||||
|
||||
#ifndef LWIP_PLATFORM_BYTESWAP
|
||||
#define LWIP_PLATFORM_BYTESWAP 0
|
||||
#endif
|
||||
/* Definitions of the bits in an Internet address integer.
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define htons(x) (x)
|
||||
#define ntohs(x) (x)
|
||||
#define htonl(x) (x)
|
||||
#define ntohl(x) (x)
|
||||
#else /* BYTE_ORDER != BIG_ENDIAN */
|
||||
#ifdef LWIP_PREFIX_BYTEORDER_FUNCS
|
||||
/* workaround for naming collisions on some platforms */
|
||||
#define htons lwip_htons
|
||||
#define ntohs lwip_ntohs
|
||||
#define htonl lwip_htonl
|
||||
#define ntohl lwip_ntohl
|
||||
#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */
|
||||
#if LWIP_PLATFORM_BYTESWAP
|
||||
#define htons(x) LWIP_PLATFORM_HTONS(x)
|
||||
#define ntohs(x) LWIP_PLATFORM_HTONS(x)
|
||||
#define htonl(x) LWIP_PLATFORM_HTONL(x)
|
||||
#define ntohl(x) LWIP_PLATFORM_HTONL(x)
|
||||
#else /* LWIP_PLATFORM_BYTESWAP */
|
||||
u16_t htons(u16_t x);
|
||||
u16_t ntohs(u16_t x);
|
||||
u32_t htonl(u32_t x);
|
||||
u32_t ntohl(u32_t x);
|
||||
#endif /* LWIP_PLATFORM_BYTESWAP */
|
||||
On subnets, host and network parts are found according to
|
||||
the subnet mask, not these masks. */
|
||||
#define IN_CLASSA(a) IP_CLASSA(a)
|
||||
#define IN_CLASSA_NET IP_CLASSA_NET
|
||||
#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT
|
||||
#define IN_CLASSA_HOST IP_CLASSA_HOST
|
||||
#define IN_CLASSA_MAX IP_CLASSA_MAX
|
||||
|
||||
#endif /* BYTE_ORDER == BIG_ENDIAN */
|
||||
#define IN_CLASSB(b) IP_CLASSB(b)
|
||||
#define IN_CLASSB_NET IP_CLASSB_NET
|
||||
#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT
|
||||
#define IN_CLASSB_HOST IP_CLASSB_HOST
|
||||
#define IN_CLASSB_MAX IP_CLASSB_MAX
|
||||
|
||||
#define IN_CLASSC(c) IP_CLASSC(c)
|
||||
#define IN_CLASSC_NET IP_CLASSC_NET
|
||||
#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT
|
||||
#define IN_CLASSC_HOST IP_CLASSC_HOST
|
||||
#define IN_CLASSC_MAX IP_CLASSC_MAX
|
||||
|
||||
#define IN_CLASSD(d) IP_CLASSD(d)
|
||||
#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */
|
||||
#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */
|
||||
#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */
|
||||
#define IN_CLASSD_MAX IP_CLASSD_MAX
|
||||
|
||||
#define IN_MULTICAST(a) IP_MULTICAST(a)
|
||||
|
||||
#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a)
|
||||
#define IN_BADCLASS(a) IP_BADCLASS(a)
|
||||
|
||||
#define IN_LOOPBACKNET IP_LOOPBACKNET
|
||||
|
||||
#define inet_addr_from_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr))
|
||||
#define inet_addr_to_ipaddr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr))
|
||||
/* ATTENTION: the next define only works because both s_addr and ip_addr_t are an u32_t effectively! */
|
||||
#define inet_addr_to_ipaddr_p(target_ipaddr_p, source_inaddr) ((target_ipaddr_p) = (ip_addr_t*)&((source_inaddr)->s_addr))
|
||||
|
||||
/* directly map this to the lwip internal functions */
|
||||
#define inet_addr(cp) ipaddr_addr(cp)
|
||||
#define inet_aton(cp, addr) ipaddr_aton(cp, (ip_addr_t*)addr)
|
||||
#define inet_ntoa(addr) ipaddr_ntoa((ip_addr_t*)&(addr))
|
||||
#define inet_ntoa_r(addr, buf, buflen) ipaddr_ntoa_r((ip_addr_t*)&(addr), buf, buflen)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -29,86 +29,33 @@
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef __LWIP_IP_H__
|
||||
#define __LWIP_IP_H__
|
||||
#ifndef __LWIP_IP4_H__
|
||||
#define __LWIP_IP4_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ip_init() /* Compatibility define, not init needed. */
|
||||
struct netif *ip_route(struct ip_addr *dest);
|
||||
err_t ip_input(struct pbuf *p, struct netif *inp);
|
||||
err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto);
|
||||
err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto,
|
||||
struct netif *netif);
|
||||
/** Currently, the function ip_output_if_opt() is only used with IGMP */
|
||||
#define IP_OPTIONS_SEND LWIP_IGMP
|
||||
|
||||
#define IP_HLEN 20
|
||||
|
||||
#define IP_PROTO_ICMP 1
|
||||
#define IP_PROTO_IGMP 2
|
||||
#define IP_PROTO_UDP 17
|
||||
#define IP_PROTO_UDPLITE 136
|
||||
#define IP_PROTO_TCP 6
|
||||
|
||||
/* This is passed as the destination address to ip_output_if (not
|
||||
to ip_output), meaning that an IP header already is constructed
|
||||
in the pbuf. This is used when TCP retransmits. */
|
||||
#ifdef IP_HDRINCL
|
||||
#undef IP_HDRINCL
|
||||
#endif /* IP_HDRINCL */
|
||||
#define IP_HDRINCL NULL
|
||||
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
#define IP_PCB_ADDRHINT ;u8_t addr_hint
|
||||
#else
|
||||
#define IP_PCB_ADDRHINT
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
|
||||
/* This is the common part of all PCB types. It needs to be at the
|
||||
beginning of a PCB type definition. It is located here so that
|
||||
changes to this common part are made in one location instead of
|
||||
having to change all PCB structs. */
|
||||
#define IP_PCB \
|
||||
/* ip addresses in network byte order */ \
|
||||
struct ip_addr local_ip; \
|
||||
struct ip_addr remote_ip; \
|
||||
/* Socket options */ \
|
||||
u16_t so_options; \
|
||||
/* Type Of Service */ \
|
||||
u8_t tos; \
|
||||
/* Time To Live */ \
|
||||
u8_t ttl \
|
||||
/* link layer address resolution hint */ \
|
||||
IP_PCB_ADDRHINT
|
||||
|
||||
struct ip_pcb {
|
||||
/* Common members of all PCB types */
|
||||
IP_PCB;
|
||||
};
|
||||
|
||||
/*
|
||||
* Option flags per-socket. These are the same like SO_XXX.
|
||||
*/
|
||||
#define SOF_DEBUG (u16_t)0x0001U /* turn on debugging info recording */
|
||||
#define SOF_ACCEPTCONN (u16_t)0x0002U /* socket has had listen() */
|
||||
#define SOF_REUSEADDR (u16_t)0x0004U /* allow local address reuse */
|
||||
#define SOF_KEEPALIVE (u16_t)0x0008U /* keep connections alive */
|
||||
#define SOF_DONTROUTE (u16_t)0x0010U /* just use interface addresses */
|
||||
#define SOF_BROADCAST (u16_t)0x0020U /* permit sending of broadcast msgs */
|
||||
#define SOF_USELOOPBACK (u16_t)0x0040U /* bypass hardware when possible */
|
||||
#define SOF_LINGER (u16_t)0x0080U /* linger on close if data present */
|
||||
#define SOF_OOBINLINE (u16_t)0x0100U /* leave received OOB data in line */
|
||||
#define SOF_REUSEPORT (u16_t)0x0200U /* allow local address & port reuse */
|
||||
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
@@ -123,17 +70,19 @@ struct ip_hdr {
|
||||
PACK_STRUCT_FIELD(u16_t _id);
|
||||
/* fragment offset field */
|
||||
PACK_STRUCT_FIELD(u16_t _offset);
|
||||
#define IP_RF 0x8000 /* reserved fragment flag */
|
||||
#define IP_DF 0x4000 /* dont fragment flag */
|
||||
#define IP_MF 0x2000 /* more fragments flag */
|
||||
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
|
||||
/* time to live / protocol*/
|
||||
PACK_STRUCT_FIELD(u16_t _ttl_proto);
|
||||
#define IP_RF 0x8000U /* reserved fragment flag */
|
||||
#define IP_DF 0x4000U /* dont fragment flag */
|
||||
#define IP_MF 0x2000U /* more fragments flag */
|
||||
#define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */
|
||||
/* time to live */
|
||||
PACK_STRUCT_FIELD(u8_t _ttl);
|
||||
/* protocol*/
|
||||
PACK_STRUCT_FIELD(u8_t _proto);
|
||||
/* checksum */
|
||||
PACK_STRUCT_FIELD(u16_t _chksum);
|
||||
/* source and destination IP addresses */
|
||||
PACK_STRUCT_FIELD(struct ip_addr src);
|
||||
PACK_STRUCT_FIELD(struct ip_addr dest);
|
||||
PACK_STRUCT_FIELD(ip_addr_p_t src);
|
||||
PACK_STRUCT_FIELD(ip_addr_p_t dest);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
@@ -146,18 +95,39 @@ PACK_STRUCT_END
|
||||
#define IPH_LEN(hdr) ((hdr)->_len)
|
||||
#define IPH_ID(hdr) ((hdr)->_id)
|
||||
#define IPH_OFFSET(hdr) ((hdr)->_offset)
|
||||
#define IPH_TTL(hdr) (ntohs((hdr)->_ttl_proto) >> 8)
|
||||
#define IPH_PROTO(hdr) (ntohs((hdr)->_ttl_proto) & 0xff)
|
||||
#define IPH_TTL(hdr) ((hdr)->_ttl)
|
||||
#define IPH_PROTO(hdr) ((hdr)->_proto)
|
||||
#define IPH_CHKSUM(hdr) ((hdr)->_chksum)
|
||||
|
||||
#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos)))
|
||||
#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)
|
||||
#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)
|
||||
#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)
|
||||
#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl_proto = (htons(IPH_PROTO(hdr) | ((u16_t)(ttl) << 8)))
|
||||
#define IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8)))
|
||||
#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl)
|
||||
#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto)
|
||||
#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
|
||||
|
||||
|
||||
#define ip_init() /* Compatibility define, no init needed. */
|
||||
struct netif *ip_route(ip_addr_t *dest);
|
||||
err_t ip_input(struct pbuf *p, struct netif *inp);
|
||||
err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto);
|
||||
err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto,
|
||||
struct netif *netif);
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
#if IP_OPTIONS_SEND
|
||||
err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
|
||||
u16_t optlen);
|
||||
#endif /* IP_OPTIONS_SEND */
|
||||
|
||||
#define ip_netif_get_local_ipX(netif) (((netif) != NULL) ? ip_2_ipX(&((netif)->ip_addr)) : NULL)
|
||||
|
||||
#if IP_DEBUG
|
||||
void ip_debug_print(struct pbuf *p);
|
||||
#else
|
||||
244
src/include/ipv4/lwip/ip4_addr.h
Normal file
244
src/include/ipv4/lwip/ip4_addr.h
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
#ifndef __LWIP_IP4_ADDR_H__
|
||||
#define __LWIP_IP4_ADDR_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This is the aligned version of ip_addr_t,
|
||||
used as local variable, on the stack, etc. */
|
||||
struct ip_addr {
|
||||
u32_t addr;
|
||||
};
|
||||
|
||||
/* This is the packed version of ip_addr_t,
|
||||
used in network headers that are itself packed */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip_addr_packed {
|
||||
PACK_STRUCT_FIELD(u32_t addr);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** ip_addr_t uses a struct for convenience only, so that the same defines can
|
||||
* operate both on ip_addr_t as well as on ip_addr_p_t. */
|
||||
typedef struct ip_addr ip_addr_t;
|
||||
typedef struct ip_addr_packed ip_addr_p_t;
|
||||
|
||||
/*
|
||||
* struct ipaddr2 is used in the definition of the ARP packet format in
|
||||
* order to support compilers that don't have structure packing.
|
||||
*/
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip_addr2 {
|
||||
PACK_STRUCT_FIELD(u16_t addrw[2]);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/* Forward declaration to not include netif.h */
|
||||
struct netif;
|
||||
|
||||
extern const ip_addr_t ip_addr_any;
|
||||
extern const ip_addr_t ip_addr_broadcast;
|
||||
|
||||
/** IP_ADDR_ can be used as a fixed IP address
|
||||
* for the wildcard and the broadcast address
|
||||
*/
|
||||
#define IP_ADDR_ANY ((ip_addr_t *)&ip_addr_any)
|
||||
#define IP_ADDR_BROADCAST ((ip_addr_t *)&ip_addr_broadcast)
|
||||
|
||||
/** 255.255.255.255 */
|
||||
#define IPADDR_NONE ((u32_t)0xffffffffUL)
|
||||
/** 127.0.0.1 */
|
||||
#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL)
|
||||
/** 0.0.0.0 */
|
||||
#define IPADDR_ANY ((u32_t)0x00000000UL)
|
||||
/** 255.255.255.255 */
|
||||
#define IPADDR_BROADCAST ((u32_t)0xffffffffUL)
|
||||
|
||||
/* Definitions of the bits in an Internet address integer.
|
||||
|
||||
On subnets, host and network parts are found according to
|
||||
the subnet mask, not these masks. */
|
||||
#define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0)
|
||||
#define IP_CLASSA_NET 0xff000000
|
||||
#define IP_CLASSA_NSHIFT 24
|
||||
#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET)
|
||||
#define IP_CLASSA_MAX 128
|
||||
|
||||
#define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL)
|
||||
#define IP_CLASSB_NET 0xffff0000
|
||||
#define IP_CLASSB_NSHIFT 16
|
||||
#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET)
|
||||
#define IP_CLASSB_MAX 65536
|
||||
|
||||
#define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)
|
||||
#define IP_CLASSC_NET 0xffffff00
|
||||
#define IP_CLASSC_NSHIFT 8
|
||||
#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET)
|
||||
|
||||
#define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL)
|
||||
#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */
|
||||
#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */
|
||||
#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */
|
||||
#define IP_MULTICAST(a) IP_CLASSD(a)
|
||||
|
||||
#define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
|
||||
#define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
|
||||
|
||||
#define IP_LOOPBACKNET 127 /* official! */
|
||||
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
/** Set an IP address given by the four byte-parts */
|
||||
#define IP4_ADDR(ipaddr, a,b,c,d) \
|
||||
(ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \
|
||||
((u32_t)((b) & 0xff) << 16) | \
|
||||
((u32_t)((c) & 0xff) << 8) | \
|
||||
(u32_t)((d) & 0xff)
|
||||
#else
|
||||
/** Set an IP address given by the four byte-parts.
|
||||
Little-endian version that prevents the use of htonl. */
|
||||
#define IP4_ADDR(ipaddr, a,b,c,d) \
|
||||
(ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \
|
||||
((u32_t)((c) & 0xff) << 16) | \
|
||||
((u32_t)((b) & 0xff) << 8) | \
|
||||
(u32_t)((a) & 0xff)
|
||||
#endif
|
||||
|
||||
/** MEMCPY-like copying of IP addresses where addresses are known to be
|
||||
* 16-bit-aligned if the port is correctly configured (so a port could define
|
||||
* this to copying 2 u16_t's) - no NULL-pointer-checking needed. */
|
||||
#ifndef IPADDR2_COPY
|
||||
#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip_addr_t))
|
||||
#endif
|
||||
|
||||
/** Copy IP address - faster than ip_addr_set: no NULL check */
|
||||
#define ip_addr_copy(dest, src) ((dest).addr = (src).addr)
|
||||
/** Safely copy one IP address to another (src may be NULL) */
|
||||
#define ip_addr_set(dest, src) ((dest)->addr = \
|
||||
((src) == NULL ? 0 : \
|
||||
(src)->addr))
|
||||
/** Set complete address to zero */
|
||||
#define ip_addr_set_zero(ipaddr) ((ipaddr)->addr = 0)
|
||||
/** Set address to IPADDR_ANY (no need for htonl()) */
|
||||
#define ip_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY)
|
||||
/** Set address to loopback address */
|
||||
#define ip_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK))
|
||||
/** Safely copy one IP address to another and change byte order
|
||||
* from host- to network-order. */
|
||||
#define ip_addr_set_hton(dest, src) ((dest)->addr = \
|
||||
((src) == NULL ? 0:\
|
||||
htonl((src)->addr)))
|
||||
/** IPv4 only: set the IP address given as an u32_t */
|
||||
#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32))
|
||||
/** IPv4 only: get the IP address as an u32_t */
|
||||
#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr)
|
||||
|
||||
/** Get the network address by combining host address with netmask */
|
||||
#define ip_addr_get_network(target, host, netmask) ((target)->addr = ((host)->addr) & ((netmask)->addr))
|
||||
|
||||
/**
|
||||
* Determine if two address are on the same network.
|
||||
*
|
||||
* @arg addr1 IP address 1
|
||||
* @arg addr2 IP address 2
|
||||
* @arg mask network identifier mask
|
||||
* @return !0 if the network identifiers of both address match
|
||||
*/
|
||||
#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \
|
||||
(mask)->addr) == \
|
||||
((addr2)->addr & \
|
||||
(mask)->addr))
|
||||
#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)
|
||||
|
||||
#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == IPADDR_ANY)
|
||||
|
||||
#define ip_addr_isbroadcast(ipaddr, netif) ip4_addr_isbroadcast((ipaddr)->addr, (netif))
|
||||
u8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif);
|
||||
|
||||
#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr)
|
||||
u8_t ip4_addr_netmask_valid(u32_t netmask);
|
||||
|
||||
#define ip_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL))
|
||||
|
||||
#define ip_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL))
|
||||
|
||||
#define ip_addr_debug_print(debug, ipaddr) \
|
||||
LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \
|
||||
ipaddr != NULL ? ip4_addr1_16(ipaddr) : 0, \
|
||||
ipaddr != NULL ? ip4_addr2_16(ipaddr) : 0, \
|
||||
ipaddr != NULL ? ip4_addr3_16(ipaddr) : 0, \
|
||||
ipaddr != NULL ? ip4_addr4_16(ipaddr) : 0))
|
||||
|
||||
/* Get one byte from the 4-byte address */
|
||||
#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0])
|
||||
#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1])
|
||||
#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2])
|
||||
#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3])
|
||||
/* These are cast to u16_t, with the intent that they are often arguments
|
||||
* to printf using the U16_F format from cc.h. */
|
||||
#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr))
|
||||
#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr))
|
||||
#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr))
|
||||
#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr))
|
||||
|
||||
/** For backwards compatibility */
|
||||
#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr)
|
||||
|
||||
u32_t ipaddr_addr(const char *cp);
|
||||
int ipaddr_aton(const char *cp, ip_addr_t *addr);
|
||||
/** returns ptr to static buffer; not reentrant! */
|
||||
char *ipaddr_ntoa(const ip_addr_t *addr);
|
||||
char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LWIP_IP_ADDR_H__ */
|
||||
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
#ifndef __LWIP_IP_ADDR_H__
|
||||
#define __LWIP_IP_ADDR_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip_addr {
|
||||
PACK_STRUCT_FIELD(u32_t addr);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* struct ipaddr2 is used in the definition of the ARP packet format in
|
||||
* order to support compilers that don't have structure packing.
|
||||
*/
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip_addr2 {
|
||||
PACK_STRUCT_FIELD(u16_t addrw[2]);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/* For compatibility with BSD code */
|
||||
struct in_addr {
|
||||
u32_t s_addr;
|
||||
};
|
||||
|
||||
struct netif;
|
||||
|
||||
extern const struct ip_addr ip_addr_any;
|
||||
extern const struct ip_addr ip_addr_broadcast;
|
||||
|
||||
/** IP_ADDR_ can be used as a fixed IP address
|
||||
* for the wildcard and the broadcast address
|
||||
*/
|
||||
#define IP_ADDR_ANY ((struct ip_addr *)&ip_addr_any)
|
||||
#define IP_ADDR_BROADCAST ((struct ip_addr *)&ip_addr_broadcast)
|
||||
|
||||
#define INADDR_NONE ((u32_t)0xffffffffUL) /* 255.255.255.255 */
|
||||
#define INADDR_LOOPBACK ((u32_t)0x7f000001UL) /* 127.0.0.1 */
|
||||
|
||||
/* Definitions of the bits in an Internet address integer.
|
||||
|
||||
On subnets, host and network parts are found according to
|
||||
the subnet mask, not these masks. */
|
||||
|
||||
#define IN_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0)
|
||||
#define IN_CLASSA_NET 0xff000000
|
||||
#define IN_CLASSA_NSHIFT 24
|
||||
#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET)
|
||||
#define IN_CLASSA_MAX 128
|
||||
|
||||
#define IN_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL)
|
||||
#define IN_CLASSB_NET 0xffff0000
|
||||
#define IN_CLASSB_NSHIFT 16
|
||||
#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET)
|
||||
#define IN_CLASSB_MAX 65536
|
||||
|
||||
#define IN_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)
|
||||
#define IN_CLASSC_NET 0xffffff00
|
||||
#define IN_CLASSC_NSHIFT 8
|
||||
#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET)
|
||||
|
||||
#define IN_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL)
|
||||
#define IN_CLASSD_NET 0xf0000000 /* These ones aren't really */
|
||||
#define IN_CLASSD_NSHIFT 28 /* net and host fields, but */
|
||||
#define IN_CLASSD_HOST 0x0fffffff /* routing needn't know. */
|
||||
#define IN_MULTICAST(a) IN_CLASSD(a)
|
||||
|
||||
#define IN_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
|
||||
#define IN_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
|
||||
|
||||
#define IN_LOOPBACKNET 127 /* official! */
|
||||
|
||||
#define IP4_ADDR(ipaddr, a,b,c,d) \
|
||||
(ipaddr)->addr = htonl(((u32_t)((a) & 0xff) << 24) | \
|
||||
((u32_t)((b) & 0xff) << 16) | \
|
||||
((u32_t)((c) & 0xff) << 8) | \
|
||||
(u32_t)((d) & 0xff))
|
||||
|
||||
#define ip_addr_set(dest, src) (dest)->addr = \
|
||||
((src) == NULL? 0:\
|
||||
(src)->addr)
|
||||
/**
|
||||
* Determine if two address are on the same network.
|
||||
*
|
||||
* @arg addr1 IP address 1
|
||||
* @arg addr2 IP address 2
|
||||
* @arg mask network identifier mask
|
||||
* @return !0 if the network identifiers of both address match
|
||||
*/
|
||||
#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \
|
||||
(mask)->addr) == \
|
||||
((addr2)->addr & \
|
||||
(mask)->addr))
|
||||
#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)
|
||||
|
||||
#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0)
|
||||
|
||||
u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *);
|
||||
|
||||
#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000UL)) == ntohl(0xe0000000UL))
|
||||
|
||||
#define ip_addr_islinklocal(addr1) (((addr1)->addr & ntohl(0xffff0000UL)) == ntohl(0xa9fe0000UL))
|
||||
|
||||
#define ip_addr_debug_print(debug, ipaddr) \
|
||||
LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \
|
||||
ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0, \
|
||||
ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0, \
|
||||
ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0, \
|
||||
ipaddr ? (u16_t)ntohl((ipaddr)->addr) & 0xff : 0))
|
||||
|
||||
/* These are cast to u16_t, with the intent that they are often arguments
|
||||
* to printf using the U16_F format from cc.h. */
|
||||
#define ip4_addr1(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff)
|
||||
#define ip4_addr2(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff)
|
||||
#define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff)
|
||||
#define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LWIP_IP_ADDR_H__ */
|
||||
@@ -66,7 +66,22 @@ struct pbuf * ip_reass(struct pbuf *p);
|
||||
#endif /* IP_REASSEMBLY */
|
||||
|
||||
#if IP_FRAG
|
||||
err_t ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest);
|
||||
#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
|
||||
/** A custom pbuf that holds a reference to another pbuf, which is freed
|
||||
* when this custom pbuf is freed. This is used to create a custom PBUF_REF
|
||||
* that points into the original pbuf. */
|
||||
#ifndef __LWIP_PBUF_CUSTOM_REF__
|
||||
#define __LWIP_PBUF_CUSTOM_REF__
|
||||
struct pbuf_custom_ref {
|
||||
/** 'base class' */
|
||||
struct pbuf_custom pc;
|
||||
/** pointer to the original pbuf that is referenced */
|
||||
struct pbuf *original;
|
||||
};
|
||||
#endif /* __LWIP_PBUF_CUSTOM_REF__ */
|
||||
#endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
|
||||
|
||||
err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest);
|
||||
#endif /* IP_FRAG */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* IPv6 address autoconfiguration as per RFC 4862.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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,58 +17,42 @@
|
||||
* 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>
|
||||
*
|
||||
* IPv6 address autoconfiguration as per RFC 4862.
|
||||
*
|
||||
* Please coordinate changes and requests with Ivan Delamer
|
||||
* <delamer@inicotech.com>
|
||||
*/
|
||||
#ifndef __LWIP_INET_H__
|
||||
#define __LWIP_INET_H__
|
||||
|
||||
#ifndef __LWIP_IP6_DHCP6_H__
|
||||
#define __LWIP_IP6_DHCP6_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#if LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
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);
|
||||
struct dhcp6
|
||||
{
|
||||
//TODO: implement DHCP6
|
||||
};
|
||||
|
||||
#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__ */
|
||||
#endif /* LWIP_IPV6_DHCP6 */
|
||||
|
||||
#endif /* __LWIP_IP6_DHCP6_H__ */
|
||||
@@ -1,8 +1,14 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Ethernet output for IPv6. Uses ND tables for link-layer addressing.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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,48 +17,52 @@
|
||||
* 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>
|
||||
*/
|
||||
#ifndef __LWIP_INET_CHKSUM_H__
|
||||
#define __LWIP_INET_CHKSUM_H__
|
||||
|
||||
#ifndef __LWIP_ETHIP6_H__
|
||||
#define __LWIP_ETHIP6_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_IPV6 && LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
u16_t inet_chksum(void *dataptr, 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, u16_t proto_len);
|
||||
u16_t inet_chksum_pseudo_partial(struct pbuf *p,
|
||||
struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t proto, u16_t proto_len, u16_t chksum_len);
|
||||
|
||||
err_t ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LWIP_INET_H__ */
|
||||
#endif /* LWIP_IPV6 && LWIP_ETHERNET */
|
||||
|
||||
#endif /* __LWIP_ETHIP6_H__ */
|
||||
152
src/include/ipv6/lwip/icmp6.h
Normal file
152
src/include/ipv6/lwip/icmp6.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* IPv6 version of ICMP, as per RFC 4443.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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>
|
||||
*/
|
||||
#ifndef __LWIP_ICMP6_H__
|
||||
#define __LWIP_ICMP6_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum icmp6_type {
|
||||
ICMP6_TYPE_DUR = 1, /* Destination unreachable */
|
||||
ICMP6_TYPE_PTB = 2, /* Packet too big */
|
||||
ICMP6_TYPE_TE = 3, /* Time exceeded */
|
||||
ICMP6_TYPE_PP = 4, /* Parameter problem */
|
||||
ICMP6_TYPE_PE1 = 100, /* Private experimentation */
|
||||
ICMP6_TYPE_PE2 = 101, /* Private experimentation */
|
||||
ICMP6_TYPE_RSV_ERR = 127, /* Reserved for expansion of error messages */
|
||||
|
||||
ICMP6_TYPE_EREQ = 128, /* Echo request */
|
||||
ICMP6_TYPE_EREP = 129, /* Echo reply */
|
||||
ICMP6_TYPE_MLQ = 130, /* Multicast listener query */
|
||||
ICMP6_TYPE_MLR = 131, /* Multicast listener report */
|
||||
ICMP6_TYPE_MLD = 132, /* Multicast listener done */
|
||||
ICMP6_TYPE_RS = 133, /* Router solicitation */
|
||||
ICMP6_TYPE_RA = 134, /* Router advertisement */
|
||||
ICMP6_TYPE_NS = 135, /* Neighbor solicitation */
|
||||
ICMP6_TYPE_NA = 136, /* Neighbor advertisement */
|
||||
ICMP6_TYPE_RD = 137, /* Redirect */
|
||||
ICMP6_TYPE_MRA = 151, /* Multicast router advertisement */
|
||||
ICMP6_TYPE_MRS = 152, /* Multicast router solicitation */
|
||||
ICMP6_TYPE_MRT = 153, /* Multicast router termination */
|
||||
ICMP6_TYPE_PE3 = 200, /* Private experimentation */
|
||||
ICMP6_TYPE_PE4 = 201, /* Private experimentation */
|
||||
ICMP6_TYPE_RSV_INF = 255 /* Reserved for expansion of informational messages */
|
||||
};
|
||||
|
||||
enum icmp6_dur_code {
|
||||
ICMP6_DUR_NO_ROUTE = 0, /* No route to destination */
|
||||
ICMP6_DUR_PROHIBITED = 1, /* Communication with destination administratively prohibited */
|
||||
ICMP6_DUR_SCOPE = 2, /* Beyond scope of source address */
|
||||
ICMP6_DUR_ADDRESS = 3, /* Address unreachable */
|
||||
ICMP6_DUR_PORT = 4, /* Port unreachable */
|
||||
ICMP6_DUR_POLICY = 5, /* Source address failed ingress/egress policy */
|
||||
ICMP6_DUR_REJECT_ROUTE = 6 /* Reject route to destination */
|
||||
};
|
||||
|
||||
enum icmp6_te_code {
|
||||
ICMP6_TE_HL = 0, /* Hop limit exceeded in transit */
|
||||
ICMP6_TE_FRAG = 1 /* Fragment reassembly time exceeded */
|
||||
};
|
||||
|
||||
enum icmp6_pp_code {
|
||||
ICMP6_PP_FIELD = 0, /* Erroneous header field encountered */
|
||||
ICMP6_PP_HEADER = 1, /* Unrecognized next header type encountered */
|
||||
ICMP6_PP_OPTION = 2, /* Unrecognized IPv6 option encountered */
|
||||
};
|
||||
|
||||
/** This is the standard ICMP6 header. */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct icmp6_hdr {
|
||||
PACK_STRUCT_FIELD(u8_t type);
|
||||
PACK_STRUCT_FIELD(u8_t code);
|
||||
PACK_STRUCT_FIELD(u16_t chksum);
|
||||
PACK_STRUCT_FIELD(u32_t data);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** This is the ICMP6 header adapted for echo req/resp. */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct icmp6_echo_hdr {
|
||||
PACK_STRUCT_FIELD(u8_t type);
|
||||
PACK_STRUCT_FIELD(u8_t code);
|
||||
PACK_STRUCT_FIELD(u16_t chksum);
|
||||
PACK_STRUCT_FIELD(u16_t id);
|
||||
PACK_STRUCT_FIELD(u16_t seqno);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
void icmp6_input(struct pbuf *p, struct netif *inp);
|
||||
void icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c);
|
||||
void icmp6_packet_too_big(struct pbuf *p, u32_t mtu);
|
||||
void icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c);
|
||||
void icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer);
|
||||
|
||||
#endif /* LWIP_ICMP6 && LWIP_IPV6 */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __LWIP_ICMP6_H__ */
|
||||
89
src/include/ipv6/lwip/inet6.h
Normal file
89
src/include/ipv6/lwip/inet6.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* INET v6 addresses.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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>
|
||||
*/
|
||||
#ifndef __LWIP_INET6_H__
|
||||
#define __LWIP_INET6_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** For compatibility with BSD code */
|
||||
struct in6_addr {
|
||||
u32_t s_addr[4];
|
||||
};
|
||||
|
||||
#define IN6ADDR_ANY_INIT {0,0,0,0}
|
||||
#define IN6ADDR_LOOPBACK_INIT {0,0,0,PP_HTONL(1)}
|
||||
|
||||
|
||||
|
||||
#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->s_addr[0] = (source_ip6addr)->addr[0]; \
|
||||
(target_in6addr)->s_addr[1] = (source_ip6addr)->addr[1]; \
|
||||
(target_in6addr)->s_addr[2] = (source_ip6addr)->addr[2]; \
|
||||
(target_in6addr)->s_addr[3] = (source_ip6addr)->addr[3];}
|
||||
#define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr) {(target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0]; \
|
||||
(target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0]; \
|
||||
(target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0]; \
|
||||
(target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0];}
|
||||
/* ATTENTION: the next define only works because both in6_addr and ip6_addr_t are an u32_t[4] effectively! */
|
||||
#define inet6_addr_to_ip6addr_p(target_ip6addr_p, source_in6addr) ((target_ip6addr_p) = (ip6_addr_t*)(source_in6addr))
|
||||
|
||||
/* directly map this to the lwip internal functions */
|
||||
#define inet6_aton(cp, addr) ip6addr_aton(cp, (ip6_addr_t*)addr)
|
||||
#define inet6_ntoa(addr) ip6addr_ntoa((ip6_addr_t*)&(addr))
|
||||
#define inet6_ntoa_r(addr, buf, buflen) ip6addr_ntoa_r((ip6_addr_t*)&(addr), buf, buflen)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#endif /* __LWIP_INET6_H__ */
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
#ifndef __LWIP_IP_H__
|
||||
#define __LWIP_IP_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define IP_HLEN 40
|
||||
|
||||
#define IP_PROTO_ICMP 58
|
||||
#define IP_PROTO_UDP 17
|
||||
#define IP_PROTO_UDPLITE 136
|
||||
#define IP_PROTO_TCP 6
|
||||
|
||||
/* This is passed as the destination address to ip_output_if (not
|
||||
to ip_output), meaning that an IP header already is constructed
|
||||
in the pbuf. This is used when TCP retransmits. */
|
||||
#ifdef IP_HDRINCL
|
||||
#undef IP_HDRINCL
|
||||
#endif /* IP_HDRINCL */
|
||||
#define IP_HDRINCL NULL
|
||||
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
#define IP_PCB_ADDRHINT ;u8_t addr_hint
|
||||
#else
|
||||
#define IP_PCB_ADDRHINT
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
|
||||
/* This is the common part of all PCB types. It needs to be at the
|
||||
beginning of a PCB type definition. It is located here so that
|
||||
changes to this common part are made in one location instead of
|
||||
having to change all PCB structs. */
|
||||
#define IP_PCB struct ip_addr local_ip; \
|
||||
struct ip_addr remote_ip; \
|
||||
/* Socket options */ \
|
||||
u16_t so_options; \
|
||||
/* Type Of Service */ \
|
||||
u8_t tos; \
|
||||
/* Time To Live */ \
|
||||
u8_t ttl; \
|
||||
/* link layer address resolution hint */ \
|
||||
IP_PCB_ADDRHINT
|
||||
|
||||
|
||||
/* The IPv6 header. */
|
||||
struct ip_hdr {
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
u8_t tclass1:4, v:4;
|
||||
u8_t flow1:4, tclass2:4;
|
||||
#else
|
||||
u8_t v:4, tclass1:4;
|
||||
u8_t tclass2:8, flow1:4;
|
||||
#endif
|
||||
u16_t flow2;
|
||||
u16_t len; /* payload length */
|
||||
u8_t nexthdr; /* next header */
|
||||
u8_t hoplim; /* hop limit (TTL) */
|
||||
struct ip_addr src, dest; /* source and destination IP addresses */
|
||||
};
|
||||
|
||||
#define IPH_PROTO(hdr) (iphdr->nexthdr)
|
||||
|
||||
void ip_init(void);
|
||||
|
||||
#include "lwip/netif.h"
|
||||
|
||||
struct netif *ip_route(struct ip_addr *dest);
|
||||
|
||||
void ip_input(struct pbuf *p, struct netif *inp);
|
||||
|
||||
/* source and destination addresses in network byte order, please */
|
||||
err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl, u8_t proto);
|
||||
|
||||
err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl, u8_t proto,
|
||||
struct netif *netif);
|
||||
|
||||
#if IP_DEBUG
|
||||
void ip_debug_print(struct pbuf *p);
|
||||
#endif /* IP_DEBUG */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LWIP_IP_H__ */
|
||||
|
||||
|
||||
197
src/include/ipv6/lwip/ip6.h
Normal file
197
src/include/ipv6/lwip/ip6.h
Normal file
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* IPv6 layer.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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>
|
||||
*/
|
||||
#ifndef __LWIP_IP6_H__
|
||||
#define __LWIP_IP6_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define IP6_HLEN 40
|
||||
|
||||
#define IP6_NEXTH_HOPBYHOP 0
|
||||
#define IP6_NEXTH_TCP 6
|
||||
#define IP6_NEXTH_UDP 17
|
||||
#define IP6_NEXTH_ENCAPS 41
|
||||
#define IP6_NEXTH_ROUTING 43
|
||||
#define IP6_NEXTH_FRAGMENT 44
|
||||
#define IP6_NEXTH_ICMP6 58
|
||||
#define IP6_NEXTH_NONE 59
|
||||
#define IP6_NEXTH_DESTOPTS 60
|
||||
#define IP6_NEXTH_UDPLITE 136
|
||||
|
||||
|
||||
/* The IPv6 header. */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip6_hdr {
|
||||
/* version / traffic class / flow label */
|
||||
PACK_STRUCT_FIELD(u32_t _v_tc_fl);
|
||||
/* payload length */
|
||||
PACK_STRUCT_FIELD(u16_t _plen);
|
||||
/* next header */
|
||||
PACK_STRUCT_FIELD(u8_t _nexth);
|
||||
/* hop limit */
|
||||
PACK_STRUCT_FIELD(u8_t _hoplim);
|
||||
/* source and destination IP addresses */
|
||||
PACK_STRUCT_FIELD(ip6_addr_p_t src);
|
||||
PACK_STRUCT_FIELD(ip6_addr_p_t dest);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/* Hop-by-hop router alert option. */
|
||||
#define IP6_HBH_HLEN 8
|
||||
#define IP6_PAD1_OPTION 0
|
||||
#define IP6_PADN_ALERT_OPTION 1
|
||||
#define IP6_ROUTER_ALERT_OPTION 5
|
||||
#define IP6_ROUTER_ALERT_VALUE_MLD 0
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip6_hbh_hdr {
|
||||
/* next header */
|
||||
PACK_STRUCT_FIELD(u8_t _nexth);
|
||||
/* header length */
|
||||
PACK_STRUCT_FIELD(u8_t _hlen);
|
||||
/* router alert option type */
|
||||
PACK_STRUCT_FIELD(u8_t _ra_opt_type);
|
||||
/* router alert option data len */
|
||||
PACK_STRUCT_FIELD(u8_t _ra_opt_dlen);
|
||||
/* router alert option data */
|
||||
PACK_STRUCT_FIELD(u16_t _ra_opt_data);
|
||||
/* PadN option type */
|
||||
PACK_STRUCT_FIELD(u8_t _padn_opt_type);
|
||||
/* PadN option data len */
|
||||
PACK_STRUCT_FIELD(u8_t _padn_opt_dlen);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/* Fragment header. */
|
||||
#define IP6_FRAG_HLEN 8
|
||||
#define IP6_FRAG_OFFSET_MASK 0xfff8
|
||||
#define IP6_FRAG_MORE_FLAG 0x0001
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip6_frag_hdr {
|
||||
/* next header */
|
||||
PACK_STRUCT_FIELD(u8_t _nexth);
|
||||
/* reserved */
|
||||
PACK_STRUCT_FIELD(u8_t reserved);
|
||||
/* fragment offset */
|
||||
PACK_STRUCT_FIELD(u16_t _fragment_offset);
|
||||
/* fragmented packet identification */
|
||||
PACK_STRUCT_FIELD(u32_t _identification);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
#define IP6H_V(hdr) ((ntohl((hdr)->_v_tc_fl) >> 28) & 0x0f)
|
||||
#define IP6H_TC(hdr) ((ntohl((hdr)->_v_tc_fl) >> 20) & 0xff)
|
||||
#define IP6H_FL(hdr) (ntohl((hdr)->_v_tc_fl) & 0x000fffff)
|
||||
#define IP6H_PLEN(hdr) (ntohs((hdr)->_plen))
|
||||
#define IP6H_NEXTH(hdr) ((hdr)->_nexth)
|
||||
#define IP6H_NEXTH_P(hdr) ((u8_t *)(hdr) + 6)
|
||||
#define IP6H_HOPLIM(hdr) ((hdr)->_hoplim)
|
||||
|
||||
#define IP6H_VTCFL_SET(hdr, v, tc, fl) (hdr)->_v_tc_fl = (htonl(((v) << 28) | ((tc) << 20) | (fl)))
|
||||
#define IP6H_PLEN_SET(hdr, plen) (hdr)->_plen = htons(plen)
|
||||
#define IP6H_NEXTH_SET(hdr, nexth) (hdr)->_nexth = (nexth)
|
||||
#define IP6H_HOPLIM_SET(hdr, hl) (hdr)->_hoplim = (u8_t)(hl)
|
||||
|
||||
|
||||
#define ip6_init() /* TODO should we init current addresses and header pointer? */
|
||||
struct netif *ip6_route(struct ip6_addr *src, struct ip6_addr *dest);
|
||||
ip6_addr_t *ip6_select_source_address(struct netif *netif, ip6_addr_t * dest);
|
||||
err_t ip6_input(struct pbuf *p, struct netif *inp);
|
||||
err_t ip6_output(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *dest,
|
||||
u8_t hl, u8_t tc, u8_t nexth);
|
||||
err_t ip6_output_if(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *dest,
|
||||
u8_t hl, u8_t tc, u8_t nexth, struct netif *netif);
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
err_t ip6_output_hinted(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest,
|
||||
u8_t hl, u8_t tc, u8_t nexth, u8_t *addr_hint);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
#if LWIP_IPV6_MLD
|
||||
err_t ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value);
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
|
||||
#define ip6_netif_get_local_ipX(netif, dest) (((netif) != NULL) ? \
|
||||
ip6_2_ipX(ip6_select_source_address(netif, dest)) : NULL)
|
||||
|
||||
#if IP6_DEBUG
|
||||
void ip6_debug_print(struct pbuf *p);
|
||||
#else
|
||||
#define ip6_debug_print(p)
|
||||
#endif /* IP6_DEBUG */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#endif /* __LWIP_IP6_H__ */
|
||||
282
src/include/ipv6/lwip/ip6_addr.h
Normal file
282
src/include/ipv6/lwip/ip6_addr.h
Normal file
@@ -0,0 +1,282 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* IPv6 addresses.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
* Structs and macros for handling IPv6 addresses.
|
||||
*
|
||||
* Please coordinate changes and requests with Ivan Delamer
|
||||
* <delamer@inicotech.com>
|
||||
*/
|
||||
#ifndef __LWIP_IP6_ADDR_H__
|
||||
#define __LWIP_IP6_ADDR_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* This is the aligned version of ip6_addr_t,
|
||||
used as local variable, on the stack, etc. */
|
||||
struct ip6_addr {
|
||||
u32_t addr[4];
|
||||
};
|
||||
|
||||
/* This is the packed version of ip6_addr_t,
|
||||
used in network headers that are itself packed */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip6_addr_packed {
|
||||
PACK_STRUCT_FIELD(u32_t addr[4]);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** ip6_addr_t uses a struct for convenience only, so that the same defines can
|
||||
* operate both on ip6_addr_t as well as on ip6_addr_p_t. */
|
||||
typedef struct ip6_addr ip6_addr_t;
|
||||
typedef struct ip6_addr_packed ip6_addr_p_t;
|
||||
|
||||
|
||||
/** IP6_ADDR_ANY can be used as a fixed IPv6 address
|
||||
* for the wildcard
|
||||
*/
|
||||
extern const ip6_addr_t ip6_addr_any;
|
||||
#define IP6_ADDR_ANY ((ip6_addr_t *)&ip6_addr_any)
|
||||
|
||||
|
||||
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
/** Set an IPv6 partial address given by byte-parts. */
|
||||
#define IP6_ADDR(ip6addr, index, a,b,c,d) \
|
||||
(ip6addr)->addr[index] = ((u32_t)((a) & 0xff) << 24) | \
|
||||
((u32_t)((b) & 0xff) << 16) | \
|
||||
((u32_t)((c) & 0xff) << 8) | \
|
||||
(u32_t)((d) & 0xff)
|
||||
#else
|
||||
/** Set an IPv6 partial address given by byte-parts.
|
||||
Little-endian version, stored in network order (no htonl). */
|
||||
#define IP6_ADDR(ip6addr, index, a,b,c,d) \
|
||||
(ip6addr)->addr[index] = ((u32_t)((d) & 0xff) << 24) | \
|
||||
((u32_t)((c) & 0xff) << 16) | \
|
||||
((u32_t)((b) & 0xff) << 8) | \
|
||||
(u32_t)((a) & 0xff)
|
||||
#endif
|
||||
|
||||
/** Access address in 16-bit block */
|
||||
#define IP6_ADDR_BLOCK1(ip6addr) ((htonl((ip6addr)->addr[0]) >> 16) & 0xffff)
|
||||
#define IP6_ADDR_BLOCK2(ip6addr) ((htonl((ip6addr)->addr[0])) & 0xffff)
|
||||
#define IP6_ADDR_BLOCK3(ip6addr) ((htonl((ip6addr)->addr[1]) >> 16) & 0xffff)
|
||||
#define IP6_ADDR_BLOCK4(ip6addr) ((htonl((ip6addr)->addr[1])) & 0xffff)
|
||||
#define IP6_ADDR_BLOCK5(ip6addr) ((htonl((ip6addr)->addr[2]) >> 16) & 0xffff)
|
||||
#define IP6_ADDR_BLOCK6(ip6addr) ((htonl((ip6addr)->addr[2])) & 0xffff)
|
||||
#define IP6_ADDR_BLOCK7(ip6addr) ((htonl((ip6addr)->addr[3]) >> 16) & 0xffff)
|
||||
#define IP6_ADDR_BLOCK8(ip6addr) ((htonl((ip6addr)->addr[3])) & 0xffff)
|
||||
|
||||
/** Copy IPv6 address - faster than ip6_addr_set: no NULL check */
|
||||
#define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \
|
||||
(dest).addr[1] = (src).addr[1]; \
|
||||
(dest).addr[2] = (src).addr[2]; \
|
||||
(dest).addr[3] = (src).addr[3];}while(0)
|
||||
/** Safely copy one IPv6 address to another (src may be NULL) */
|
||||
#define ip6_addr_set(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : (src)->addr[0]; \
|
||||
(dest)->addr[1] = (src) == NULL ? 0 : (src)->addr[1]; \
|
||||
(dest)->addr[2] = (src) == NULL ? 0 : (src)->addr[2]; \
|
||||
(dest)->addr[3] = (src) == NULL ? 0 : (src)->addr[3];}while(0)
|
||||
|
||||
/** Set complete address to zero */
|
||||
#define ip6_addr_set_zero(ip6addr) do{(ip6addr)->addr[0] = 0; \
|
||||
(ip6addr)->addr[1] = 0; \
|
||||
(ip6addr)->addr[2] = 0; \
|
||||
(ip6addr)->addr[3] = 0;}while(0)
|
||||
|
||||
/** Set address to ipv6 'any' (no need for htonl()) */
|
||||
#define ip6_addr_set_any(ip6addr) ip6_addr_set_zero(ip6addr)
|
||||
/** Set address to ipv6 loopback address */
|
||||
#define ip6_addr_set_loopback(ip6addr) do{(ip6addr)->addr[0] = 0; \
|
||||
(ip6addr)->addr[1] = 0; \
|
||||
(ip6addr)->addr[2] = 0; \
|
||||
(ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0)
|
||||
/** Safely copy one IPv6 address to another and change byte order
|
||||
* from host- to network-order. */
|
||||
#define ip6_addr_set_hton(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : htonl((src)->addr[0]); \
|
||||
(dest)->addr[1] = (src) == NULL ? 0 : htonl((src)->addr[1]); \
|
||||
(dest)->addr[2] = (src) == NULL ? 0 : htonl((src)->addr[2]); \
|
||||
(dest)->addr[3] = (src) == NULL ? 0 : htonl((src)->addr[3]);}while(0)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Determine if two IPv6 address are on the same network.
|
||||
*
|
||||
* @arg addr1 IPv6 address 1
|
||||
* @arg addr2 IPv6 address 2
|
||||
* @return !0 if the network identifiers of both address match
|
||||
*/
|
||||
#define ip6_addr_netcmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \
|
||||
((addr1)->addr[1] == (addr2)->addr[1]))
|
||||
|
||||
#define ip6_addr_cmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \
|
||||
((addr1)->addr[1] == (addr2)->addr[1]) && \
|
||||
((addr1)->addr[2] == (addr2)->addr[2]) && \
|
||||
((addr1)->addr[3] == (addr2)->addr[3]))
|
||||
|
||||
#define ip6_get_subnet_id(ip6addr) (htonl((ip6addr)->addr[2]) & 0x0000ffffUL)
|
||||
|
||||
#define ip6_addr_isany(ip6addr) (((ip6addr) == NULL) || \
|
||||
(((ip6addr)->addr[0] == 0) && \
|
||||
((ip6addr)->addr[1] == 0) && \
|
||||
((ip6addr)->addr[2] == 0) && \
|
||||
((ip6addr)->addr[3] == 0)))
|
||||
|
||||
|
||||
#define ip6_addr_isglobal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xe0000000UL)) == PP_HTONL(0x20000000UL))
|
||||
|
||||
#define ip6_addr_islinklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfe800000UL))
|
||||
|
||||
#define ip6_addr_issitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfec00000UL))
|
||||
|
||||
#define ip6_addr_isuniquelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xfe000000UL)) == PP_HTONL(0xfc000000UL))
|
||||
|
||||
#define ip6_addr_ismulticast(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL))
|
||||
#define ip6_addr_multicast_transient_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00100000UL))
|
||||
#define ip6_addr_multicast_prefix_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00200000UL))
|
||||
#define ip6_addr_multicast_rendezvous_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00400000UL))
|
||||
#define ip6_addr_multicast_scope(ip6addr) ((htonl((ip6addr)->addr[0]) >> 16) & 0xf)
|
||||
#define IP6_MULTICAST_SCOPE_RESERVED 0x0
|
||||
#define IP6_MULTICAST_SCOPE_RESERVED0 0x0
|
||||
#define IP6_MULTICAST_SCOPE_INTERFACE_LOCAL 0x1
|
||||
#define IP6_MULTICAST_SCOPE_LINK_LOCAL 0x2
|
||||
#define IP6_MULTICAST_SCOPE_RESERVED3 0x3
|
||||
#define IP6_MULTICAST_SCOPE_ADMIN_LOCAL 0x4
|
||||
#define IP6_MULTICAST_SCOPE_SITE_LOCAL 0x5
|
||||
#define IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL 0x8
|
||||
#define IP6_MULTICAST_SCOPE_GLOBAL 0xe
|
||||
#define IP6_MULTICAST_SCOPE_RESERVEDF 0xf
|
||||
#define ip6_addr_ismulticast_iflocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff010000UL))
|
||||
#define ip6_addr_ismulticast_linklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff020000UL))
|
||||
#define ip6_addr_ismulticast_adminlocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff040000UL))
|
||||
#define ip6_addr_ismulticast_sitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff050000UL))
|
||||
#define ip6_addr_ismulticast_orglocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff080000UL))
|
||||
#define ip6_addr_ismulticast_global(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff0e0000UL))
|
||||
|
||||
/* TODO define get/set for well-know multicast addresses, e.g. ff02::1 */
|
||||
#define ip6_addr_isallnodes_iflocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff010000UL)) && \
|
||||
((ip6addr)->addr[1] == 0UL) && \
|
||||
((ip6addr)->addr[2] == 0UL) && \
|
||||
((ip6addr)->addr[3] == PP_HTONL(0x00000001UL)))
|
||||
|
||||
#define ip6_addr_isallnodes_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \
|
||||
((ip6addr)->addr[1] == 0UL) && \
|
||||
((ip6addr)->addr[2] == 0UL) && \
|
||||
((ip6addr)->addr[3] == PP_HTONL(0x00000001UL)))
|
||||
#define ip6_addr_set_allnodes_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \
|
||||
(ip6addr)->addr[1] = 0; \
|
||||
(ip6addr)->addr[2] = 0; \
|
||||
(ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0)
|
||||
|
||||
#define ip6_addr_isallrouters_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \
|
||||
((ip6addr)->addr[1] == 0UL) && \
|
||||
((ip6addr)->addr[2] == 0UL) && \
|
||||
((ip6addr)->addr[3] == PP_HTONL(0x00000002UL)))
|
||||
#define ip6_addr_set_allrouters_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \
|
||||
(ip6addr)->addr[1] = 0; \
|
||||
(ip6addr)->addr[2] = 0; \
|
||||
(ip6addr)->addr[3] = PP_HTONL(0x00000002UL);}while(0)
|
||||
|
||||
#define ip6_addr_issolicitednode(ip6addr) ( ((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \
|
||||
((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \
|
||||
(((ip6addr)->addr[3] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) )
|
||||
|
||||
#define ip6_addr_set_solicitednode(ip6addr, if_id) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \
|
||||
(ip6addr)->addr[1] = 0; \
|
||||
(ip6addr)->addr[2] = PP_HTONL(0x00000001UL); \
|
||||
(ip6addr)->addr[3] = htonl(0xff000000UL | (htonl(if_id) & 0x00ffffffUL));}while(0)
|
||||
|
||||
|
||||
/* IPv6 address states. */
|
||||
#define IP6_ADDR_INVALID 0x00
|
||||
#define IP6_ADDR_TENTATIVE 0x08
|
||||
#define IP6_ADDR_TENTATIVE_1 0x09 /* 1 probe sent */
|
||||
#define IP6_ADDR_TENTATIVE_2 0x0a /* 2 probes sent */
|
||||
#define IP6_ADDR_TENTATIVE_3 0x0b /* 3 probes sent */
|
||||
#define IP6_ADDR_TENTATIVE_4 0x0c /* 4 probes sent */
|
||||
#define IP6_ADDR_TENTATIVE_5 0x0d /* 5 probes sent */
|
||||
#define IP6_ADDR_TENTATIVE_6 0x0e /* 6 probes sent */
|
||||
#define IP6_ADDR_TENTATIVE_7 0x0f /* 7 probes sent */
|
||||
#define IP6_ADDR_VALID 0x10
|
||||
#define IP6_ADDR_PREFERRED 0x30
|
||||
#define IP6_ADDR_DEPRECATED 0x50
|
||||
|
||||
#define ip6_addr_isinvalid(addr_state) (addr_state == IP6_ADDR_INVALID)
|
||||
#define ip6_addr_istentative(addr_state) (addr_state & IP6_ADDR_TENTATIVE)
|
||||
#define ip6_addr_isvalid(addr_state) (addr_state & IP6_ADDR_VALID) /* Include valid, preferred, and deprecated. */
|
||||
#define ip6_addr_ispreferred(addr_state) (addr_state == IP6_ADDR_PREFERRED)
|
||||
#define ip6_addr_isdeprecated(addr_state) (addr_state == IP6_ADDR_DEPRECATED)
|
||||
|
||||
#define ip6_addr_debug_print(debug, ipaddr) \
|
||||
LWIP_DEBUGF(debug, ("%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F, \
|
||||
ipaddr != NULL ? IP6_ADDR_BLOCK1(ipaddr) : 0, \
|
||||
ipaddr != NULL ? IP6_ADDR_BLOCK2(ipaddr) : 0, \
|
||||
ipaddr != NULL ? IP6_ADDR_BLOCK3(ipaddr) : 0, \
|
||||
ipaddr != NULL ? IP6_ADDR_BLOCK4(ipaddr) : 0, \
|
||||
ipaddr != NULL ? IP6_ADDR_BLOCK5(ipaddr) : 0, \
|
||||
ipaddr != NULL ? IP6_ADDR_BLOCK6(ipaddr) : 0, \
|
||||
ipaddr != NULL ? IP6_ADDR_BLOCK7(ipaddr) : 0, \
|
||||
ipaddr != NULL ? IP6_ADDR_BLOCK8(ipaddr) : 0))
|
||||
|
||||
int ip6addr_aton(const char *cp, ip6_addr_t *addr);
|
||||
/** returns ptr to static buffer; not reentrant! */
|
||||
char *ip6addr_ntoa(const ip6_addr_t *addr);
|
||||
char *ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#endif /* __LWIP_IP6_ADDR_H__ */
|
||||
102
src/include/ipv6/lwip/ip6_frag.h
Normal file
102
src/include/ipv6/lwip/ip6_frag.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @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>
|
||||
*/
|
||||
#ifndef __LWIP_IP6_FRAG_H__
|
||||
#define __LWIP_IP6_FRAG_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
/* The IPv6 reassembly timer interval in milliseconds. */
|
||||
#define IP6_REASS_TMR_INTERVAL 1000
|
||||
|
||||
/* IPv6 reassembly helper struct.
|
||||
* This is exported because memp needs to know the size.
|
||||
*/
|
||||
struct ip6_reassdata {
|
||||
struct ip6_reassdata *next;
|
||||
struct pbuf *p;
|
||||
struct ip6_hdr * iphdr;
|
||||
u32_t identification;
|
||||
u16_t datagram_len;
|
||||
u8_t nexth;
|
||||
u8_t timer;
|
||||
};
|
||||
|
||||
#define ip6_reass_init() /* Compatibility define */
|
||||
void ip6_reass_tmr(void);
|
||||
struct pbuf * ip6_reass(struct pbuf *p);
|
||||
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */
|
||||
|
||||
#if LWIP_IPV6 && LWIP_IPV6_FRAG /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
/** A custom pbuf that holds a reference to another pbuf, which is freed
|
||||
* when this custom pbuf is freed. This is used to create a custom PBUF_REF
|
||||
* that points into the original pbuf. */
|
||||
#ifndef __LWIP_PBUF_CUSTOM_REF__
|
||||
#define __LWIP_PBUF_CUSTOM_REF__
|
||||
struct pbuf_custom_ref {
|
||||
/** 'base class' */
|
||||
struct pbuf_custom pc;
|
||||
/** pointer to the original pbuf that is referenced */
|
||||
struct pbuf *original;
|
||||
};
|
||||
#endif /* __LWIP_PBUF_CUSTOM_REF__ */
|
||||
|
||||
err_t ip6_frag(struct pbuf *p, struct netif *netif, ip6_addr_t *dest);
|
||||
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LWIP_IP6_FRAG_H__ */
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
#ifndef __LWIP_IP_ADDR_H__
|
||||
#define __LWIP_IP_ADDR_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define IP_ADDR_ANY 0
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip_addr {
|
||||
PACK_STRUCT_FIELD(u32_t addr[4]);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* struct ipaddr2 is used in the definition of the ARP packet format in
|
||||
* order to support compilers that don't have structure packing.
|
||||
*/
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ip_addr2 {
|
||||
PACK_STRUCT_FIELD(u16_t addrw[2]);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
#define IP6_ADDR(ipaddr, a,b,c,d,e,f,g,h) do { (ipaddr)->addr[0] = htonl((u32_t)((a & 0xffff) << 16) | (b & 0xffff)); \
|
||||
(ipaddr)->addr[1] = htonl(((c & 0xffff) << 16) | (d & 0xffff)); \
|
||||
(ipaddr)->addr[2] = htonl(((e & 0xffff) << 16) | (f & 0xffff)); \
|
||||
(ipaddr)->addr[3] = htonl(((g & 0xffff) << 16) | (h & 0xffff)); } while(0)
|
||||
|
||||
u8_t ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
|
||||
struct ip_addr *mask);
|
||||
u8_t ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2);
|
||||
void ip_addr_set(struct ip_addr *dest, struct ip_addr *src);
|
||||
u8_t ip_addr_isany(struct ip_addr *addr);
|
||||
|
||||
#define ip_addr_debug_print(debug, ipaddr) \
|
||||
LWIP_DEBUGF(debug, ("%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F"\n", \
|
||||
(ntohl(ipaddr->addr[0]) >> 16) & 0xffff, \
|
||||
ntohl(ipaddr->addr[0]) & 0xffff, \
|
||||
(ntohl(ipaddr->addr[1]) >> 16) & 0xffff, \
|
||||
ntohl(ipaddr->addr[1]) & 0xffff, \
|
||||
(ntohl(ipaddr->addr[2]) >> 16) & 0xffff, \
|
||||
ntohl(ipaddr->addr[2]) & 0xffff, \
|
||||
(ntohl(ipaddr->addr[3]) >> 16) & 0xffff, \
|
||||
ntohl(ipaddr->addr[3]) & 0xffff));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LWIP_IP_ADDR_H__ */
|
||||
118
src/include/ipv6/lwip/mld6.h
Normal file
118
src/include/ipv6/lwip/mld6.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710.
|
||||
* No support for MLDv2.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifndef __LWIP_MLD6_H__
|
||||
#define __LWIP_MLD6_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_IPV6_MLD && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct mld_group {
|
||||
/** next link */
|
||||
struct mld_group *next;
|
||||
/** interface on which the group is active */
|
||||
struct netif *netif;
|
||||
/** multicast address */
|
||||
ip6_addr_t group_address;
|
||||
/** signifies we were the last person to report */
|
||||
u8_t last_reporter_flag;
|
||||
/** current state of the group */
|
||||
u8_t group_state;
|
||||
/** timer for reporting */
|
||||
u16_t timer;
|
||||
/** counter of simultaneous uses */
|
||||
u8_t use;
|
||||
};
|
||||
|
||||
/** Multicast listener report/query/done message header. */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct mld_header {
|
||||
PACK_STRUCT_FIELD(u8_t type);
|
||||
PACK_STRUCT_FIELD(u8_t code);
|
||||
PACK_STRUCT_FIELD(u16_t chksum);
|
||||
PACK_STRUCT_FIELD(u16_t max_resp_delay);
|
||||
PACK_STRUCT_FIELD(u16_t reserved);
|
||||
PACK_STRUCT_FIELD(ip6_addr_p_t multicast_address);
|
||||
/* Options follow. */
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
#define MLD6_TMR_INTERVAL 100 /* Milliseconds */
|
||||
|
||||
/* MAC Filter Actions, these are passed to a netif's
|
||||
* mld_mac_filter callback function. */
|
||||
#define MLD6_DEL_MAC_FILTER 0
|
||||
#define MLD6_ADD_MAC_FILTER 1
|
||||
|
||||
|
||||
#define mld6_init() /* TODO should we init tables? */
|
||||
err_t mld6_stop(struct netif *netif);
|
||||
void mld6_report_groups(struct netif *netif);
|
||||
void mld6_tmr(void);
|
||||
struct mld_group *mld6_lookfor_group(struct netif *ifp, ip6_addr_t *addr);
|
||||
void mld6_input(struct pbuf *p, struct netif *inp);
|
||||
err_t mld6_joingroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr);
|
||||
err_t mld6_leavegroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_IPV6_MLD && LWIP_IPV6 */
|
||||
|
||||
#endif /* __LWIP_MLD6_H__ */
|
||||
368
src/include/ipv6/lwip/nd6.h
Normal file
368
src/include/ipv6/lwip/nd6.h
Normal file
@@ -0,0 +1,368 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Neighbor discovery and stateless address autoconfiguration for IPv6.
|
||||
* Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862
|
||||
* (Address autoconfiguration).
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifndef __LWIP_ND6_H__
|
||||
#define __LWIP_ND6_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Struct for tables. */
|
||||
struct nd6_neighbor_cache_entry {
|
||||
ip6_addr_t next_hop_address;
|
||||
struct netif * netif;
|
||||
u8_t lladdr[NETIF_MAX_HWADDR_LEN];
|
||||
/*u32_t pmtu;*/
|
||||
#if LWIP_ND6_QUEUEING
|
||||
/** Pointer to queue of pending outgoing packets on this entry. */
|
||||
struct nd6_q_entry *q;
|
||||
#endif /* LWIP_ND6_QUEUEING */
|
||||
u8_t state;
|
||||
u8_t isrouter;
|
||||
union {
|
||||
u32_t reachable_time;
|
||||
u32_t delay_time;
|
||||
u32_t probes_sent;
|
||||
u32_t stale_time;
|
||||
} counter;
|
||||
};
|
||||
|
||||
struct nd6_destination_cache_entry {
|
||||
ip6_addr_t destination_addr;
|
||||
ip6_addr_t next_hop_addr;
|
||||
u32_t pmtu;
|
||||
u32_t age;
|
||||
};
|
||||
|
||||
struct nd6_prefix_list_entry {
|
||||
ip6_addr_t prefix;
|
||||
struct netif * netif;
|
||||
u32_t invalidation_timer;
|
||||
#if LWIP_IPV6_AUTOCONFIG
|
||||
u8_t flags;
|
||||
#define ND6_PREFIX_AUTOCONFIG_AUTONOMOUS 0x01
|
||||
#define ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED 0x02
|
||||
#define ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE 0x04
|
||||
#endif /* LWIP_IPV6_AUTOCONFIG */
|
||||
};
|
||||
|
||||
struct nd6_router_list_entry {
|
||||
struct nd6_neighbor_cache_entry * neighbor_entry;
|
||||
u32_t invalidation_timer;
|
||||
u8_t flags;
|
||||
};
|
||||
|
||||
|
||||
enum nd6_neighbor_cache_entry_state {
|
||||
ND6_NO_ENTRY = 0,
|
||||
ND6_INCOMPLETE,
|
||||
ND6_REACHABLE,
|
||||
ND6_STALE,
|
||||
ND6_DELAY,
|
||||
ND6_PROBE
|
||||
};
|
||||
|
||||
#if LWIP_ND6_QUEUEING
|
||||
/** struct for queueing outgoing packets for unknown address
|
||||
* defined here to be accessed by memp.h
|
||||
*/
|
||||
struct nd6_q_entry {
|
||||
struct nd6_q_entry *next;
|
||||
struct pbuf *p;
|
||||
};
|
||||
#endif /* LWIP_ND6_QUEUEING */
|
||||
|
||||
/** Neighbor solicitation message header. */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ns_header {
|
||||
PACK_STRUCT_FIELD(u8_t type);
|
||||
PACK_STRUCT_FIELD(u8_t code);
|
||||
PACK_STRUCT_FIELD(u16_t chksum);
|
||||
PACK_STRUCT_FIELD(u32_t reserved);
|
||||
PACK_STRUCT_FIELD(ip6_addr_p_t target_address);
|
||||
/* Options follow. */
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** Neighbor advertisement message header. */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct na_header {
|
||||
PACK_STRUCT_FIELD(u8_t type);
|
||||
PACK_STRUCT_FIELD(u8_t code);
|
||||
PACK_STRUCT_FIELD(u16_t chksum);
|
||||
PACK_STRUCT_FIELD(u8_t flags);
|
||||
PACK_STRUCT_FIELD(u8_t reserved[3]);
|
||||
PACK_STRUCT_FIELD(ip6_addr_p_t target_address);
|
||||
/* Options follow. */
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
#define ND6_FLAG_ROUTER (0x80)
|
||||
#define ND6_FLAG_SOLICITED (0x40)
|
||||
#define ND6_FLAG_OVERRIDE (0x20)
|
||||
|
||||
/** Router solicitation message header. */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct rs_header {
|
||||
PACK_STRUCT_FIELD(u8_t type);
|
||||
PACK_STRUCT_FIELD(u8_t code);
|
||||
PACK_STRUCT_FIELD(u16_t chksum);
|
||||
PACK_STRUCT_FIELD(u32_t reserved);
|
||||
/* Options follow. */
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** Router advertisement message header. */
|
||||
#define ND6_RA_FLAG_MANAGED_ADDR_CONFIG (0x80)
|
||||
#define ND6_RA_FLAG_OTHER_STATEFUL_CONFIG (0x40)
|
||||
#define ND6_RA_FLAG_HOME_AGENT (0x20)
|
||||
#define ND6_RA_PREFERENCE_MASK (0x18)
|
||||
#define ND6_RA_PREFERENCE_HIGH (0x08)
|
||||
#define ND6_RA_PREFERENCE_MEDIUM (0x00)
|
||||
#define ND6_RA_PREFERENCE_LOW (0x18)
|
||||
#define ND6_RA_PREFERENCE_DISABLED (0x10)
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct ra_header {
|
||||
PACK_STRUCT_FIELD(u8_t type);
|
||||
PACK_STRUCT_FIELD(u8_t code);
|
||||
PACK_STRUCT_FIELD(u16_t chksum);
|
||||
PACK_STRUCT_FIELD(u8_t current_hop_limit);
|
||||
PACK_STRUCT_FIELD(u8_t flags);
|
||||
PACK_STRUCT_FIELD(u16_t router_lifetime);
|
||||
PACK_STRUCT_FIELD(u32_t reachable_time);
|
||||
PACK_STRUCT_FIELD(u32_t retrans_timer);
|
||||
/* Options follow. */
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** Redirect message header. */
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct redirect_header {
|
||||
PACK_STRUCT_FIELD(u8_t type);
|
||||
PACK_STRUCT_FIELD(u8_t code);
|
||||
PACK_STRUCT_FIELD(u16_t chksum);
|
||||
PACK_STRUCT_FIELD(u32_t reserved);
|
||||
PACK_STRUCT_FIELD(ip6_addr_p_t target_address);
|
||||
PACK_STRUCT_FIELD(ip6_addr_p_t destination_address);
|
||||
/* Options follow. */
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** Link-layer address option. */
|
||||
#define ND6_OPTION_TYPE_SOURCE_LLADDR (0x01)
|
||||
#define ND6_OPTION_TYPE_TARGET_LLADDR (0x02)
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct lladdr_option {
|
||||
PACK_STRUCT_FIELD(u8_t type);
|
||||
PACK_STRUCT_FIELD(u8_t length);
|
||||
PACK_STRUCT_FIELD(u8_t addr[NETIF_MAX_HWADDR_LEN]);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** Prefix information option. */
|
||||
#define ND6_OPTION_TYPE_PREFIX_INFO (0x03)
|
||||
#define ND6_PREFIX_FLAG_ON_LINK (0x80)
|
||||
#define ND6_PREFIX_FLAG_AUTONOMOUS (0x40)
|
||||
#define ND6_PREFIX_FLAG_ROUTER_ADDRESS (0x20)
|
||||
#define ND6_PREFIX_FLAG_SITE_PREFIX (0x10)
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct prefix_option {
|
||||
PACK_STRUCT_FIELD(u8_t type);
|
||||
PACK_STRUCT_FIELD(u8_t length);
|
||||
PACK_STRUCT_FIELD(u8_t prefix_length);
|
||||
PACK_STRUCT_FIELD(u8_t flags);
|
||||
PACK_STRUCT_FIELD(u32_t valid_lifetime);
|
||||
PACK_STRUCT_FIELD(u32_t preferred_lifetime);
|
||||
PACK_STRUCT_FIELD(u8_t reserved2[3]);
|
||||
PACK_STRUCT_FIELD(u8_t site_prefix_length);
|
||||
PACK_STRUCT_FIELD(ip6_addr_p_t prefix);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** Redirected header option. */
|
||||
#define ND6_OPTION_TYPE_REDIR_HDR (0x04)
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct redirected_header_option {
|
||||
PACK_STRUCT_FIELD(u8_t type);
|
||||
PACK_STRUCT_FIELD(u8_t length);
|
||||
PACK_STRUCT_FIELD(u8_t reserved[6]);
|
||||
/* Portion of redirected packet follows. */
|
||||
/* PACK_STRUCT_FIELD(u8_t redirected[8]); */
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** MTU option. */
|
||||
#define ND6_OPTION_TYPE_MTU (0x05)
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct mtu_option {
|
||||
PACK_STRUCT_FIELD(u8_t type);
|
||||
PACK_STRUCT_FIELD(u8_t length);
|
||||
PACK_STRUCT_FIELD(u16_t reserved);
|
||||
PACK_STRUCT_FIELD(u32_t mtu);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/** Route information option. */
|
||||
#define ND6_OPTION_TYPE_ROUTE_INFO (24)
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
PACK_STRUCT_BEGIN
|
||||
struct route_option {
|
||||
PACK_STRUCT_FIELD(u8_t type);
|
||||
PACK_STRUCT_FIELD(u8_t length);
|
||||
PACK_STRUCT_FIELD(u8_t prefix_length);
|
||||
PACK_STRUCT_FIELD(u8_t preference);
|
||||
PACK_STRUCT_FIELD(u32_t route_lifetime);
|
||||
PACK_STRUCT_FIELD(ip6_addr_p_t prefix);
|
||||
} PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
/* the possible states of an IP address */
|
||||
#define IP6_ADDRESS_STATE_INVALID (0)
|
||||
#define IP6_ADDRESS_STATE_VALID (0x4)
|
||||
#define IP6_ADDRESS_STATE_PREFERRED (0x5) /* includes valid */
|
||||
#define IP6_ADDRESS_STATE_DEPRECATED (0x6) /* includes valid */
|
||||
#define IP6_ADDRESS_STATE_TENTATIV (0x8)
|
||||
|
||||
/** 1 second period */
|
||||
#define ND6_TMR_INTERVAL 1000
|
||||
|
||||
/* Router tables. */
|
||||
/* TODO make these static? and entries accessible through API? */
|
||||
extern struct nd6_neighbor_cache_entry neighbor_cache[];
|
||||
extern struct nd6_destination_cache_entry destination_cache[];
|
||||
extern struct nd6_prefix_list_entry prefix_list[];
|
||||
extern struct nd6_router_list_entry default_router_list[];
|
||||
|
||||
/* Default values, can be updated by a RA message. */
|
||||
extern u32_t reachable_time;
|
||||
extern u32_t retrans_timer;
|
||||
|
||||
#define nd6_init() /* TODO should we init tables? */
|
||||
void nd6_tmr(void);
|
||||
void nd6_input(struct pbuf *p, struct netif *inp);
|
||||
s8_t nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif);
|
||||
s8_t nd6_select_router(ip6_addr_t * ip6addr, struct netif * netif);
|
||||
u16_t nd6_get_destination_mtu(ip6_addr_t * ip6addr, struct netif * netif);
|
||||
#if LWIP_ND6_QUEUEING
|
||||
err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf * p);
|
||||
#endif /* LWIP_ND6_QUEUEING */
|
||||
#if LWIP_ND6_TCP_REACHABILITY_HINTS
|
||||
void nd6_reachability_hint(ip6_addr_t * ip6addr);
|
||||
#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#endif /* __LWIP_ND6_H__ */
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include <stddef.h> /* for size_t */
|
||||
|
||||
#include "lwip/netbuf.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
@@ -49,28 +51,69 @@ extern "C" {
|
||||
* the same byte order as in the corresponding pcb.
|
||||
*/
|
||||
|
||||
/* Flags for netconn_write */
|
||||
#define NETCONN_NOFLAG 0x00
|
||||
#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */
|
||||
#define NETCONN_COPY 0x01
|
||||
#define NETCONN_MORE 0x02
|
||||
/* Flags for netconn_write (u8_t) */
|
||||
#define NETCONN_NOFLAG 0x00
|
||||
#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */
|
||||
#define NETCONN_COPY 0x01
|
||||
#define NETCONN_MORE 0x02
|
||||
#define NETCONN_DONTBLOCK 0x04
|
||||
|
||||
/* Flags for struct netconn.flags (u8_t) */
|
||||
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
|
||||
this temporarily stores whether to wake up the original application task
|
||||
if data couldn't be sent in the first try. */
|
||||
#define NETCONN_FLAG_WRITE_DELAYED 0x01
|
||||
/** Should this netconn avoid blocking? */
|
||||
#define NETCONN_FLAG_NON_BLOCKING 0x02
|
||||
/** Was the last connect action a non-blocking one? */
|
||||
#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04
|
||||
/** If this is set, a TCP netconn must call netconn_recved() to update
|
||||
the TCP receive window (done automatically if not set). */
|
||||
#define NETCONN_FLAG_NO_AUTO_RECVED 0x08
|
||||
/** If a nonblocking write has been rejected before, poll_tcp needs to
|
||||
check if the netconn is writable again */
|
||||
#define NETCONN_FLAG_CHECK_WRITESPACE 0x10
|
||||
|
||||
|
||||
/* Helpers to process several netconn_types by the same code */
|
||||
#define NETCONNTYPE_GROUP(t) (t&0xF0)
|
||||
#define NETCONNTYPE_DATAGRAM(t) (t&0xE0)
|
||||
#define NETCONNTYPE_GROUP(t) ((t)&0xF0)
|
||||
#define NETCONNTYPE_DATAGRAM(t) ((t)&0xE0)
|
||||
#if LWIP_IPV6
|
||||
#define NETCONN_TYPE_IPV6 0x08
|
||||
#define NETCONNTYPE_ISIPV6(t) ((t)&0x08)
|
||||
#define NETCONNTYPE_ISUDPLITE(t) (((t)&0xF7) == NETCONN_UDPLITE)
|
||||
#define NETCONNTYPE_ISUDPNOCHKSUM(t) (((t)&0xF7) == NETCONN_UDPNOCHKSUM)
|
||||
#else /* LWIP_IPV6 */
|
||||
#define NETCONNTYPE_ISUDPLITE(t) ((t) == NETCONN_UDPLITE)
|
||||
#define NETCONNTYPE_ISUDPNOCHKSUM(t) ((t) == NETCONN_UDPNOCHKSUM)
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
/** Protocol family and type of the netconn */
|
||||
enum netconn_type {
|
||||
NETCONN_INVALID = 0,
|
||||
NETCONN_INVALID = 0,
|
||||
/* NETCONN_TCP Group */
|
||||
NETCONN_TCP = 0x10,
|
||||
NETCONN_TCP = 0x10,
|
||||
#if LWIP_IPV6
|
||||
NETCONN_TCP_IPV6 = NETCONN_TCP | NETCONN_TYPE_IPV6 /* 0x18 */,
|
||||
#endif /* LWIP_IPV6 */
|
||||
/* NETCONN_UDP Group */
|
||||
NETCONN_UDP = 0x20,
|
||||
NETCONN_UDPLITE = 0x21,
|
||||
NETCONN_UDPNOCHKSUM= 0x22,
|
||||
NETCONN_UDP = 0x20,
|
||||
NETCONN_UDPLITE = 0x21,
|
||||
NETCONN_UDPNOCHKSUM = 0x22,
|
||||
#if LWIP_IPV6
|
||||
NETCONN_UDP_IPV6 = NETCONN_UDP | NETCONN_TYPE_IPV6 /* 0x28 */,
|
||||
NETCONN_UDPLITE_IPV6 = NETCONN_UDPLITE | NETCONN_TYPE_IPV6 /* 0x29 */,
|
||||
NETCONN_UDPNOCHKSUM_IPV6 = NETCONN_UDPNOCHKSUM | NETCONN_TYPE_IPV6 /* 0x2a */,
|
||||
#endif /* LWIP_IPV6 */
|
||||
/* NETCONN_RAW Group */
|
||||
NETCONN_RAW = 0x40
|
||||
NETCONN_RAW = 0x40,
|
||||
#if LWIP_IPV6
|
||||
NETCONN_RAW_IPV6 = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */,
|
||||
#endif /* LWIP_IPV6 */
|
||||
};
|
||||
|
||||
/** Current state of the netconn. Non-TCP netconns are always
|
||||
* in state NETCONN_NONE! */
|
||||
enum netconn_state {
|
||||
NETCONN_NONE,
|
||||
NETCONN_WRITE,
|
||||
@@ -79,19 +122,22 @@ enum netconn_state {
|
||||
NETCONN_CLOSE
|
||||
};
|
||||
|
||||
/** Use to inform the callback function about changes */
|
||||
enum netconn_evt {
|
||||
NETCONN_EVT_RCVPLUS,
|
||||
NETCONN_EVT_RCVMINUS,
|
||||
NETCONN_EVT_SENDPLUS,
|
||||
NETCONN_EVT_SENDMINUS
|
||||
NETCONN_EVT_SENDMINUS,
|
||||
NETCONN_EVT_ERROR
|
||||
};
|
||||
|
||||
#if LWIP_IGMP
|
||||
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
|
||||
/** Used for netconn_join_leave_group() */
|
||||
enum netconn_igmp {
|
||||
NETCONN_JOIN,
|
||||
NETCONN_LEAVE
|
||||
};
|
||||
#endif /* LWIP_IGMP */
|
||||
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
|
||||
|
||||
/* forward-declare some structs to avoid to include their headers */
|
||||
struct ip_pcb;
|
||||
@@ -99,6 +145,7 @@ struct tcp_pcb;
|
||||
struct udp_pcb;
|
||||
struct raw_pcb;
|
||||
struct netconn;
|
||||
struct api_msg_msg;
|
||||
|
||||
/** A callback prototype to inform about events for a netconn */
|
||||
typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len);
|
||||
@@ -117,96 +164,150 @@ struct netconn {
|
||||
struct raw_pcb *raw;
|
||||
} pcb;
|
||||
/** the last error this netconn had */
|
||||
err_t err;
|
||||
err_t last_err;
|
||||
/** sem that is used to synchroneously execute functions in the core context */
|
||||
sys_sem_t op_completed;
|
||||
/** mbox where received packets are stored until they are fetched
|
||||
by the netconn application thread (can grow quite big) */
|
||||
sys_mbox_t recvmbox;
|
||||
#if LWIP_TCP
|
||||
/** mbox where new connections are stored until processed
|
||||
by the application thread */
|
||||
sys_mbox_t acceptmbox;
|
||||
#endif /* LWIP_TCP */
|
||||
/** only used for socket layer */
|
||||
#if LWIP_SOCKET
|
||||
int socket;
|
||||
#endif /* LWIP_SOCKET */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
/** timeout to wait for new data to be received
|
||||
(or connections to arrive for listening netconns) */
|
||||
int recv_timeout;
|
||||
#endif /* LWIP_SO_RCVTIMEO */
|
||||
#if LWIP_SO_RCVBUF
|
||||
/** maximum amount of bytes queued in recvmbox */
|
||||
/** maximum amount of bytes queued in recvmbox
|
||||
not used for TCP: adjust TCP_WND instead! */
|
||||
int recv_bufsize;
|
||||
/** number of bytes currently in recvmbox to be received,
|
||||
tested against recv_bufsize to limit bytes on recvmbox
|
||||
for UDP and RAW, used for FIONREAD */
|
||||
s16_t recv_avail;
|
||||
#endif /* LWIP_SO_RCVBUF */
|
||||
u16_t recv_avail;
|
||||
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
|
||||
this temporarily stores the message. */
|
||||
struct api_msg_msg *write_msg;
|
||||
/** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */
|
||||
u8_t flags;
|
||||
#if LWIP_TCP
|
||||
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
|
||||
this temporarily stores how much is already sent. */
|
||||
int write_offset;
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
size_t write_offset;
|
||||
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
|
||||
this temporarily stores whether to wake up the original application task
|
||||
if data couldn't be sent in the first try. */
|
||||
u8_t write_delayed;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
this temporarily stores the message.
|
||||
Also used during connect and close. */
|
||||
struct api_msg_msg *current_msg;
|
||||
#endif /* LWIP_TCP */
|
||||
/** A callback function that is informed about events for this netconn */
|
||||
netconn_callback callback;
|
||||
};
|
||||
|
||||
/* Register an Network connection event */
|
||||
/** Register an Network connection event */
|
||||
#define API_EVENT(c,e,l) if (c->callback) { \
|
||||
(*c->callback)(c, e, l); \
|
||||
}
|
||||
|
||||
/** Set conn->last_err to err but don't overwrite fatal errors */
|
||||
#define NETCONN_SET_SAFE_ERR(conn, err) do { \
|
||||
SYS_ARCH_DECL_PROTECT(lev); \
|
||||
SYS_ARCH_PROTECT(lev); \
|
||||
if (!ERR_IS_FATAL((conn)->last_err)) { \
|
||||
(conn)->last_err = err; \
|
||||
} \
|
||||
SYS_ARCH_UNPROTECT(lev); \
|
||||
} while(0);
|
||||
|
||||
/* Network connection functions: */
|
||||
#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL)
|
||||
#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c)
|
||||
struct
|
||||
netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,
|
||||
netconn_callback callback);
|
||||
err_t netconn_delete (struct netconn *conn);
|
||||
enum netconn_type netconn_type (struct netconn *conn);
|
||||
netconn_callback callback);
|
||||
err_t netconn_delete(struct netconn *conn);
|
||||
/** Get the type of a netconn (as enum netconn_type). */
|
||||
#define netconn_type(conn) (conn->type)
|
||||
|
||||
err_t netconn_getaddr (struct netconn *conn,
|
||||
struct ip_addr *addr,
|
||||
u16_t *port,
|
||||
u8_t local);
|
||||
err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr,
|
||||
u16_t *port, u8_t local);
|
||||
#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0)
|
||||
#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1)
|
||||
|
||||
err_t netconn_bind (struct netconn *conn,
|
||||
struct ip_addr *addr,
|
||||
u16_t port);
|
||||
err_t netconn_connect (struct netconn *conn,
|
||||
struct ip_addr *addr,
|
||||
u16_t port);
|
||||
err_t netconn_disconnect (struct netconn *conn);
|
||||
err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);
|
||||
err_t netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port);
|
||||
err_t netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port);
|
||||
err_t netconn_disconnect (struct netconn *conn);
|
||||
err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);
|
||||
#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG)
|
||||
struct netconn * netconn_accept (struct netconn *conn);
|
||||
struct netbuf * netconn_recv (struct netconn *conn);
|
||||
err_t netconn_sendto (struct netconn *conn,
|
||||
struct netbuf *buf, struct ip_addr *addr, u16_t port);
|
||||
err_t netconn_send (struct netconn *conn,
|
||||
struct netbuf *buf);
|
||||
err_t netconn_write (struct netconn *conn,
|
||||
const void *dataptr, int size,
|
||||
u8_t apiflags);
|
||||
err_t netconn_close (struct netconn *conn);
|
||||
err_t netconn_accept(struct netconn *conn, struct netconn **new_conn);
|
||||
err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf);
|
||||
err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf);
|
||||
void netconn_recved(struct netconn *conn, u32_t length);
|
||||
err_t netconn_sendto(struct netconn *conn, struct netbuf *buf,
|
||||
ip_addr_t *addr, u16_t port);
|
||||
err_t netconn_send(struct netconn *conn, struct netbuf *buf);
|
||||
err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size,
|
||||
u8_t apiflags);
|
||||
err_t netconn_close(struct netconn *conn);
|
||||
err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx);
|
||||
|
||||
#if LWIP_IGMP
|
||||
err_t netconn_join_leave_group (struct netconn *conn,
|
||||
struct ip_addr *multiaddr,
|
||||
struct ip_addr *interface,
|
||||
enum netconn_igmp join_or_leave);
|
||||
#endif /* LWIP_IGMP */
|
||||
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
|
||||
err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr,
|
||||
ip_addr_t *netif_addr, enum netconn_igmp join_or_leave);
|
||||
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
|
||||
#if LWIP_DNS
|
||||
err_t netconn_gethostbyname(const char *name, struct ip_addr *addr);
|
||||
err_t netconn_gethostbyname(const char *name, ip_addr_t *addr);
|
||||
#endif /* LWIP_DNS */
|
||||
#if LWIP_IPV6
|
||||
|
||||
#define netconn_err(conn) ((conn)->err)
|
||||
#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize)
|
||||
#define netconn_bind_ip6(conn, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \
|
||||
netconn_bind(conn, ip6_2_ip(ip6addr), port) : ERR_VAL)
|
||||
#define netconn_connect_ip6(conn, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \
|
||||
netconn_connect(conn, ip6_2_ip(ip6addr), port) : ERR_VAL)
|
||||
#define netconn_sendto_ip6(conn, buf, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \
|
||||
netconn_sendto(conn, buf, ip6_2_ip(ip6addr), port) : ERR_VAL)
|
||||
#if LWIP_IPV6_MLD
|
||||
#define netconn_join_leave_group_ip6(conn, multiaddr, srcaddr, join_or_leave) (NETCONNTYPE_ISIPV6((conn)->type) ? \
|
||||
netconn_join_leave_group(conn, ip6_2_ip(multiaddr), ip6_2_ip(srcaddr), join_or_leave) :\
|
||||
ERR_VAL)
|
||||
#endif /* LWIP_IPV6_MLD*/
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#define netconn_err(conn) ((conn)->last_err)
|
||||
#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize)
|
||||
|
||||
/** Set the blocking status of netconn calls (@todo: write/send is missing) */
|
||||
#define netconn_set_nonblocking(conn, val) do { if(val) { \
|
||||
(conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \
|
||||
} else { \
|
||||
(conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0)
|
||||
/** Get the blocking status of netconn calls (@todo: write/send is missing) */
|
||||
#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0)
|
||||
|
||||
/** TCP: Set the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
|
||||
#define netconn_set_noautorecved(conn, val) do { if(val) { \
|
||||
(conn)->flags |= NETCONN_FLAG_NO_AUTO_RECVED; \
|
||||
} else { \
|
||||
(conn)->flags &= ~ NETCONN_FLAG_NO_AUTO_RECVED; }} while(0)
|
||||
/** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
|
||||
#define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0)
|
||||
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
/** Set the receive timeout in milliseconds */
|
||||
#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout))
|
||||
/** Get the receive timeout in milliseconds */
|
||||
#define netconn_get_recvtimeout(conn) ((conn)->recv_timeout)
|
||||
#endif /* LWIP_SO_RCVTIMEO */
|
||||
#if LWIP_SO_RCVBUF
|
||||
/** Set the receive buffer in bytes */
|
||||
#define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize))
|
||||
/** Get the receive buffer in bytes */
|
||||
#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize)
|
||||
#endif /* LWIP_SO_RCVBUF*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include <stddef.h> /* for size_t */
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sys.h"
|
||||
@@ -46,6 +48,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* For the netconn API, these values are use as a bitmask! */
|
||||
#define NETCONN_SHUT_RD 1
|
||||
#define NETCONN_SHUT_WR 2
|
||||
#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR)
|
||||
|
||||
/* IP addresses and port numbers are expected to be in
|
||||
* the same byte order as in the corresponding pcb.
|
||||
*/
|
||||
@@ -56,6 +63,8 @@ struct api_msg_msg {
|
||||
/** The netconn which to process - always needed: it includes the semaphore
|
||||
which is used to block the application thread until the function finished. */
|
||||
struct netconn *conn;
|
||||
/** The return value of the function executed in tcpip_thread. */
|
||||
err_t err;
|
||||
/** Depending on the executed function, one of these union members is used */
|
||||
union {
|
||||
/** used for do_send */
|
||||
@@ -66,33 +75,37 @@ struct api_msg_msg {
|
||||
} n;
|
||||
/** used for do_bind and do_connect */
|
||||
struct {
|
||||
struct ip_addr *ipaddr;
|
||||
ip_addr_t *ipaddr;
|
||||
u16_t port;
|
||||
} bc;
|
||||
/** used for do_getaddr */
|
||||
struct {
|
||||
struct ip_addr *ipaddr;
|
||||
ipX_addr_t *ipaddr;
|
||||
u16_t *port;
|
||||
u8_t local;
|
||||
} ad;
|
||||
/** used for do_write */
|
||||
struct {
|
||||
const void *dataptr;
|
||||
int len;
|
||||
size_t len;
|
||||
u8_t apiflags;
|
||||
} w;
|
||||
/** used ofr do_recv */
|
||||
/** used for do_recv */
|
||||
struct {
|
||||
u16_t len;
|
||||
u32_t len;
|
||||
} r;
|
||||
#if LWIP_IGMP
|
||||
/** used for do_close (/shutdown) */
|
||||
struct {
|
||||
u8_t shut;
|
||||
} sd;
|
||||
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
|
||||
/** used for do_join_leave_group */
|
||||
struct {
|
||||
struct ip_addr *multiaddr;
|
||||
struct ip_addr *interface;
|
||||
ipX_addr_t *multiaddr;
|
||||
ipX_addr_t *netif_addr;
|
||||
enum netconn_igmp join_or_leave;
|
||||
} jl;
|
||||
#endif /* LWIP_IGMP */
|
||||
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
struct {
|
||||
u8_t backlog;
|
||||
@@ -120,10 +133,10 @@ struct dns_api_msg {
|
||||
/** Hostname to query or dotted IP address string */
|
||||
const char *name;
|
||||
/** Rhe resolved address is stored here */
|
||||
struct ip_addr *addr;
|
||||
ip_addr_t *addr;
|
||||
/** This semaphore is posted when the name is resolved, the application thread
|
||||
should wait on it. */
|
||||
sys_sem_t sem;
|
||||
sys_sem_t *sem;
|
||||
/** Errors are given back here */
|
||||
err_t *err;
|
||||
};
|
||||
@@ -140,9 +153,10 @@ void do_recv ( struct api_msg_msg *msg);
|
||||
void do_write ( struct api_msg_msg *msg);
|
||||
void do_getaddr ( struct api_msg_msg *msg);
|
||||
void do_close ( struct api_msg_msg *msg);
|
||||
#if LWIP_IGMP
|
||||
void do_shutdown ( struct api_msg_msg *msg);
|
||||
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
|
||||
void do_join_leave_group( struct api_msg_msg *msg);
|
||||
#endif /* LWIP_IGMP */
|
||||
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
|
||||
|
||||
#if LWIP_DNS
|
||||
void do_gethostbyname(void *arg);
|
||||
|
||||
@@ -42,6 +42,16 @@
|
||||
|
||||
#include "arch/cc.h"
|
||||
|
||||
/** Temporary: define format string for size_t if not defined in cc.h */
|
||||
#ifndef SZT_F
|
||||
#define SZT_F U32_F
|
||||
#endif /* SZT_F */
|
||||
/** Temporary upgrade helper: define format string for u8_t as hex if not
|
||||
defined in cc.h */
|
||||
#ifndef X8_F
|
||||
#define X8_F "02x"
|
||||
#endif /* X8_F */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -66,154 +76,154 @@ extern "C" {
|
||||
|
||||
#ifdef LWIP_PROVIDE_ERRNO
|
||||
|
||||
#define EPERM 1 /* Operation not permitted */
|
||||
#define ENOENT 2 /* No such file or directory */
|
||||
#define ESRCH 3 /* No such process */
|
||||
#define EINTR 4 /* Interrupted system call */
|
||||
#define EIO 5 /* I/O error */
|
||||
#define ENXIO 6 /* No such device or address */
|
||||
#define E2BIG 7 /* Arg list too long */
|
||||
#define ENOEXEC 8 /* Exec format error */
|
||||
#define EBADF 9 /* Bad file number */
|
||||
#define ECHILD 10 /* No child processes */
|
||||
#define EAGAIN 11 /* Try again */
|
||||
#define ENOMEM 12 /* Out of memory */
|
||||
#define EACCES 13 /* Permission denied */
|
||||
#define EFAULT 14 /* Bad address */
|
||||
#define ENOTBLK 15 /* Block device required */
|
||||
#define EBUSY 16 /* Device or resource busy */
|
||||
#define EEXIST 17 /* File exists */
|
||||
#define EXDEV 18 /* Cross-device link */
|
||||
#define ENODEV 19 /* No such device */
|
||||
#define ENOTDIR 20 /* Not a directory */
|
||||
#define EISDIR 21 /* Is a directory */
|
||||
#define EINVAL 22 /* Invalid argument */
|
||||
#define ENFILE 23 /* File table overflow */
|
||||
#define EMFILE 24 /* Too many open files */
|
||||
#define ENOTTY 25 /* Not a typewriter */
|
||||
#define ETXTBSY 26 /* Text file busy */
|
||||
#define EFBIG 27 /* File too large */
|
||||
#define ENOSPC 28 /* No space left on device */
|
||||
#define ESPIPE 29 /* Illegal seek */
|
||||
#define EROFS 30 /* Read-only file system */
|
||||
#define EMLINK 31 /* Too many links */
|
||||
#define EPIPE 32 /* Broken pipe */
|
||||
#define EDOM 33 /* Math argument out of domain of func */
|
||||
#define ERANGE 34 /* Math result not representable */
|
||||
#define EDEADLK 35 /* Resource deadlock would occur */
|
||||
#define ENAMETOOLONG 36 /* File name too long */
|
||||
#define ENOLCK 37 /* No record locks available */
|
||||
#define ENOSYS 38 /* Function not implemented */
|
||||
#define ENOTEMPTY 39 /* Directory not empty */
|
||||
#define ELOOP 40 /* Too many symbolic links encountered */
|
||||
#define EPERM 1 /* Operation not permitted */
|
||||
#define ENOENT 2 /* No such file or directory */
|
||||
#define ESRCH 3 /* No such process */
|
||||
#define EINTR 4 /* Interrupted system call */
|
||||
#define EIO 5 /* I/O error */
|
||||
#define ENXIO 6 /* No such device or address */
|
||||
#define E2BIG 7 /* Arg list too long */
|
||||
#define ENOEXEC 8 /* Exec format error */
|
||||
#define EBADF 9 /* Bad file number */
|
||||
#define ECHILD 10 /* No child processes */
|
||||
#define EAGAIN 11 /* Try again */
|
||||
#define ENOMEM 12 /* Out of memory */
|
||||
#define EACCES 13 /* Permission denied */
|
||||
#define EFAULT 14 /* Bad address */
|
||||
#define ENOTBLK 15 /* Block device required */
|
||||
#define EBUSY 16 /* Device or resource busy */
|
||||
#define EEXIST 17 /* File exists */
|
||||
#define EXDEV 18 /* Cross-device link */
|
||||
#define ENODEV 19 /* No such device */
|
||||
#define ENOTDIR 20 /* Not a directory */
|
||||
#define EISDIR 21 /* Is a directory */
|
||||
#define EINVAL 22 /* Invalid argument */
|
||||
#define ENFILE 23 /* File table overflow */
|
||||
#define EMFILE 24 /* Too many open files */
|
||||
#define ENOTTY 25 /* Not a typewriter */
|
||||
#define ETXTBSY 26 /* Text file busy */
|
||||
#define EFBIG 27 /* File too large */
|
||||
#define ENOSPC 28 /* No space left on device */
|
||||
#define ESPIPE 29 /* Illegal seek */
|
||||
#define EROFS 30 /* Read-only file system */
|
||||
#define EMLINK 31 /* Too many links */
|
||||
#define EPIPE 32 /* Broken pipe */
|
||||
#define EDOM 33 /* Math argument out of domain of func */
|
||||
#define ERANGE 34 /* Math result not representable */
|
||||
#define EDEADLK 35 /* Resource deadlock would occur */
|
||||
#define ENAMETOOLONG 36 /* File name too long */
|
||||
#define ENOLCK 37 /* No record locks available */
|
||||
#define ENOSYS 38 /* Function not implemented */
|
||||
#define ENOTEMPTY 39 /* Directory not empty */
|
||||
#define ELOOP 40 /* Too many symbolic links encountered */
|
||||
#define EWOULDBLOCK EAGAIN /* Operation would block */
|
||||
#define ENOMSG 42 /* No message of desired type */
|
||||
#define EIDRM 43 /* Identifier removed */
|
||||
#define ECHRNG 44 /* Channel number out of range */
|
||||
#define EL2NSYNC 45 /* Level 2 not synchronized */
|
||||
#define EL3HLT 46 /* Level 3 halted */
|
||||
#define EL3RST 47 /* Level 3 reset */
|
||||
#define ELNRNG 48 /* Link number out of range */
|
||||
#define EUNATCH 49 /* Protocol driver not attached */
|
||||
#define ENOCSI 50 /* No CSI structure available */
|
||||
#define EL2HLT 51 /* Level 2 halted */
|
||||
#define EBADE 52 /* Invalid exchange */
|
||||
#define EBADR 53 /* Invalid request descriptor */
|
||||
#define EXFULL 54 /* Exchange full */
|
||||
#define ENOANO 55 /* No anode */
|
||||
#define EBADRQC 56 /* Invalid request code */
|
||||
#define EBADSLT 57 /* Invalid slot */
|
||||
#define ENOMSG 42 /* No message of desired type */
|
||||
#define EIDRM 43 /* Identifier removed */
|
||||
#define ECHRNG 44 /* Channel number out of range */
|
||||
#define EL2NSYNC 45 /* Level 2 not synchronized */
|
||||
#define EL3HLT 46 /* Level 3 halted */
|
||||
#define EL3RST 47 /* Level 3 reset */
|
||||
#define ELNRNG 48 /* Link number out of range */
|
||||
#define EUNATCH 49 /* Protocol driver not attached */
|
||||
#define ENOCSI 50 /* No CSI structure available */
|
||||
#define EL2HLT 51 /* Level 2 halted */
|
||||
#define EBADE 52 /* Invalid exchange */
|
||||
#define EBADR 53 /* Invalid request descriptor */
|
||||
#define EXFULL 54 /* Exchange full */
|
||||
#define ENOANO 55 /* No anode */
|
||||
#define EBADRQC 56 /* Invalid request code */
|
||||
#define EBADSLT 57 /* Invalid slot */
|
||||
|
||||
#define EDEADLOCK EDEADLK
|
||||
#define EDEADLOCK EDEADLK
|
||||
|
||||
#define EBFONT 59 /* Bad font file format */
|
||||
#define ENOSTR 60 /* Device not a stream */
|
||||
#define ENODATA 61 /* No data available */
|
||||
#define ETIME 62 /* Timer expired */
|
||||
#define ENOSR 63 /* Out of streams resources */
|
||||
#define ENONET 64 /* Machine is not on the network */
|
||||
#define ENOPKG 65 /* Package not installed */
|
||||
#define EREMOTE 66 /* Object is remote */
|
||||
#define ENOLINK 67 /* Link has been severed */
|
||||
#define EADV 68 /* Advertise error */
|
||||
#define ESRMNT 69 /* Srmount error */
|
||||
#define ECOMM 70 /* Communication error on send */
|
||||
#define EPROTO 71 /* Protocol error */
|
||||
#define EMULTIHOP 72 /* Multihop attempted */
|
||||
#define EDOTDOT 73 /* RFS specific error */
|
||||
#define EBADMSG 74 /* Not a data message */
|
||||
#define EOVERFLOW 75 /* Value too large for defined data type */
|
||||
#define ENOTUNIQ 76 /* Name not unique on network */
|
||||
#define EBADFD 77 /* File descriptor in bad state */
|
||||
#define EREMCHG 78 /* Remote address changed */
|
||||
#define ELIBACC 79 /* Can not access a needed shared library */
|
||||
#define ELIBBAD 80 /* Accessing a corrupted shared library */
|
||||
#define ELIBSCN 81 /* .lib section in a.out corrupted */
|
||||
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
|
||||
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
|
||||
#define EILSEQ 84 /* Illegal byte sequence */
|
||||
#define ERESTART 85 /* Interrupted system call should be restarted */
|
||||
#define ESTRPIPE 86 /* Streams pipe error */
|
||||
#define EUSERS 87 /* Too many users */
|
||||
#define ENOTSOCK 88 /* Socket operation on non-socket */
|
||||
#define EDESTADDRREQ 89 /* Destination address required */
|
||||
#define EMSGSIZE 90 /* Message too long */
|
||||
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
|
||||
#define EBFONT 59 /* Bad font file format */
|
||||
#define ENOSTR 60 /* Device not a stream */
|
||||
#define ENODATA 61 /* No data available */
|
||||
#define ETIME 62 /* Timer expired */
|
||||
#define ENOSR 63 /* Out of streams resources */
|
||||
#define ENONET 64 /* Machine is not on the network */
|
||||
#define ENOPKG 65 /* Package not installed */
|
||||
#define EREMOTE 66 /* Object is remote */
|
||||
#define ENOLINK 67 /* Link has been severed */
|
||||
#define EADV 68 /* Advertise error */
|
||||
#define ESRMNT 69 /* Srmount error */
|
||||
#define ECOMM 70 /* Communication error on send */
|
||||
#define EPROTO 71 /* Protocol error */
|
||||
#define EMULTIHOP 72 /* Multihop attempted */
|
||||
#define EDOTDOT 73 /* RFS specific error */
|
||||
#define EBADMSG 74 /* Not a data message */
|
||||
#define EOVERFLOW 75 /* Value too large for defined data type */
|
||||
#define ENOTUNIQ 76 /* Name not unique on network */
|
||||
#define EBADFD 77 /* File descriptor in bad state */
|
||||
#define EREMCHG 78 /* Remote address changed */
|
||||
#define ELIBACC 79 /* Can not access a needed shared library */
|
||||
#define ELIBBAD 80 /* Accessing a corrupted shared library */
|
||||
#define ELIBSCN 81 /* .lib section in a.out corrupted */
|
||||
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
|
||||
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
|
||||
#define EILSEQ 84 /* Illegal byte sequence */
|
||||
#define ERESTART 85 /* Interrupted system call should be restarted */
|
||||
#define ESTRPIPE 86 /* Streams pipe error */
|
||||
#define EUSERS 87 /* Too many users */
|
||||
#define ENOTSOCK 88 /* Socket operation on non-socket */
|
||||
#define EDESTADDRREQ 89 /* Destination address required */
|
||||
#define EMSGSIZE 90 /* Message too long */
|
||||
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
|
||||
#define ENOPROTOOPT 92 /* Protocol not available */
|
||||
#define EPROTONOSUPPORT 93 /* Protocol not supported */
|
||||
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
|
||||
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
|
||||
#define EPFNOSUPPORT 96 /* Protocol family not supported */
|
||||
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
|
||||
#define EADDRINUSE 98 /* Address already in use */
|
||||
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
|
||||
#define ENETDOWN 100 /* Network is down */
|
||||
#define ENETUNREACH 101 /* Network is unreachable */
|
||||
#define ENETRESET 102 /* Network dropped connection because of reset */
|
||||
#define ECONNABORTED 103 /* Software caused connection abort */
|
||||
#define ECONNRESET 104 /* Connection reset by peer */
|
||||
#define ENOBUFS 105 /* No buffer space available */
|
||||
#define EISCONN 106 /* Transport endpoint is already connected */
|
||||
#define ENOTCONN 107 /* Transport endpoint is not connected */
|
||||
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
|
||||
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
|
||||
#define ETIMEDOUT 110 /* Connection timed out */
|
||||
#define ECONNREFUSED 111 /* Connection refused */
|
||||
#define EHOSTDOWN 112 /* Host is down */
|
||||
#define EHOSTUNREACH 113 /* No route to host */
|
||||
#define EALREADY 114 /* Operation already in progress */
|
||||
#define EINPROGRESS 115 /* Operation now in progress */
|
||||
#define ESTALE 116 /* Stale NFS file handle */
|
||||
#define EUCLEAN 117 /* Structure needs cleaning */
|
||||
#define ENOTNAM 118 /* Not a XENIX named type file */
|
||||
#define ENAVAIL 119 /* No XENIX semaphores available */
|
||||
#define EISNAM 120 /* Is a named type file */
|
||||
#define EREMOTEIO 121 /* Remote I/O error */
|
||||
#define EDQUOT 122 /* Quota exceeded */
|
||||
#define EPROTONOSUPPORT 93 /* Protocol not supported */
|
||||
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
|
||||
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
|
||||
#define EPFNOSUPPORT 96 /* Protocol family not supported */
|
||||
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
|
||||
#define EADDRINUSE 98 /* Address already in use */
|
||||
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
|
||||
#define ENETDOWN 100 /* Network is down */
|
||||
#define ENETUNREACH 101 /* Network is unreachable */
|
||||
#define ENETRESET 102 /* Network dropped connection because of reset */
|
||||
#define ECONNABORTED 103 /* Software caused connection abort */
|
||||
#define ECONNRESET 104 /* Connection reset by peer */
|
||||
#define ENOBUFS 105 /* No buffer space available */
|
||||
#define EISCONN 106 /* Transport endpoint is already connected */
|
||||
#define ENOTCONN 107 /* Transport endpoint is not connected */
|
||||
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
|
||||
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
|
||||
#define ETIMEDOUT 110 /* Connection timed out */
|
||||
#define ECONNREFUSED 111 /* Connection refused */
|
||||
#define EHOSTDOWN 112 /* Host is down */
|
||||
#define EHOSTUNREACH 113 /* No route to host */
|
||||
#define EALREADY 114 /* Operation already in progress */
|
||||
#define EINPROGRESS 115 /* Operation now in progress */
|
||||
#define ESTALE 116 /* Stale NFS file handle */
|
||||
#define EUCLEAN 117 /* Structure needs cleaning */
|
||||
#define ENOTNAM 118 /* Not a XENIX named type file */
|
||||
#define ENAVAIL 119 /* No XENIX semaphores available */
|
||||
#define EISNAM 120 /* Is a named type file */
|
||||
#define EREMOTEIO 121 /* Remote I/O error */
|
||||
#define EDQUOT 122 /* Quota exceeded */
|
||||
|
||||
#define ENOMEDIUM 123 /* No medium found */
|
||||
#define EMEDIUMTYPE 124 /* Wrong medium type */
|
||||
#define ENOMEDIUM 123 /* No medium found */
|
||||
#define EMEDIUMTYPE 124 /* Wrong medium type */
|
||||
|
||||
|
||||
#define ENSROK 0 /* DNS server returned answer with no data */
|
||||
#define ENSRNODATA 160 /* DNS server returned answer with no data */
|
||||
#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
|
||||
#define ENSRSERVFAIL 162 /* DNS server returned general failure */
|
||||
#define ENSRNOTFOUND 163 /* Domain name not found */
|
||||
#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */
|
||||
#define ENSRREFUSED 165 /* DNS server refused query */
|
||||
#define ENSRBADQUERY 166 /* Misformatted DNS query */
|
||||
#define ENSRBADNAME 167 /* Misformatted domain name */
|
||||
#define ENSRBADFAMILY 168 /* Unsupported address family */
|
||||
#define ENSRBADRESP 169 /* Misformatted DNS reply */
|
||||
#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
|
||||
#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
|
||||
#define ENSROF 172 /* End of file */
|
||||
#define ENSRFILE 173 /* Error reading file */
|
||||
#define ENSRNOMEM 174 /* Out of memory */
|
||||
#define ENSRDESTRUCTION 175 /* Application terminated lookup */
|
||||
#define ENSROK 0 /* DNS server returned answer with no data */
|
||||
#define ENSRNODATA 160 /* DNS server returned answer with no data */
|
||||
#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
|
||||
#define ENSRSERVFAIL 162 /* DNS server returned general failure */
|
||||
#define ENSRNOTFOUND 163 /* Domain name not found */
|
||||
#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */
|
||||
#define ENSRREFUSED 165 /* DNS server refused query */
|
||||
#define ENSRBADQUERY 166 /* Misformatted DNS query */
|
||||
#define ENSRBADNAME 167 /* Misformatted domain name */
|
||||
#define ENSRBADFAMILY 168 /* Unsupported address family */
|
||||
#define ENSRBADRESP 169 /* Misformatted DNS reply */
|
||||
#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
|
||||
#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
|
||||
#define ENSROF 172 /* End of file */
|
||||
#define ENSRFILE 173 /* Error reading file */
|
||||
#define ENSRNOMEM 174 /* Out of memory */
|
||||
#define ENSRDESTRUCTION 175 /* Application terminated lookup */
|
||||
#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */
|
||||
#define ENSRCNAMELOOP 177 /* Domain name is too long */
|
||||
#define ENSRCNAMELOOP 177 /* Domain name is too long */
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
|
||||
@@ -33,14 +33,16 @@
|
||||
#define __LWIP_DEBUG_H__
|
||||
|
||||
#include "lwip/arch.h"
|
||||
#include "lwip/opt.h"
|
||||
|
||||
/** lower two bits indicate debug level
|
||||
* - 0 off
|
||||
* - 0 all
|
||||
* - 1 warning
|
||||
* - 2 serious
|
||||
* - 3 severe
|
||||
*/
|
||||
#define LWIP_DBG_LEVEL_OFF 0x00
|
||||
#define LWIP_DBG_LEVEL_ALL 0x00
|
||||
#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL /* compatibility define only */
|
||||
#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */
|
||||
#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */
|
||||
#define LWIP_DBG_LEVEL_SEVERE 0x03
|
||||
@@ -61,26 +63,28 @@
|
||||
#define LWIP_DBG_HALT 0x08U
|
||||
|
||||
#ifndef LWIP_NOASSERT
|
||||
#define LWIP_ASSERT(x,y) do { if(!(y)) LWIP_PLATFORM_ASSERT(x); } while(0)
|
||||
#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \
|
||||
LWIP_PLATFORM_ASSERT(message); } while(0)
|
||||
#else /* LWIP_NOASSERT */
|
||||
#define LWIP_ASSERT(x,y)
|
||||
#define LWIP_ASSERT(message, assertion)
|
||||
#endif /* LWIP_NOASSERT */
|
||||
|
||||
/** print "m" message only if "e" is true, and execute "h" expression */
|
||||
/** if "expression" isn't true, then print "message" and execute "handler" expression */
|
||||
#ifndef LWIP_ERROR
|
||||
#define LWIP_ERROR(m,e,h) do { if (!(e)) { LWIP_PLATFORM_ASSERT(m); h;}} while(0)
|
||||
#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
|
||||
LWIP_PLATFORM_ASSERT(message); handler;}} while(0)
|
||||
#endif /* LWIP_ERROR */
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
/** print debug message only if debug message type is enabled...
|
||||
* AND is of correct type AND is at least LWIP_DBG_LEVEL
|
||||
*/
|
||||
#define LWIP_DEBUGF(debug,x) do { \
|
||||
#define LWIP_DEBUGF(debug, message) do { \
|
||||
if ( \
|
||||
((debug) & LWIP_DBG_ON) && \
|
||||
((debug) & LWIP_DBG_TYPES_ON) && \
|
||||
((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \
|
||||
LWIP_PLATFORM_DIAG(x); \
|
||||
LWIP_PLATFORM_DIAG(message); \
|
||||
if ((debug) & LWIP_DBG_HALT) { \
|
||||
while(1); \
|
||||
} \
|
||||
@@ -88,7 +92,7 @@
|
||||
} while(0)
|
||||
|
||||
#else /* LWIP_DEBUG */
|
||||
#define LWIP_DEBUGF(debug,x)
|
||||
#define LWIP_DEBUGF(debug, message)
|
||||
#endif /* LWIP_DEBUG */
|
||||
|
||||
#endif /* __LWIP_DEBUG_H__ */
|
||||
|
||||
@@ -32,8 +32,13 @@
|
||||
#ifndef __LWIP_DEF_H__
|
||||
#define __LWIP_DEF_H__
|
||||
|
||||
/* this might define NULL already */
|
||||
/* arch.h might define NULL already */
|
||||
#include "lwip/arch.h"
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y))
|
||||
#define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y))
|
||||
@@ -42,6 +47,81 @@
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
/** Get the absolute difference between 2 u32_t values (correcting overflows)
|
||||
* 'a' is expected to be 'higher' (without overflow) than 'b'. */
|
||||
#define LWIP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))
|
||||
|
||||
/* Endianess-optimized shifting of two u8_t to create one u16_t */
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define LWIP_MAKE_U16(a, b) ((a << 8) | b)
|
||||
#else
|
||||
#define LWIP_MAKE_U16(a, b) ((b << 8) | a)
|
||||
#endif
|
||||
|
||||
#ifndef LWIP_PLATFORM_BYTESWAP
|
||||
#define LWIP_PLATFORM_BYTESWAP 0
|
||||
#endif
|
||||
|
||||
#ifndef LWIP_PREFIX_BYTEORDER_FUNCS
|
||||
/* workaround for naming collisions on some platforms */
|
||||
|
||||
#ifdef htons
|
||||
#undef htons
|
||||
#endif /* htons */
|
||||
#ifdef htonl
|
||||
#undef htonl
|
||||
#endif /* htonl */
|
||||
#ifdef ntohs
|
||||
#undef ntohs
|
||||
#endif /* ntohs */
|
||||
#ifdef ntohl
|
||||
#undef ntohl
|
||||
#endif /* ntohl */
|
||||
|
||||
#define htons(x) lwip_htons(x)
|
||||
#define ntohs(x) lwip_ntohs(x)
|
||||
#define htonl(x) lwip_htonl(x)
|
||||
#define ntohl(x) lwip_ntohl(x)
|
||||
#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define lwip_htons(x) (x)
|
||||
#define lwip_ntohs(x) (x)
|
||||
#define lwip_htonl(x) (x)
|
||||
#define lwip_ntohl(x) (x)
|
||||
#define PP_HTONS(x) (x)
|
||||
#define PP_NTOHS(x) (x)
|
||||
#define PP_HTONL(x) (x)
|
||||
#define PP_NTOHL(x) (x)
|
||||
#else /* BYTE_ORDER != BIG_ENDIAN */
|
||||
#if LWIP_PLATFORM_BYTESWAP
|
||||
#define lwip_htons(x) LWIP_PLATFORM_HTONS(x)
|
||||
#define lwip_ntohs(x) LWIP_PLATFORM_HTONS(x)
|
||||
#define lwip_htonl(x) LWIP_PLATFORM_HTONL(x)
|
||||
#define lwip_ntohl(x) LWIP_PLATFORM_HTONL(x)
|
||||
#else /* LWIP_PLATFORM_BYTESWAP */
|
||||
u16_t lwip_htons(u16_t x);
|
||||
u16_t lwip_ntohs(u16_t x);
|
||||
u32_t lwip_htonl(u32_t x);
|
||||
u32_t lwip_ntohl(u32_t x);
|
||||
#endif /* LWIP_PLATFORM_BYTESWAP */
|
||||
|
||||
/* These macros should be calculated by the preprocessor and are used
|
||||
with compile-time constants only (so that there is no little-endian
|
||||
overhead at runtime). */
|
||||
#define PP_HTONS(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
|
||||
#define PP_NTOHS(x) PP_HTONS(x)
|
||||
#define PP_HTONL(x) ((((x) & 0xff) << 24) | \
|
||||
(((x) & 0xff00) << 8) | \
|
||||
(((x) & 0xff0000UL) >> 8) | \
|
||||
(((x) & 0xff000000UL) >> 24))
|
||||
#define PP_NTOHL(x) PP_HTONL(x)
|
||||
|
||||
#endif /* BYTE_ORDER == BIG_ENDIAN */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LWIP_DEF_H__ */
|
||||
|
||||
|
||||
@@ -18,28 +18,30 @@ extern "C" {
|
||||
/** period (in seconds) of the application calling dhcp_coarse_tmr() */
|
||||
#define DHCP_COARSE_TIMER_SECS 60
|
||||
/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */
|
||||
#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS*1000)
|
||||
#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL)
|
||||
/** period (in milliseconds) of the application calling dhcp_fine_tmr() */
|
||||
#define DHCP_FINE_TIMER_MSECS 500
|
||||
|
||||
#define DHCP_CHADDR_LEN 16U
|
||||
#define DHCP_SNAME_LEN 64U
|
||||
#define DHCP_FILE_LEN 128U
|
||||
|
||||
struct dhcp
|
||||
{
|
||||
/** current DHCP state machine state */
|
||||
u8_t state;
|
||||
/** retries of current request */
|
||||
u8_t tries;
|
||||
/** transaction identifier of last sent request */
|
||||
u32_t xid;
|
||||
/** our connection to the DHCP server */
|
||||
struct udp_pcb *pcb;
|
||||
/** (first) pbuf of incoming msg */
|
||||
struct pbuf *p;
|
||||
/** incoming msg */
|
||||
struct dhcp_msg *msg_in;
|
||||
/** incoming msg options */
|
||||
struct dhcp_msg *options_in;
|
||||
/** ingoing msg options length */
|
||||
u16_t options_in_len;
|
||||
/** current DHCP state machine state */
|
||||
u8_t state;
|
||||
/** retries of current request */
|
||||
u8_t tries;
|
||||
#if LWIP_DHCP_AUTOIP_COOP
|
||||
u8_t autoip_coop_state;
|
||||
#endif
|
||||
u8_t subnet_mask_given;
|
||||
|
||||
struct pbuf *p_out; /* pbuf of outcoming msg */
|
||||
struct dhcp_msg *msg_out; /* outgoing msg */
|
||||
@@ -47,28 +49,20 @@ struct dhcp
|
||||
u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */
|
||||
u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */
|
||||
u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */
|
||||
struct ip_addr server_ip_addr; /* dhcp server address that offered this lease */
|
||||
struct ip_addr offered_ip_addr;
|
||||
struct ip_addr offered_sn_mask;
|
||||
struct ip_addr offered_gw_addr;
|
||||
struct ip_addr offered_bc_addr;
|
||||
#define DHCP_MAX_DNS 2
|
||||
u32_t dns_count; /* actual number of DNS servers obtained */
|
||||
struct ip_addr offered_dns_addr[DHCP_MAX_DNS]; /* DNS server addresses */
|
||||
ip_addr_t server_ip_addr; /* dhcp server address that offered this lease */
|
||||
ip_addr_t offered_ip_addr;
|
||||
ip_addr_t offered_sn_mask;
|
||||
ip_addr_t offered_gw_addr;
|
||||
|
||||
u32_t offered_t0_lease; /* lease period (in seconds) */
|
||||
u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */
|
||||
u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */
|
||||
#if LWIP_DHCP_AUTOIP_COOP
|
||||
u8_t autoip_coop_state;
|
||||
#endif
|
||||
/** Patch #1308
|
||||
* TODO: See dhcp.c "TODO"s
|
||||
*/
|
||||
#if 0
|
||||
struct ip_addr offered_si_addr;
|
||||
u8_t *boot_file_name;
|
||||
#endif
|
||||
/* @todo: LWIP_DHCP_BOOTP_FILE configuration option?
|
||||
integrate with possible TFTP-client for booting? */
|
||||
#if LWIP_DHCP_BOOTP_FILE
|
||||
ip_addr_t offered_si_addr;
|
||||
char boot_file_name[DHCP_FILE_LEN];
|
||||
#endif /* LWIP_DHCP_BOOTPFILE */
|
||||
};
|
||||
|
||||
/* MUST be compiled with "pack structs" or equivalent! */
|
||||
@@ -86,15 +80,12 @@ struct dhcp_msg
|
||||
PACK_STRUCT_FIELD(u32_t xid);
|
||||
PACK_STRUCT_FIELD(u16_t secs);
|
||||
PACK_STRUCT_FIELD(u16_t flags);
|
||||
PACK_STRUCT_FIELD(struct ip_addr ciaddr);
|
||||
PACK_STRUCT_FIELD(struct ip_addr yiaddr);
|
||||
PACK_STRUCT_FIELD(struct ip_addr siaddr);
|
||||
PACK_STRUCT_FIELD(struct ip_addr giaddr);
|
||||
#define DHCP_CHADDR_LEN 16U
|
||||
PACK_STRUCT_FIELD(ip_addr_p_t ciaddr);
|
||||
PACK_STRUCT_FIELD(ip_addr_p_t yiaddr);
|
||||
PACK_STRUCT_FIELD(ip_addr_p_t siaddr);
|
||||
PACK_STRUCT_FIELD(ip_addr_p_t giaddr);
|
||||
PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);
|
||||
#define DHCP_SNAME_LEN 64U
|
||||
PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]);
|
||||
#define DHCP_FILE_LEN 128U
|
||||
PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);
|
||||
PACK_STRUCT_FIELD(u32_t cookie);
|
||||
#define DHCP_MIN_OPTIONS_LEN 68U
|
||||
@@ -114,6 +105,10 @@ PACK_STRUCT_END
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp);
|
||||
/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */
|
||||
#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0)
|
||||
void dhcp_cleanup(struct netif *netif);
|
||||
/** start DHCP configuration */
|
||||
err_t dhcp_start(struct netif *netif);
|
||||
/** enforce early lease renewal (not needed normally)*/
|
||||
@@ -124,10 +119,12 @@ err_t dhcp_release(struct netif *netif);
|
||||
void dhcp_stop(struct netif *netif);
|
||||
/** inform server of our manual IP address */
|
||||
void dhcp_inform(struct netif *netif);
|
||||
/** Handle a possible change in the network configuration */
|
||||
void dhcp_network_changed(struct netif *netif);
|
||||
|
||||
/** if enabled, check whether the offered IP address is not in use, using ARP */
|
||||
#if DHCP_DOES_ARP_CHECK
|
||||
void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr);
|
||||
void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr);
|
||||
#endif
|
||||
|
||||
/** to be called every minute */
|
||||
@@ -136,66 +133,66 @@ void dhcp_coarse_tmr(void);
|
||||
void dhcp_fine_tmr(void);
|
||||
|
||||
/** DHCP message item offsets and length */
|
||||
#define DHCP_MSG_OFS (UDP_DATA_OFS)
|
||||
#define DHCP_OP_OFS (DHCP_MSG_OFS + 0)
|
||||
#define DHCP_HTYPE_OFS (DHCP_MSG_OFS + 1)
|
||||
#define DHCP_HLEN_OFS (DHCP_MSG_OFS + 2)
|
||||
#define DHCP_HOPS_OFS (DHCP_MSG_OFS + 3)
|
||||
#define DHCP_XID_OFS (DHCP_MSG_OFS + 4)
|
||||
#define DHCP_SECS_OFS (DHCP_MSG_OFS + 8)
|
||||
#define DHCP_FLAGS_OFS (DHCP_MSG_OFS + 10)
|
||||
#define DHCP_CIADDR_OFS (DHCP_MSG_OFS + 12)
|
||||
#define DHCP_YIADDR_OFS (DHCP_MSG_OFS + 16)
|
||||
#define DHCP_SIADDR_OFS (DHCP_MSG_OFS + 20)
|
||||
#define DHCP_GIADDR_OFS (DHCP_MSG_OFS + 24)
|
||||
#define DHCP_CHADDR_OFS (DHCP_MSG_OFS + 28)
|
||||
#define DHCP_SNAME_OFS (DHCP_MSG_OFS + 44)
|
||||
#define DHCP_FILE_OFS (DHCP_MSG_OFS + 108)
|
||||
#define DHCP_MSG_LEN 236
|
||||
#define DHCP_OP_OFS 0
|
||||
#define DHCP_HTYPE_OFS 1
|
||||
#define DHCP_HLEN_OFS 2
|
||||
#define DHCP_HOPS_OFS 3
|
||||
#define DHCP_XID_OFS 4
|
||||
#define DHCP_SECS_OFS 8
|
||||
#define DHCP_FLAGS_OFS 10
|
||||
#define DHCP_CIADDR_OFS 12
|
||||
#define DHCP_YIADDR_OFS 16
|
||||
#define DHCP_SIADDR_OFS 20
|
||||
#define DHCP_GIADDR_OFS 24
|
||||
#define DHCP_CHADDR_OFS 28
|
||||
#define DHCP_SNAME_OFS 44
|
||||
#define DHCP_FILE_OFS 108
|
||||
#define DHCP_MSG_LEN 236
|
||||
|
||||
#define DHCP_COOKIE_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN)
|
||||
#define DHCP_OPTIONS_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN + 4)
|
||||
#define DHCP_COOKIE_OFS DHCP_MSG_LEN
|
||||
#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4)
|
||||
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
#define DHCP_SERVER_PORT 67
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
#define DHCP_SERVER_PORT 67
|
||||
|
||||
/** DHCP client states */
|
||||
#define DHCP_REQUESTING 1
|
||||
#define DHCP_INIT 2
|
||||
#define DHCP_REBOOTING 3
|
||||
#define DHCP_REBINDING 4
|
||||
#define DHCP_RENEWING 5
|
||||
#define DHCP_SELECTING 6
|
||||
#define DHCP_INFORMING 7
|
||||
#define DHCP_CHECKING 8
|
||||
#define DHCP_PERMANENT 9
|
||||
#define DHCP_BOUND 10
|
||||
#define DHCP_OFF 0
|
||||
#define DHCP_REQUESTING 1
|
||||
#define DHCP_INIT 2
|
||||
#define DHCP_REBOOTING 3
|
||||
#define DHCP_REBINDING 4
|
||||
#define DHCP_RENEWING 5
|
||||
#define DHCP_SELECTING 6
|
||||
#define DHCP_INFORMING 7
|
||||
#define DHCP_CHECKING 8
|
||||
#define DHCP_PERMANENT 9
|
||||
#define DHCP_BOUND 10
|
||||
/** not yet implemented #define DHCP_RELEASING 11 */
|
||||
#define DHCP_BACKING_OFF 12
|
||||
#define DHCP_OFF 13
|
||||
#define DHCP_BACKING_OFF 12
|
||||
|
||||
/** AUTOIP cooperatation flags */
|
||||
#define DHCP_AUTOIP_COOP_STATE_OFF 0
|
||||
#define DHCP_AUTOIP_COOP_STATE_ON 1
|
||||
#define DHCP_AUTOIP_COOP_STATE_OFF 0
|
||||
#define DHCP_AUTOIP_COOP_STATE_ON 1
|
||||
|
||||
#define DHCP_BOOTREQUEST 1
|
||||
#define DHCP_BOOTREPLY 2
|
||||
#define DHCP_BOOTREQUEST 1
|
||||
#define DHCP_BOOTREPLY 2
|
||||
|
||||
/** DHCP message types */
|
||||
#define DHCP_DISCOVER 1
|
||||
#define DHCP_OFFER 2
|
||||
#define DHCP_REQUEST 3
|
||||
#define DHCP_DECLINE 4
|
||||
#define DHCP_ACK 5
|
||||
#define DHCP_NAK 6
|
||||
#define DHCP_RELEASE 7
|
||||
#define DHCP_INFORM 8
|
||||
#define DHCP_OFFER 2
|
||||
#define DHCP_REQUEST 3
|
||||
#define DHCP_DECLINE 4
|
||||
#define DHCP_ACK 5
|
||||
#define DHCP_NAK 6
|
||||
#define DHCP_RELEASE 7
|
||||
#define DHCP_INFORM 8
|
||||
|
||||
/** DHCP hardware type, currently only ethernet is supported */
|
||||
#define DHCP_HTYPE_ETH 1
|
||||
|
||||
#define DHCP_HLEN_ETH 6
|
||||
#define DHCP_MAGIC_COOKIE 0x63825363UL
|
||||
|
||||
#define DHCP_BROADCAST_FLAG 15
|
||||
#define DHCP_BROADCAST_MASK (1 << DHCP_FLAG_BROADCAST)
|
||||
/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */
|
||||
|
||||
/** BootP options */
|
||||
#define DHCP_OPTION_PAD 0
|
||||
@@ -217,7 +214,6 @@ void dhcp_fine_tmr(void);
|
||||
#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */
|
||||
#define DHCP_OPTION_MESSAGE_TYPE_LEN 1
|
||||
|
||||
|
||||
#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */
|
||||
#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */
|
||||
|
||||
|
||||
@@ -38,6 +38,10 @@
|
||||
|
||||
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** DNS timer period */
|
||||
#define DNS_TMR_INTERVAL 1000
|
||||
|
||||
@@ -66,27 +70,55 @@
|
||||
#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */
|
||||
#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */
|
||||
|
||||
/* The size used for the next line is rather a hack, but it prevents including socket.h in all files
|
||||
that include memp.h, and that would possibly break portability (since socket.h defines some types
|
||||
and constants possibly already define by the OS).
|
||||
Calculation rule:
|
||||
sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */
|
||||
#define NETDB_ELEM_SIZE (32 + 16 + DNS_MAX_NAME_LENGTH + 1)
|
||||
|
||||
#if DNS_LOCAL_HOSTLIST
|
||||
/** struct used for local host-list */
|
||||
struct local_hostlist_entry {
|
||||
/** static hostname */
|
||||
const char *name;
|
||||
/** static host address in network byteorder */
|
||||
ip_addr_t addr;
|
||||
struct local_hostlist_entry *next;
|
||||
};
|
||||
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
||||
#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN
|
||||
#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH
|
||||
#endif
|
||||
#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1))
|
||||
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||
#endif /* DNS_LOCAL_HOSTLIST */
|
||||
|
||||
/** Callback which is invoked when a hostname is found.
|
||||
* A function of this type must be implemented by the application using the DNS resolver.
|
||||
* @param name pointer to the name that was looked up.
|
||||
* @param ipaddr pointer to a struct ip_addr containing the IP address of the hostname,
|
||||
* @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname,
|
||||
* or NULL if the name could not be found (or on any other error).
|
||||
* @param callback_arg a user-specified callback argument passed to dns_gethostbyname
|
||||
*/
|
||||
typedef void (*dns_found_callback)(const char *name, struct ip_addr *ipaddr, void *callback_arg);
|
||||
|
||||
typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg);
|
||||
|
||||
void dns_init(void);
|
||||
|
||||
void dns_tmr(void);
|
||||
|
||||
void dns_setserver(u8_t numdns, struct ip_addr *dnsserver);
|
||||
|
||||
struct ip_addr dns_getserver(u8_t numdns);
|
||||
|
||||
err_t dns_gethostbyname(const char *hostname, struct ip_addr *addr,
|
||||
void dns_setserver(u8_t numdns, ip_addr_t *dnsserver);
|
||||
ip_addr_t dns_getserver(u8_t numdns);
|
||||
err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr,
|
||||
dns_found_callback found, void *callback_arg);
|
||||
|
||||
#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
||||
int dns_local_removehost(const char *hostname, const ip_addr_t *addr);
|
||||
err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr);
|
||||
#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_DNS */
|
||||
|
||||
#endif /* __LWIP_DNS_H__ */
|
||||
|
||||
@@ -33,39 +33,43 @@
|
||||
#define __LWIP_ERR_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/arch.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Define LWIP_ERR_T in cc.h if you want to use
|
||||
* a different type for your platform (must be signed). */
|
||||
#ifdef LWIP_ERR_T
|
||||
typedef LWIP_ERR_T err_t;
|
||||
#else /* LWIP_ERR_T */
|
||||
typedef s8_t err_t;
|
||||
#endif /* LWIP_ERR_T*/
|
||||
|
||||
/* Definitions for error constants. */
|
||||
|
||||
#define ERR_OK 0 /* No error, everything OK. */
|
||||
#define ERR_MEM -1 /* Out of memory error. */
|
||||
#define ERR_BUF -2 /* Buffer error. */
|
||||
#define ERR_RTE -3 /* Routing problem. */
|
||||
#define ERR_TIMEOUT -3 /* Timeout. */
|
||||
#define ERR_RTE -4 /* Routing problem. */
|
||||
#define ERR_INPROGRESS -5 /* Operation in progress */
|
||||
#define ERR_VAL -6 /* Illegal value. */
|
||||
#define ERR_WOULDBLOCK -7 /* Operation would block. */
|
||||
#define ERR_USE -8 /* Address in use. */
|
||||
#define ERR_ISCONN -9 /* Already connected. */
|
||||
|
||||
#define ERR_IS_FATAL(e) ((e) < ERR_RTE)
|
||||
#define ERR_IS_FATAL(e) ((e) < ERR_ISCONN)
|
||||
|
||||
#define ERR_ABRT -4 /* Connection aborted. */
|
||||
#define ERR_RST -5 /* Connection reset. */
|
||||
#define ERR_CLSD -6 /* Connection closed. */
|
||||
#define ERR_CONN -7 /* Not connected. */
|
||||
#define ERR_ABRT -10 /* Connection aborted. */
|
||||
#define ERR_RST -11 /* Connection reset. */
|
||||
#define ERR_CLSD -12 /* Connection closed. */
|
||||
#define ERR_CONN -13 /* Not connected. */
|
||||
|
||||
#define ERR_VAL -8 /* Illegal value. */
|
||||
#define ERR_ARG -14 /* Illegal argument. */
|
||||
|
||||
#define ERR_ARG -9 /* Illegal argument. */
|
||||
|
||||
#define ERR_USE -10 /* Address in use. */
|
||||
|
||||
#define ERR_IF -11 /* Low-level netif error */
|
||||
#define ERR_ISCONN -12 /* Already connected. */
|
||||
|
||||
#define ERR_TIMEOUT -13 /* Timeout. */
|
||||
|
||||
#define ERR_INPROGRESS -14 /* Operation in progress */
|
||||
#define ERR_IF -15 /* Low-level netif error */
|
||||
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
|
||||
112
src/include/lwip/inet_chksum.h
Normal file
112
src/include/lwip/inet_chksum.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
#ifndef __LWIP_INET_CHKSUM_H__
|
||||
#define __LWIP_INET_CHKSUM_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
/** Swap the bytes in an u16_t: much like htons() for little-endian */
|
||||
#ifndef SWAP_BYTES_IN_WORD
|
||||
#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
/* little endian and PLATFORM_BYTESWAP defined */
|
||||
#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w)
|
||||
#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */
|
||||
/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */
|
||||
#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8)
|
||||
#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/
|
||||
#endif /* SWAP_BYTES_IN_WORD */
|
||||
|
||||
/** Split an u32_t in two u16_ts and add them up */
|
||||
#ifndef FOLD_U32T
|
||||
#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL))
|
||||
#endif
|
||||
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
/** Function-like macro: same as MEMCPY but returns the checksum of copied data
|
||||
as u16_t */
|
||||
#ifndef LWIP_CHKSUM_COPY
|
||||
#define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len)
|
||||
#ifndef LWIP_CHKSUM_COPY_ALGORITHM
|
||||
#define LWIP_CHKSUM_COPY_ALGORITHM 1
|
||||
#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
|
||||
#endif /* LWIP_CHKSUM_COPY */
|
||||
#else /* LWIP_CHECKSUM_ON_COPY */
|
||||
#define LWIP_CHKSUM_COPY_ALGORITHM 0
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
u16_t inet_chksum(void *dataptr, u16_t len);
|
||||
u16_t inet_chksum_pbuf(struct pbuf *p);
|
||||
u16_t inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
|
||||
ip_addr_t *src, ip_addr_t *dest);
|
||||
u16_t inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto,
|
||||
u16_t proto_len, u16_t chksum_len, ip_addr_t *src, ip_addr_t *dest);
|
||||
#if LWIP_CHKSUM_COPY_ALGORITHM
|
||||
u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len);
|
||||
#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
|
||||
|
||||
#if LWIP_IPV6
|
||||
u16_t ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
|
||||
ip6_addr_t *src, ip6_addr_t *dest);
|
||||
u16_t ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
|
||||
u16_t chksum_len, ip6_addr_t *src, ip6_addr_t *dest);
|
||||
|
||||
#define ipX_chksum_pseudo(isipv6, p, proto, proto_len, src, dest) \
|
||||
((isipv6) ? \
|
||||
ip6_chksum_pseudo(p, proto, proto_len, ipX_2_ip6(src), ipX_2_ip6(dest)) :\
|
||||
inet_chksum_pseudo(p, proto, proto_len, ipX_2_ip(src), ipX_2_ip(dest)))
|
||||
#define ipX_chksum_pseudo_partial(isipv6, p, proto, proto_len, chksum_len, src, dest) \
|
||||
((isipv6) ? \
|
||||
ip6_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ipX_2_ip6(src), ipX_2_ip6(dest)) :\
|
||||
inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ipX_2_ip(src), ipX_2_ip(dest)))
|
||||
|
||||
#else /* LWIP_IPV6 */
|
||||
|
||||
#define ipX_chksum_pseudo(isipv6, p, proto, proto_len, src, dest) \
|
||||
inet_chksum_pseudo(p, proto, proto_len, src, dest)
|
||||
#define ipX_chksum_pseudo_partial(isipv6, p, proto, proto_len, chksum_len, src, dest) \
|
||||
inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, src, dest)
|
||||
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LWIP_INET_H__ */
|
||||
|
||||
@@ -38,6 +38,30 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** X.x.x: Major version of the stack */
|
||||
#define LWIP_VERSION_MAJOR 1U
|
||||
/** x.X.x: Minor version of the stack */
|
||||
#define LWIP_VERSION_MINOR 4U
|
||||
/** x.x.X: Revision of the stack */
|
||||
#define LWIP_VERSION_REVISION 1U
|
||||
/** For release candidates, this is set to 1..254
|
||||
* For official releases, this is set to 255 (LWIP_RC_RELEASE)
|
||||
* For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */
|
||||
#define LWIP_VERSION_RC 0U
|
||||
|
||||
/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */
|
||||
#define LWIP_RC_RELEASE 255U
|
||||
/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */
|
||||
#define LWIP_RC_DEVELOPMENT 0U
|
||||
|
||||
#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE)
|
||||
#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT)
|
||||
#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT))
|
||||
|
||||
/** Provides the version of the stack */
|
||||
#define LWIP_VERSION (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 | \
|
||||
LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC)
|
||||
|
||||
/* Modules initialization */
|
||||
void lwip_init(void);
|
||||
|
||||
|
||||
247
src/include/lwip/ip.h
Normal file
247
src/include/lwip/ip.h
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
#ifndef __LWIP_IP_H__
|
||||
#define __LWIP_IP_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/ip4.h"
|
||||
#include "lwip/ip6.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This is passed as the destination address to ip_output_if (not
|
||||
to ip_output), meaning that an IP header already is constructed
|
||||
in the pbuf. This is used when TCP retransmits. */
|
||||
#ifdef IP_HDRINCL
|
||||
#undef IP_HDRINCL
|
||||
#endif /* IP_HDRINCL */
|
||||
#define IP_HDRINCL NULL
|
||||
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
#define IP_PCB_ADDRHINT ;u8_t addr_hint
|
||||
#else
|
||||
#define IP_PCB_ADDRHINT
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
|
||||
#if LWIP_IPV6
|
||||
#define IP_PCB_ISIPV6_MEMBER u8_t isipv6;
|
||||
#define IP_PCB_IPVER_EQ(pcb1, pcb2) ((pcb1)->isipv6 == (pcb2)->isipv6)
|
||||
#define IP_PCB_IPVER_INPUT_MATCH(pcb) (ip_current_is_v6() ? \
|
||||
((pcb)->isipv6 != 0) : \
|
||||
((pcb)->isipv6 == 0))
|
||||
#define PCB_ISIPV6(pcb) ((pcb)->isipv6)
|
||||
#else
|
||||
#define IP_PCB_ISIPV6_MEMBER
|
||||
#define IP_PCB_IPVER_EQ(pcb1, pcb2) 1
|
||||
#define IP_PCB_IPVER_INPUT_MATCH(pcb) 1
|
||||
#define PCB_ISIPV6(pcb) 0
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
/* This is the common part of all PCB types. It needs to be at the
|
||||
beginning of a PCB type definition. It is located here so that
|
||||
changes to this common part are made in one location instead of
|
||||
having to change all PCB structs. */
|
||||
#define IP_PCB \
|
||||
IP_PCB_ISIPV6_MEMBER \
|
||||
/* ip addresses in network byte order */ \
|
||||
ipX_addr_t local_ip; \
|
||||
ipX_addr_t remote_ip; \
|
||||
/* Socket options */ \
|
||||
u8_t so_options; \
|
||||
/* Type Of Service */ \
|
||||
u8_t tos; \
|
||||
/* Time To Live */ \
|
||||
u8_t ttl \
|
||||
/* link layer address resolution hint */ \
|
||||
IP_PCB_ADDRHINT
|
||||
|
||||
struct ip_pcb {
|
||||
/* Common members of all PCB types */
|
||||
IP_PCB;
|
||||
};
|
||||
|
||||
/*
|
||||
* Option flags per-socket. These are the same like SO_XXX.
|
||||
*/
|
||||
/*#define SOF_DEBUG (u8_t)0x01U Unimplemented: turn on debugging info recording */
|
||||
#define SOF_ACCEPTCONN (u8_t)0x02U /* socket has had listen() */
|
||||
#define SOF_REUSEADDR (u8_t)0x04U /* allow local address reuse */
|
||||
#define SOF_KEEPALIVE (u8_t)0x08U /* keep connections alive */
|
||||
/*#define SOF_DONTROUTE (u8_t)0x10U Unimplemented: just use interface addresses */
|
||||
#define SOF_BROADCAST (u8_t)0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
|
||||
/*#define SOF_USELOOPBACK (u8_t)0x40U Unimplemented: bypass hardware when possible */
|
||||
#define SOF_LINGER (u8_t)0x80U /* linger on close if data present */
|
||||
/*#define SOF_OOBINLINE (u16_t)0x0100U Unimplemented: leave received OOB data in line */
|
||||
/*#define SOF_REUSEPORT (u16_t)0x0200U Unimplemented: allow local address & port reuse */
|
||||
|
||||
/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */
|
||||
#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/)
|
||||
|
||||
/* Global variables of this module, kept in a struct for efficient access using base+index. */
|
||||
struct ip_globals
|
||||
{
|
||||
/** The interface that provided the packet for the current callback invocation. */
|
||||
struct netif *current_netif;
|
||||
/** Header of the input packet currently being processed. */
|
||||
const struct ip_hdr *current_ip4_header;
|
||||
#if LWIP_IPV6
|
||||
/** Header of the input IPv6 packet currently being processed. */
|
||||
const struct ip6_hdr *current_ip6_header;
|
||||
#endif /* LWIP_IPV6 */
|
||||
/** Total header length of current_ip4/6_header (i.e. after this, the UDP/TCP header starts) */
|
||||
u16_t current_ip_header_tot_len;
|
||||
/** Source IP address of current_header */
|
||||
ipX_addr_t current_iphdr_src;
|
||||
/** Destination IP address of current_header */
|
||||
ipX_addr_t current_iphdr_dest;
|
||||
};
|
||||
extern struct ip_globals ip_data;
|
||||
|
||||
|
||||
/** Get the interface that received the current packet.
|
||||
* This function must only be called from a receive callback (udp_recv,
|
||||
* raw_recv, tcp_accept). It will return NULL otherwise. */
|
||||
#define ip_current_netif() (ip_data.current_netif)
|
||||
/** Get the IP header of the current packet.
|
||||
* This function must only be called from a receive callback (udp_recv,
|
||||
* raw_recv, tcp_accept). It will return NULL otherwise. */
|
||||
#define ip_current_header() (ip_data.current_ip4_header)
|
||||
/** Total header length of ip(6)_current_header() (i.e. after this, the UDP/TCP header starts) */
|
||||
#define ip_current_header_tot_len() (ip_data.current_ip_header_tot_len)
|
||||
/** Source IP address of current_header */
|
||||
#define ipX_current_src_addr() (&ip_data.current_iphdr_src)
|
||||
/** Destination IP address of current_header */
|
||||
#define ipX_current_dest_addr() (&ip_data.current_iphdr_dest)
|
||||
|
||||
#if LWIP_IPV6
|
||||
/** Get the IPv6 header of the current packet.
|
||||
* This function must only be called from a receive callback (udp_recv,
|
||||
* raw_recv, tcp_accept). It will return NULL otherwise. */
|
||||
#define ip6_current_header() (ip_data.current_ip6_header)
|
||||
/** Returns TRUE if the current IP input packet is IPv6, FALSE if it is IPv4 */
|
||||
#define ip_current_is_v6() (ip6_current_header() != NULL)
|
||||
/** Source IPv6 address of current_header */
|
||||
#define ip6_current_src_addr() (ipX_2_ip6(&ip_data.current_iphdr_src))
|
||||
/** Destination IPv6 address of current_header */
|
||||
#define ip6_current_dest_addr() (ipX_2_ip6(&ip_data.current_iphdr_dest))
|
||||
/** Get the transport layer protocol */
|
||||
#define ip_current_header_proto() (ip_current_is_v6() ? \
|
||||
IP6H_NEXTH(ip6_current_header()) :\
|
||||
IPH_PROTO(ip_current_header()))
|
||||
/** Get the transport layer header */
|
||||
#define ipX_next_header_ptr() ((void*)((ip_current_is_v6() ? \
|
||||
(u8_t*)ip6_current_header() : (u8_t*)ip_current_header()) + ip_current_header_tot_len()))
|
||||
|
||||
/** Set an IP_PCB to IPv6 (IPv4 is the default) */
|
||||
#define ip_set_v6(pcb, val) do{if(pcb != NULL) { pcb->isipv6 = val; }}while(0)
|
||||
|
||||
/** Source IP4 address of current_header */
|
||||
#define ip_current_src_addr() (ipX_2_ip(&ip_data.current_iphdr_src))
|
||||
/** Destination IP4 address of current_header */
|
||||
#define ip_current_dest_addr() (ipX_2_ip(&ip_data.current_iphdr_dest))
|
||||
|
||||
#else /* LWIP_IPV6 */
|
||||
|
||||
/** Always returns FALSE when only supporting IPv4 */
|
||||
#define ip_current_is_v6() 0
|
||||
/** Get the transport layer protocol */
|
||||
#define ip_current_header_proto() IPH_PROTO(ip_current_header())
|
||||
/** Get the transport layer header */
|
||||
#define ipX_next_header_ptr() ((void*)((u8_t*)ip_current_header() + ip_current_header_tot_len()))
|
||||
/** Source IP4 address of current_header */
|
||||
#define ip_current_src_addr() (&ip_data.current_iphdr_src)
|
||||
/** Destination IP4 address of current_header */
|
||||
#define ip_current_dest_addr() (&ip_data.current_iphdr_dest)
|
||||
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
/** Union source address of current_header */
|
||||
#define ipX_current_src_addr() (&ip_data.current_iphdr_src)
|
||||
/** Union destination address of current_header */
|
||||
#define ipX_current_dest_addr() (&ip_data.current_iphdr_dest)
|
||||
|
||||
#if LWIP_IPV6
|
||||
#define ipX_output(isipv6, p, src, dest, ttl, tos, proto) \
|
||||
((isipv6) ? \
|
||||
ip6_output(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto) : \
|
||||
ip_output(p, ipX_2_ip(src), ipX_2_ip(dest), ttl, tos, proto))
|
||||
#define ipX_output_if(isipv6, p, src, dest, ttl, tos, proto, netif) \
|
||||
((isipv6) ? \
|
||||
ip6_output_if(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \
|
||||
ip_output_if(p, (src), (dest), ttl, tos, proto, netif))
|
||||
#define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \
|
||||
((isipv6) ? \
|
||||
ip6_output_hinted(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto, addr_hint) : \
|
||||
ip_output_hinted(p, ipX_2_ip(src), ipX_2_ip(dest), ttl, tos, proto, addr_hint))
|
||||
#define ipX_route(isipv6, src, dest) \
|
||||
((isipv6) ? \
|
||||
ip6_route(ipX_2_ip6(src), ipX_2_ip6(dest)) : \
|
||||
ip_route(ipX_2_ip(dest)))
|
||||
#define ipX_netif_get_local_ipX(isipv6, netif, dest) \
|
||||
((isipv6) ? \
|
||||
ip6_netif_get_local_ipX(netif, ipX_2_ip6(dest)) : \
|
||||
ip_netif_get_local_ipX(netif))
|
||||
#define ipX_debug_print(is_ipv6, p) ((is_ipv6) ? ip6_debug_print(p) : ip_debug_print(p))
|
||||
#else /* LWIP_IPV6 */
|
||||
#define ipX_output(isipv6, p, src, dest, ttl, tos, proto) \
|
||||
ip_output(p, src, dest, ttl, tos, proto)
|
||||
#define ipX_output_if(isipv6, p, src, dest, ttl, tos, proto, netif) \
|
||||
ip_output_if(p, src, dest, ttl, tos, proto, netif)
|
||||
#define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \
|
||||
ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint)
|
||||
#define ipX_route(isipv6, src, dest) \
|
||||
ip_route(ipX_2_ip(dest))
|
||||
#define ipX_netif_get_local_ipX(isipv6, netif, dest) \
|
||||
ip_netif_get_local_ipX(netif)
|
||||
#define ipX_debug_print(is_ipv6, p) ip_debug_print(p)
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#define ipX_route_get_local_ipX(isipv6, src, dest, netif, ipXaddr) do { \
|
||||
(netif) = ipX_route(isipv6, src, dest); \
|
||||
(ipXaddr) = ipX_netif_get_local_ipX(isipv6, netif, dest); \
|
||||
}while(0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LWIP_IP_H__ */
|
||||
|
||||
|
||||
130
src/include/lwip/ip_addr.h
Normal file
130
src/include/lwip/ip_addr.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
#ifndef __LWIP_IP_ADDR_H__
|
||||
#define __LWIP_IP_ADDR_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
#include "lwip/ip4_addr.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if LWIP_IPV6
|
||||
/* A union struct for both IP version's addresses. */
|
||||
typedef union {
|
||||
ip_addr_t ip4;
|
||||
ip6_addr_t ip6;
|
||||
} ipX_addr_t;
|
||||
|
||||
/** These functions only exist for type-safe conversion from ip_addr_t to
|
||||
ip6_addr_t and back */
|
||||
#if LWIP_ALLOW_STATIC_FN_IN_HEADER
|
||||
static ip6_addr_t* ip_2_ip6(ip_addr_t *ipaddr)
|
||||
{ return (ip6_addr_t*)ipaddr;}
|
||||
static ip_addr_t* ip6_2_ip(ip6_addr_t *ip6addr)
|
||||
{ return (ip_addr_t*)ip6addr; }
|
||||
static ipX_addr_t* ip_2_ipX(ip_addr_t *ipaddr)
|
||||
{ return (ipX_addr_t*)ipaddr; }
|
||||
static ipX_addr_t* ip6_2_ipX(ip6_addr_t *ip6addr)
|
||||
{ return (ipX_addr_t*)ip6addr; }
|
||||
#else /* LWIP_ALLOW_STATIC_FN_IN_HEADER */
|
||||
#define ip_2_ip6(ipaddr) ((ip6_addr_t*)(ipaddr))
|
||||
#define ip6_2_ip(ip6addr) ((ip_addr_t*)(ip6addr))
|
||||
#define ip_2_ipX(ipaddr) ((ipX_addr_t*)ipaddr)
|
||||
#define ip6_2_ipX(ip6addr) ((ipX_addr_t*)ip6addr)
|
||||
#endif /* LWIP_ALLOW_STATIC_FN_IN_HEADER*/
|
||||
#define ipX_2_ip6(ip6addr) (&((ip6addr)->ip6))
|
||||
#define ipX_2_ip(ipaddr) (&((ipaddr)->ip4))
|
||||
|
||||
#define ipX_addr_copy(is_ipv6, dest, src) do{if(is_ipv6){ \
|
||||
ip6_addr_copy((dest).ip6, (src).ip6); }else{ \
|
||||
ip_addr_copy((dest).ip4, (src).ip4); }}while(0)
|
||||
#define ipX_addr_set(is_ipv6, dest, src) do{if(is_ipv6){ \
|
||||
ip6_addr_set(ipX_2_ip6(dest), ipX_2_ip6(src)); }else{ \
|
||||
ip_addr_set(ipX_2_ip(dest), ipX_2_ip(src)); }}while(0)
|
||||
#define ipX_addr_set_ipaddr(is_ipv6, dest, src) do{if(is_ipv6){ \
|
||||
ip6_addr_set(ipX_2_ip6(dest), ip_2_ip6(src)); }else{ \
|
||||
ip_addr_set(ipX_2_ip(dest), src); }}while(0)
|
||||
#define ipX_addr_set_zero(is_ipv6, ipaddr) do{if(is_ipv6){ \
|
||||
ip6_addr_set_zero(ipX_2_ip6(ipaddr)); }else{ \
|
||||
ip_addr_set_zero(ipX_2_ip(ipaddr)); }}while(0)
|
||||
#define ipX_addr_set_any(is_ipv6, ipaddr) do{if(is_ipv6){ \
|
||||
ip6_addr_set_any(ipX_2_ip6(ipaddr)); }else{ \
|
||||
ip_addr_set_any(ipX_2_ip(ipaddr)); }}while(0)
|
||||
#define ipX_addr_set_loopback(is_ipv6, ipaddr) do{if(is_ipv6){ \
|
||||
ip6_addr_set_loopback(ipX_2_ip6(ipaddr)); }else{ \
|
||||
ip_addr_set_loopback(ipX_2_ip(ipaddr)); }}while(0)
|
||||
#define ipX_addr_set_hton(is_ipv6, dest, src) do{if(is_ipv6){ \
|
||||
ip6_addr_set_hton(ipX_2_ip6(ipaddr), (src)) ;}else{ \
|
||||
ip_addr_set_hton(ipX_2_ip(ipaddr), (src));}}while(0)
|
||||
#define ipX_addr_cmp(is_ipv6, addr1, addr2) ((is_ipv6) ? \
|
||||
ip6_addr_cmp(ipX_2_ip6(addr1), ipX_2_ip6(addr2)) : \
|
||||
ip_addr_cmp(ipX_2_ip(addr1), ipX_2_ip(addr2)))
|
||||
#define ipX_addr_isany(is_ipv6, ipaddr) ((is_ipv6) ? \
|
||||
ip6_addr_isany(ipX_2_ip6(ipaddr)) : \
|
||||
ip_addr_isany(ipX_2_ip(ipaddr)))
|
||||
#define ipX_addr_ismulticast(is_ipv6, ipaddr) ((is_ipv6) ? \
|
||||
ip6_addr_ismulticast(ipX_2_ip6(ipaddr)) : \
|
||||
ip_addr_ismulticast(ipX_2_ip(ipaddr)))
|
||||
#define ipX_addr_debug_print(is_ipv6, debug, ipaddr) do { if(is_ipv6) { \
|
||||
ip6_addr_debug_print(debug, ipX_2_ip6(ipaddr)); } else { \
|
||||
ip_addr_debug_print(debug, ipX_2_ip(ipaddr)); }}while(0)
|
||||
|
||||
#else /* LWIP_IPV6 */
|
||||
|
||||
typedef ip_addr_t ipX_addr_t;
|
||||
#define ipX_2_ip(ipaddr) (ipaddr)
|
||||
#define ip_2_ipX(ipaddr) (ipaddr)
|
||||
|
||||
#define ipX_addr_copy(is_ipv6, dest, src) ip_addr_copy(dest, src)
|
||||
#define ipX_addr_set(is_ipv6, dest, src) ip_addr_set(dest, src)
|
||||
#define ipX_addr_set_ipaddr(is_ipv6, dest, src) ip_addr_set(dest, src)
|
||||
#define ipX_addr_set_zero(is_ipv6, ipaddr) ip_addr_set_zero(ipaddr)
|
||||
#define ipX_addr_set_any(is_ipv6, ipaddr) ip_addr_set_any(ipaddr)
|
||||
#define ipX_addr_set_loopback(is_ipv6, ipaddr) ip_addr_set_loopback(ipaddr)
|
||||
#define ipX_addr_set_hton(is_ipv6, dest, src) ip_addr_set_hton(dest, src)
|
||||
#define ipX_addr_cmp(is_ipv6, addr1, addr2) ip_addr_cmp(addr1, addr2)
|
||||
#define ipX_addr_isany(is_ipv6, ipaddr) ip_addr_isany(ipaddr)
|
||||
#define ipX_addr_ismulticast(is_ipv6, ipaddr) ip_addr_ismulticast(ipaddr)
|
||||
#define ipX_addr_debug_print(is_ipv6, debug, ipaddr) ip_addr_debug_print(debug, ipaddr)
|
||||
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LWIP_IP_ADDR_H__ */
|
||||
@@ -50,48 +50,67 @@ typedef size_t mem_size_t;
|
||||
* allow these defines to be overridden.
|
||||
*/
|
||||
#ifndef mem_free
|
||||
#define mem_free(x) free(x)
|
||||
#define mem_free free
|
||||
#endif
|
||||
#ifndef mem_malloc
|
||||
#define mem_malloc(x) malloc(x)
|
||||
#define mem_malloc malloc
|
||||
#endif
|
||||
#ifndef mem_calloc
|
||||
#define mem_calloc(x, y) calloc(x, y)
|
||||
#define mem_calloc calloc
|
||||
#endif
|
||||
#ifndef mem_realloc
|
||||
#define mem_realloc(x, size) (x)
|
||||
/* Since there is no C library allocation function to shrink memory without
|
||||
moving it, define this to nothing. */
|
||||
#ifndef mem_trim
|
||||
#define mem_trim(mem, size) (mem)
|
||||
#endif
|
||||
#else /* MEM_LIBC_MALLOC */
|
||||
|
||||
/* MEM_SIZE would have to be aligned, but using 64000 here instead of
|
||||
* 65535 leaves some room for alignment...
|
||||
*/
|
||||
#if MEM_SIZE > 64000l
|
||||
#if MEM_SIZE > 64000L
|
||||
typedef u32_t mem_size_t;
|
||||
#define MEM_SIZE_F U32_F
|
||||
#else
|
||||
typedef u16_t mem_size_t;
|
||||
#define MEM_SIZE_F U16_F
|
||||
#endif /* MEM_SIZE > 64000 */
|
||||
|
||||
#if MEM_USE_POOLS
|
||||
/** mem_init is not used when using pools instead of a heap */
|
||||
#define mem_init()
|
||||
/** mem_realloc is not used when using pools instead of a heap:
|
||||
/** mem_trim is not used when using pools instead of a heap:
|
||||
we can't free part of a pool element and don't want to copy the rest */
|
||||
#define mem_realloc(mem, size) (mem)
|
||||
#define mem_trim(mem, size) (mem)
|
||||
#else /* MEM_USE_POOLS */
|
||||
/* lwIP alternative malloc */
|
||||
void mem_init(void);
|
||||
void *mem_realloc(void *mem, mem_size_t size);
|
||||
void *mem_trim(void *mem, mem_size_t size);
|
||||
#endif /* MEM_USE_POOLS */
|
||||
void *mem_malloc(mem_size_t size);
|
||||
void *mem_calloc(mem_size_t count, mem_size_t size);
|
||||
void mem_free(void *mem);
|
||||
#endif /* MEM_LIBC_MALLOC */
|
||||
|
||||
/** Calculate memory size for an aligned buffer - returns the next highest
|
||||
* multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and
|
||||
* LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4).
|
||||
*/
|
||||
#ifndef LWIP_MEM_ALIGN_SIZE
|
||||
#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))
|
||||
#endif
|
||||
|
||||
/** Calculate safe memory size for an aligned buffer when using an unaligned
|
||||
* type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the
|
||||
* start (e.g. if buffer is u8_t[] and actual data will be u32_t*)
|
||||
*/
|
||||
#ifndef LWIP_MEM_ALIGN_BUFFER
|
||||
#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1))
|
||||
#endif
|
||||
|
||||
/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT
|
||||
* so that ADDR % MEM_ALIGNMENT == 0
|
||||
*/
|
||||
#ifndef LWIP_MEM_ALIGN
|
||||
#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1)))
|
||||
#endif
|
||||
|
||||
@@ -73,8 +73,28 @@ typedef enum {
|
||||
We use this helper type and these defines so we can avoid using const memp_t values */
|
||||
#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST)
|
||||
#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST)
|
||||
#endif /* MEM_USE_POOLS */
|
||||
|
||||
#if MEMP_MEM_MALLOC || MEM_USE_POOLS
|
||||
extern const u16_t memp_sizes[MEMP_MAX];
|
||||
#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */
|
||||
|
||||
#if MEMP_MEM_MALLOC
|
||||
|
||||
#include "mem.h"
|
||||
|
||||
#define memp_init()
|
||||
#define memp_malloc(type) mem_malloc(memp_sizes[type])
|
||||
#define memp_free(type, mem) mem_free(mem)
|
||||
|
||||
#else /* MEMP_MEM_MALLOC */
|
||||
|
||||
#if MEM_USE_POOLS
|
||||
/** This structure is used to save the pool one element came from. */
|
||||
struct memp_malloc_helper
|
||||
{
|
||||
memp_t poolnr;
|
||||
};
|
||||
#endif /* MEM_USE_POOLS */
|
||||
|
||||
void memp_init(void);
|
||||
@@ -87,6 +107,8 @@ void *memp_malloc(memp_t type);
|
||||
#endif
|
||||
void memp_free(memp_t type, void *mem);
|
||||
|
||||
#endif /* MEMP_MEM_MALLOC */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
* above, then will declare #2 & #3 to be just standard mempools.
|
||||
*/
|
||||
#ifndef LWIP_MALLOC_MEMPOOL
|
||||
/* This treats "malloc pools" just like any other pool */
|
||||
#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, size, "MALLOC_"#size)
|
||||
/* This treats "malloc pools" just like any other pool.
|
||||
The pools are a little bigger to provide 'size' as the amount of user data. */
|
||||
#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + sizeof(struct memp_malloc_helper)), "MALLOC_"#size)
|
||||
#define LWIP_MALLOC_MEMPOOL_START
|
||||
#define LWIP_MALLOC_MEMPOOL_END
|
||||
#endif /* LWIP_MALLOC_MEMPOOL */
|
||||
@@ -46,6 +47,9 @@ LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg),
|
||||
#if IP_REASSEMBLY
|
||||
LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA")
|
||||
#endif /* IP_REASSEMBLY */
|
||||
#if (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) || LWIP_IPv6_FRAG
|
||||
LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF")
|
||||
#endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
|
||||
|
||||
#if LWIP_NETCONN
|
||||
LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF")
|
||||
@@ -54,7 +58,9 @@ LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn),
|
||||
|
||||
#if NO_SYS==0
|
||||
LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API")
|
||||
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||
LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT")
|
||||
#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||
#endif /* NO_SYS==0 */
|
||||
|
||||
#if ARP_QUEUEING
|
||||
@@ -65,9 +71,37 @@ LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_en
|
||||
LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP")
|
||||
#endif /* LWIP_IGMP */
|
||||
|
||||
#if NO_SYS==0
|
||||
#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */
|
||||
LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT")
|
||||
#endif /* NO_SYS==0 */
|
||||
#endif /* LWIP_TIMERS */
|
||||
|
||||
#if LWIP_SNMP
|
||||
LWIP_MEMPOOL(SNMP_ROOTNODE, MEMP_NUM_SNMP_ROOTNODE, sizeof(struct mib_list_rootnode), "SNMP_ROOTNODE")
|
||||
LWIP_MEMPOOL(SNMP_NODE, MEMP_NUM_SNMP_NODE, sizeof(struct mib_list_node), "SNMP_NODE")
|
||||
LWIP_MEMPOOL(SNMP_VARBIND, MEMP_NUM_SNMP_VARBIND, sizeof(struct snmp_varbind), "SNMP_VARBIND")
|
||||
LWIP_MEMPOOL(SNMP_VALUE, MEMP_NUM_SNMP_VALUE, SNMP_MAX_VALUE_SIZE, "SNMP_VALUE")
|
||||
#endif /* LWIP_SNMP */
|
||||
#if LWIP_DNS && LWIP_SOCKET
|
||||
LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB")
|
||||
#endif /* LWIP_DNS && LWIP_SOCKET */
|
||||
#if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
||||
LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST")
|
||||
#endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
||||
#if PPP_SUPPORT && PPPOE_SUPPORT
|
||||
LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF")
|
||||
#endif /* PPP_SUPPORT && PPPOE_SUPPORT */
|
||||
|
||||
#if LWIP_IPV6 && LWIP_ND6_QUEUEING
|
||||
LWIP_MEMPOOL(ND6_QUEUE, MEMP_NUM_ND6_QUEUE, sizeof(struct nd6_q_entry), "ND6_QUEUE")
|
||||
#endif /* LWIP_IPV6 && LWIP_ND6_QUEUEING */
|
||||
|
||||
#if LWIP_IPV6 && LWIP_IPV6_REASS
|
||||
LWIP_MEMPOOL(IP6_REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip6_reassdata), "IP6_REASSDATA")
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */
|
||||
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
LWIP_MEMPOOL(MLD6_GROUP, MEMP_NUM_MLD6_GROUP, sizeof(struct mld_group), "MLD6_GROUP")
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -34,15 +34,31 @@
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** This netbuf has dest-addr/port set */
|
||||
#define NETBUF_FLAG_DESTADDR 0x01
|
||||
/** This netbuf includes a checksum */
|
||||
#define NETBUF_FLAG_CHKSUM 0x02
|
||||
|
||||
struct netbuf {
|
||||
struct pbuf *p, *ptr;
|
||||
struct ip_addr *addr;
|
||||
ipX_addr_t addr;
|
||||
u16_t port;
|
||||
#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
u8_t flags;
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
u16_t toport_chksum;
|
||||
#if LWIP_NETBUF_RECVINFO
|
||||
ipX_addr_t toaddr;
|
||||
#endif /* LWIP_NETBUF_RECVINFO */
|
||||
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
|
||||
};
|
||||
|
||||
/* Network buffer functions: */
|
||||
@@ -51,13 +67,12 @@ void netbuf_delete (struct netbuf *buf);
|
||||
void * netbuf_alloc (struct netbuf *buf, u16_t size);
|
||||
void netbuf_free (struct netbuf *buf);
|
||||
err_t netbuf_ref (struct netbuf *buf,
|
||||
const void *dataptr, u16_t size);
|
||||
const void *dataptr, u16_t size);
|
||||
void netbuf_chain (struct netbuf *head,
|
||||
struct netbuf *tail);
|
||||
|
||||
u16_t netbuf_len (struct netbuf *buf);
|
||||
err_t netbuf_data (struct netbuf *buf,
|
||||
void **dataptr, u16_t *len);
|
||||
void **dataptr, u16_t *len);
|
||||
s8_t netbuf_next (struct netbuf *buf);
|
||||
void netbuf_first (struct netbuf *buf);
|
||||
|
||||
@@ -65,9 +80,30 @@ void netbuf_first (struct netbuf *buf);
|
||||
#define netbuf_copy_partial(buf, dataptr, len, offset) \
|
||||
pbuf_copy_partial((buf)->p, (dataptr), (len), (offset))
|
||||
#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0)
|
||||
#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len)
|
||||
#define netbuf_len(buf) ((buf)->p->tot_len)
|
||||
#define netbuf_fromaddr(buf) ((buf)->addr)
|
||||
#define netbuf_fromaddr(buf) (ipX_2_ip(&((buf)->addr)))
|
||||
#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set(ipX_2_ip(&((buf)->addr)), fromaddr)
|
||||
#define netbuf_fromport(buf) ((buf)->port)
|
||||
#if LWIP_NETBUF_RECVINFO
|
||||
#define netbuf_destaddr(buf) (ipX_2_ip(&((buf)->toaddr)))
|
||||
#define netbuf_set_destaddr(buf, destaddr) ip_addr_set(ipX_2_ip(&((buf)->toaddr)), destaddr)
|
||||
#define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0)
|
||||
#endif /* LWIP_NETBUF_RECVINFO */
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
#define netbuf_set_chksum(buf, chksum) do { (buf)->flags = NETBUF_FLAG_CHKSUM; \
|
||||
(buf)->toport_chksum = chksum; } while(0)
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
|
||||
#if LWIP_IPV6
|
||||
#define netbuf_fromaddr_ip6(buf) (ipX_2_ip6(&((buf)->addr)))
|
||||
#define netbuf_set_fromaddr_ip6(buf, fromaddr) ip6_addr_set(ipX_2_ip6(&((buf)->addr)), fromaddr)
|
||||
#define netbuf_destaddr_ip6(buf) (ipX_2_ip6(&((buf)->toaddr)))
|
||||
#define netbuf_set_destaddr_ip6(buf, destaddr) ip6_addr_set(ipX_2_ip6(&((buf)->toaddr)), destaddr)
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#define netbuf_fromaddr_ipX(buf) (&((buf)->addr))
|
||||
#define netbuf_destaddr_ipX(buf) (&((buf)->toaddr))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -26,13 +26,22 @@
|
||||
* Author: Simon Goldschmidt
|
||||
*
|
||||
*/
|
||||
#ifndef __LWIP_NETDB_H__
|
||||
#define __LWIP_NETDB_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_DNS && LWIP_SOCKET
|
||||
|
||||
#include <stddef.h> /* for size_t */
|
||||
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/sockets.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* some rarely used options */
|
||||
#ifndef LWIP_DNS_API_DECLARE_H_ERRNO
|
||||
#define LWIP_DNS_API_DECLARE_H_ERRNO 1
|
||||
@@ -101,9 +110,15 @@ int lwip_getaddrinfo(const char *nodename,
|
||||
#define gethostbyname(name) lwip_gethostbyname(name)
|
||||
#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \
|
||||
lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop)
|
||||
#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(a)
|
||||
#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo)
|
||||
#define getaddrinfo(nodname, servname, hints, res) \
|
||||
lwip_getaddrinfo(nodname, servname, hints, res)
|
||||
#endif /* LWIP_COMPAT_SOCKETS */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_DNS && LWIP_SOCKET */
|
||||
|
||||
#endif /* __LWIP_NETDB_H__ */
|
||||
|
||||
@@ -34,11 +34,14 @@
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF)
|
||||
|
||||
#include "lwip/err.h"
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#if LWIP_DHCP
|
||||
struct dhcp;
|
||||
@@ -46,6 +49,9 @@ struct dhcp;
|
||||
#if LWIP_AUTOIP
|
||||
struct autoip;
|
||||
#endif
|
||||
#if LWIP_IPV6_DHCP6
|
||||
#include "lwip/dhcp6.h"
|
||||
#endif /* LWIP_IPV6_DHCP6 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -58,61 +64,138 @@ extern "C" {
|
||||
across all types of interfaces in use */
|
||||
#define NETIF_MAX_HWADDR_LEN 6U
|
||||
|
||||
/** TODO: define the use (where, when, whom) of netif flags */
|
||||
|
||||
/** whether the network interface is 'up'. this is
|
||||
/** Whether the network interface is 'up'. This is
|
||||
* a software flag used to control whether this network
|
||||
* interface is enabled and processes traffic.
|
||||
* It is set by the startup code (for static IP configuration) or
|
||||
* by dhcp/autoip when an address has been assigned.
|
||||
*/
|
||||
#define NETIF_FLAG_UP 0x01U
|
||||
/** if set, the netif has broadcast capability */
|
||||
/** If set, the netif has broadcast capability.
|
||||
* Set by the netif driver in its init function. */
|
||||
#define NETIF_FLAG_BROADCAST 0x02U
|
||||
/** if set, the netif is one end of a point-to-point connection */
|
||||
/** If set, the netif is one end of a point-to-point connection.
|
||||
* Set by the netif driver in its init function. */
|
||||
#define NETIF_FLAG_POINTTOPOINT 0x04U
|
||||
/** if set, the interface is configured using DHCP */
|
||||
/** If set, the interface is configured using DHCP.
|
||||
* Set by the DHCP code when starting or stopping DHCP. */
|
||||
#define NETIF_FLAG_DHCP 0x08U
|
||||
/** if set, the interface has an active link
|
||||
* (set by the network interface driver) */
|
||||
/** If set, the interface has an active link
|
||||
* (set by the network interface driver).
|
||||
* Either set by the netif driver in its init function (if the link
|
||||
* is up at that time) or at a later point once the link comes up
|
||||
* (if link detection is supported by the hardware). */
|
||||
#define NETIF_FLAG_LINK_UP 0x10U
|
||||
/** if set, the netif is an device using ARP */
|
||||
/** If set, the netif is an ethernet device using ARP.
|
||||
* Set by the netif driver in its init function.
|
||||
* Used to check input packet types and use of DHCP. */
|
||||
#define NETIF_FLAG_ETHARP 0x20U
|
||||
/** if set, the netif has IGMP capability */
|
||||
#define NETIF_FLAG_IGMP 0x40U
|
||||
/** If set, the netif is an ethernet device. It might not use
|
||||
* ARP or TCP/IP if it is used for PPPoE only.
|
||||
*/
|
||||
#define NETIF_FLAG_ETHERNET 0x40U
|
||||
/** If set, the netif has IGMP capability.
|
||||
* Set by the netif driver in its init function. */
|
||||
#define NETIF_FLAG_IGMP 0x80U
|
||||
|
||||
/** Function prototype for netif init functions. Set up flags and output/linkoutput
|
||||
* callback functions in this function.
|
||||
*
|
||||
* @param netif The netif to initialize
|
||||
*/
|
||||
typedef err_t (*netif_init_fn)(struct netif *netif);
|
||||
/** Function prototype for netif->input functions. This function is saved as 'input'
|
||||
* callback function in the netif struct. Call it when a packet has been received.
|
||||
*
|
||||
* @param p The received packet, copied into a pbuf
|
||||
* @param inp The netif which received the packet
|
||||
*/
|
||||
typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp);
|
||||
/** Function prototype for netif->output functions. Called by lwIP when a packet
|
||||
* shall be sent. For ethernet netif, set this to 'etharp_output' and set
|
||||
* 'linkoutput'.
|
||||
*
|
||||
* @param netif The netif which shall send a packet
|
||||
* @param p The packet to send (p->payload points to IP header)
|
||||
* @param ipaddr The IP address to which the packet shall be sent
|
||||
*/
|
||||
typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p,
|
||||
ip_addr_t *ipaddr);
|
||||
#if LWIP_IPV6
|
||||
/** Function prototype for netif->output_ip6 functions. Called by lwIP when a packet
|
||||
* shall be sent. For ethernet netif, set this to 'nd_output' and set
|
||||
* 'linkoutput'.
|
||||
*
|
||||
* @param netif The netif which shall send a packet
|
||||
* @param p The packet to send (p->payload points to IP header)
|
||||
* @param ipaddr The IPv6 address to which the packet shall be sent
|
||||
*/
|
||||
typedef err_t (*netif_output_ip6_fn)(struct netif *netif, struct pbuf *p,
|
||||
ip6_addr_t *ipaddr);
|
||||
#endif /* LWIP_IPV6 */
|
||||
/** Function prototype for netif->linkoutput functions. Only used for ethernet
|
||||
* netifs. This function is called by ARP when a packet shall be sent.
|
||||
*
|
||||
* @param netif The netif which shall send a packet
|
||||
* @param p The packet to send (raw ethernet packet)
|
||||
*/
|
||||
typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p);
|
||||
/** Function prototype for netif status- or link-callback functions. */
|
||||
typedef void (*netif_status_callback_fn)(struct netif *netif);
|
||||
/** Function prototype for netif igmp_mac_filter functions */
|
||||
typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif,
|
||||
ip_addr_t *group, u8_t action);
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
/** Function prototype for netif mld_mac_filter functions */
|
||||
typedef err_t (*netif_mld_mac_filter_fn)(struct netif *netif,
|
||||
ip6_addr_t *group, u8_t action);
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
|
||||
|
||||
/** Generic data structure used for all lwIP network interfaces.
|
||||
* The following fields should be filled in by the initialization
|
||||
* function for the device driver: hwaddr_len, hwaddr[], mtu, flags */
|
||||
|
||||
struct netif {
|
||||
/** pointer to next in linked list */
|
||||
struct netif *next;
|
||||
|
||||
/** IP address configuration in network byte order */
|
||||
struct ip_addr ip_addr;
|
||||
struct ip_addr netmask;
|
||||
struct ip_addr gw;
|
||||
ip_addr_t ip_addr;
|
||||
ip_addr_t netmask;
|
||||
ip_addr_t gw;
|
||||
|
||||
#if LWIP_IPV6
|
||||
/** Array of IPv6 addresses for this netif. */
|
||||
ip6_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES];
|
||||
/** The state of each IPv6 address (Tentative, Preferred, etc).
|
||||
* @see ip6_addr.h */
|
||||
u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES];
|
||||
#endif /* LWIP_IPV6 */
|
||||
/** This function is called by the network device driver
|
||||
* to pass a packet up the TCP/IP stack. */
|
||||
err_t (* input)(struct pbuf *p, struct netif *inp);
|
||||
netif_input_fn input;
|
||||
/** This function is called by the IP module when it wants
|
||||
* to send a packet on the interface. This function typically
|
||||
* first resolves the hardware address, then sends the packet. */
|
||||
err_t (* output)(struct netif *netif, struct pbuf *p,
|
||||
struct ip_addr *ipaddr);
|
||||
netif_output_fn output;
|
||||
/** This function is called by the ARP module when it wants
|
||||
* to send a packet on the interface. This function outputs
|
||||
* the pbuf as-is on the link medium. */
|
||||
err_t (* linkoutput)(struct netif *netif, struct pbuf *p);
|
||||
netif_linkoutput_fn linkoutput;
|
||||
#if LWIP_IPV6
|
||||
/** This function is called by the IPv6 module when it wants
|
||||
* to send a packet on the interface. This function typically
|
||||
* first resolves the hardware address, then sends the packet. */
|
||||
netif_output_ip6_fn output_ip6;
|
||||
#endif /* LWIP_IPV6 */
|
||||
#if LWIP_NETIF_STATUS_CALLBACK
|
||||
/** This function is called when the netif state is set to up or down
|
||||
*/
|
||||
void (* status_callback)(struct netif *netif);
|
||||
netif_status_callback_fn status_callback;
|
||||
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
||||
#if LWIP_NETIF_LINK_CALLBACK
|
||||
/** This function is called when the netif link is set to up or down
|
||||
*/
|
||||
void (* link_callback)(struct netif *netif);
|
||||
netif_status_callback_fn link_callback;
|
||||
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
||||
/** This field can be set by the device driver and could point
|
||||
* to state information for the device. */
|
||||
@@ -125,16 +208,28 @@ struct netif {
|
||||
/** the AutoIP client state information for this netif */
|
||||
struct autoip *autoip;
|
||||
#endif
|
||||
#if LWIP_IPV6_AUTOCONFIG
|
||||
/** is this netif enabled for IPv6 autoconfiguration */
|
||||
u8_t ip6_autoconfig_enabled;
|
||||
#endif /* LWIP_IPV6_AUTOCONFIG */
|
||||
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
|
||||
/** Number of Router Solicitation messages that remain to be sent. */
|
||||
u8_t rs_count;
|
||||
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
|
||||
#if LWIP_IPV6_DHCP6
|
||||
/** the DHCPv6 client state information for this netif */
|
||||
struct dhcp6 *dhcp6;
|
||||
#endif /* LWIP_IPV6_DHCP6 */
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
/* the hostname for this netif, NULL is a valid value */
|
||||
char* hostname;
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
/** maximum transfer unit (in bytes) */
|
||||
u16_t mtu;
|
||||
/** number of bytes used in hwaddr */
|
||||
u8_t hwaddr_len;
|
||||
/** link level hardware address of this interface */
|
||||
u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
|
||||
/** maximum transfer unit (in bytes) */
|
||||
u16_t mtu;
|
||||
/** flags (see NETIF_FLAG_ above) */
|
||||
u8_t flags;
|
||||
/** descriptive abbreviation */
|
||||
@@ -159,29 +254,43 @@ struct netif {
|
||||
u32_t ifoutdiscards;
|
||||
#endif /* LWIP_SNMP */
|
||||
#if LWIP_IGMP
|
||||
/* This function could be called to add or delete a entry in the multicast filter table of the ethernet MAC.*/
|
||||
err_t (*igmp_mac_filter)( struct netif *netif, struct ip_addr *group, u8_t action);
|
||||
/** This function could be called to add or delete an entry in the multicast
|
||||
filter table of the ethernet MAC.*/
|
||||
netif_igmp_mac_filter_fn igmp_mac_filter;
|
||||
#endif /* LWIP_IGMP */
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
/** This function could be called to add or delete an entry in the IPv6 multicast
|
||||
filter table of the ethernet MAC. */
|
||||
netif_mld_mac_filter_fn mld_mac_filter;
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
u8_t *addr_hint;
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
#if ENABLE_LOOPBACK
|
||||
/* List of packets to be queued for ourselves. */
|
||||
struct pbuf *loop_first;
|
||||
struct pbuf *loop_last;
|
||||
#if LWIP_LOOPBACK_MAX_PBUFS
|
||||
u16_t loop_cnt_current;
|
||||
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
};
|
||||
|
||||
#if LWIP_SNMP
|
||||
#define NETIF_INIT_SNMP(netif, type, speed) \
|
||||
/* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \
|
||||
netif->link_type = type; \
|
||||
(netif)->link_type = (type); \
|
||||
/* your link speed here (units: bits per second) */ \
|
||||
netif->link_speed = speed; \
|
||||
netif->ts = 0; \
|
||||
netif->ifinoctets = 0; \
|
||||
netif->ifinucastpkts = 0; \
|
||||
netif->ifinnucastpkts = 0; \
|
||||
netif->ifindiscards = 0; \
|
||||
netif->ifoutoctets = 0; \
|
||||
netif->ifoutucastpkts = 0; \
|
||||
netif->ifoutnucastpkts = 0; \
|
||||
netif->ifoutdiscards = 0
|
||||
(netif)->link_speed = (speed); \
|
||||
(netif)->ts = 0; \
|
||||
(netif)->ifinoctets = 0; \
|
||||
(netif)->ifinucastpkts = 0; \
|
||||
(netif)->ifinnucastpkts = 0; \
|
||||
(netif)->ifindiscards = 0; \
|
||||
(netif)->ifoutoctets = 0; \
|
||||
(netif)->ifoutucastpkts = 0; \
|
||||
(netif)->ifoutnucastpkts = 0; \
|
||||
(netif)->ifoutdiscards = 0
|
||||
#else /* LWIP_SNMP */
|
||||
#define NETIF_INIT_SNMP(netif, type, speed)
|
||||
#endif /* LWIP_SNMP */
|
||||
@@ -192,17 +301,14 @@ extern struct netif *netif_list;
|
||||
/** The default network interface. */
|
||||
extern struct netif *netif_default;
|
||||
|
||||
#define netif_init() /* Compatibility define, not init needed. */
|
||||
void netif_init(void);
|
||||
|
||||
struct netif *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));
|
||||
struct netif *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);
|
||||
|
||||
void
|
||||
netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask,
|
||||
struct ip_addr *gw);
|
||||
netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
|
||||
ip_addr_t *gw);
|
||||
void netif_remove(struct netif * netif);
|
||||
|
||||
/* Returns a network interface given its name. The name is of the form
|
||||
@@ -213,31 +319,60 @@ struct netif *netif_find(char *name);
|
||||
|
||||
void netif_set_default(struct netif *netif);
|
||||
|
||||
void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr);
|
||||
void netif_set_netmask(struct netif *netif, struct ip_addr *netmask);
|
||||
void netif_set_gw(struct netif *netif, struct ip_addr *gw);
|
||||
void netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr);
|
||||
void netif_set_netmask(struct netif *netif, ip_addr_t *netmask);
|
||||
void netif_set_gw(struct netif *netif, ip_addr_t *gw);
|
||||
|
||||
void netif_set_up(struct netif *netif);
|
||||
void netif_set_down(struct netif *netif);
|
||||
u8_t netif_is_up(struct netif *netif);
|
||||
/** Ask if an interface is up */
|
||||
#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0)
|
||||
|
||||
#if LWIP_NETIF_STATUS_CALLBACK
|
||||
/*
|
||||
* Set callback to be called when interface is brought up/down
|
||||
*/
|
||||
void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif));
|
||||
void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback);
|
||||
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
||||
|
||||
#if LWIP_NETIF_LINK_CALLBACK
|
||||
void netif_set_link_up(struct netif *netif);
|
||||
void netif_set_link_down(struct netif *netif);
|
||||
u8_t netif_is_link_up(struct netif *netif);
|
||||
/*
|
||||
* Set callback to be called when link is brought up/down
|
||||
*/
|
||||
void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif));
|
||||
/** Ask if a link is up */
|
||||
#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0)
|
||||
|
||||
#if LWIP_NETIF_LINK_CALLBACK
|
||||
void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback);
|
||||
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0)
|
||||
#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL)
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
#if LWIP_IGMP
|
||||
#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0)
|
||||
#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL)
|
||||
#endif /* LWIP_IGMP */
|
||||
|
||||
#if ENABLE_LOOPBACK
|
||||
err_t netif_loop_output(struct netif *netif, struct pbuf *p, ip_addr_t *dest_ip);
|
||||
void netif_poll(struct netif *netif);
|
||||
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
|
||||
void netif_poll_all(void);
|
||||
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
|
||||
#if LWIP_IPV6
|
||||
#define netif_ip6_addr(netif, i) (&(netif->ip6_addr[(i)]))
|
||||
#define netif_ip6_addr_state(netif, i) (netif->ip6_addr_state[(i)])
|
||||
#define netif_ip6_addr_set_state(netif, i, state) (netif->ip6_addr_state[(i)] = (state))
|
||||
s8_t netif_matches_ip6_addr(struct netif * netif, ip6_addr_t * ip6addr);
|
||||
void netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit);
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
#define NETIF_SET_HWADDRHINT(netif, hint) ((netif)->addr_hint = (hint))
|
||||
#else /* LWIP_NETIF_HWADDRHINT */
|
||||
#define NETIF_SET_HWADDRHINT(netif, hint)
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -41,6 +41,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*netifapi_void_fn)(struct netif *netif);
|
||||
typedef err_t (*netifapi_errt_fn)(struct netif *netif);
|
||||
|
||||
struct netifapi_msg_msg {
|
||||
#if !LWIP_TCPIP_CORE_LOCKING
|
||||
sys_sem_t sem;
|
||||
@@ -49,16 +52,16 @@ struct netifapi_msg_msg {
|
||||
struct netif *netif;
|
||||
union {
|
||||
struct {
|
||||
struct ip_addr *ipaddr;
|
||||
struct ip_addr *netmask;
|
||||
struct ip_addr *gw;
|
||||
ip_addr_t *ipaddr;
|
||||
ip_addr_t *netmask;
|
||||
ip_addr_t *gw;
|
||||
void *state;
|
||||
err_t (* init) (struct netif *netif);
|
||||
err_t (* input)(struct pbuf *p, struct netif *netif);
|
||||
netif_init_fn init;
|
||||
netif_input_fn input;
|
||||
} add;
|
||||
struct {
|
||||
void (* voidfunc)(struct netif *netif);
|
||||
err_t (* errtfunc)(struct netif *netif);
|
||||
netifapi_void_fn voidfunc;
|
||||
netifapi_errt_fn errtfunc;
|
||||
} common;
|
||||
} msg;
|
||||
};
|
||||
@@ -71,16 +74,21 @@ struct netifapi_msg {
|
||||
|
||||
/* API for application */
|
||||
err_t netifapi_netif_add ( struct netif *netif,
|
||||
struct ip_addr *ipaddr,
|
||||
struct ip_addr *netmask,
|
||||
struct ip_addr *gw,
|
||||
ip_addr_t *ipaddr,
|
||||
ip_addr_t *netmask,
|
||||
ip_addr_t *gw,
|
||||
void *state,
|
||||
err_t (* init)(struct netif *netif),
|
||||
err_t (* input)(struct pbuf *p, struct netif *netif) );
|
||||
netif_init_fn init,
|
||||
netif_input_fn input);
|
||||
|
||||
err_t netifapi_netif_set_addr ( struct netif *netif,
|
||||
ip_addr_t *ipaddr,
|
||||
ip_addr_t *netmask,
|
||||
ip_addr_t *gw );
|
||||
|
||||
err_t netifapi_netif_common ( struct netif *netif,
|
||||
void (* voidfunc)(struct netif *netif),
|
||||
err_t (* errtfunc)(struct netif *netif) );
|
||||
netifapi_void_fn voidfunc,
|
||||
netifapi_errt_fn errtfunc);
|
||||
|
||||
#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL)
|
||||
#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,8 +40,19 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Currently, the pbuf_custom code is only needed for one specific configuration
|
||||
* of IP_FRAG */
|
||||
#define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF)
|
||||
|
||||
/* @todo: We need a mechanism to prevent wasting memory in every pbuf
|
||||
(TCP vs. UDP, IPv4 vs. IPv6: UDP/IPv4 packets may waste up to 28 bytes) */
|
||||
|
||||
#define PBUF_TRANSPORT_HLEN 20
|
||||
#if LWIP_IPV6
|
||||
#define PBUF_IP_HLEN 40
|
||||
#else
|
||||
#define PBUF_IP_HLEN 20
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
PBUF_TRANSPORT,
|
||||
@@ -59,7 +70,12 @@ typedef enum {
|
||||
|
||||
|
||||
/** indicates this packet's data should be immediately passed to the application */
|
||||
#define PBUF_FLAG_PUSH 0x01U
|
||||
#define PBUF_FLAG_PUSH 0x01U
|
||||
/** indicates this is a custom pbuf: pbuf_free and pbuf_header handle such a
|
||||
a pbuf differently */
|
||||
#define PBUF_FLAG_IS_CUSTOM 0x02U
|
||||
/** indicates this pbuf is UDP multicast to be looped back */
|
||||
#define PBUF_FLAG_MCASTLOOP 0x04U
|
||||
|
||||
struct pbuf {
|
||||
/** next pbuf in singly linked pbuf chain */
|
||||
@@ -67,7 +83,7 @@ struct pbuf {
|
||||
|
||||
/** pointer to the actual data in the buffer */
|
||||
void *payload;
|
||||
|
||||
|
||||
/**
|
||||
* total length of this buffer and all next buffers in chain
|
||||
* belonging to the same packet.
|
||||
@@ -76,9 +92,9 @@ struct pbuf {
|
||||
* p->tot_len == p->len + (p->next? p->next->tot_len: 0)
|
||||
*/
|
||||
u16_t tot_len;
|
||||
|
||||
|
||||
/** length of this buffer */
|
||||
u16_t len;
|
||||
u16_t len;
|
||||
|
||||
/** pbuf_type as u8_t instead of enum to save space */
|
||||
u8_t /*pbuf_type*/ type;
|
||||
@@ -92,17 +108,33 @@ struct pbuf {
|
||||
* the stack itself, or pbuf->next pointers from a chain.
|
||||
*/
|
||||
u16_t ref;
|
||||
|
||||
};
|
||||
|
||||
#if LWIP_SUPPORT_CUSTOM_PBUF
|
||||
/** Prototype for a function to free a custom pbuf */
|
||||
typedef void (*pbuf_free_custom_fn)(struct pbuf *p);
|
||||
|
||||
/** A custom pbuf: like a pbuf, but following a function pointer to free it. */
|
||||
struct pbuf_custom {
|
||||
/** The actual pbuf */
|
||||
struct pbuf pbuf;
|
||||
/** This function is called when pbuf_free deallocates this pbuf(_custom) */
|
||||
pbuf_free_custom_fn custom_free_function;
|
||||
};
|
||||
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
|
||||
|
||||
/* Initializes the pbuf module. This call is empty for now, but may not be in future. */
|
||||
#define pbuf_init()
|
||||
|
||||
struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_type type);
|
||||
struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type);
|
||||
#if LWIP_SUPPORT_CUSTOM_PBUF
|
||||
struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type,
|
||||
struct pbuf_custom *p, void *payload_mem,
|
||||
u16_t payload_mem_len);
|
||||
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
|
||||
void pbuf_realloc(struct pbuf *p, u16_t size);
|
||||
u8_t pbuf_header(struct pbuf *p, s16_t header_size);
|
||||
void pbuf_ref(struct pbuf *p);
|
||||
void pbuf_ref_chain(struct pbuf *p);
|
||||
u8_t pbuf_free(struct pbuf *p);
|
||||
u8_t pbuf_clen(struct pbuf *p);
|
||||
void pbuf_cat(struct pbuf *head, struct pbuf *tail);
|
||||
@@ -110,6 +142,17 @@ void pbuf_chain(struct pbuf *head, struct pbuf *tail);
|
||||
struct pbuf *pbuf_dechain(struct pbuf *p);
|
||||
err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from);
|
||||
u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset);
|
||||
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len);
|
||||
struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer);
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
|
||||
u16_t len, u16_t *chksum);
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
|
||||
u8_t pbuf_get_at(struct pbuf* p, u16_t offset);
|
||||
u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n);
|
||||
u16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset);
|
||||
u16_t pbuf_strstr(struct pbuf* p, const char* substr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -37,34 +37,64 @@
|
||||
#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct raw_pcb;
|
||||
|
||||
/** Function prototype for raw pcb receive callback functions.
|
||||
* @param arg user supplied argument (raw_pcb.recv_arg)
|
||||
* @param pcb the raw_pcb which received data
|
||||
* @param p the packet buffer that was received
|
||||
* @param addr the remote IP address from which the packet was received
|
||||
* @return 1 if the packet was 'eaten' (aka. deleted),
|
||||
* 0 if the packet lives on
|
||||
* If returning 1, the callback is responsible for freeing the pbuf
|
||||
* if it's not used any more.
|
||||
*/
|
||||
typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
|
||||
ip_addr_t *addr);
|
||||
|
||||
#if LWIP_IPV6
|
||||
/** Function prototype for raw pcb IPv6 receive callback functions.
|
||||
* @param arg user supplied argument (raw_pcb.recv_arg)
|
||||
* @param pcb the raw_pcb which received data
|
||||
* @param p the packet buffer that was received
|
||||
* @param addr the remote IPv6 address from which the packet was received
|
||||
* @return 1 if the packet was 'eaten' (aka. deleted),
|
||||
* 0 if the packet lives on
|
||||
* If returning 1, the callback is responsible for freeing the pbuf
|
||||
* if it's not used any more.
|
||||
*/
|
||||
typedef u8_t (*raw_recv_ip6_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
|
||||
ip6_addr_t *addr);
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#if LWIP_IPV6
|
||||
#define RAW_PCB_RECV_IP6 raw_recv_ip6_fn ip6;
|
||||
#else
|
||||
#define RAW_PCB_RECV_IP6
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
struct raw_pcb {
|
||||
/* Common members of all PCB types */
|
||||
/* Common members of all PCB types */
|
||||
IP_PCB;
|
||||
|
||||
struct raw_pcb *next;
|
||||
|
||||
u8_t protocol;
|
||||
|
||||
/* receive callback function
|
||||
* @param arg user supplied argument (raw_pcb.recv_arg)
|
||||
* @param pcb the raw_pcb which received data
|
||||
* @param p the packet buffer that was received
|
||||
* @param addr the remote IP address from which the packet was received
|
||||
* @return 1 if the packet was 'eaten' (aka. deleted),
|
||||
* 0 if the packet lives on
|
||||
* If returning 1, the callback is responsible for freeing the pbuf
|
||||
* if it's not used any more.
|
||||
*/
|
||||
u8_t (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
|
||||
struct ip_addr *addr);
|
||||
/** receive callback function */
|
||||
union {
|
||||
raw_recv_fn ip4;
|
||||
RAW_PCB_RECV_IP6
|
||||
} recv;
|
||||
/* user-supplied argument for the recv callback */
|
||||
void *recv_arg;
|
||||
};
|
||||
@@ -73,17 +103,21 @@ struct raw_pcb {
|
||||
RAW code. */
|
||||
struct raw_pcb * raw_new (u8_t proto);
|
||||
void raw_remove (struct raw_pcb *pcb);
|
||||
err_t raw_bind (struct raw_pcb *pcb, struct ip_addr *ipaddr);
|
||||
err_t raw_connect (struct raw_pcb *pcb, struct ip_addr *ipaddr);
|
||||
err_t raw_bind (struct raw_pcb *pcb, ip_addr_t *ipaddr);
|
||||
err_t raw_connect (struct raw_pcb *pcb, ip_addr_t *ipaddr);
|
||||
|
||||
void raw_recv (struct raw_pcb *pcb,
|
||||
u8_t (* recv)(void *arg, struct raw_pcb *pcb,
|
||||
struct pbuf *p,
|
||||
struct ip_addr *addr),
|
||||
void *recv_arg);
|
||||
err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr);
|
||||
void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg);
|
||||
err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr);
|
||||
err_t raw_send (struct raw_pcb *pcb, struct pbuf *p);
|
||||
|
||||
#if LWIP_IPV6
|
||||
struct raw_pcb * raw_new_ip6 (u8_t proto);
|
||||
#define raw_bind_ip6(pcb, ip6addr) raw_bind(pcb, ip6_2_ip(ip6addr))
|
||||
#define raw_connect_ip6(pcb, ip6addr) raw_connect(pcb, ip6_2_ip(ip6addr))
|
||||
#define raw_recv_ip6(pcb, recv_ip6_fn, recv_arg) raw_recv(pcb, (raw_recv_fn)recv_ip6_fn, recv_arg)
|
||||
#define raw_sendto_ip6(pcb, pbuf, ip6addr) raw_sendto(pcb, pbuf, ip6_2_ip(ip6addr))
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
/* The following functions are the lower layer interface to RAW. */
|
||||
u8_t raw_input (struct pbuf *p, struct netif *inp);
|
||||
#define raw_init() /* Compatibility define, not init needed. */
|
||||
|
||||
@@ -32,40 +32,110 @@
|
||||
* It needs to be implemented by those platforms which need SLIP or PPP
|
||||
*/
|
||||
|
||||
#ifndef __SIO_H__
|
||||
#define __SIO_H__
|
||||
|
||||
#include "lwip/arch.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* If you want to define sio_fd_t elsewhere or differently,
|
||||
define this in your cc.h file. */
|
||||
#ifndef __sio_fd_t_defined
|
||||
typedef void * sio_fd_t;
|
||||
#endif
|
||||
|
||||
/* The following functions can be defined to something else in your cc.h file
|
||||
or be implemented in your custom sio.c file. */
|
||||
|
||||
#ifndef sio_open
|
||||
sio_fd_t sio_open(u8_t);
|
||||
/**
|
||||
* Opens a serial device for communication.
|
||||
*
|
||||
* @param devnum device number
|
||||
* @return handle to serial device if successful, NULL otherwise
|
||||
*/
|
||||
sio_fd_t sio_open(u8_t devnum);
|
||||
#endif
|
||||
|
||||
#ifndef sio_send
|
||||
void sio_send(u8_t, sio_fd_t);
|
||||
/**
|
||||
* Sends a single character to the serial device.
|
||||
*
|
||||
* @param c character to send
|
||||
* @param fd serial device handle
|
||||
*
|
||||
* @note This function will block until the character can be sent.
|
||||
*/
|
||||
void sio_send(u8_t c, sio_fd_t fd);
|
||||
#endif
|
||||
|
||||
#ifndef sio_recv
|
||||
u8_t sio_recv(sio_fd_t);
|
||||
/**
|
||||
* Receives a single character from the serial device.
|
||||
*
|
||||
* @param fd serial device handle
|
||||
*
|
||||
* @note This function will block until a character is received.
|
||||
*/
|
||||
u8_t sio_recv(sio_fd_t fd);
|
||||
#endif
|
||||
|
||||
#ifndef sio_read
|
||||
u32_t sio_read(sio_fd_t, u8_t *, u32_t);
|
||||
/**
|
||||
* Reads from the serial device.
|
||||
*
|
||||
* @param fd serial device handle
|
||||
* @param data pointer to data buffer for receiving
|
||||
* @param len maximum length (in bytes) of data to receive
|
||||
* @return number of bytes actually received - may be 0 if aborted by sio_read_abort
|
||||
*
|
||||
* @note This function will block until data can be received. The blocking
|
||||
* can be cancelled by calling sio_read_abort().
|
||||
*/
|
||||
u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len);
|
||||
#endif
|
||||
|
||||
#ifndef sio_tryread
|
||||
/**
|
||||
* Tries to read from the serial device. Same as sio_read but returns
|
||||
* immediately if no data is available and never blocks.
|
||||
*
|
||||
* @param fd serial device handle
|
||||
* @param data pointer to data buffer for receiving
|
||||
* @param len maximum length (in bytes) of data to receive
|
||||
* @return number of bytes actually received
|
||||
*/
|
||||
u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len);
|
||||
#endif
|
||||
|
||||
#ifndef sio_write
|
||||
u32_t sio_write(sio_fd_t, u8_t *, u32_t);
|
||||
/**
|
||||
* Writes to the serial device.
|
||||
*
|
||||
* @param fd serial device handle
|
||||
* @param data pointer to data to send
|
||||
* @param len length (in bytes) of data to send
|
||||
* @return number of bytes actually sent
|
||||
*
|
||||
* @note This function will block until all data can be sent.
|
||||
*/
|
||||
u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len);
|
||||
#endif
|
||||
|
||||
#ifndef sio_read_abort
|
||||
void sio_read_abort(sio_fd_t);
|
||||
/**
|
||||
* Aborts a blocking sio_read() call.
|
||||
*
|
||||
* @param fd serial device handle
|
||||
*/
|
||||
void sio_read_abort(sio_fd_t fd);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SIO_H__ */
|
||||
|
||||
@@ -34,13 +34,16 @@
|
||||
#define __LWIP_SNMP_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/udp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
struct udp_pcb;
|
||||
struct netif;
|
||||
|
||||
/**
|
||||
* @see RFC1213, "MIB-II, 6. Definitions"
|
||||
*/
|
||||
@@ -118,8 +121,8 @@ void snmp_inc_iflist(void);
|
||||
void snmp_dec_iflist(void);
|
||||
|
||||
/* ARP (for atTable and ipNetToMediaTable) */
|
||||
void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip);
|
||||
void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip);
|
||||
void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip);
|
||||
void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip);
|
||||
|
||||
/* IP */
|
||||
void snmp_inc_ipinreceives(void);
|
||||
|
||||
@@ -40,16 +40,18 @@
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/snmp.h"
|
||||
|
||||
#if LWIP_SNMP
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SNMP_ASN1_UNIV (!0x80 | !0x40)
|
||||
#define SNMP_ASN1_APPLIC (!0x80 | 0x40)
|
||||
#define SNMP_ASN1_CONTXT ( 0x80 | !0x40)
|
||||
#define SNMP_ASN1_UNIV (0) /* (!0x80 | !0x40) */
|
||||
#define SNMP_ASN1_APPLIC (0x40) /* (!0x80 | 0x40) */
|
||||
#define SNMP_ASN1_CONTXT (0x80) /* ( 0x80 | !0x40) */
|
||||
|
||||
#define SNMP_ASN1_CONSTR (0x20)
|
||||
#define SNMP_ASN1_PRIMIT (!0x20)
|
||||
#define SNMP_ASN1_CONSTR (0x20) /* ( 0x20) */
|
||||
#define SNMP_ASN1_PRIMIT (0) /* (!0x20) */
|
||||
|
||||
/* universal tags */
|
||||
#define SNMP_ASN1_INTEG 2
|
||||
@@ -85,13 +87,15 @@ void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);
|
||||
void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed);
|
||||
err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type);
|
||||
err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length);
|
||||
err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value);
|
||||
err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value);
|
||||
err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value);
|
||||
err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value);
|
||||
err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident);
|
||||
err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw);
|
||||
err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
|
||||
#endif /* __LWIP_SNMP_ASN1_H__ */
|
||||
|
||||
@@ -38,8 +38,14 @@
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/snmp_structs.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/err.h"
|
||||
|
||||
#if LWIP_SNMP
|
||||
|
||||
#if SNMP_PRIVATE_MIB
|
||||
/* When using a private MIB, you have to create a file 'private_mib.h' that contains
|
||||
* a 'struct mib_array_node mib_private' which contains your MIB. */
|
||||
#include "private_mib.h"
|
||||
#endif
|
||||
|
||||
@@ -217,7 +223,7 @@ struct snmp_msg_pstat
|
||||
/* lwIP local port (161) binding */
|
||||
struct udp_pcb *pcb;
|
||||
/* source IP address */
|
||||
struct ip_addr sip;
|
||||
ip_addr_t sip;
|
||||
/* source UDP port */
|
||||
u16_t sp;
|
||||
/* request type */
|
||||
@@ -256,7 +262,7 @@ struct snmp_msg_trap
|
||||
/* lwIP local port (161) binding */
|
||||
struct udp_pcb *pcb;
|
||||
/* destination IP address in network order */
|
||||
struct ip_addr dip;
|
||||
ip_addr_t dip;
|
||||
|
||||
/* source enterprise ID (sysObjectID) */
|
||||
struct snmp_obj_id *enterprise;
|
||||
@@ -284,7 +290,7 @@ extern struct snmp_msg_trap trap_msg;
|
||||
/** Agent setup, start listening to port 161. */
|
||||
void snmp_init(void);
|
||||
void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable);
|
||||
void snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst);
|
||||
void snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst);
|
||||
|
||||
/** Varbind-list functions. */
|
||||
struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len);
|
||||
@@ -304,4 +310,6 @@ void snmp_authfail_trap(void);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
|
||||
#endif /* __LWIP_SNMP_MSG_H__ */
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
#include "lwip/snmp.h"
|
||||
|
||||
#if SNMP_PRIVATE_MIB
|
||||
/* When using a private MIB, you have to create a file 'private_mib.h' that contains
|
||||
* a 'struct mib_array_node mib_private' which contains your MIB. */
|
||||
#include "private_mib.h"
|
||||
#endif
|
||||
|
||||
@@ -56,11 +58,15 @@ extern "C" {
|
||||
#define MIB_OBJECT_SCALAR 1
|
||||
#define MIB_OBJECT_TAB 2
|
||||
|
||||
/* MIB access types */
|
||||
#define MIB_ACCESS_READ 1
|
||||
#define MIB_ACCESS_WRITE 2
|
||||
|
||||
/* MIB object access */
|
||||
#define MIB_OBJECT_READ_ONLY 0
|
||||
#define MIB_OBJECT_READ_WRITE 1
|
||||
#define MIB_OBJECT_WRITE_ONLY 2
|
||||
#define MIB_OBJECT_NOT_ACCESSIBLE 3
|
||||
#define MIB_OBJECT_READ_ONLY MIB_ACCESS_READ
|
||||
#define MIB_OBJECT_READ_WRITE (MIB_ACCESS_READ | MIB_ACCESS_WRITE)
|
||||
#define MIB_OBJECT_WRITE_ONLY MIB_ACCESS_WRITE
|
||||
#define MIB_OBJECT_NOT_ACCESSIBLE 0
|
||||
|
||||
/** object definition returned by (get_object_def)() */
|
||||
struct obj_def
|
||||
@@ -109,9 +115,9 @@ struct mib_node
|
||||
/** sets object value, only to be called when set_test() */
|
||||
void (*set_value)(struct obj_def *od, u16_t len, void *value);
|
||||
/** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */
|
||||
const u8_t node_type;
|
||||
u8_t node_type;
|
||||
/* array or max list length */
|
||||
const u16_t maxlength;
|
||||
u16_t maxlength;
|
||||
};
|
||||
|
||||
/** derived node for scalars .0 index */
|
||||
@@ -122,15 +128,15 @@ typedef struct mib_node mib_scalar_node;
|
||||
struct mib_array_node
|
||||
{
|
||||
/* inherited "base class" members */
|
||||
void (* const get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
|
||||
void (* const get_value)(struct obj_def *od, u16_t len, void *value);
|
||||
void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
|
||||
void (*get_value)(struct obj_def *od, u16_t len, void *value);
|
||||
u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
|
||||
void (*set_value)(struct obj_def *od, u16_t len, void *value);
|
||||
|
||||
const u8_t node_type;
|
||||
const u16_t maxlength;
|
||||
u8_t node_type;
|
||||
u16_t maxlength;
|
||||
|
||||
/* aditional struct members */
|
||||
/* additional struct members */
|
||||
const s32_t *objid;
|
||||
struct mib_node* const *nptr;
|
||||
};
|
||||
@@ -174,7 +180,7 @@ struct mib_list_rootnode
|
||||
u8_t node_type;
|
||||
u16_t maxlength;
|
||||
|
||||
/* aditional struct members */
|
||||
/* additional struct members */
|
||||
struct mib_list_node *head;
|
||||
struct mib_list_node *tail;
|
||||
/* counts list nodes in list */
|
||||
@@ -194,8 +200,8 @@ struct mib_external_node
|
||||
u8_t node_type;
|
||||
u16_t maxlength;
|
||||
|
||||
/* aditional struct members */
|
||||
/** points to an extenal (in memory) record of some sort of addressing
|
||||
/* additional struct members */
|
||||
/** points to an external (in memory) record of some sort of addressing
|
||||
information, passed to and interpreted by the funtions below */
|
||||
void* addr_inf;
|
||||
/** tree levels under this node */
|
||||
@@ -234,8 +240,8 @@ void noleafs_get_value(struct obj_def *od, u16_t len, void *value);
|
||||
u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value);
|
||||
void noleafs_set_value(struct obj_def *od, u16_t len, void *value);
|
||||
|
||||
void snmp_oidtoip(s32_t *ident, struct ip_addr *ip);
|
||||
void snmp_iptooid(struct ip_addr *ip, s32_t *ident);
|
||||
void snmp_oidtoip(s32_t *ident, ip_addr_t *ip);
|
||||
void snmp_iptooid(ip_addr_t *ip, s32_t *ident);
|
||||
void snmp_ifindextonetif(s32_t ifindex, struct netif **netif);
|
||||
void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user