55 |
*/ |
*/ |
56 |
static struct pbuf * |
static struct pbuf * |
57 |
copy_from_pbuf(struct pbuf *p, u16_t * offset, |
copy_from_pbuf(struct pbuf *p, u16_t * offset, |
58 |
u8_t * buffer, u16_t len) |
u8_t * buffer, u16_t len) |
59 |
{ |
{ |
60 |
u16_t l; |
u16_t l; |
61 |
|
|
98 |
ip_reasstmr--; |
ip_reasstmr--; |
99 |
sys_timeout(IP_REASS_TMO, ip_reass_timer, NULL); |
sys_timeout(IP_REASS_TMO, ip_reass_timer, NULL); |
100 |
} else if (ip_reasstmr == 1) |
} else if (ip_reasstmr == 1) |
101 |
ip_reasstmr = 0; |
ip_reasstmr = 0; |
102 |
} |
} |
103 |
|
|
104 |
struct pbuf * |
struct pbuf * |
147 |
reassembly buffer, we discard the entire packet. */ |
reassembly buffer, we discard the entire packet. */ |
148 |
if (offset > IP_REASS_BUFSIZE || offset + len > IP_REASS_BUFSIZE) { |
if (offset > IP_REASS_BUFSIZE || offset + len > IP_REASS_BUFSIZE) { |
149 |
DEBUGF(IP_REASS_DEBUG, |
DEBUGF(IP_REASS_DEBUG, |
150 |
("ip_reass: fragment outside of buffer (%d:%d/%d).\n", offset, |
("ip_reass: fragment outside of buffer (%d:%d/%d).\n", offset, |
151 |
offset + len, IP_REASS_BUFSIZE)); |
offset + len, IP_REASS_BUFSIZE)); |
152 |
sys_untimeout(ip_reass_timer, NULL); |
sys_untimeout(ip_reass_timer, NULL); |
153 |
ip_reasstmr = 0; |
ip_reasstmr = 0; |
154 |
goto nullreturn; |
goto nullreturn; |
157 |
/* Copy the fragment into the reassembly buffer, at the right |
/* Copy the fragment into the reassembly buffer, at the right |
158 |
offset. */ |
offset. */ |
159 |
DEBUGF(IP_REASS_DEBUG, |
DEBUGF(IP_REASS_DEBUG, |
160 |
("ip_reass: copying with offset %d into %d:%d\n", offset, |
("ip_reass: copying with offset %d into %d:%d\n", offset, |
161 |
IP_HLEN + offset, IP_HLEN + offset + len)); |
IP_HLEN + offset, IP_HLEN + offset + len)); |
162 |
i = IPH_HL(fraghdr) * 4; |
i = IPH_HL(fraghdr) * 4; |
163 |
copy_from_pbuf(p, &i, &ip_reassbuf[IP_HLEN + offset], len); |
copy_from_pbuf(p, &i, &ip_reassbuf[IP_HLEN + offset], len); |
164 |
|
|
165 |
/* Update the bitmap. */ |
/* Update the bitmap. */ |
166 |
if (offset / (8 * 8) == (offset + len) / (8 * 8)) { |
if (offset / (8 * 8) == (offset + len) / (8 * 8)) { |
167 |
DEBUGF(IP_REASS_DEBUG, |
DEBUGF(IP_REASS_DEBUG, |
168 |
("ip_reass: updating single byte in bitmap.\n")); |
("ip_reass: updating single byte in bitmap.\n")); |
169 |
/* If the two endpoints are in the same byte, we only update |
/* If the two endpoints are in the same byte, we only update |
170 |
that byte. */ |
that byte. */ |
171 |
ip_reassbitmap[offset / (8 * 8)] |= |
ip_reassbitmap[offset / (8 * 8)] |= |
172 |
bitmap_bits[(offset / 8) & 7] & |
bitmap_bits[(offset / 8) & 7] & |
173 |
~bitmap_bits[((offset + len) / 8) & 7]; |
~bitmap_bits[((offset + len) / 8) & 7]; |
174 |
} else { |
} else { |
175 |
/* If the two endpoints are in different bytes, we update the |
/* If the two endpoints are in different bytes, we update the |
176 |
bytes in the endpoints and fill the stuff inbetween with |
bytes in the endpoints and fill the stuff inbetween with |
177 |
0xff. */ |
0xff. */ |
178 |
ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8) & 7]; |
ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8) & 7]; |
179 |
DEBUGF(IP_REASS_DEBUG, |
DEBUGF(IP_REASS_DEBUG, |
180 |
("ip_reass: updating many bytes in bitmap (%d:%d).\n", |
("ip_reass: updating many bytes in bitmap (%d:%d).\n", |
181 |
1 + offset / (8 * 8), (offset + len) / (8 * 8))); |
1 + offset / (8 * 8), (offset + len) / (8 * 8))); |
182 |
for (i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) { |
for (i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) { |
183 |
ip_reassbitmap[i] = 0xff; |
ip_reassbitmap[i] = 0xff; |
184 |
} |
} |
185 |
ip_reassbitmap[(offset + len) / (8 * 8)] |= |
ip_reassbitmap[(offset + len) / (8 * 8)] |= |
186 |
~bitmap_bits[((offset + len) / 8) & 7]; |
~bitmap_bits[((offset + len) / 8) & 7]; |
187 |
} |
} |
188 |
|
|
189 |
/* If this fragment has the More Fragments flag set to zero, we |
/* If this fragment has the More Fragments flag set to zero, we |
196 |
ip_reassflags |= IP_REASS_FLAG_LASTFRAG; |
ip_reassflags |= IP_REASS_FLAG_LASTFRAG; |
197 |
ip_reasslen = offset + len; |
ip_reasslen = offset + len; |
198 |
DEBUGF(IP_REASS_DEBUG, |
DEBUGF(IP_REASS_DEBUG, |
199 |
("ip_reass: last fragment seen, total len %d\n", |
("ip_reass: last fragment seen, total len %d\n", |
200 |
ip_reasslen)); |
ip_reasslen)); |
201 |
} |
} |
202 |
|
|
203 |
/* Finally, we check if we have a full packet in the buffer. We do |
/* Finally, we check if we have a full packet in the buffer. We do |
207 |
/* Check all bytes up to and including all but the last byte in |
/* Check all bytes up to and including all but the last byte in |
208 |
the bitmap. */ |
the bitmap. */ |
209 |
for (i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) { |
for (i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) { |
210 |
if (ip_reassbitmap[i] != 0xff) { |
if (ip_reassbitmap[i] != 0xff) { |
211 |
DEBUGF(IP_REASS_DEBUG, |
DEBUGF(IP_REASS_DEBUG, |
212 |
("ip_reass: last fragment seen, bitmap %d/%d failed (%x)\n", |
("ip_reass: last fragment seen, bitmap %d/%d failed (%x)\n", |
213 |
i, ip_reasslen / (8 * 8) - 1, ip_reassbitmap[i])); |
i, ip_reasslen / (8 * 8) - 1, ip_reassbitmap[i])); |
214 |
goto nullreturn; |
goto nullreturn; |
215 |
} |
} |
216 |
} |
} |
217 |
/* Check the last byte in the bitmap. It should contain just the |
/* Check the last byte in the bitmap. It should contain just the |
218 |
right amount of bits. */ |
right amount of bits. */ |
219 |
if (ip_reassbitmap[ip_reasslen / (8 * 8)] != |
if (ip_reassbitmap[ip_reasslen / (8 * 8)] != |
220 |
(u8_t) ~ bitmap_bits[ip_reasslen / 8 & 7]) { |
(u8_t) ~ bitmap_bits[ip_reasslen / 8 & 7]) { |
221 |
DEBUGF(IP_REASS_DEBUG, |
DEBUGF(IP_REASS_DEBUG, |
222 |
("ip_reass: last fragment seen, bitmap %d didn't contain %x (%x)\n", |
("ip_reass: last fragment seen, bitmap %d didn't contain %x (%x)\n", |
223 |
ip_reasslen / (8 * 8), ~bitmap_bits[ip_reasslen / 8 & 7], |
ip_reasslen / (8 * 8), ~bitmap_bits[ip_reasslen / 8 & 7], |
224 |
ip_reassbitmap[ip_reasslen / (8 * 8)])); |
ip_reassbitmap[ip_reasslen / (8 * 8)])); |
225 |
goto nullreturn; |
goto nullreturn; |
226 |
} |
} |
227 |
|
|
228 |
/* Pretend to be a "normal" (i.e., not fragmented) IP packet |
/* Pretend to be a "normal" (i.e., not fragmented) IP packet |
242 |
pbuf_free(p); |
pbuf_free(p); |
243 |
p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL); |
p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL); |
244 |
if (p != NULL) { |
if (p != NULL) { |
245 |
i = 0; |
i = 0; |
246 |
for (q = p; q != NULL; q = q->next) { |
for (q = p; q != NULL; q = q->next) { |
247 |
/* Copy enough bytes to fill this pbuf in the chain. The |
/* Copy enough bytes to fill this pbuf in the chain. The |
248 |
available data in the pbuf is given by the q->len |
available data in the pbuf is given by the q->len |
249 |
variable. */ |
variable. */ |
250 |
DEBUGF(IP_REASS_DEBUG, |
DEBUGF(IP_REASS_DEBUG, |
251 |
("ip_reass: memcpy from %p (%d) to %p, %d bytes\n", |
("ip_reass: memcpy from %p (%d) to %p, %d bytes\n", |
252 |
&ip_reassbuf[i], i, q->payload, |
&ip_reassbuf[i], i, q->payload, |
253 |
q->len > ip_reasslen - i ? ip_reasslen - i : q->len)); |
q->len > ip_reasslen - i ? ip_reasslen - i : q->len)); |
254 |
memcpy(q->payload, &ip_reassbuf[i], |
memcpy(q->payload, &ip_reassbuf[i], |
255 |
q->len > ip_reasslen - i ? ip_reasslen - i : q->len); |
q->len > ip_reasslen - i ? ip_reasslen - i : q->len); |
256 |
i += q->len; |
i += q->len; |
257 |
} |
} |
258 |
#ifdef IP_STATS |
#ifdef IP_STATS |
259 |
++lwip_stats.ip_frag.fw; |
++lwip_stats.ip_frag.fw; |
260 |
#endif /* IP_STATS */ |
#endif /* IP_STATS */ |
261 |
} else { |
} else { |
262 |
#ifdef IP_STATS |
#ifdef IP_STATS |
263 |
++lwip_stats.ip_frag.memerr; |
++lwip_stats.ip_frag.memerr; |
264 |
#endif /* IP_STATS */ |
#endif /* IP_STATS */ |
265 |
} |
} |
266 |
DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", (void*)p)); |
DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", (void*)p)); |