Revision 429d0a3d slirp/ip_input.c
b/slirp/ip_input.c | ||
---|---|---|
43 | 43 |
*/ |
44 | 44 |
|
45 | 45 |
#include <slirp.h> |
46 |
#include <osdep.h> |
|
46 | 47 |
#include "ip_icmp.h" |
47 | 48 |
|
48 | 49 |
#ifdef LOG_ENABLED |
... | ... | |
51 | 52 |
|
52 | 53 |
struct ipq ipq; |
53 | 54 |
|
54 |
static struct ip *ip_reass(register struct ipasfrag *ip,
|
|
55 |
static struct ip *ip_reass(register struct ip *ip, |
|
55 | 56 |
register struct ipq *fp); |
56 | 57 |
static void ip_freef(struct ipq *fp); |
57 | 58 |
static void ip_enq(register struct ipasfrag *p, |
... | ... | |
65 | 66 |
void |
66 | 67 |
ip_init() |
67 | 68 |
{ |
68 |
ipq.next = ipq.prev = (ipqp_32)&ipq;
|
|
69 |
ipq.ip_link.next = ipq.ip_link.prev = &ipq.ip_link;
|
|
69 | 70 |
ip_id = tt.tv_sec & 0xffff; |
70 | 71 |
udp_init(); |
71 | 72 |
tcp_init(); |
... | ... | |
188 | 189 |
*/ |
189 | 190 |
if (ip->ip_off &~ IP_DF) { |
190 | 191 |
register struct ipq *fp; |
192 |
struct qlink *l; |
|
191 | 193 |
/* |
192 | 194 |
* Look for queue of fragments |
193 | 195 |
* of this datagram. |
194 | 196 |
*/ |
195 |
for (fp = (struct ipq *) ipq.next; fp != &ipq;
|
|
196 |
fp = (struct ipq *) fp->next)
|
|
197 |
if (ip->ip_id == fp->ipq_id &&
|
|
198 |
ip->ip_src.s_addr == fp->ipq_src.s_addr &&
|
|
199 |
ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
|
|
200 |
ip->ip_p == fp->ipq_p)
|
|
197 |
for (l = ipq.ip_link.next; l != &ipq.ip_link; l = l->next) {
|
|
198 |
fp = container_of(l, struct ipq, ip_link);
|
|
199 |
if (ip->ip_id == fp->ipq_id &&
|
|
200 |
ip->ip_src.s_addr == fp->ipq_src.s_addr &&
|
|
201 |
ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
|
|
202 |
ip->ip_p == fp->ipq_p)
|
|
201 | 203 |
goto found; |
202 |
fp = 0; |
|
204 |
} |
|
205 |
fp = NULL; |
|
203 | 206 |
found: |
204 | 207 |
|
205 | 208 |
/* |
... | ... | |
209 | 212 |
*/ |
210 | 213 |
ip->ip_len -= hlen; |
211 | 214 |
if (ip->ip_off & IP_MF) |
212 |
((struct ipasfrag *)ip)->ipf_mff |= 1;
|
|
215 |
ip->ip_tos |= 1;
|
|
213 | 216 |
else |
214 |
((struct ipasfrag *)ip)->ipf_mff &= ~1;
|
|
217 |
ip->ip_tos &= ~1;
|
|
215 | 218 |
|
216 | 219 |
ip->ip_off <<= 3; |
217 | 220 |
|
... | ... | |
220 | 223 |
* or if this is not the first fragment, |
221 | 224 |
* attempt reassembly; if it succeeds, proceed. |
222 | 225 |
*/ |
223 |
if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) {
|
|
226 |
if (ip->ip_tos & 1 || ip->ip_off) {
|
|
224 | 227 |
STAT(ipstat.ips_fragments++); |
225 |
ip = ip_reass((struct ipasfrag *)ip, fp);
|
|
228 |
ip = ip_reass(ip, fp); |
|
226 | 229 |
if (ip == 0) |
227 | 230 |
return; |
228 | 231 |
STAT(ipstat.ips_reassembled++); |
... | ... | |
258 | 261 |
return; |
259 | 262 |
} |
260 | 263 |
|
264 |
#define iptofrag(P) ((struct ipasfrag *)(((char*)(P)) - sizeof(struct qlink))) |
|
265 |
#define fragtoip(P) ((struct ip*)(((char*)(P)) + sizeof(struct qlink))) |
|
261 | 266 |
/* |
262 | 267 |
* Take incoming datagram fragment and try to |
263 | 268 |
* reassemble it into whole datagram. If a chain for |
... | ... | |
265 | 270 |
* is given as fp; otherwise have to make a chain. |
266 | 271 |
*/ |
267 | 272 |
static struct ip * |
268 |
ip_reass(register struct ipasfrag *ip, register struct ipq *fp)
|
|
273 |
ip_reass(register struct ip *ip, register struct ipq *fp) |
|
269 | 274 |
{ |
270 | 275 |
register struct mbuf *m = dtom(ip); |
271 | 276 |
register struct ipasfrag *q; |
... | ... | |
292 | 297 |
struct mbuf *t; |
293 | 298 |
if ((t = m_get()) == NULL) goto dropfrag; |
294 | 299 |
fp = mtod(t, struct ipq *); |
295 |
insque_32(fp, &ipq);
|
|
300 |
insque(&fp->ip_link, &ipq.ip_link);
|
|
296 | 301 |
fp->ipq_ttl = IPFRAGTTL; |
297 | 302 |
fp->ipq_p = ip->ip_p; |
298 | 303 |
fp->ipq_id = ip->ip_id; |
299 |
fp->ipq_next = fp->ipq_prev = (ipasfragp_32)fp;
|
|
300 |
fp->ipq_src = ((struct ip *)ip)->ip_src;
|
|
301 |
fp->ipq_dst = ((struct ip *)ip)->ip_dst;
|
|
304 |
fp->frag_link.next = fp->frag_link.prev = &fp->frag_link;
|
|
305 |
fp->ipq_src = ip->ip_src;
|
|
306 |
fp->ipq_dst = ip->ip_dst;
|
|
302 | 307 |
q = (struct ipasfrag *)fp; |
303 | 308 |
goto insert; |
304 | 309 |
} |
... | ... | |
306 | 311 |
/* |
307 | 312 |
* Find a segment which begins after this one does. |
308 | 313 |
*/ |
309 |
for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp;
|
|
310 |
q = (struct ipasfrag *)q->ipf_next)
|
|
311 |
if (q->ip_off > ip->ip_off) |
|
314 |
for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
|
|
315 |
q = q->ipf_next)
|
|
316 |
if (q->ipf_off > ip->ip_off)
|
|
312 | 317 |
break; |
313 | 318 |
|
314 | 319 |
/* |
... | ... | |
316 | 321 |
* our data already. If so, drop the data from the incoming |
317 | 322 |
* segment. If it provides all of our data, drop us. |
318 | 323 |
*/ |
319 |
if (q->ipf_prev != (ipasfragp_32)fp) {
|
|
320 |
i = ((struct ipasfrag *)(q->ipf_prev))->ip_off +
|
|
321 |
((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off;
|
|
324 |
if (q->ipf_prev != &fp->frag_link) {
|
|
325 |
struct ipasfrag *pq = q->ipf_prev;
|
|
326 |
i = pq->ipf_off + pq->ipf_len - ip->ip_off;
|
|
322 | 327 |
if (i > 0) { |
323 | 328 |
if (i >= ip->ip_len) |
324 | 329 |
goto dropfrag; |
... | ... | |
332 | 337 |
* While we overlap succeeding segments trim them or, |
333 | 338 |
* if they are completely covered, dequeue them. |
334 | 339 |
*/ |
335 |
while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { |
|
336 |
i = (ip->ip_off + ip->ip_len) - q->ip_off; |
|
337 |
if (i < q->ip_len) { |
|
338 |
q->ip_len -= i; |
|
339 |
q->ip_off += i; |
|
340 |
while (q != (struct ipasfrag*)&fp->frag_link && |
|
341 |
ip->ip_off + ip->ip_len > q->ipf_off) { |
|
342 |
i = (ip->ip_off + ip->ip_len) - q->ipf_off; |
|
343 |
if (i < q->ipf_len) { |
|
344 |
q->ipf_len -= i; |
|
345 |
q->ipf_off += i; |
|
340 | 346 |
m_adj(dtom(q), i); |
341 | 347 |
break; |
342 | 348 |
} |
343 |
q = (struct ipasfrag *) q->ipf_next;
|
|
344 |
m_freem(dtom((struct ipasfrag *) q->ipf_prev));
|
|
345 |
ip_deq((struct ipasfrag *) q->ipf_prev);
|
|
349 |
q = q->ipf_next; |
|
350 |
m_freem(dtom(q->ipf_prev)); |
|
351 |
ip_deq(q->ipf_prev); |
|
346 | 352 |
} |
347 | 353 |
|
348 | 354 |
insert: |
... | ... | |
350 | 356 |
* Stick new segment in its place; |
351 | 357 |
* check for complete reassembly. |
352 | 358 |
*/ |
353 |
ip_enq(ip, (struct ipasfrag *) q->ipf_prev);
|
|
359 |
ip_enq(iptofrag(ip), q->ipf_prev);
|
|
354 | 360 |
next = 0; |
355 |
for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp;
|
|
356 |
q = (struct ipasfrag *) q->ipf_next) {
|
|
357 |
if (q->ip_off != next) |
|
361 |
for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link;
|
|
362 |
q = q->ipf_next) {
|
|
363 |
if (q->ipf_off != next)
|
|
358 | 364 |
return (0); |
359 |
next += q->ip_len; |
|
365 |
next += q->ipf_len;
|
|
360 | 366 |
} |
361 |
if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1)
|
|
367 |
if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1)
|
|
362 | 368 |
return (0); |
363 | 369 |
|
364 | 370 |
/* |
365 | 371 |
* Reassembly is complete; concatenate fragments. |
366 | 372 |
*/ |
367 |
q = (struct ipasfrag *) fp->ipq_next;
|
|
373 |
q = fp->frag_link.next;
|
|
368 | 374 |
m = dtom(q); |
369 | 375 |
|
370 | 376 |
q = (struct ipasfrag *) q->ipf_next; |
371 |
while (q != (struct ipasfrag *)fp) { |
|
372 |
struct mbuf *t; |
|
373 |
t = dtom(q); |
|
377 |
while (q != (struct ipasfrag*)&fp->frag_link) { |
|
378 |
struct mbuf *t = dtom(q); |
|
374 | 379 |
q = (struct ipasfrag *) q->ipf_next; |
375 | 380 |
m_cat(m, t); |
376 | 381 |
} |
... | ... | |
381 | 386 |
* dequeue and discard fragment reassembly header. |
382 | 387 |
* Make header visible. |
383 | 388 |
*/ |
384 |
ip = (struct ipasfrag *) fp->ipq_next;
|
|
389 |
q = fp->frag_link.next;
|
|
385 | 390 |
|
386 | 391 |
/* |
387 | 392 |
* If the fragments concatenated to an mbuf that's |
... | ... | |
393 | 398 |
if (m->m_flags & M_EXT) { |
394 | 399 |
int delta; |
395 | 400 |
delta = (char *)ip - m->m_dat; |
396 |
ip = (struct ipasfrag *)(m->m_ext + delta);
|
|
401 |
q = (struct ipasfrag *)(m->m_ext + delta);
|
|
397 | 402 |
} |
398 | 403 |
|
399 | 404 |
/* DEBUG_ARG("ip = %lx", (long)ip); |
400 | 405 |
* ip=(struct ipasfrag *)m->m_data; */ |
401 | 406 |
|
407 |
ip = fragtoip(q); |
|
402 | 408 |
ip->ip_len = next; |
403 |
ip->ipf_mff &= ~1;
|
|
404 |
((struct ip *)ip)->ip_src = fp->ipq_src;
|
|
405 |
((struct ip *)ip)->ip_dst = fp->ipq_dst;
|
|
406 |
remque_32(fp);
|
|
409 |
ip->ip_tos &= ~1;
|
|
410 |
ip->ip_src = fp->ipq_src;
|
|
411 |
ip->ip_dst = fp->ipq_dst;
|
|
412 |
remque(&fp->ip_link);
|
|
407 | 413 |
(void) m_free(dtom(fp)); |
408 |
m = dtom(ip); |
|
409 | 414 |
m->m_len += (ip->ip_hl << 2); |
410 | 415 |
m->m_data -= (ip->ip_hl << 2); |
411 | 416 |
|
412 |
return ((struct ip *)ip);
|
|
417 |
return ip;
|
|
413 | 418 |
|
414 | 419 |
dropfrag: |
415 | 420 |
STAT(ipstat.ips_fragdropped++); |
... | ... | |
426 | 431 |
{ |
427 | 432 |
register struct ipasfrag *q, *p; |
428 | 433 |
|
429 |
for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; |
|
430 |
q = p) { |
|
431 |
p = (struct ipasfrag *) q->ipf_next; |
|
434 |
for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link; q = p) { |
|
435 |
p = q->ipf_next; |
|
432 | 436 |
ip_deq(q); |
433 | 437 |
m_freem(dtom(q)); |
434 | 438 |
} |
435 |
remque_32(fp);
|
|
439 |
remque(&fp->ip_link);
|
|
436 | 440 |
(void) m_free(dtom(fp)); |
437 | 441 |
} |
438 | 442 |
|
... | ... | |
445 | 449 |
{ |
446 | 450 |
DEBUG_CALL("ip_enq"); |
447 | 451 |
DEBUG_ARG("prev = %lx", (long)prev); |
448 |
p->ipf_prev = (ipasfragp_32) prev;
|
|
452 |
p->ipf_prev = prev; |
|
449 | 453 |
p->ipf_next = prev->ipf_next; |
450 |
((struct ipasfrag *)(prev->ipf_next))->ipf_prev = (ipasfragp_32) p;
|
|
451 |
prev->ipf_next = (ipasfragp_32) p;
|
|
454 |
((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p; |
|
455 |
prev->ipf_next = p; |
|
452 | 456 |
} |
453 | 457 |
|
454 | 458 |
/* |
... | ... | |
469 | 473 |
void |
470 | 474 |
ip_slowtimo() |
471 | 475 |
{ |
472 |
register struct ipq *fp;
|
|
476 |
struct qlink *l;
|
|
473 | 477 |
|
474 | 478 |
DEBUG_CALL("ip_slowtimo"); |
475 | 479 |
|
476 |
fp = (struct ipq *) ipq.next; |
|
477 |
if (fp == 0) |
|
480 |
l = ipq.ip_link.next; |
|
481 |
|
|
482 |
if (l == 0) |
|
478 | 483 |
return; |
479 | 484 |
|
480 |
while (fp != &ipq) {
|
|
481 |
--fp->ipq_ttl;
|
|
482 |
fp = (struct ipq *) fp->next;
|
|
483 |
if (((struct ipq *)(fp->prev))->ipq_ttl == 0) {
|
|
485 |
while (l != &ipq.ip_link) {
|
|
486 |
struct ipq *fp = container_of(l, struct ipq, ip_link);
|
|
487 |
l = l->next;
|
|
488 |
if (--fp->ipq_ttl == 0) {
|
|
484 | 489 |
STAT(ipstat.ips_fragtimeout++); |
485 |
ip_freef((struct ipq *) fp->prev);
|
|
490 |
ip_freef(fp);
|
|
486 | 491 |
} |
487 | 492 |
} |
488 | 493 |
} |
Also available in: Unified diff