]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeNetLib/NetBuffer.c
Add more comments to describe the net buffer operation functions.
[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 vector.
141
142 Decrease the reference count of the vector by one. The real resource free
143 operation isn't performed until the reference count of the vector is decreased
144 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) {
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
194 vector and itself if the reference count of the net buffer is decreased to 0.
195 The vector free operation just decrease the reference count of the vector by
196 one and do the real resource free operation when the reference count of the
197 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 NOT YET
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 nth byte of data in the net buffer, or NULL
366 indicating 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 NetbufClone. It is necessary because NetbufGetFragment
490 may allocate the first block to accomodate the HeadSpace and HeadLen. So, it
491 need to create a new NET_VECTOR. But, we want to avoid data copy by sharing
492 the old NET_VECTOR.
493
494 @param[in] Arg Point to the old NET_VECTOR.
495 NOT YET
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 indicating
524 the 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 indicating the allocation failed due to
713 resource 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) {
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 indicating 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 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 indicating there is no net buffer in the specific
1424 queue.
1425
1426 **/
1427 NET_BUF *
1428 EFIAPI
1429 NetbufQueRemove (
1430 IN OUT NET_BUF_QUEUE *NbufQue
1431 )
1432 {
1433 NET_BUF *First;
1434
1435 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1436
1437 if (NbufQue->BufNum == 0) {
1438 return NULL;
1439 }
1440
1441 First = NET_LIST_USER_STRUCT (NbufQue->BufList.ForwardLink, NET_BUF, List);
1442
1443 NetListRemoveHead (&NbufQue->BufList);
1444
1445 NbufQue->BufSize -= First->TotalSize;
1446 NbufQue->BufNum--;
1447 return First;
1448 }
1449
1450
1451 /**
1452 Copy Len bytes of data from the net buffer queue at the specific offset to the
1453 destination memory.
1454
1455 The copying operation is the same as NetbufCopy but applies to the net buffer
1456 queue instead of the net buffer.
1457
1458 @param[in] NbufQue Pointer to the net buffer queue.
1459 @param[in] Offset The sequence number of the first byte to copy.
1460 @param[in] Len Length of the data to copy.
1461 @param[out] Dest The destination of the data to copy to.
1462
1463 @return The length of the actual copied data, or 0 indicating the offset
1464 specified exceeds the total size of net buffer queue.
1465
1466 **/
1467 UINT32
1468 EFIAPI
1469 NetbufQueCopy (
1470 IN NET_BUF_QUEUE *NbufQue,
1471 IN UINT32 Offset,
1472 IN UINT32 Len,
1473 OUT UINT8 *Dest
1474 )
1475 {
1476 LIST_ENTRY *Entry;
1477 NET_BUF *Nbuf;
1478 UINT32 Skip;
1479 UINT32 Left;
1480 UINT32 Cur;
1481 UINT32 Copied;
1482
1483 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1484 ASSERT (Dest != NULL);
1485
1486 if ((Len == 0) || (NbufQue->BufSize <= Offset)) {
1487 return 0;
1488 }
1489
1490 if (NbufQue->BufSize - Offset < Len) {
1491 Len = NbufQue->BufSize - Offset;
1492 }
1493
1494 //
1495 // skip to the Offset
1496 //
1497 Cur = 0;
1498 Nbuf = NULL;
1499
1500 NET_LIST_FOR_EACH (Entry, &NbufQue->BufList) {
1501 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1502
1503 if (Offset < Cur + Nbuf->TotalSize) {
1504 break;
1505 }
1506
1507 Cur += Nbuf->TotalSize;
1508 }
1509
1510 //
1511 // Copy the data in the first buffer.
1512 //
1513 Skip = Offset - Cur;
1514 Left = Nbuf->TotalSize - Skip;
1515
1516 if (Len < Left) {
1517 return NetbufCopy (Nbuf, Skip, Len, Dest);
1518 }
1519
1520 NetbufCopy (Nbuf, Skip, Left, Dest);
1521 Dest += Left;
1522 Len -= Left;
1523 Copied = Left;
1524
1525 //
1526 // Iterate over the others
1527 //
1528 Entry = Entry->ForwardLink;
1529
1530 while ((Len > 0) && (Entry != &NbufQue->BufList)) {
1531 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1532
1533 if (Len > Nbuf->TotalSize) {
1534 Len -= Nbuf->TotalSize;
1535 Copied += Nbuf->TotalSize;
1536
1537 NetbufCopy (Nbuf, 0, Nbuf->TotalSize, Dest);
1538 Dest += Nbuf->TotalSize;
1539
1540 } else {
1541 NetbufCopy (Nbuf, 0, Len, Dest);
1542 Copied += Len;
1543 break;
1544 }
1545
1546 Entry = Entry->ForwardLink;
1547 }
1548
1549 return Copied;
1550 }
1551
1552
1553 /**
1554 Trim Len bytes of data from the queue header, release any of the net buffer
1555 whom is trimmed wholely.
1556
1557 The trimming operation is the same as NetbufTrim but applies to the net buffer
1558 queue instead of the net buffer.
1559
1560 @param[in, out] NbufQue Pointer to the net buffer queue.
1561 @param[in] Len Length of the data to trim.
1562
1563 @return The actual length of the data trimmed.
1564
1565 **/
1566 UINT32
1567 EFIAPI
1568 NetbufQueTrim (
1569 IN OUT NET_BUF_QUEUE *NbufQue,
1570 IN UINT32 Len
1571 )
1572 {
1573 LIST_ENTRY *Entry;
1574 LIST_ENTRY *Next;
1575 NET_BUF *Nbuf;
1576 UINT32 Trimmed;
1577
1578 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1579
1580 if (Len == 0) {
1581 return 0;
1582 }
1583
1584 if (Len > NbufQue->BufSize) {
1585 Len = NbufQue->BufSize;
1586 }
1587
1588 NbufQue->BufSize -= Len;
1589 Trimmed = 0;
1590
1591 NET_LIST_FOR_EACH_SAFE (Entry, Next, &NbufQue->BufList) {
1592 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1593
1594 if (Len >= Nbuf->TotalSize) {
1595 Trimmed += Nbuf->TotalSize;
1596 Len -= Nbuf->TotalSize;
1597
1598 RemoveEntryList (Entry);
1599 NetbufFree (Nbuf);
1600
1601 NbufQue->BufNum--;
1602
1603 if (Len == 0) {
1604 break;
1605 }
1606
1607 } else {
1608 Trimmed += NetbufTrim (Nbuf, Len, NET_BUF_HEAD);
1609 break;
1610 }
1611 }
1612
1613 return Trimmed;
1614 }
1615
1616
1617 /**
1618 Flush the net buffer queue.
1619
1620 @param[in, out] NbufQue Pointer to the queue to be flushed.
1621
1622 **/
1623 VOID
1624 EFIAPI
1625 NetbufQueFlush (
1626 IN OUT NET_BUF_QUEUE *NbufQue
1627 )
1628 {
1629 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
1630
1631 NetbufFreeList (&NbufQue->BufList);
1632
1633 NbufQue->BufNum = 0;
1634 NbufQue->BufSize = 0;
1635 }
1636
1637
1638 /**
1639 Compute the checksum for a bulk of data.
1640
1641 @param[in] Bulk Pointer to the data.
1642 @param[in] Len Length of the data, in bytes.
1643
1644 @return The computed checksum.
1645
1646 **/
1647 UINT16
1648 EFIAPI
1649 NetblockChecksum (
1650 IN UINT8 *Bulk,
1651 IN UINT32 Len
1652 )
1653 {
1654 register UINT32 Sum;
1655
1656 Sum = 0;
1657
1658 while (Len > 1) {
1659 Sum += *(UINT16 *) Bulk;
1660 Bulk += 2;
1661 Len -= 2;
1662 }
1663
1664 //
1665 // Add left-over byte, if any
1666 //
1667 if (Len > 0) {
1668 Sum += *(UINT8 *) Bulk;
1669 }
1670
1671 //
1672 // Fold 32-bit sum to 16 bits
1673 //
1674 while ((Sum >> 16) != 0) {
1675 Sum = (Sum & 0xffff) + (Sum >> 16);
1676
1677 }
1678
1679 return (UINT16) Sum;
1680 }
1681
1682
1683 /**
1684 Add two checksums.
1685
1686 @param[in] Checksum1 The first checksum to be added.
1687 @param[in] Checksum2 The second checksum to be added.
1688
1689 @return The new checksum.
1690
1691 **/
1692 UINT16
1693 EFIAPI
1694 NetAddChecksum (
1695 IN UINT16 Checksum1,
1696 IN UINT16 Checksum2
1697 )
1698 {
1699 UINT32 Sum;
1700
1701 Sum = Checksum1 + Checksum2;
1702
1703 //
1704 // two UINT16 can only add up to a carry of 1.
1705 //
1706 if ((Sum >> 16) != 0) {
1707 Sum = (Sum & 0xffff) + 1;
1708
1709 }
1710
1711 return (UINT16) Sum;
1712 }
1713
1714
1715 /**
1716 Compute the checksum for a NET_BUF.
1717
1718 @param[in] Nbuf Pointer to the net buffer.
1719
1720 @return The computed checksum.
1721
1722 **/
1723 UINT16
1724 EFIAPI
1725 NetbufChecksum (
1726 IN NET_BUF *Nbuf
1727 )
1728 {
1729 NET_BLOCK_OP *BlockOp;
1730 UINT32 Offset;
1731 UINT16 TotalSum;
1732 UINT16 BlockSum;
1733 UINT32 Index;
1734
1735 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1736
1737 TotalSum = 0;
1738 Offset = 0;
1739 BlockOp = Nbuf->BlockOp;
1740
1741 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
1742 if (BlockOp[Index].Size == 0) {
1743 continue;
1744 }
1745
1746 BlockSum = NetblockChecksum (BlockOp[Index].Head, BlockOp[Index].Size);
1747
1748 if ((Offset & 0x01) != 0) {
1749 //
1750 // The checksum starts with an odd byte, swap
1751 // the checksum before added to total checksum
1752 //
1753 BlockSum = (UINT16) NET_SWAP_SHORT (BlockSum);
1754 }
1755
1756 TotalSum = NetAddChecksum (BlockSum, TotalSum);
1757 Offset += BlockOp[Index].Size;
1758 }
1759
1760 return TotalSum;
1761 }
1762
1763
1764 /**
1765 Compute the checksum for TCP/UDP pseudo header.
1766
1767 Src and Dst are in network byte order, and Len is in host byte order.
1768
1769 @param[in] Src The source address of the packet.
1770 @param[in] Dst The destination address of the packet.
1771 @param[in] Proto The protocol type of the packet.
1772 @param[in] Len The length of the packet.
1773
1774 @return The computed checksum.
1775
1776 **/
1777 UINT16
1778 EFIAPI
1779 NetPseudoHeadChecksum (
1780 IN IP4_ADDR Src,
1781 IN IP4_ADDR Dst,
1782 IN UINT8 Proto,
1783 IN UINT16 Len
1784 )
1785 {
1786 NET_PSEUDO_HDR Hdr;
1787
1788 //
1789 // Zero the memory to relieve align problems
1790 //
1791 ZeroMem (&Hdr, sizeof (Hdr));
1792
1793 Hdr.SrcIp = Src;
1794 Hdr.DstIp = Dst;
1795 Hdr.Protocol = Proto;
1796 Hdr.Len = HTONS (Len);
1797
1798 return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));
1799 }