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