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