1 /** @file 2 Network library functions providing net buffer operation support. 3 4 Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 **/ 13 14 #include <Uefi.h> 15 16 #include <Library/NetLib.h> 17 #include <Library/BaseLib.h> 18 #include <Library/DebugLib.h> 19 #include <Library/BaseMemoryLib.h> 20 #include <Library/UefiBootServicesTableLib.h> 21 #include <Library/MemoryAllocationLib.h> 22 23 24 /** 25 Allocate and build up the sketch for a NET_BUF. 26 27 The net buffer allocated has the BlockOpNum's NET_BLOCK_OP, and its associated 28 NET_VECTOR has the BlockNum's NET_BLOCK. But all the NET_BLOCK_OP and 29 NET_BLOCK remain un-initialized. 30 31 @param[in] BlockNum The number of NET_BLOCK in the vector of net buffer 32 @param[in] BlockOpNum The number of NET_BLOCK_OP in the net buffer 33 34 @return Pointer to the allocated NET_BUF, or NULL if the 35 allocation failed due to resource limit. 36 37 **/ 38 NET_BUF * 39 NetbufAllocStruct ( 40 IN UINT32 BlockNum, 41 IN UINT32 BlockOpNum 42 ) 43 { 44 NET_BUF *Nbuf; 45 NET_VECTOR *Vector; 46 47 ASSERT (BlockOpNum >= 1); 48 49 // 50 // Allocate three memory blocks. 51 // 52 Nbuf = AllocateZeroPool (NET_BUF_SIZE (BlockOpNum)); 53 54 if (Nbuf == NULL) { 55 return NULL; 56 } 57 58 Nbuf->Signature = NET_BUF_SIGNATURE; 59 Nbuf->RefCnt = 1; 60 Nbuf->BlockOpNum = BlockOpNum; 61 InitializeListHead (&Nbuf->List); 62 63 if (BlockNum != 0) { 64 Vector = AllocateZeroPool (NET_VECTOR_SIZE (BlockNum)); 65 66 if (Vector == NULL) { 67 goto FreeNbuf; 68 } 69 70 Vector->Signature = NET_VECTOR_SIGNATURE; 71 Vector->RefCnt = 1; 72 Vector->BlockNum = BlockNum; 73 Nbuf->Vector = Vector; 74 } 75 76 return Nbuf; 77 78 FreeNbuf: 79 80 FreePool (Nbuf); 81 return NULL; 82 } 83 84 85 /** 86 Allocate a single block NET_BUF. Upon allocation, all the 87 free space is in the tail room. 88 89 @param[in] Len The length of the block. 90 91 @return Pointer to the allocated NET_BUF, or NULL if the 92 allocation failed due to resource limit. 93 94 **/ 95 NET_BUF * 96 EFIAPI 97 NetbufAlloc ( 98 IN UINT32 Len 99 ) 100 { 101 NET_BUF *Nbuf; 102 NET_VECTOR *Vector; 103 UINT8 *Bulk; 104 105 ASSERT (Len > 0); 106 107 Nbuf = NetbufAllocStruct (1, 1); 108 109 if (Nbuf == NULL) { 110 return NULL; 111 } 112 113 Bulk = AllocatePool (Len); 114 115 if (Bulk == NULL) { 116 goto FreeNBuf; 117 } 118 119 Vector = Nbuf->Vector; 120 Vector->Len = Len; 121 122 Vector->Block[0].Bulk = Bulk; 123 Vector->Block[0].Len = Len; 124 125 Nbuf->BlockOp[0].BlockHead = Bulk; 126 Nbuf->BlockOp[0].BlockTail = Bulk + Len; 127 128 Nbuf->BlockOp[0].Head = Bulk; 129 Nbuf->BlockOp[0].Tail = Bulk; 130 Nbuf->BlockOp[0].Size = 0; 131 132 return Nbuf; 133 134 FreeNBuf: 135 FreePool (Nbuf); 136 return NULL; 137 } 138 139 /** 140 Free the net vector. 141 142 Decrease the reference count of the net vector by one. The real resource free 143 operation isn't performed until the reference count of the net vector is 144 decreased to 0. 145 146 @param[in] Vector Pointer to the NET_VECTOR to be freed. 147 148 **/ 149 VOID 150 NetbufFreeVector ( 151 IN NET_VECTOR *Vector 152 ) 153 { 154 UINT32 Index; 155 156 ASSERT (Vector != NULL); 157 NET_CHECK_SIGNATURE (Vector, NET_VECTOR_SIGNATURE); 158 ASSERT (Vector->RefCnt > 0); 159 160 Vector->RefCnt--; 161 162 if (Vector->RefCnt > 0) { 163 return; 164 } 165 166 if (Vector->Free != NULL) { 167 // 168 // Call external free function to free the vector if it 169 // isn't NULL. If NET_VECTOR_OWN_FIRST is set, release the 170 // first block since it is allocated by us 171 // 172 if ((Vector->Flag & NET_VECTOR_OWN_FIRST) != 0) { 173 gBS->FreePool (Vector->Block[0].Bulk); 174 } 175 176 Vector->Free (Vector->Arg); 177 178 } else { 179 // 180 // Free each memory block associated with the Vector 181 // 182 for (Index = 0; Index < Vector->BlockNum; Index++) { 183 gBS->FreePool (Vector->Block[Index].Bulk); 184 } 185 } 186 187 FreePool (Vector); 188 } 189 190 191 /** 192 Free the net buffer and its associated NET_VECTOR. 193 194 Decrease the reference count of the net buffer by one. Free the associated net 195 vector and itself if the reference count of the net buffer is decreased to 0. 196 The net vector free operation just decrease the reference count of the net 197 vector by one and do the real resource free operation when the reference count 198 of the net vector is 0. 199 200 @param[in] Nbuf Pointer to the NET_BUF to be freed. 201 202 **/ 203 VOID 204 EFIAPI 205 NetbufFree ( 206 IN NET_BUF *Nbuf 207 ) 208 { 209 ASSERT (Nbuf != NULL); 210 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 211 ASSERT (Nbuf->RefCnt > 0); 212 213 Nbuf->RefCnt--; 214 215 if (Nbuf->RefCnt == 0) { 216 // 217 // Update Vector only when NBuf is to be released. That is, 218 // all the sharing of Nbuf increse Vector's RefCnt by one 219 // 220 NetbufFreeVector (Nbuf->Vector); 221 FreePool (Nbuf); 222 } 223 } 224 225 226 /** 227 Create a copy of the net buffer that shares the associated net vector. 228 229 The reference count of the newly created net buffer is set to 1. The reference 230 count of the associated net vector is increased by one. 231 232 @param[in] Nbuf Pointer to the net buffer to be cloned. 233 234 @return Pointer to the cloned net buffer, or NULL if the 235 allocation failed due to resource limit. 236 237 **/ 238 NET_BUF * 239 EFIAPI 240 NetbufClone ( 241 IN NET_BUF *Nbuf 242 ) 243 { 244 NET_BUF *Clone; 245 246 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 247 248 Clone = AllocatePool (NET_BUF_SIZE (Nbuf->BlockOpNum)); 249 250 if (Clone == NULL) { 251 return NULL; 252 } 253 254 Clone->Signature = NET_BUF_SIGNATURE; 255 Clone->RefCnt = 1; 256 InitializeListHead (&Clone->List); 257 258 Clone->Ip = Nbuf->Ip; 259 Clone->Tcp = Nbuf->Tcp; 260 261 CopyMem (Clone->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA); 262 263 NET_GET_REF (Nbuf->Vector); 264 265 Clone->Vector = Nbuf->Vector; 266 Clone->BlockOpNum = Nbuf->BlockOpNum; 267 Clone->TotalSize = Nbuf->TotalSize; 268 CopyMem (Clone->BlockOp, Nbuf->BlockOp, sizeof (NET_BLOCK_OP) * Nbuf->BlockOpNum); 269 270 return Clone; 271 } 272 273 274 /** 275 Create a duplicated copy of the net buffer with data copied and HeadSpace 276 bytes of head space reserved. 277 278 The duplicated net buffer will allocate its own memory to hold the data of the 279 source net buffer. 280 281 @param[in] Nbuf Pointer to the net buffer to be duplicated from. 282 @param[in, out] Duplicate Pointer to the net buffer to duplicate to, if 283 NULL a new net buffer is allocated. 284 @param[in] HeadSpace Length of the head space to reserve. 285 286 @return Pointer to the duplicated net buffer, or NULL if 287 the allocation failed due to resource limit. 288 289 **/ 290 NET_BUF * 291 EFIAPI 292 NetbufDuplicate ( 293 IN NET_BUF *Nbuf, 294 IN OUT NET_BUF *Duplicate OPTIONAL, 295 IN UINT32 HeadSpace 296 ) 297 { 298 UINT8 *Dst; 299 300 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 301 302 if (Duplicate == NULL) { 303 Duplicate = NetbufAlloc (Nbuf->TotalSize + HeadSpace); 304 } 305 306 if (Duplicate == NULL) { 307 return NULL; 308 } 309 310 // 311 // Don't set the IP and TCP head point, since it is most 312 // like that they are pointing to the memory of Nbuf. 313 // 314 CopyMem (Duplicate->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA); 315 NetbufReserve (Duplicate, HeadSpace); 316 317 Dst = NetbufAllocSpace (Duplicate, Nbuf->TotalSize, NET_BUF_TAIL); 318 NetbufCopy (Nbuf, 0, Nbuf->TotalSize, Dst); 319 320 return Duplicate; 321 } 322 323 324 /** 325 Free a list of net buffers. 326 327 @param[in, out] Head Pointer to the head of linked net buffers. 328 329 **/ 330 VOID 331 EFIAPI 332 NetbufFreeList ( 333 IN OUT LIST_ENTRY *Head 334 ) 335 { 336 LIST_ENTRY *Entry; 337 LIST_ENTRY *Next; 338 NET_BUF *Nbuf; 339 340 Entry = Head->ForwardLink; 341 342 NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) { 343 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List); 344 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 345 346 RemoveEntryList (Entry); 347 NetbufFree (Nbuf); 348 } 349 350 ASSERT (IsListEmpty (Head)); 351 } 352 353 354 /** 355 Get the index of NET_BLOCK_OP that contains the byte at Offset in the net 356 buffer. 357 358 This can be used to, for example, retrieve the IP header in the packet. It 359 also can be used to get the fragment that contains the byte which is used 360 mainly by the library implementation itself. 361 362 @param[in] Nbuf Pointer to the net buffer. 363 @param[in] Offset The offset of the byte. 364 @param[out] Index Index of the NET_BLOCK_OP that contains the byte at 365 Offset. 366 367 @return Pointer to the Offset'th byte of data in the net buffer, or NULL 368 if there is no such data in the net buffer. 369 370 **/ 371 UINT8 * 372 EFIAPI 373 NetbufGetByte ( 374 IN NET_BUF *Nbuf, 375 IN UINT32 Offset, 376 OUT UINT32 *Index OPTIONAL 377 ) 378 { 379 NET_BLOCK_OP *BlockOp; 380 UINT32 Loop; 381 UINT32 Len; 382 383 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 384 385 if (Offset >= Nbuf->TotalSize) { 386 return NULL; 387 } 388 389 BlockOp = Nbuf->BlockOp; 390 Len = 0; 391 392 for (Loop = 0; Loop < Nbuf->BlockOpNum; Loop++) { 393 394 if (Len + BlockOp[Loop].Size <= Offset) { 395 Len += BlockOp[Loop].Size; 396 continue; 397 } 398 399 if (Index != NULL) { 400 *Index = Loop; 401 } 402 403 return BlockOp[Loop].Head + (Offset - Len); 404 } 405 406 return NULL; 407 } 408 409 410 411 /** 412 Set the NET_BLOCK and corresponding NET_BLOCK_OP in the net buffer and 413 corresponding net vector according to the bulk pointer and bulk length. 414 415 All the pointers in the Index'th NET_BLOCK and NET_BLOCK_OP are set to the 416 bulk's head and tail respectively. So, this function alone can't be used by 417 NetbufAlloc. 418 419 @param[in, out] Nbuf Pointer to the net buffer. 420 @param[in] Bulk Pointer to the data. 421 @param[in] Len Length of the bulk data. 422 @param[in] Index The data block index in the net buffer the bulk 423 data should belong to. 424 425 **/ 426 VOID 427 NetbufSetBlock ( 428 IN OUT NET_BUF *Nbuf, 429 IN UINT8 *Bulk, 430 IN UINT32 Len, 431 IN UINT32 Index 432 ) 433 { 434 NET_BLOCK_OP *BlockOp; 435 NET_BLOCK *Block; 436 437 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 438 NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE); 439 ASSERT (Index < Nbuf->BlockOpNum); 440 441 Block = &(Nbuf->Vector->Block[Index]); 442 BlockOp = &(Nbuf->BlockOp[Index]); 443 Block->Len = Len; 444 Block->Bulk = Bulk; 445 BlockOp->BlockHead = Bulk; 446 BlockOp->BlockTail = Bulk + Len; 447 BlockOp->Head = Bulk; 448 BlockOp->Tail = Bulk + Len; 449 BlockOp->Size = Len; 450 } 451 452 453 454 /** 455 Set the NET_BLOCK_OP in the net buffer. The corresponding NET_BLOCK 456 structure is left untouched. 457 458 Some times, there is no 1:1 relationship between NET_BLOCK and NET_BLOCK_OP. 459 For example, that in NetbufGetFragment. 460 461 @param[in, out] Nbuf Pointer to the net buffer. 462 @param[in] Bulk Pointer to the data. 463 @param[in] Len Length of the bulk data. 464 @param[in] Index The data block index in the net buffer the bulk 465 data should belong to. 466 467 **/ 468 VOID 469 NetbufSetBlockOp ( 470 IN OUT NET_BUF *Nbuf, 471 IN UINT8 *Bulk, 472 IN UINT32 Len, 473 IN UINT32 Index 474 ) 475 { 476 NET_BLOCK_OP *BlockOp; 477 478 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 479 ASSERT (Index < Nbuf->BlockOpNum); 480 481 BlockOp = &(Nbuf->BlockOp[Index]); 482 BlockOp->BlockHead = Bulk; 483 BlockOp->BlockTail = Bulk + Len; 484 BlockOp->Head = Bulk; 485 BlockOp->Tail = Bulk + Len; 486 BlockOp->Size = Len; 487 } 488 489 490 /** 491 Helper function for NetbufGetFragment. NetbufGetFragment may allocate the 492 first block to reserve HeadSpace bytes header space. So it needs to create a 493 new net vector for the first block and can avoid copy for the remaining data 494 by sharing the old net vector. 495 496 @param[in] Arg Point to the old NET_VECTOR. 497 498 **/ 499 VOID 500 EFIAPI 501 NetbufGetFragmentFree ( 502 IN VOID *Arg 503 ) 504 { 505 NET_VECTOR *Vector; 506 507 Vector = (NET_VECTOR *)Arg; 508 NetbufFreeVector (Vector); 509 } 510 511 512 /** 513 Create a NET_BUF structure which contains Len byte data of Nbuf starting from 514 Offset. 515 516 A new NET_BUF structure will be created but the associated data in NET_VECTOR 517 is shared. This function exists to do IP packet fragmentation. 518 519 @param[in] Nbuf Pointer to the net buffer to be extracted. 520 @param[in] Offset Starting point of the data to be included in the new 521 net buffer. 522 @param[in] Len Bytes of data to be included in the new net buffer. 523 @param[in] HeadSpace Bytes of head space to reserve for protocol header. 524 525 @return Pointer to the cloned net buffer, or NULL if the 526 allocation failed due to resource limit. 527 528 **/ 529 NET_BUF * 530 EFIAPI 531 NetbufGetFragment ( 532 IN NET_BUF *Nbuf, 533 IN UINT32 Offset, 534 IN UINT32 Len, 535 IN UINT32 HeadSpace 536 ) 537 { 538 NET_BUF *Child; 539 NET_VECTOR *Vector; 540 NET_BLOCK_OP *BlockOp; 541 UINT32 CurBlockOp; 542 UINT32 BlockOpNum; 543 UINT8 *FirstBulk; 544 UINT32 Index; 545 UINT32 First; 546 UINT32 Last; 547 UINT32 FirstSkip; 548 UINT32 FirstLen; 549 UINT32 LastLen; 550 UINT32 Cur; 551 552 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 553 554 if ((Len == 0) || (Offset + Len > Nbuf->TotalSize)) { 555 return NULL; 556 } 557 558 // 559 // First find the first and last BlockOp that contains 560 // the valid data, and compute the offset of the first 561 // BlockOp and length of the last BlockOp 562 // 563 BlockOp = Nbuf->BlockOp; 564 Cur = 0; 565 566 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) { 567 if (Offset < Cur + BlockOp[Index].Size) { 568 break; 569 } 570 571 Cur += BlockOp[Index].Size; 572 } 573 574 // 575 // First is the index of the first BlockOp, FirstSkip is 576 // the offset of the first byte in the first BlockOp. 577 // 578 First = Index; 579 FirstSkip = Offset - Cur; 580 FirstLen = BlockOp[Index].Size - FirstSkip; 581 582 Last = 0; 583 LastLen = 0; 584 585 if (Len > FirstLen) { 586 Cur += BlockOp[Index].Size; 587 Index++; 588 589 for (; Index < Nbuf->BlockOpNum; Index++) { 590 if (Offset + Len <= Cur + BlockOp[Index].Size) { 591 Last = Index; 592 LastLen = Offset + Len - Cur; 593 break; 594 } 595 596 Cur += BlockOp[Index].Size; 597 } 598 599 } else { 600 Last = First; 601 LastLen = Len; 602 FirstLen = Len; 603 } 604 605 ASSERT (Last >= First); 606 BlockOpNum = Last - First + 1; 607 CurBlockOp = 0; 608 609 if (HeadSpace != 0) { 610 // 611 // Allocate an extra block to accomdate the head space. 612 // 613 BlockOpNum++; 614 615 Child = NetbufAllocStruct (1, BlockOpNum); 616 617 if (Child == NULL) { 618 return NULL; 619 } 620 621 FirstBulk = AllocatePool (HeadSpace); 622 623 if (FirstBulk == NULL) { 624 goto FreeChild; 625 } 626 627 Vector = Child->Vector; 628 Vector->Free = NetbufGetFragmentFree; 629 Vector->Arg = Nbuf->Vector; 630 Vector->Flag = NET_VECTOR_OWN_FIRST; 631 Vector->Len = HeadSpace; 632 633 // 634 // Reserve the head space in the first block 635 // 636 NetbufSetBlock (Child, FirstBulk, HeadSpace, 0); 637 Child->BlockOp[0].Head += HeadSpace; 638 Child->BlockOp[0].Size = 0; 639 CurBlockOp++; 640 641 } else { 642 Child = NetbufAllocStruct (0, BlockOpNum); 643 644 if (Child == NULL) { 645 return NULL; 646 } 647 648 Child->Vector = Nbuf->Vector; 649 } 650 651 NET_GET_REF (Nbuf->Vector); 652 Child->TotalSize = Len; 653 654 // 655 // Set all the BlockOp up, the first and last one are special 656 // and need special process. 657 // 658 NetbufSetBlockOp ( 659 Child, 660 Nbuf->BlockOp[First].Head + FirstSkip, 661 FirstLen, 662 CurBlockOp++ 663 ); 664 665 for (Index = First + 1; Index < Last; Index++) { 666 NetbufSetBlockOp ( 667 Child, 668 BlockOp[Index].Head, 669 BlockOp[Index].Size, 670 CurBlockOp++ 671 ); 672 } 673 674 if (First != Last) { 675 NetbufSetBlockOp ( 676 Child, 677 BlockOp[Last].Head, 678 LastLen, 679 CurBlockOp 680 ); 681 } 682 683 CopyMem (Child->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA); 684 return Child; 685 686 FreeChild: 687 688 FreePool (Child); 689 return NULL; 690 } 691 692 693 694 /** 695 Build a NET_BUF from external blocks. 696 697 A new NET_BUF structure will be created from external blocks. Additional block 698 of memory will be allocated to hold reserved HeadSpace bytes of header room 699 and existing HeadLen bytes of header but the external blocks are shared by the 700 net buffer to avoid data copying. 701 702 @param[in] ExtFragment Pointer to the data block. 703 @param[in] ExtNum The number of the data blocks. 704 @param[in] HeadSpace The head space to be reserved. 705 @param[in] HeadLen The length of the protocol header, This function 706 will pull that number of data into a linear block. 707 @param[in] ExtFree Pointer to the caller provided free function. 708 @param[in] Arg The argument passed to ExtFree when ExtFree is 709 called. 710 711 @return Pointer to the net buffer built from the data blocks, 712 or NULL if the allocation failed due to resource 713 limit. 714 715 **/ 716 NET_BUF * 717 EFIAPI 718 NetbufFromExt ( 719 IN NET_FRAGMENT *ExtFragment, 720 IN UINT32 ExtNum, 721 IN UINT32 HeadSpace, 722 IN UINT32 HeadLen, 723 IN NET_VECTOR_EXT_FREE ExtFree, 724 IN VOID *Arg OPTIONAL 725 ) 726 { 727 NET_BUF *Nbuf; 728 NET_VECTOR *Vector; 729 NET_FRAGMENT SavedFragment; 730 UINT32 SavedIndex; 731 UINT32 TotalLen; 732 UINT32 BlockNum; 733 UINT8 *FirstBlock; 734 UINT32 FirstBlockLen; 735 UINT8 *Header; 736 UINT32 CurBlock; 737 UINT32 Index; 738 UINT32 Len; 739 UINT32 Copied; 740 741 ASSERT ((ExtFragment != NULL) && (ExtNum > 0) && (ExtFree != NULL)); 742 743 SavedFragment.Bulk = NULL; 744 SavedFragment.Len = 0; 745 746 FirstBlockLen = 0; 747 FirstBlock = NULL; 748 BlockNum = ExtNum; 749 Index = 0; 750 TotalLen = 0; 751 SavedIndex = 0; 752 Len = 0; 753 Copied = 0; 754 755 // 756 // No need to consolidate the header if the first block is 757 // longer than the header length or there is only one block. 758 // 759 if ((ExtFragment[0].Len >= HeadLen) || (ExtNum == 1)) { 760 HeadLen = 0; 761 } 762 763 // 764 // Allocate an extra block if we need to: 765 // 1. Allocate some header space 766 // 2. aggreate the packet header 767 // 768 if ((HeadSpace != 0) || (HeadLen != 0)) { 769 FirstBlockLen = HeadLen + HeadSpace; 770 FirstBlock = AllocatePool (FirstBlockLen); 771 772 if (FirstBlock == NULL) { 773 return NULL; 774 } 775 776 BlockNum++; 777 } 778 779 // 780 // Copy the header to the first block, reduce the NET_BLOCK 781 // to allocate by one for each block that is completely covered 782 // by the first bulk. 783 // 784 if (HeadLen != 0) { 785 Len = HeadLen; 786 Header = FirstBlock + HeadSpace; 787 788 for (Index = 0; Index < ExtNum; Index++) { 789 if (Len >= ExtFragment[Index].Len) { 790 CopyMem (Header, ExtFragment[Index].Bulk, ExtFragment[Index].Len); 791 792 Copied += ExtFragment[Index].Len; 793 Len -= ExtFragment[Index].Len; 794 Header += ExtFragment[Index].Len; 795 TotalLen += ExtFragment[Index].Len; 796 BlockNum--; 797 798 if (Len == 0) { 799 // 800 // Increament the index number to point to the next 801 // non-empty fragment. 802 // 803 Index++; 804 break; 805 } 806 807 } else { 808 CopyMem (Header, ExtFragment[Index].Bulk, Len); 809 810 Copied += Len; 811 TotalLen += Len; 812 813 // 814 // Adjust the block structure to exclude the data copied, 815 // So, the left-over block can be processed as other blocks. 816 // But it must be recovered later. (SavedIndex > 0) always 817 // holds since we don't aggreate the header if the first block 818 // is bigger enough that the header is continuous 819 // 820 SavedIndex = Index; 821 SavedFragment = ExtFragment[Index]; 822 ExtFragment[Index].Bulk += Len; 823 ExtFragment[Index].Len -= Len; 824 break; 825 } 826 } 827 } 828 829 Nbuf = NetbufAllocStruct (BlockNum, BlockNum); 830 831 if (Nbuf == NULL) { 832 goto FreeFirstBlock; 833 } 834 835 Vector = Nbuf->Vector; 836 Vector->Free = ExtFree; 837 Vector->Arg = Arg; 838 Vector->Flag = ((FirstBlockLen != 0) ? NET_VECTOR_OWN_FIRST : 0); 839 840 // 841 // Set the first block up which may contain 842 // some head space and aggregated header 843 // 844 CurBlock = 0; 845 846 if (FirstBlockLen != 0) { 847 NetbufSetBlock (Nbuf, FirstBlock, HeadSpace + Copied, 0); 848 Nbuf->BlockOp[0].Head += HeadSpace; 849 Nbuf->BlockOp[0].Size = Copied; 850 851 CurBlock++; 852 } 853 854 for (; Index < ExtNum; Index++) { 855 NetbufSetBlock (Nbuf, ExtFragment[Index].Bulk, ExtFragment[Index].Len, CurBlock); 856 TotalLen += ExtFragment[Index].Len; 857 CurBlock++; 858 } 859 860 Vector->Len = TotalLen + HeadSpace; 861 Nbuf->TotalSize = TotalLen; 862 863 if (SavedIndex != 0) { 864 ExtFragment[SavedIndex] = SavedFragment; 865 } 866 867 return Nbuf; 868 869 FreeFirstBlock: 870 if (FirstBlock != NULL) { 871 FreePool (FirstBlock); 872 } 873 return NULL; 874 } 875 876 877 /** 878 Build a fragment table to contain the fragments in the net buffer. This is the 879 opposite operation of the NetbufFromExt. 880 881 @param[in] Nbuf Point to the net buffer. 882 @param[in, out] ExtFragment Pointer to the data block. 883 @param[in, out] ExtNum The number of the data blocks. 884 885 @retval EFI_BUFFER_TOO_SMALL The number of non-empty block is bigger than 886 ExtNum. 887 @retval EFI_SUCCESS Fragment table is built successfully. 888 889 **/ 890 EFI_STATUS 891 EFIAPI 892 NetbufBuildExt ( 893 IN NET_BUF *Nbuf, 894 IN OUT NET_FRAGMENT *ExtFragment, 895 IN OUT UINT32 *ExtNum 896 ) 897 { 898 UINT32 Index; 899 UINT32 Current; 900 901 Current = 0; 902 903 for (Index = 0; (Index < Nbuf->BlockOpNum); Index++) { 904 if (Nbuf->BlockOp[Index].Size == 0) { 905 continue; 906 } 907 908 if (Current < *ExtNum) { 909 ExtFragment[Current].Bulk = Nbuf->BlockOp[Index].Head; 910 ExtFragment[Current].Len = Nbuf->BlockOp[Index].Size; 911 Current++; 912 } else { 913 return EFI_BUFFER_TOO_SMALL; 914 } 915 } 916 917 *ExtNum = Current; 918 return EFI_SUCCESS; 919 } 920 921 922 /** 923 Build a net buffer from a list of net buffers. 924 925 All the fragments will be collected from the list of NEW_BUF and then a new 926 net buffer will be created through NetbufFromExt. 927 928 @param[in] BufList A List of the net buffer. 929 @param[in] HeadSpace The head space to be reserved. 930 @param[in] HeaderLen The length of the protocol header, This function 931 will pull that number of data into a linear block. 932 @param[in] ExtFree Pointer to the caller provided free function. 933 @param[in] Arg The argument passed to ExtFree when ExtFree is called. 934 935 @return Pointer to the net buffer built from the list of net 936 buffers. 937 938 **/ 939 NET_BUF * 940 EFIAPI 941 NetbufFromBufList ( 942 IN LIST_ENTRY *BufList, 943 IN UINT32 HeadSpace, 944 IN UINT32 HeaderLen, 945 IN NET_VECTOR_EXT_FREE ExtFree, 946 IN VOID *Arg OPTIONAL 947 ) 948 { 949 NET_FRAGMENT *Fragment; 950 UINT32 FragmentNum; 951 LIST_ENTRY *Entry; 952 NET_BUF *Nbuf; 953 UINT32 Index; 954 UINT32 Current; 955 956 // 957 //Compute how many blocks are there 958 // 959 FragmentNum = 0; 960 961 NET_LIST_FOR_EACH (Entry, BufList) { 962 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List); 963 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 964 FragmentNum += Nbuf->BlockOpNum; 965 } 966 967 // 968 //Allocate and copy block points 969 // 970 Fragment = AllocatePool (sizeof (NET_FRAGMENT) * FragmentNum); 971 972 if (Fragment == NULL) { 973 return NULL; 974 } 975 976 Current = 0; 977 978 NET_LIST_FOR_EACH (Entry, BufList) { 979 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List); 980 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 981 982 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) { 983 if (Nbuf->BlockOp[Index].Size != 0) { 984 Fragment[Current].Bulk = Nbuf->BlockOp[Index].Head; 985 Fragment[Current].Len = Nbuf->BlockOp[Index].Size; 986 Current++; 987 } 988 } 989 } 990 991 Nbuf = NetbufFromExt (Fragment, Current, HeadSpace, HeaderLen, ExtFree, Arg); 992 FreePool (Fragment); 993 994 return Nbuf; 995 } 996 997 998 /** 999 Reserve some space in the header room of the net buffer. 1000 1001 Upon allocation, all the space are in the tail room of the buffer. Call this 1002 function to move some space to the header room. This function is quite limited 1003 in that it can only reserve space from the first block of an empty NET_BUF not 1004 built from the external. But it should be enough for the network stack. 1005 1006 @param[in, out] Nbuf Pointer to the net buffer. 1007 @param[in] Len The length of buffer to be reserved from the header. 1008 1009 **/ 1010 VOID 1011 EFIAPI 1012 NetbufReserve ( 1013 IN OUT NET_BUF *Nbuf, 1014 IN UINT32 Len 1015 ) 1016 { 1017 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 1018 NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE); 1019 1020 ASSERT ((Nbuf->BlockOpNum == 1) && (Nbuf->TotalSize == 0)); 1021 ASSERT ((Nbuf->Vector->Free == NULL) && (Nbuf->Vector->Len >= Len)); 1022 1023 Nbuf->BlockOp[0].Head += Len; 1024 Nbuf->BlockOp[0].Tail += Len; 1025 1026 ASSERT (Nbuf->BlockOp[0].Tail <= Nbuf->BlockOp[0].BlockTail); 1027 } 1028 1029 1030 /** 1031 Allocate Len bytes of space from the header or tail of the buffer. 1032 1033 @param[in, out] Nbuf Pointer to the net buffer. 1034 @param[in] Len The length of the buffer to be allocated. 1035 @param[in] FromHead The flag to indicate whether reserve the data 1036 from head (TRUE) or tail (FALSE). 1037 1038 @return Pointer to the first byte of the allocated buffer, 1039 or NULL if there is no sufficient space. 1040 1041 **/ 1042 UINT8* 1043 EFIAPI 1044 NetbufAllocSpace ( 1045 IN OUT NET_BUF *Nbuf, 1046 IN UINT32 Len, 1047 IN BOOLEAN FromHead 1048 ) 1049 { 1050 NET_BLOCK_OP *BlockOp; 1051 UINT32 Index; 1052 UINT8 *SavedTail; 1053 1054 Index = 0; 1055 1056 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 1057 NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE); 1058 1059 ASSERT (Len > 0); 1060 1061 if (FromHead) { 1062 // 1063 // Allocate some space from head. If the buffer is empty, 1064 // allocate from the first block. If it isn't, allocate 1065 // from the first non-empty block, or the block before that. 1066 // 1067 if (Nbuf->TotalSize == 0) { 1068 Index = 0; 1069 } else { 1070 NetbufGetByte (Nbuf, 0, &Index); 1071 1072 if ((NET_HEADSPACE(&(Nbuf->BlockOp[Index])) < Len) && (Index > 0)) { 1073 Index--; 1074 } 1075 } 1076 1077 BlockOp = &(Nbuf->BlockOp[Index]); 1078 1079 if (NET_HEADSPACE (BlockOp) < Len) { 1080 return NULL; 1081 } 1082 1083 BlockOp->Head -= Len; 1084 BlockOp->Size += Len; 1085 Nbuf->TotalSize += Len; 1086 1087 return BlockOp->Head; 1088 1089 } else { 1090 // 1091 // Allocate some space from the tail. If the buffer is empty, 1092 // allocate from the first block. If it isn't, allocate 1093 // from the last non-empty block, or the block after that. 1094 // 1095 if (Nbuf->TotalSize == 0) { 1096 Index = 0; 1097 } else { 1098 NetbufGetByte (Nbuf, Nbuf->TotalSize - 1, &Index); 1099 1100 if ((NET_TAILSPACE(&(Nbuf->BlockOp[Index])) < Len) && 1101 (Index < Nbuf->BlockOpNum - 1)) { 1102 1103 Index++; 1104 } 1105 } 1106 1107 BlockOp = &(Nbuf->BlockOp[Index]); 1108 1109 if (NET_TAILSPACE (BlockOp) < Len) { 1110 return NULL; 1111 } 1112 1113 SavedTail = BlockOp->Tail; 1114 1115 BlockOp->Tail += Len; 1116 BlockOp->Size += Len; 1117 Nbuf->TotalSize += Len; 1118 1119 return SavedTail; 1120 } 1121 } 1122 1123 1124 /** 1125 Trim a single NET_BLOCK by Len bytes from the header or tail. 1126 1127 @param[in, out] BlockOp Pointer to the NET_BLOCK. 1128 @param[in] Len The length of the data to be trimmed. 1129 @param[in] FromHead The flag to indicate whether trim data from head 1130 (TRUE) or tail (FALSE). 1131 1132 **/ 1133 VOID 1134 NetblockTrim ( 1135 IN OUT NET_BLOCK_OP *BlockOp, 1136 IN UINT32 Len, 1137 IN BOOLEAN FromHead 1138 ) 1139 { 1140 ASSERT ((BlockOp != NULL) && (BlockOp->Size >= Len)); 1141 1142 BlockOp->Size -= Len; 1143 1144 if (FromHead) { 1145 BlockOp->Head += Len; 1146 } else { 1147 BlockOp->Tail -= Len; 1148 } 1149 } 1150 1151 1152 /** 1153 Trim Len bytes from the header or tail of the net buffer. 1154 1155 @param[in, out] Nbuf Pointer to the net buffer. 1156 @param[in] Len The length of the data to be trimmed. 1157 @param[in] FromHead The flag to indicate whether trim data from head 1158 (TRUE) or tail (FALSE). 1159 1160 @return Length of the actually trimmed data, which is possible to be less 1161 than Len because the TotalSize of Nbuf is less than Len. 1162 1163 **/ 1164 UINT32 1165 EFIAPI 1166 NetbufTrim ( 1167 IN OUT NET_BUF *Nbuf, 1168 IN UINT32 Len, 1169 IN BOOLEAN FromHead 1170 ) 1171 { 1172 NET_BLOCK_OP *BlockOp; 1173 UINT32 Index; 1174 UINT32 Trimmed; 1175 1176 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 1177 1178 if (Len > Nbuf->TotalSize) { 1179 Len = Nbuf->TotalSize; 1180 } 1181 1182 // 1183 // If FromTail is true, iterate backward. That 1184 // is, init Index to NBuf->BlockNum - 1, and 1185 // decrease it by 1 during each loop. Otherwise, 1186 // iterate forward. That is, init Index to 0, and 1187 // increase it by 1 during each loop. 1188 // 1189 Trimmed = 0; 1190 Nbuf->TotalSize -= Len; 1191 1192 Index = (FromHead ? 0 : Nbuf->BlockOpNum - 1); 1193 BlockOp = Nbuf->BlockOp; 1194 1195 for (;;) { 1196 if (BlockOp[Index].Size == 0) { 1197 Index += (FromHead ? 1 : -1); 1198 continue; 1199 } 1200 1201 if (Len > BlockOp[Index].Size) { 1202 Len -= BlockOp[Index].Size; 1203 Trimmed += BlockOp[Index].Size; 1204 NetblockTrim (&BlockOp[Index], BlockOp[Index].Size, FromHead); 1205 } else { 1206 Trimmed += Len; 1207 NetblockTrim (&BlockOp[Index], Len, FromHead); 1208 break; 1209 } 1210 1211 Index += (FromHead ? 1 : -1); 1212 } 1213 1214 return Trimmed; 1215 } 1216 1217 1218 /** 1219 Copy Len bytes of data from the specific offset of the net buffer to the 1220 destination memory. 1221 1222 The Len bytes of data may cross the several fragments of the net buffer. 1223 1224 @param[in] Nbuf Pointer to the net buffer. 1225 @param[in] Offset The sequence number of the first byte to copy. 1226 @param[in] Len Length of the data to copy. 1227 @param[in] Dest The destination of the data to copy to. 1228 1229 @return The length of the actual copied data, or 0 if the offset 1230 specified exceeds the total size of net buffer. 1231 1232 **/ 1233 UINT32 1234 EFIAPI 1235 NetbufCopy ( 1236 IN NET_BUF *Nbuf, 1237 IN UINT32 Offset, 1238 IN UINT32 Len, 1239 IN UINT8 *Dest 1240 ) 1241 { 1242 NET_BLOCK_OP *BlockOp; 1243 UINT32 Skip; 1244 UINT32 Left; 1245 UINT32 Copied; 1246 UINT32 Index; 1247 UINT32 Cur; 1248 1249 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 1250 ASSERT (Dest); 1251 1252 if ((Len == 0) || (Nbuf->TotalSize <= Offset)) { 1253 return 0; 1254 } 1255 1256 if (Nbuf->TotalSize - Offset < Len) { 1257 Len = Nbuf->TotalSize - Offset; 1258 } 1259 1260 BlockOp = Nbuf->BlockOp; 1261 1262 // 1263 // Skip to the offset. Don't make "Offset-By-One" error here. 1264 // Cur + BLOCK.SIZE is the first sequence number of next block. 1265 // So, (Offset < Cur + BLOCK.SIZE) means that the first byte 1266 // is in the current block. if (Offset == Cur + BLOCK.SIZE), the 1267 // first byte is the next block's first byte. 1268 // 1269 Cur = 0; 1270 1271 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) { 1272 if (BlockOp[Index].Size == 0) { 1273 continue; 1274 } 1275 1276 if (Offset < Cur + BlockOp[Index].Size) { 1277 break; 1278 } 1279 1280 Cur += BlockOp[Index].Size; 1281 } 1282 1283 // 1284 // Cur is the sequence number of the first byte in the block 1285 // Offset - Cur is the number of bytes before first byte to 1286 // to copy in the current block. 1287 // 1288 Skip = Offset - Cur; 1289 Left = BlockOp[Index].Size - Skip; 1290 1291 if (Len <= Left) { 1292 CopyMem (Dest, BlockOp[Index].Head + Skip, Len); 1293 return Len; 1294 } 1295 1296 CopyMem (Dest, BlockOp[Index].Head + Skip, Left); 1297 1298 Dest += Left; 1299 Len -= Left; 1300 Copied = Left; 1301 1302 Index++; 1303 1304 for (; Index < Nbuf->BlockOpNum; Index++) { 1305 if (Len > BlockOp[Index].Size) { 1306 Len -= BlockOp[Index].Size; 1307 Copied += BlockOp[Index].Size; 1308 1309 CopyMem (Dest, BlockOp[Index].Head, BlockOp[Index].Size); 1310 Dest += BlockOp[Index].Size; 1311 } else { 1312 Copied += Len; 1313 CopyMem (Dest, BlockOp[Index].Head, Len); 1314 break; 1315 } 1316 } 1317 1318 return Copied; 1319 } 1320 1321 1322 /** 1323 Initiate the net buffer queue. 1324 1325 @param[in, out] NbufQue Pointer to the net buffer queue to be initialized. 1326 1327 **/ 1328 VOID 1329 EFIAPI 1330 NetbufQueInit ( 1331 IN OUT NET_BUF_QUEUE *NbufQue 1332 ) 1333 { 1334 NbufQue->Signature = NET_QUE_SIGNATURE; 1335 NbufQue->RefCnt = 1; 1336 InitializeListHead (&NbufQue->List); 1337 1338 InitializeListHead (&NbufQue->BufList); 1339 NbufQue->BufSize = 0; 1340 NbufQue->BufNum = 0; 1341 } 1342 1343 1344 /** 1345 Allocate and initialize a net buffer queue. 1346 1347 @return Pointer to the allocated net buffer queue, or NULL if the 1348 allocation failed due to resource limit. 1349 1350 **/ 1351 NET_BUF_QUEUE * 1352 EFIAPI 1353 NetbufQueAlloc ( 1354 VOID 1355 ) 1356 { 1357 NET_BUF_QUEUE *NbufQue; 1358 1359 NbufQue = AllocatePool (sizeof (NET_BUF_QUEUE)); 1360 if (NbufQue == NULL) { 1361 return NULL; 1362 } 1363 1364 NetbufQueInit (NbufQue); 1365 1366 return NbufQue; 1367 } 1368 1369 1370 /** 1371 Free a net buffer queue. 1372 1373 Decrease the reference count of the net buffer queue by one. The real resource 1374 free operation isn't performed until the reference count of the net buffer 1375 queue is decreased to 0. 1376 1377 @param[in] NbufQue Pointer to the net buffer queue to be freed. 1378 1379 **/ 1380 VOID 1381 EFIAPI 1382 NetbufQueFree ( 1383 IN NET_BUF_QUEUE *NbufQue 1384 ) 1385 { 1386 ASSERT (NbufQue != NULL); 1387 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE); 1388 1389 NbufQue->RefCnt--; 1390 1391 if (NbufQue->RefCnt == 0) { 1392 NetbufQueFlush (NbufQue); 1393 FreePool (NbufQue); 1394 } 1395 } 1396 1397 1398 /** 1399 Append a net buffer to the net buffer queue. 1400 1401 @param[in, out] NbufQue Pointer to the net buffer queue. 1402 @param[in, out] Nbuf Pointer to the net buffer to be appended. 1403 1404 **/ 1405 VOID 1406 EFIAPI 1407 NetbufQueAppend ( 1408 IN OUT NET_BUF_QUEUE *NbufQue, 1409 IN OUT NET_BUF *Nbuf 1410 ) 1411 { 1412 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE); 1413 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 1414 1415 InsertTailList (&NbufQue->BufList, &Nbuf->List); 1416 1417 NbufQue->BufSize += Nbuf->TotalSize; 1418 NbufQue->BufNum++; 1419 } 1420 1421 1422 /** 1423 Remove a net buffer from the head in the specific queue and return it. 1424 1425 @param[in, out] NbufQue Pointer to the net buffer queue. 1426 1427 @return Pointer to the net buffer removed from the specific queue, 1428 or NULL if there is no net buffer in the specific queue. 1429 1430 **/ 1431 NET_BUF * 1432 EFIAPI 1433 NetbufQueRemove ( 1434 IN OUT NET_BUF_QUEUE *NbufQue 1435 ) 1436 { 1437 NET_BUF *First; 1438 1439 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE); 1440 1441 if (NbufQue->BufNum == 0) { 1442 return NULL; 1443 } 1444 1445 First = NET_LIST_USER_STRUCT (NbufQue->BufList.ForwardLink, NET_BUF, List); 1446 1447 NetListRemoveHead (&NbufQue->BufList); 1448 1449 NbufQue->BufSize -= First->TotalSize; 1450 NbufQue->BufNum--; 1451 return First; 1452 } 1453 1454 1455 /** 1456 Copy Len bytes of data from the net buffer queue at the specific offset to the 1457 destination memory. 1458 1459 The copying operation is the same as NetbufCopy but applies to the net buffer 1460 queue instead of the net buffer. 1461 1462 @param[in] NbufQue Pointer to the net buffer queue. 1463 @param[in] Offset The sequence number of the first byte to copy. 1464 @param[in] Len Length of the data to copy. 1465 @param[out] Dest The destination of the data to copy to. 1466 1467 @return The length of the actual copied data, or 0 if the offset 1468 specified exceeds the total size of net buffer queue. 1469 1470 **/ 1471 UINT32 1472 EFIAPI 1473 NetbufQueCopy ( 1474 IN NET_BUF_QUEUE *NbufQue, 1475 IN UINT32 Offset, 1476 IN UINT32 Len, 1477 OUT UINT8 *Dest 1478 ) 1479 { 1480 LIST_ENTRY *Entry; 1481 NET_BUF *Nbuf; 1482 UINT32 Skip; 1483 UINT32 Left; 1484 UINT32 Cur; 1485 UINT32 Copied; 1486 1487 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE); 1488 ASSERT (Dest != NULL); 1489 1490 if ((Len == 0) || (NbufQue->BufSize <= Offset)) { 1491 return 0; 1492 } 1493 1494 if (NbufQue->BufSize - Offset < Len) { 1495 Len = NbufQue->BufSize - Offset; 1496 } 1497 1498 // 1499 // skip to the Offset 1500 // 1501 Cur = 0; 1502 Nbuf = NULL; 1503 1504 NET_LIST_FOR_EACH (Entry, &NbufQue->BufList) { 1505 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List); 1506 1507 if (Offset < Cur + Nbuf->TotalSize) { 1508 break; 1509 } 1510 1511 Cur += Nbuf->TotalSize; 1512 } 1513 1514 ASSERT (Nbuf != NULL); 1515 1516 // 1517 // Copy the data in the first buffer. 1518 // 1519 Skip = Offset - Cur; 1520 Left = Nbuf->TotalSize - Skip; 1521 1522 if (Len < Left) { 1523 return NetbufCopy (Nbuf, Skip, Len, Dest); 1524 } 1525 1526 NetbufCopy (Nbuf, Skip, Left, Dest); 1527 Dest += Left; 1528 Len -= Left; 1529 Copied = Left; 1530 1531 // 1532 // Iterate over the others 1533 // 1534 Entry = Entry->ForwardLink; 1535 1536 while ((Len > 0) && (Entry != &NbufQue->BufList)) { 1537 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List); 1538 1539 if (Len > Nbuf->TotalSize) { 1540 Len -= Nbuf->TotalSize; 1541 Copied += Nbuf->TotalSize; 1542 1543 NetbufCopy (Nbuf, 0, Nbuf->TotalSize, Dest); 1544 Dest += Nbuf->TotalSize; 1545 1546 } else { 1547 NetbufCopy (Nbuf, 0, Len, Dest); 1548 Copied += Len; 1549 break; 1550 } 1551 1552 Entry = Entry->ForwardLink; 1553 } 1554 1555 return Copied; 1556 } 1557 1558 1559 /** 1560 Trim Len bytes of data from the buffer queue and free any net buffer 1561 that is completely trimmed. 1562 1563 The trimming operation is the same as NetbufTrim but applies to the net buffer 1564 queue instead of the net buffer. 1565 1566 @param[in, out] NbufQue Pointer to the net buffer queue. 1567 @param[in] Len Length of the data to trim. 1568 1569 @return The actual length of the data trimmed. 1570 1571 **/ 1572 UINT32 1573 EFIAPI 1574 NetbufQueTrim ( 1575 IN OUT NET_BUF_QUEUE *NbufQue, 1576 IN UINT32 Len 1577 ) 1578 { 1579 LIST_ENTRY *Entry; 1580 LIST_ENTRY *Next; 1581 NET_BUF *Nbuf; 1582 UINT32 Trimmed; 1583 1584 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE); 1585 1586 if (Len == 0) { 1587 return 0; 1588 } 1589 1590 if (Len > NbufQue->BufSize) { 1591 Len = NbufQue->BufSize; 1592 } 1593 1594 NbufQue->BufSize -= Len; 1595 Trimmed = 0; 1596 1597 NET_LIST_FOR_EACH_SAFE (Entry, Next, &NbufQue->BufList) { 1598 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List); 1599 1600 if (Len >= Nbuf->TotalSize) { 1601 Trimmed += Nbuf->TotalSize; 1602 Len -= Nbuf->TotalSize; 1603 1604 RemoveEntryList (Entry); 1605 NetbufFree (Nbuf); 1606 1607 NbufQue->BufNum--; 1608 1609 if (Len == 0) { 1610 break; 1611 } 1612 1613 } else { 1614 Trimmed += NetbufTrim (Nbuf, Len, NET_BUF_HEAD); 1615 break; 1616 } 1617 } 1618 1619 return Trimmed; 1620 } 1621 1622 1623 /** 1624 Flush the net buffer queue. 1625 1626 @param[in, out] NbufQue Pointer to the queue to be flushed. 1627 1628 **/ 1629 VOID 1630 EFIAPI 1631 NetbufQueFlush ( 1632 IN OUT NET_BUF_QUEUE *NbufQue 1633 ) 1634 { 1635 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE); 1636 1637 NetbufFreeList (&NbufQue->BufList); 1638 1639 NbufQue->BufNum = 0; 1640 NbufQue->BufSize = 0; 1641 } 1642 1643 1644 /** 1645 Compute the checksum for a bulk of data. 1646 1647 @param[in] Bulk Pointer to the data. 1648 @param[in] Len Length of the data, in bytes. 1649 1650 @return The computed checksum. 1651 1652 **/ 1653 UINT16 1654 EFIAPI 1655 NetblockChecksum ( 1656 IN UINT8 *Bulk, 1657 IN UINT32 Len 1658 ) 1659 { 1660 register UINT32 Sum; 1661 1662 Sum = 0; 1663 1664 while (Len > 1) { 1665 Sum += *(UINT16 *) Bulk; 1666 Bulk += 2; 1667 Len -= 2; 1668 } 1669 1670 // 1671 // Add left-over byte, if any 1672 // 1673 if (Len > 0) { 1674 Sum += *(UINT8 *) Bulk; 1675 } 1676 1677 // 1678 // Fold 32-bit sum to 16 bits 1679 // 1680 while ((Sum >> 16) != 0) { 1681 Sum = (Sum & 0xffff) + (Sum >> 16); 1682 1683 } 1684 1685 return (UINT16) Sum; 1686 } 1687 1688 1689 /** 1690 Add two checksums. 1691 1692 @param[in] Checksum1 The first checksum to be added. 1693 @param[in] Checksum2 The second checksum to be added. 1694 1695 @return The new checksum. 1696 1697 **/ 1698 UINT16 1699 EFIAPI 1700 NetAddChecksum ( 1701 IN UINT16 Checksum1, 1702 IN UINT16 Checksum2 1703 ) 1704 { 1705 UINT32 Sum; 1706 1707 Sum = Checksum1 + Checksum2; 1708 1709 // 1710 // two UINT16 can only add up to a carry of 1. 1711 // 1712 if ((Sum >> 16) != 0) { 1713 Sum = (Sum & 0xffff) + 1; 1714 1715 } 1716 1717 return (UINT16) Sum; 1718 } 1719 1720 1721 /** 1722 Compute the checksum for a NET_BUF. 1723 1724 @param[in] Nbuf Pointer to the net buffer. 1725 1726 @return The computed checksum. 1727 1728 **/ 1729 UINT16 1730 EFIAPI 1731 NetbufChecksum ( 1732 IN NET_BUF *Nbuf 1733 ) 1734 { 1735 NET_BLOCK_OP *BlockOp; 1736 UINT32 Offset; 1737 UINT16 TotalSum; 1738 UINT16 BlockSum; 1739 UINT32 Index; 1740 1741 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 1742 1743 TotalSum = 0; 1744 Offset = 0; 1745 BlockOp = Nbuf->BlockOp; 1746 1747 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) { 1748 if (BlockOp[Index].Size == 0) { 1749 continue; 1750 } 1751 1752 BlockSum = NetblockChecksum (BlockOp[Index].Head, BlockOp[Index].Size); 1753 1754 if ((Offset & 0x01) != 0) { 1755 // 1756 // The checksum starts with an odd byte, swap 1757 // the checksum before added to total checksum 1758 // 1759 BlockSum = SwapBytes16 (BlockSum); 1760 } 1761 1762 TotalSum = NetAddChecksum (BlockSum, TotalSum); 1763 Offset += BlockOp[Index].Size; 1764 } 1765 1766 return TotalSum; 1767 } 1768 1769 1770 /** 1771 Compute the checksum for TCP/UDP pseudo header. 1772 1773 Src and Dst are in network byte order, and Len is in host byte order. 1774 1775 @param[in] Src The source address of the packet. 1776 @param[in] Dst The destination address of the packet. 1777 @param[in] Proto The protocol type of the packet. 1778 @param[in] Len The length of the packet. 1779 1780 @return The computed checksum. 1781 1782 **/ 1783 UINT16 1784 EFIAPI 1785 NetPseudoHeadChecksum ( 1786 IN IP4_ADDR Src, 1787 IN IP4_ADDR Dst, 1788 IN UINT8 Proto, 1789 IN UINT16 Len 1790 ) 1791 { 1792 NET_PSEUDO_HDR Hdr; 1793 1794 // 1795 // Zero the memory to relieve align problems 1796 // 1797 ZeroMem (&Hdr, sizeof (Hdr)); 1798 1799 Hdr.SrcIp = Src; 1800 Hdr.DstIp = Dst; 1801 Hdr.Protocol = Proto; 1802 Hdr.Len = HTONS (Len); 1803 1804 return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr)); 1805 } 1806 1807 /** 1808 Compute the checksum for TCP6/UDP6 pseudo header. 1809 1810 Src and Dst are in network byte order, and Len is in host byte order. 1811 1812 @param[in] Src The source address of the packet. 1813 @param[in] Dst The destination address of the packet. 1814 @param[in] NextHeader The protocol type of the packet. 1815 @param[in] Len The length of the packet. 1816 1817 @return The computed checksum. 1818 1819 **/ 1820 UINT16 1821 EFIAPI 1822 NetIp6PseudoHeadChecksum ( 1823 IN EFI_IPv6_ADDRESS *Src, 1824 IN EFI_IPv6_ADDRESS *Dst, 1825 IN UINT8 NextHeader, 1826 IN UINT32 Len 1827 ) 1828 { 1829 NET_IP6_PSEUDO_HDR Hdr; 1830 1831 // 1832 // Zero the memory to relieve align problems 1833 // 1834 ZeroMem (&Hdr, sizeof (Hdr)); 1835 1836 IP6_COPY_ADDRESS (&Hdr.SrcIp, Src); 1837 IP6_COPY_ADDRESS (&Hdr.DstIp, Dst); 1838 1839 Hdr.NextHeader = NextHeader; 1840 Hdr.Len = HTONL (Len); 1841 1842 return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr)); 1843 } 1844 1845 /** 1846 The function frees the net buffer which allocated by the IP protocol. It releases 1847 only the net buffer and doesn't call the external free function. 1848 1849 This function should be called after finishing the process of mIpSec->ProcessExt() 1850 for outbound traffic. The (EFI_IPSEC2_PROTOCOL)->ProcessExt() allocates a new 1851 buffer for the ESP, so there needs a function to free the old net buffer. 1852 1853 @param[in] Nbuf The network buffer to be freed. 1854 1855 **/ 1856 VOID 1857 NetIpSecNetbufFree ( 1858 NET_BUF *Nbuf 1859 ) 1860 { 1861 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 1862 ASSERT (Nbuf->RefCnt > 0); 1863 1864 Nbuf->RefCnt--; 1865 1866 if (Nbuf->RefCnt == 0) { 1867 1868 // 1869 // Update Vector only when NBuf is to be released. That is, 1870 // all the sharing of Nbuf increse Vector's RefCnt by one 1871 // 1872 NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE); 1873 ASSERT (Nbuf->Vector->RefCnt > 0); 1874 1875 Nbuf->Vector->RefCnt--; 1876 1877 if (Nbuf->Vector->RefCnt > 0) { 1878 return; 1879 } 1880 1881 // 1882 // If NET_VECTOR_OWN_FIRST is set, release the first block since it is 1883 // allocated by us 1884 // 1885 if ((Nbuf->Vector->Flag & NET_VECTOR_OWN_FIRST) != 0) { 1886 FreePool (Nbuf->Vector->Block[0].Bulk); 1887 } 1888 FreePool (Nbuf->Vector); 1889 FreePool (Nbuf); 1890 } 1891 } 1892 1893