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