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