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