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