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 *
NetbufAllocStruct(IN UINT32 BlockNum,IN UINT32 BlockOpNum)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
NetbufAlloc(IN UINT32 Len)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
NetbufFreeVector(IN NET_VECTOR * Vector)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
NetbufFree(IN NET_BUF * Nbuf)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
NetbufClone(IN NET_BUF * Nbuf)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
NetbufDuplicate(IN NET_BUF * Nbuf,IN OUT NET_BUF * Duplicate OPTIONAL,IN UINT32 HeadSpace)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
NetbufFreeList(IN OUT LIST_ENTRY * Head)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
NetbufGetByte(IN NET_BUF * Nbuf,IN UINT32 Offset,OUT UINT32 * Index OPTIONAL)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
NetbufSetBlock(IN OUT NET_BUF * Nbuf,IN UINT8 * Bulk,IN UINT32 Len,IN UINT32 Index)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
NetbufSetBlockOp(IN OUT NET_BUF * Nbuf,IN UINT8 * Bulk,IN UINT32 Len,IN UINT32 Index)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
NetbufGetFragmentFree(IN VOID * Arg)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
NetbufGetFragment(IN NET_BUF * Nbuf,IN UINT32 Offset,IN UINT32 Len,IN UINT32 HeadSpace)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
NetbufFromExt(IN NET_FRAGMENT * ExtFragment,IN UINT32 ExtNum,IN UINT32 HeadSpace,IN UINT32 HeadLen,IN NET_VECTOR_EXT_FREE ExtFree,IN VOID * Arg OPTIONAL)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
NetbufBuildExt(IN NET_BUF * Nbuf,IN OUT NET_FRAGMENT * ExtFragment,IN OUT UINT32 * ExtNum)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
NetbufFromBufList(IN LIST_ENTRY * BufList,IN UINT32 HeadSpace,IN UINT32 HeaderLen,IN NET_VECTOR_EXT_FREE ExtFree,IN VOID * Arg OPTIONAL)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
NetbufReserve(IN OUT NET_BUF * Nbuf,IN UINT32 Len)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
NetbufAllocSpace(IN OUT NET_BUF * Nbuf,IN UINT32 Len,IN BOOLEAN FromHead)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
NetblockTrim(IN OUT NET_BLOCK_OP * BlockOp,IN UINT32 Len,IN BOOLEAN FromHead)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
NetbufTrim(IN OUT NET_BUF * Nbuf,IN UINT32 Len,IN BOOLEAN FromHead)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
NetbufCopy(IN NET_BUF * Nbuf,IN UINT32 Offset,IN UINT32 Len,IN UINT8 * Dest)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
NetbufQueInit(IN OUT NET_BUF_QUEUE * NbufQue)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
NetbufQueAlloc(VOID)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
NetbufQueFree(IN NET_BUF_QUEUE * NbufQue)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
NetbufQueAppend(IN OUT NET_BUF_QUEUE * NbufQue,IN OUT NET_BUF * Nbuf)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
NetbufQueRemove(IN OUT NET_BUF_QUEUE * NbufQue)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
NetbufQueCopy(IN NET_BUF_QUEUE * NbufQue,IN UINT32 Offset,IN UINT32 Len,OUT UINT8 * Dest)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
NetbufQueTrim(IN OUT NET_BUF_QUEUE * NbufQue,IN UINT32 Len)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
NetbufQueFlush(IN OUT NET_BUF_QUEUE * NbufQue)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
NetblockChecksum(IN UINT8 * Bulk,IN UINT32 Len)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
NetAddChecksum(IN UINT16 Checksum1,IN UINT16 Checksum2)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
NetbufChecksum(IN NET_BUF * Nbuf)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
NetPseudoHeadChecksum(IN IP4_ADDR Src,IN IP4_ADDR Dst,IN UINT8 Proto,IN UINT16 Len)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
NetIp6PseudoHeadChecksum(IN EFI_IPv6_ADDRESS * Src,IN EFI_IPv6_ADDRESS * Dst,IN UINT8 NextHeader,IN UINT32 Len)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
NetIpSecNetbufFree(NET_BUF * Nbuf)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 
1891