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