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