Changeset 50023 in vbox
- Timestamp:
- Jan 6, 2014 2:15:53 AM (11 years ago)
- Location:
- trunk/src/VBox/Devices/Network/lwip-new/src
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Network/lwip-new/src/core/ipv6/ip6_frag.c
r47886 r50023 76 76 * offset and the ending offset of this fragment to 77 77 * easily chain the fragments. 78 * It has the same packing requirements as the IPv6 header, since it replaces79 * the Fragment Header in memory in incoming fragments to keep80 * track of the various fragments.81 78 */ 82 #ifdef PACK_STRUCT_USE_INCLUDES83 # include "arch/bpstruct.h"84 #endif85 PACK_STRUCT_BEGIN86 79 struct ip6_reass_helper { 87 PACK_STRUCT_FIELD(struct pbuf *next_pbuf); 88 PACK_STRUCT_FIELD(u16_t start); 89 PACK_STRUCT_FIELD(u16_t end); 90 } PACK_STRUCT_STRUCT; 91 PACK_STRUCT_END 92 #ifdef PACK_STRUCT_USE_INCLUDES 93 # include "arch/epstruct.h" 94 #endif 80 struct ip6_reass_helper *next; 81 struct pbuf *p; 82 u16_t start; 83 u16_t end; 84 }; 95 85 96 86 /* static variables */ … … 137 127 ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr) 138 128 { 139 struct ip6_reassdata * prev;129 struct ip6_reassdata **pipr; 140 130 u16_t pbufs_freed = 0; 141 131 u8_t clen; … … 143 133 struct ip6_reass_helper *iprh; 144 134 135 /* First, free all received pbufs. The individual pbufs need to be released 136 separately as they have not yet been chained */ 137 iprh = ipr->iprh; 138 while (iprh != NULL) { 139 struct ip6_reass_helper *next = iprh->next; 140 p = iprh->p; 141 145 142 #if LWIP_ICMP6 146 iprh = (struct ip6_reass_helper *)ipr->p->payload; 147 if (iprh->start == 0) { 148 /* The first fragment was received, send ICMP time exceeded. */ 149 /* First, de-queue the first pbuf from r->p. */ 150 p = ipr->p; 151 ipr->p = iprh->next_pbuf; 152 /* Then, move back to the original header (we are now pointing to Fragment header). */ 153 if (pbuf_header(p, (u8_t*)p->payload - (u8_t*)ipr->iphdr)) { 154 LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed\n", 0); 155 } 156 else { 157 icmp6_time_exceeded(p, ICMP6_TE_FRAG); 158 } 143 /* If the first fragment was received, send ICMP time exceeded. */ 144 if (iprh->start == 0) { 145 SMEMCPY(ipr->iphdr0, &ipr->iphdr, IP6_HLEN); 146 if (pbuf_header(p, (u8_t *)p->payload - (u8_t *)ipr->iphdr0) == 0) { 147 icmp6_time_exceeded(p, ICMP6_TE_FRAG); 148 } 149 else { 150 LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed\n", 0); 151 } 152 } 153 #endif /* LWIP_ICMP6 */ 154 159 155 clen = pbuf_clen(p); 160 156 LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); 161 157 pbufs_freed += clen; 162 158 pbuf_free(p); 163 } 164 #endif /* LWIP_ICMP6 */ 165 166 /* First, free all received pbufs. The individual pbufs need to be released 167 separately as they have not yet been chained */ 168 p = ipr->p; 169 while (p != NULL) { 170 struct pbuf *pcur; 171 iprh = (struct ip6_reass_helper *)p->payload; 172 pcur = p; 173 /* get the next pointer before freeing */ 174 p = iprh->next_pbuf; 175 clen = pbuf_clen(pcur); 176 LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); 177 pbufs_freed += clen; 178 pbuf_free(pcur); 159 160 iprh = next; 179 161 } 180 162 181 163 /* Then, unchain the struct ip6_reassdata from the list and free it. */ 182 if (ipr == reassdatagrams) { 183 reassdatagrams = ipr->next; 184 } else { 185 prev = reassdatagrams; 186 while (prev != NULL) { 187 if (prev->next == ipr) { 188 break; 189 } 190 prev = prev->next; 191 } 192 if (prev != NULL) { 193 prev->next = ipr->next; 164 for (pipr = &reassdatagrams; *pipr != NULL; pipr = &(*pipr)->next) { 165 if (*pipr == ipr) { 166 (*pipr) = ipr->next; 167 break; 194 168 } 195 169 } … … 246 220 ip6_reass(struct pbuf *p) 247 221 { 248 struct ip6_reassdata *ipr, *ipr_prev; 249 struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; 222 struct ip6_reassdata *ipr, **pipr; 223 struct ip6_reass_helper *iprh, *iprh_tmp; 224 struct ip6_reass_helper **pnext; 250 225 struct ip6_frag_hdr * frag_hdr; 251 u16_t offset,len;252 u 8_t clen, valid = 1;253 struct pbuf *q;226 size_t unfrag_len; 227 u16_t offset, len, start, end, validlen; 228 u8_t clen; 254 229 255 230 IP6_FRAG_STATS_INC(ip6_frag.recv); … … 268 243 len -= IP6_FRAG_HLEN; 269 244 245 start = (offset & IP6_FRAG_OFFSET_MASK); 246 end = start + len; 247 248 270 249 /* Look for the datagram the fragment belongs to in the current datagram queue, 271 250 * remembering the previous in the queue for later dequeueing. */ 272 for (ipr = reassdatagrams , ipr_prev = NULL; ipr != NULL; ipr = ipr->next) {251 for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) { 273 252 /* Check if the incoming fragment matches the one currently present 274 253 in the reassembly buffer. If so, we proceed with copying the 275 254 fragment into the buffer. */ 276 255 if ((frag_hdr->_identification == ipr->identification) && 277 ip6_addr_cmp(ip6_current_src_addr(), &(ipr->iphdr ->src)) &&278 ip6_addr_cmp(ip6_current_dest_addr(), &(ipr->iphdr ->dest))) {256 ip6_addr_cmp(ip6_current_src_addr(), &(ipr->iphdr.src)) && 257 ip6_addr_cmp(ip6_current_dest_addr(), &(ipr->iphdr.dest))) { 279 258 IP6_FRAG_STATS_INC(ip6_frag.cachehit); 280 259 break; 281 260 } 282 ipr_prev = ipr;283 261 } 284 262 … … 310 288 * Eventually, we will replace it when we get the first fragment 311 289 * (it might be this one, in any case, it is done later). */ 312 ipr->iphdr = (struct ip6_hdr *)ip6_current_header(); 290 SMEMCPY(&ipr->iphdr, ip6_current_header(), IP6_HLEN); 291 if (start == 0) { 292 ipr->iphdr0 = (struct ip6_hdr *)ip6_current_header(); 293 } 313 294 314 295 /* copy the fragmented packet id. */ 315 296 ipr->identification = frag_hdr->_identification; 316 317 /* copy the nexth field */ 318 ipr->nexth = frag_hdr->_nexth; 297 } 298 299 /* If this is the last fragment, save total packet length. */ 300 if ((offset & IP6_FRAG_MORE_FLAG) == 0) { 301 #if IP_REASS_CHECK_OVERLAP 302 if (ipr->datagram_len != 0) { 303 IP6_FRAG_STATS_INC(ip6_frag.proterr); 304 IP6_FRAG_STATS_INC(ip6_frag.drop); 305 goto nullreturn; 306 } 307 #endif /* IP_REASS_CHECK_OVERLAP */ 308 ipr->datagram_len = end; 309 } 310 311 /* find the place to insert this pbuf */ 312 validlen = 0; 313 for (pnext = &ipr->iprh; *pnext != NULL; pnext = &(*pnext)->next) { 314 iprh_tmp = *pnext; 315 316 if (start < iprh_tmp->start) { 317 /* the new pbuf should be inserted before this */ 318 #if IP_REASS_CHECK_OVERLAP 319 if (end > iprh_tmp->start) { 320 /* fragment overlaps with following, throw away */ 321 IP6_FRAG_STATS_INC(ip6_frag.proterr); 322 IP6_FRAG_STATS_INC(ip6_frag.drop); 323 goto nullreturn; 324 } 325 #endif /* IP_REASS_CHECK_OVERLAP */ 326 break; 327 } 328 else if (start == iprh_tmp->start) { 329 /* received the same datagram twice: no need to keep the datagram */ 330 IP6_FRAG_STATS_INC(ip6_frag.drop); 331 goto nullreturn; 332 } 333 #if IP_REASS_CHECK_OVERLAP 334 else if (start < iprh_tmp->end) { 335 /* overlap: no need to keep the new datagram */ 336 IP6_FRAG_STATS_INC(ip6_frag.proterr); 337 IP6_FRAG_STATS_INC(ip6_frag.drop); 338 goto nullreturn; 339 } 340 #endif /* IP_REASS_CHECK_OVERLAP */ 341 else { 342 /* Check if the fragments received so far have no gaps. */ 343 if (validlen == iprh_tmp->start) { 344 validlen = iprh_tmp->end; 345 } 346 else { 347 validlen = 0; 348 } 349 } 319 350 } 320 351 … … 334 365 } 335 366 336 /* Overwrite Fragment Header with our own helper struct. */ 337 iprh = (struct ip6_reass_helper *)p->payload; 338 iprh->next_pbuf = NULL; 339 iprh->start = (offset & IP6_FRAG_OFFSET_MASK); 340 iprh->end = (offset & IP6_FRAG_OFFSET_MASK) + len; 341 342 /* find the right place to insert this pbuf */ 343 /* Iterate through until we either get to the end of the list (append), 344 * or we find on with a larger offset (insert). */ 345 for (q = ipr->p; q != NULL;) { 346 iprh_tmp = (struct ip6_reass_helper*)q->payload; 347 if (iprh->start < iprh_tmp->start) { 348 #if IP_REASS_CHECK_OVERLAP 349 if (iprh->end > iprh_tmp->start) { 350 /* fragment overlaps with following, throw away */ 351 IP6_FRAG_STATS_INC(ip6_frag.proterr); 352 IP6_FRAG_STATS_INC(ip6_frag.drop); 353 goto nullreturn; 354 } 355 if (iprh_prev != NULL) { 356 if (iprh->start < iprh_prev->end) { 357 /* fragment overlaps with previous, throw away */ 358 IP6_FRAG_STATS_INC(ip6_frag.proterr); 359 IP6_FRAG_STATS_INC(ip6_frag.drop); 360 goto nullreturn; 361 } 362 } 363 #endif /* IP_REASS_CHECK_OVERLAP */ 364 /* the new pbuf should be inserted before this */ 365 iprh->next_pbuf = q; 366 if (iprh_prev != NULL) { 367 /* not the fragment with the lowest offset */ 368 iprh_prev->next_pbuf = p; 369 } else { 370 /* fragment with the lowest offset */ 371 ipr->p = p; 372 } 373 break; 374 } else if(iprh->start == iprh_tmp->start) { 375 /* received the same datagram twice: no need to keep the datagram */ 376 IP6_FRAG_STATS_INC(ip6_frag.drop); 377 goto nullreturn; 378 #if IP_REASS_CHECK_OVERLAP 379 } else if(iprh->start < iprh_tmp->end) { 380 /* overlap: no need to keep the new datagram */ 381 IP6_FRAG_STATS_INC(ip6_frag.proterr); 382 IP6_FRAG_STATS_INC(ip6_frag.drop); 383 goto nullreturn; 384 #endif /* IP_REASS_CHECK_OVERLAP */ 385 } else { 386 /* Check if the fragments received so far have no gaps. */ 387 if (iprh_prev != NULL) { 388 if (iprh_prev->end != iprh_tmp->start) { 389 /* There is a fragment missing between the current 390 * and the previous fragment */ 391 valid = 0; 392 } 393 } 394 } 395 q = iprh_tmp->next_pbuf; 396 iprh_prev = iprh_tmp; 397 } 398 399 /* If q is NULL, then we made it to the end of the list. Determine what to do now */ 400 if (q == NULL) { 401 if (iprh_prev != NULL) { 402 /* this is (for now), the fragment with the highest offset: 403 * chain it to the last fragment */ 404 #if IP_REASS_CHECK_OVERLAP 405 LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start); 406 #endif /* IP_REASS_CHECK_OVERLAP */ 407 iprh_prev->next_pbuf = p; 408 if (iprh_prev->end != iprh->start) { 409 valid = 0; 410 } 411 } else { 412 #if IP_REASS_CHECK_OVERLAP 413 LWIP_ASSERT("no previous fragment, this must be the first fragment!", 414 ipr->p == NULL); 415 #endif /* IP_REASS_CHECK_OVERLAP */ 416 /* this is the first fragment we ever received for this ip datagram */ 417 ipr->p = p; 418 } 419 } 367 if (start == 0 && ipr->iphdr0 == NULL) { 368 /* 369 * We've got the fragment with offset 0 out of order, remember its 370 * IPv6 header location (in the hidden part of the current pbuf) 371 * and update the copy in ip6_reassdata::iphdr. We don't need to 372 * copy complete header since src and dest are the same as in the 373 * first fragment we received. 374 */ 375 ipr->iphdr0 = (struct ip6_hdr *)ip6_current_header(); 376 SMEMCPY(&ipr->iphdr, ip6_current_header(), 377 IP6_HLEN - 2 * sizeof(ip_addr_p_t)); 378 } 379 380 /* Overwrite IPv6 Header with our own helper struct (aligned). */ 381 iprh = (struct ip6_reass_helper *) 382 (((uintptr_t)(u8_t *)ip6_current_header() + sizeof(void *) - 1) 383 & ~(sizeof(void *) - 1)); 384 iprh->p = p; 385 iprh->start = start; 386 iprh->end = end; 387 388 /* insert it into the list */ 389 iprh->next = *pnext; 390 *pnext = iprh; 420 391 421 392 /* Track the current number of pbufs current 'in-flight', in order to limit … … 423 394 ip6_reass_pbufcount += clen; 424 395 425 /* Remember IPv6 header if this is the first fragment. */426 if (iprh->start == 0) {427 ipr->iphdr = (struct ip6_hdr *)ip6_current_header();428 }429 430 /* If this is the last fragment, calculate total packet length. */431 if ((offset & IP6_FRAG_MORE_FLAG) == 0) {432 ipr->datagram_len = iprh->end;433 }434 435 /* Additional validity tests: we have received first and last fragment. */436 iprh_tmp = (struct ip6_reass_helper*)ipr->p->payload;437 if (iprh_tmp->start != 0) {438 valid = 0;439 }440 396 if (ipr->datagram_len == 0) { 441 valid = 0; 442 } 443 444 /* Final validity test: no gaps between current and last fragment. */ 445 iprh_prev = iprh; 446 q = iprh->next_pbuf; 447 while ((q != NULL) && valid) { 448 iprh = (struct ip6_reass_helper*)q->payload; 449 if (iprh_prev->end != iprh->start) { 450 valid = 0; 397 /* We still don't have the last fragment. */ 398 return NULL; 399 } 400 401 if (validlen == start) { 402 validlen = end; 403 } 404 else { 405 /* There are gaps before this fragment. */ 406 return NULL; 407 } 408 409 if (validlen != 0) { 410 /* 411 * We know we have all the data up to the end of this fragment and 412 * we know the total length. Check if the reassembly is complete. 413 */ 414 for (iprh_tmp = iprh->next; iprh_tmp != NULL; iprh_tmp = iprh_tmp->next) { 415 if (validlen == iprh_tmp->start) { 416 validlen = iprh_tmp->end; 417 } 418 else { 419 validlen = 0; 420 break; 421 } 422 } 423 424 if (validlen != ipr->datagram_len) { 425 /* the datagram is not yet reassembled completely */ 426 return NULL; 427 } 428 } 429 430 /* 431 * All fragments have been received. Reassemble original datagram 432 * and return it to ip6_input() to be processed instead of the final 433 * fragment that completed the reassembly. 434 */ 435 436 /* chain together the pbufs contained within the ip6_reassdata list. */ 437 p = NULL; 438 for (iprh = ipr->iprh; iprh != NULL; iprh = iprh->next) { 439 if (p == NULL) { 440 p = iprh->p; 441 } 442 else { 443 /* hide the fragment header for every succeeding fragment */ 444 pbuf_header(iprh->p, -IP6_FRAG_HLEN); 445 pbuf_cat(p, iprh->p); 446 } 447 } 448 449 /* Adjust datagram length by adding preceding header lengths. */ 450 unfrag_len = (u8_t *)p->payload - (u8_t *)ipr->iphdr0; 451 ipr->datagram_len += unfrag_len - IP6_HLEN + IP6_FRAG_HLEN; 452 453 /* Set payload length in ip header. */ 454 ipr->iphdr._plen = htons(ipr->datagram_len); 455 456 /* restore IPv6 header (overwritten with ip6_reass_helper) */ 457 SMEMCPY(ipr->iphdr0, &ipr->iphdr, IP6_HLEN); 458 459 /* Mark as "single fragment" packet (see caller). */ 460 frag_hdr = (struct ip6_frag_hdr *) p->payload; 461 frag_hdr->_fragment_offset = 0; 462 463 /* Unlink from the reassdatagrams list */ 464 for (pipr = &reassdatagrams; *pipr != NULL; pipr = &(*pipr)->next) { 465 if (*pipr == ipr) { 466 (*pipr) = ipr->next; 451 467 break; 452 468 } 453 iprh_prev = iprh; 454 q = iprh->next_pbuf; 455 } 456 457 if (valid) { 458 /* All fragments have been received */ 459 460 /* chain together the pbufs contained within the ip6_reassdata list. */ 461 iprh = (struct ip6_reass_helper*) ipr->p->payload; 462 while(iprh != NULL) { 463 464 if (iprh->next_pbuf != NULL) { 465 /* Save next helper struct (will be hidden in next step). */ 466 iprh_tmp = (struct ip6_reass_helper*) iprh->next_pbuf->payload; 467 468 /* hide the fragment header for every succeding fragment */ 469 pbuf_header(iprh->next_pbuf, -IP6_FRAG_HLEN); 470 pbuf_cat(ipr->p, iprh->next_pbuf); 471 } 472 else { 473 iprh_tmp = NULL; 474 } 475 476 iprh = iprh_tmp; 477 } 478 479 /* Adjust datagram length by adding header lengths. */ 480 ipr->datagram_len += ((u8_t*)ipr->p->payload - (u8_t*)ipr->iphdr) 481 + IP6_FRAG_HLEN 482 - IP6_HLEN ; 483 484 /* Set payload length in ip header. */ 485 ipr->iphdr->_plen = htons(ipr->datagram_len); 486 487 /* Get the furst pbuf. */ 488 p = ipr->p; 489 490 /* Restore Fragment Header in first pbuf. Mark as "single fragment" 491 * packet. Restore nexth. */ 492 frag_hdr = (struct ip6_frag_hdr *) p->payload; 493 frag_hdr->_nexth = ipr->nexth; 494 frag_hdr->reserved = 0; 495 frag_hdr->_fragment_offset = 0; 496 frag_hdr->_identification = 0; 497 498 /* release the sources allocate for the fragment queue entry */ 499 if (reassdatagrams == ipr) { 500 /* it was the first in the list */ 501 reassdatagrams = ipr->next; 502 } else { 503 /* it wasn't the first, so it must have a valid 'prev' */ 504 LWIP_ASSERT("sanity check linked list", ipr_prev != NULL); 505 ipr_prev->next = ipr->next; 506 } 507 memp_free(MEMP_IP6_REASSDATA, ipr); 508 509 /* adjust the number of pbufs currently queued for reassembly. */ 510 ip6_reass_pbufcount -= pbuf_clen(p); 511 512 /* Move pbuf back to IPv6 header. */ 513 if (pbuf_header(p, (u8_t*)p->payload - (u8_t*)ipr->iphdr)) { 514 LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0); 515 pbuf_free(p); 516 return NULL; 517 } 518 519 /* Return the pbuf chain */ 520 return p; 521 } 522 /* the datagram is not (yet?) reassembled completely */ 523 return NULL; 469 } 470 memp_free(MEMP_IP6_REASSDATA, ipr); 471 472 /* adjust the number of pbufs currently queued for reassembly. */ 473 ip6_reass_pbufcount -= pbuf_clen(p); 474 475 /* Move pbuf back to IPv6 header. */ 476 if (pbuf_header(p, unfrag_len) != 0) { 477 LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0); 478 goto nullreturn; 479 } 480 481 /* Return the pbuf chain */ 482 return p; 524 483 525 484 nullreturn: … … 528 487 } 529 488 530 #endif /* LWIP_IPV6 ^^LWIP_IPV6_REASS */489 #endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ 531 490 532 491 #if LWIP_IPV6 && LWIP_IPV6_FRAG -
trunk/src/VBox/Devices/Network/lwip-new/src/include/ipv6/lwip/ip6_frag.h
r47886 r50023 44 44 #include "lwip/opt.h" 45 45 #include "lwip/pbuf.h" 46 #include "lwip/ip6.h" 46 47 #include "lwip/ip6_addr.h" 47 48 #include "lwip/netif.h" … … 57 58 #define IP6_REASS_TMR_INTERVAL 1000 58 59 59 /* IPv6 reassembly helper struct. 60 struct ip6_reass_helper; 61 62 /* IPv6 reassembly struct. 60 63 * This is exported because memp needs to know the size. 61 64 */ 62 65 struct ip6_reassdata { 63 66 struct ip6_reassdata *next; 64 struct pbuf *p; 65 struct ip6_hdr * iphdr; 67 struct ip6_reass_helper *iprh; 68 struct ip6_hdr *iphdr0; 69 struct ip6_hdr iphdr; 66 70 u32_t identification; 67 71 u16_t datagram_len; 68 u8_t nexth;69 72 u8_t timer; 70 73 };
Note:
See TracChangeset
for help on using the changeset viewer.