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