1. Fix the potential issue in NetbufGetFragment() when Last is zero in Line 53.
[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 - 2010, 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   Create a NET_BUF structure which contains Len byte data of Nbuf starting from\r
513   Offset.\r
514 \r
515   A new NET_BUF structure will be created but the associated data in NET_VECTOR\r
516   is shared. This function exists to do IP packet fragmentation.\r
517 \r
518   @param[in]  Nbuf         Pointer to the net buffer to be extracted.\r
519   @param[in]  Offset       Starting point of the data to be included in the new\r
520                            net buffer.\r
521   @param[in]  Len          Bytes of data to be included in the new net buffer.\r
522   @param[in]  HeadSpace    Bytes of head space to reserve for protocol header.\r
523 \r
524   @return                  Pointer to the cloned net buffer, or NULL if the\r
525                            allocation failed due to resource limit.\r
526 \r
527 **/\r
528 NET_BUF  *\r
529 EFIAPI\r
530 NetbufGetFragment (\r
531   IN NET_BUF                *Nbuf,\r
532   IN UINT32                 Offset,\r
533   IN UINT32                 Len,\r
534   IN UINT32                 HeadSpace\r
535   )\r
536 {\r
537   NET_BUF                   *Child;\r
538   NET_VECTOR                *Vector;\r
539   NET_BLOCK_OP              *BlockOp;\r
540   UINT32                    CurBlockOp;\r
541   UINT32                    BlockOpNum;\r
542   UINT8                     *FirstBulk;\r
543   UINT32                    Index;\r
544   UINT32                    First;\r
545   UINT32                    Last;\r
546   UINT32                    FirstSkip;\r
547   UINT32                    FirstLen;\r
548   UINT32                    LastLen;\r
549   UINT32                    Cur;\r
550 \r
551   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
552 \r
553   if ((Len == 0) || (Offset + Len > Nbuf->TotalSize)) {\r
554     return NULL;\r
555   }\r
556 \r
557   //\r
558   // First find the first and last BlockOp that contains\r
559   // the valid data, and compute the offset of the first\r
560   // BlockOp and length of the last BlockOp\r
561   //\r
562   BlockOp = Nbuf->BlockOp;\r
563   Cur     = 0;\r
564 \r
565   for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {\r
566     if (Offset < Cur + BlockOp[Index].Size) {\r
567       break;\r
568     }\r
569 \r
570     Cur += BlockOp[Index].Size;\r
571   }\r
572 \r
573   //\r
574   // First is the index of the first BlockOp, FirstSkip is\r
575   // the offset of the first byte in the first BlockOp.\r
576   //\r
577   First     = Index;\r
578   FirstSkip = Offset - Cur;\r
579   FirstLen  = BlockOp[Index].Size - FirstSkip;\r
580 \r
581   Last      = 0;\r
582   LastLen   = 0;\r
583 \r
584   if (Len > FirstLen) {\r
585     Cur += BlockOp[Index].Size;\r
586     Index++;\r
587 \r
588     for (; Index < Nbuf->BlockOpNum; Index++) {\r
589       if (Offset + Len <= Cur + BlockOp[Index].Size) {\r
590         Last    = Index;\r
591         LastLen = Offset + Len - Cur;\r
592         break;\r
593       }\r
594 \r
595       Cur += BlockOp[Index].Size;\r
596     }\r
597 \r
598   } else {\r
599     Last     = First;\r
600     LastLen  = Len;\r
601     FirstLen = Len;\r
602   }\r
603 \r
604   ASSERT (Last >= First);\r
605   BlockOpNum = Last - First + 1;\r
606   CurBlockOp = 0;\r
607 \r
608   if (HeadSpace != 0) {\r
609     //\r
610     // Allocate an extra block to accomdate the head space.\r
611     //\r
612     BlockOpNum++;\r
613 \r
614     Child = NetbufAllocStruct (1, BlockOpNum);\r
615 \r
616     if (Child == NULL) {\r
617       return NULL;\r
618     }\r
619 \r
620     FirstBulk = AllocatePool (HeadSpace);\r
621 \r
622     if (FirstBulk == NULL) {\r
623       goto FreeChild;\r
624     }\r
625 \r
626     Vector        = Child->Vector;\r
627     Vector->Free  = NetbufGetFragmentFree;\r
628     Vector->Arg   = Nbuf->Vector;\r
629     Vector->Flag  = NET_VECTOR_OWN_FIRST;\r
630     Vector->Len   = HeadSpace;\r
631 \r
632     //\r
633     // Reserve the head space in the first block\r
634     //\r
635     NetbufSetBlock (Child, FirstBulk, HeadSpace, 0);\r
636     Child->BlockOp[0].Head += HeadSpace;\r
637     Child->BlockOp[0].Size =  0;\r
638     CurBlockOp++;\r
639 \r
640   } else {\r
641     Child = NetbufAllocStruct (0, BlockOpNum);\r
642 \r
643     if (Child == NULL) {\r
644       return NULL;\r
645     }\r
646 \r
647     Child->Vector = Nbuf->Vector;\r
648   }\r
649 \r
650   NET_GET_REF (Nbuf->Vector);\r
651   Child->TotalSize = Len;\r
652 \r
653   //\r
654   // Set all the BlockOp up, the first and last one are special\r
655   // and need special process.\r
656   //\r
657   NetbufSetBlockOp (\r
658     Child,\r
659     Nbuf->BlockOp[First].Head + FirstSkip,\r
660     FirstLen,\r
661     CurBlockOp++\r
662     );\r
663 \r
664   for (Index = First + 1; Index < Last; Index++) {\r
665     NetbufSetBlockOp (\r
666       Child,\r
667       BlockOp[Index].Head,\r
668       BlockOp[Index].Size,\r
669       CurBlockOp++\r
670       );\r
671   }\r
672 \r
673   if (First != Last) {\r
674     NetbufSetBlockOp (\r
675       Child,\r
676       BlockOp[Last].Head,\r
677       LastLen,\r
678       CurBlockOp\r
679       );\r
680   }\r
681 \r
682   CopyMem (Child->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);\r
683   return Child;\r
684 \r
685 FreeChild:\r
686 \r
687   FreePool (Child);\r
688   return NULL;\r
689 }\r
690 \r
691 \r
692 \r
693 /**\r
694   Build a NET_BUF from external blocks.\r
695 \r
696   A new NET_BUF structure will be created from external blocks. Additional block\r
697   of memory will be allocated to hold reserved HeadSpace bytes of header room\r
698   and existing HeadLen bytes of header but the external blocks are shared by the\r
699   net buffer to avoid data copying.\r
700 \r
701   @param[in]  ExtFragment           Pointer to the data block.\r
702   @param[in]  ExtNum                The number of the data blocks.\r
703   @param[in]  HeadSpace             The head space to be reserved.\r
704   @param[in]  HeadLen               The length of the protocol header, This function\r
705                                     will pull that number of data into a linear block.\r
706   @param[in]  ExtFree               Pointer to the caller provided free function.\r
707   @param[in]  Arg                   The argument passed to ExtFree when ExtFree is\r
708                                     called.\r
709 \r
710   @return                  Pointer to the net buffer built from the data blocks,\r
711                            or NULL if the allocation failed due to resource\r
712                            limit.\r
713 \r
714 **/\r
715 NET_BUF  *\r
716 EFIAPI\r
717 NetbufFromExt (\r
718   IN NET_FRAGMENT           *ExtFragment,\r
719   IN UINT32                 ExtNum,\r
720   IN UINT32                 HeadSpace,\r
721   IN UINT32                 HeadLen,\r
722   IN NET_VECTOR_EXT_FREE    ExtFree,\r
723   IN VOID                   *Arg          OPTIONAL\r
724   )\r
725 {\r
726   NET_BUF                   *Nbuf;\r
727   NET_VECTOR                *Vector;\r
728   NET_FRAGMENT              SavedFragment;\r
729   UINT32                    SavedIndex;\r
730   UINT32                    TotalLen;\r
731   UINT32                    BlockNum;\r
732   UINT8                     *FirstBlock;\r
733   UINT32                    FirstBlockLen;\r
734   UINT8                     *Header;\r
735   UINT32                    CurBlock;\r
736   UINT32                    Index;\r
737   UINT32                    Len;\r
738   UINT32                    Copied;\r
739 \r
740   ASSERT ((ExtFragment != NULL) && (ExtNum > 0) && (ExtFree != NULL));\r
741 \r
742   SavedFragment.Bulk = NULL;\r
743   SavedFragment.Len  = 0;\r
744 \r
745   FirstBlockLen  = 0;\r
746   FirstBlock     = NULL;\r
747   BlockNum       = ExtNum;\r
748   Index          = 0;\r
749   TotalLen       = 0;\r
750   SavedIndex     = 0;\r
751   Len            = 0;\r
752   Copied         = 0;\r
753 \r
754   //\r
755   // No need to consolidate the header if the first block is\r
756   // longer than the header length or there is only one block.\r
757   //\r
758   if ((ExtFragment[0].Len >= HeadLen) || (ExtNum == 1)) {\r
759     HeadLen = 0;\r
760   }\r
761 \r
762   //\r
763   // Allocate an extra block if we need to:\r
764   //  1. Allocate some header space\r
765   //  2. aggreate the packet header\r
766   //\r
767   if ((HeadSpace != 0) || (HeadLen != 0)) {\r
768     FirstBlockLen = HeadLen + HeadSpace;\r
769     FirstBlock    = AllocatePool (FirstBlockLen);\r
770 \r
771     if (FirstBlock == NULL) {\r
772       return NULL;\r
773     }\r
774 \r
775     BlockNum++;\r
776   }\r
777 \r
778   //\r
779   // Copy the header to the first block, reduce the NET_BLOCK\r
780   // to allocate by one for each block that is completely covered\r
781   // by the first bulk.\r
782   //\r
783   if (HeadLen != 0) {\r
784     Len    = HeadLen;\r
785     Header = FirstBlock + HeadSpace;\r
786 \r
787     for (Index = 0; Index < ExtNum; Index++) {\r
788       if (Len >= ExtFragment[Index].Len) {\r
789         CopyMem (Header, ExtFragment[Index].Bulk, ExtFragment[Index].Len);\r
790 \r
791         Copied    += ExtFragment[Index].Len;\r
792         Len       -= ExtFragment[Index].Len;\r
793         Header    += ExtFragment[Index].Len;\r
794         TotalLen  += ExtFragment[Index].Len;\r
795         BlockNum--;\r
796 \r
797         if (Len == 0) {\r
798           //\r
799           // Increament the index number to point to the next\r
800           // non-empty fragment.\r
801           //\r
802           Index++;\r
803           break;\r
804         }\r
805 \r
806       } else {\r
807         CopyMem (Header, ExtFragment[Index].Bulk, Len);\r
808 \r
809         Copied    += Len;\r
810         TotalLen  += Len;\r
811 \r
812         //\r
813         // Adjust the block structure to exclude the data copied,\r
814         // So, the left-over block can be processed as other blocks.\r
815         // But it must be recovered later. (SavedIndex > 0) always\r
816         // holds since we don't aggreate the header if the first block\r
817         // is bigger enough that the header is continuous\r
818         //\r
819         SavedIndex    = Index;\r
820         SavedFragment = ExtFragment[Index];\r
821         ExtFragment[Index].Bulk += Len;\r
822         ExtFragment[Index].Len  -= Len;\r
823         break;\r
824       }\r
825     }\r
826   }\r
827 \r
828   Nbuf = NetbufAllocStruct (BlockNum, BlockNum);\r
829 \r
830   if (Nbuf == NULL) {\r
831     goto FreeFirstBlock;\r
832   }\r
833 \r
834   Vector       = Nbuf->Vector;\r
835   Vector->Free = ExtFree;\r
836   Vector->Arg  = Arg;\r
837   Vector->Flag = ((FirstBlockLen != 0) ? NET_VECTOR_OWN_FIRST : 0);\r
838 \r
839   //\r
840   // Set the first block up which may contain\r
841   // some head space and aggregated header\r
842   //\r
843   CurBlock = 0;\r
844 \r
845   if (FirstBlockLen != 0) {\r
846     NetbufSetBlock (Nbuf, FirstBlock, HeadSpace + Copied, 0);\r
847     Nbuf->BlockOp[0].Head += HeadSpace;\r
848     Nbuf->BlockOp[0].Size =  Copied;\r
849 \r
850     CurBlock++;\r
851   }\r
852 \r
853   for (; Index < ExtNum; Index++) {\r
854     NetbufSetBlock (Nbuf, ExtFragment[Index].Bulk, ExtFragment[Index].Len, CurBlock);\r
855     TotalLen += ExtFragment[Index].Len;\r
856     CurBlock++;\r
857   }\r
858 \r
859   Vector->Len     = TotalLen + HeadSpace;\r
860   Nbuf->TotalSize = TotalLen;\r
861 \r
862   if (SavedIndex != 0) {\r
863     ExtFragment[SavedIndex] = SavedFragment;\r
864   }\r
865 \r
866   return Nbuf;\r
867 \r
868 FreeFirstBlock:\r
869   if (FirstBlock != NULL) {\r
870     FreePool (FirstBlock);\r
871   }\r
872   return NULL;\r
873 }\r
874 \r
875 \r
876 /**\r
877   Build a fragment table to contain the fragments in the net buffer. This is the\r
878   opposite operation of the NetbufFromExt.\r
879 \r
880   @param[in]       Nbuf                  Point to the net buffer.\r
881   @param[in, out]  ExtFragment           Pointer to the data block.\r
882   @param[in, out]  ExtNum                The number of the data blocks.\r
883 \r
884   @retval EFI_BUFFER_TOO_SMALL  The number of non-empty block is bigger than\r
885                                 ExtNum.\r
886   @retval EFI_SUCCESS           Fragment table is built successfully.\r
887 \r
888 **/\r
889 EFI_STATUS\r
890 EFIAPI\r
891 NetbufBuildExt (\r
892   IN NET_BUF                *Nbuf,\r
893   IN OUT NET_FRAGMENT       *ExtFragment,\r
894   IN OUT UINT32             *ExtNum\r
895   )\r
896 {\r
897   UINT32                    Index;\r
898   UINT32                    Current;\r
899 \r
900   Current = 0;\r
901 \r
902   for (Index = 0; (Index < Nbuf->BlockOpNum); Index++) {\r
903     if (Nbuf->BlockOp[Index].Size == 0) {\r
904       continue;\r
905     }\r
906 \r
907     if (Current < *ExtNum) {\r
908       ExtFragment[Current].Bulk = Nbuf->BlockOp[Index].Head;\r
909       ExtFragment[Current].Len  = Nbuf->BlockOp[Index].Size;\r
910       Current++;\r
911     } else {\r
912       return EFI_BUFFER_TOO_SMALL;\r
913     }\r
914   }\r
915 \r
916   *ExtNum = Current;\r
917   return EFI_SUCCESS;\r
918 }\r
919 \r
920 \r
921 /**\r
922   Build a net buffer from a list of net buffers.\r
923 \r
924   All the fragments will be collected from the list of NEW_BUF and then a new\r
925   net buffer will be created through NetbufFromExt.\r
926 \r
927   @param[in]   BufList    A List of the net buffer.\r
928   @param[in]   HeadSpace  The head space to be reserved.\r
929   @param[in]   HeaderLen  The length of the protocol header, This function\r
930                           will pull that number of data into a linear block.\r
931   @param[in]   ExtFree    Pointer to the caller provided free function.\r
932   @param[in]   Arg        The argument passed to ExtFree when ExtFree is called.\r
933 \r
934   @return                 Pointer to the net buffer built from the list of net\r
935                           buffers.\r
936 \r
937 **/\r
938 NET_BUF  *\r
939 EFIAPI\r
940 NetbufFromBufList (\r
941   IN LIST_ENTRY             *BufList,\r
942   IN UINT32                 HeadSpace,\r
943   IN UINT32                 HeaderLen,\r
944   IN NET_VECTOR_EXT_FREE    ExtFree,\r
945   IN VOID                   *Arg              OPTIONAL\r
946   )\r
947 {\r
948   NET_FRAGMENT              *Fragment;\r
949   UINT32                    FragmentNum;\r
950   LIST_ENTRY                *Entry;\r
951   NET_BUF                   *Nbuf;\r
952   UINT32                    Index;\r
953   UINT32                    Current;\r
954 \r
955   //\r
956   //Compute how many blocks are there\r
957   //\r
958   FragmentNum = 0;\r
959 \r
960   NET_LIST_FOR_EACH (Entry, BufList) {\r
961     Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
962     NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
963     FragmentNum += Nbuf->BlockOpNum;\r
964   }\r
965 \r
966   //\r
967   //Allocate and copy block points\r
968   //\r
969   Fragment = AllocatePool (sizeof (NET_FRAGMENT) * FragmentNum);\r
970 \r
971   if (Fragment == NULL) {\r
972     return NULL;\r
973   }\r
974 \r
975   Current = 0;\r
976 \r
977   NET_LIST_FOR_EACH (Entry, BufList) {\r
978     Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
979     NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
980 \r
981     for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {\r
982       if (Nbuf->BlockOp[Index].Size != 0) {\r
983         Fragment[Current].Bulk = Nbuf->BlockOp[Index].Head;\r
984         Fragment[Current].Len  = Nbuf->BlockOp[Index].Size;\r
985         Current++;\r
986       }\r
987     }\r
988   }\r
989 \r
990   Nbuf = NetbufFromExt (Fragment, Current, HeadSpace, HeaderLen, ExtFree, Arg);\r
991   FreePool (Fragment);\r
992 \r
993   return Nbuf;\r
994 }\r
995 \r
996 \r
997 /**\r
998   Reserve some space in the header room of the net buffer.\r
999 \r
1000   Upon allocation, all the space are in the tail room of the buffer. Call this\r
1001   function to move some space to the header room. This function is quite limited\r
1002   in that it can only reserve space from the first block of an empty NET_BUF not\r
1003   built from the external. But it should be enough for the network stack.\r
1004 \r
1005   @param[in, out]  Nbuf     Pointer to the net buffer.\r
1006   @param[in]       Len      The length of buffer to be reserved from the header.\r
1007 \r
1008 **/\r
1009 VOID\r
1010 EFIAPI\r
1011 NetbufReserve (\r
1012   IN OUT NET_BUF            *Nbuf,\r
1013   IN UINT32                 Len\r
1014   )\r
1015 {\r
1016   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
1017   NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);\r
1018 \r
1019   ASSERT ((Nbuf->BlockOpNum == 1) && (Nbuf->TotalSize == 0));\r
1020   ASSERT ((Nbuf->Vector->Free == NULL) && (Nbuf->Vector->Len >= Len));\r
1021 \r
1022   Nbuf->BlockOp[0].Head += Len;\r
1023   Nbuf->BlockOp[0].Tail += Len;\r
1024 \r
1025   ASSERT (Nbuf->BlockOp[0].Tail <= Nbuf->BlockOp[0].BlockTail);\r
1026 }\r
1027 \r
1028 \r
1029 /**\r
1030   Allocate Len bytes of space from the header or tail of the buffer.\r
1031 \r
1032   @param[in, out]  Nbuf       Pointer to the net buffer.\r
1033   @param[in]       Len        The length of the buffer to be allocated.\r
1034   @param[in]       FromHead   The flag to indicate whether reserve the data\r
1035                               from head (TRUE) or tail (FALSE).\r
1036 \r
1037   @return                     Pointer to the first byte of the allocated buffer,\r
1038                               or NULL if there is no sufficient space.\r
1039 \r
1040 **/\r
1041 UINT8*\r
1042 EFIAPI\r
1043 NetbufAllocSpace (\r
1044   IN OUT NET_BUF            *Nbuf,\r
1045   IN UINT32                 Len,\r
1046   IN BOOLEAN                FromHead\r
1047   )\r
1048 {\r
1049   NET_BLOCK_OP              *BlockOp;\r
1050   UINT32                    Index;\r
1051   UINT8                     *SavedTail;\r
1052 \r
1053   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
1054   NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);\r
1055 \r
1056   ASSERT (Len > 0);\r
1057 \r
1058   if (FromHead) {\r
1059     //\r
1060     // Allocate some space from head. If the buffer is empty,\r
1061     // allocate from the first block. If it isn't, allocate\r
1062     // from the first non-empty block, or the block before that.\r
1063     //\r
1064     if (Nbuf->TotalSize == 0) {\r
1065       Index = 0;\r
1066     } else {\r
1067       NetbufGetByte (Nbuf, 0, &Index);\r
1068 \r
1069       if ((NET_HEADSPACE(&(Nbuf->BlockOp[Index])) < Len) && (Index > 0)) {\r
1070         Index--;\r
1071       }\r
1072     }\r
1073 \r
1074     BlockOp = &(Nbuf->BlockOp[Index]);\r
1075 \r
1076     if (NET_HEADSPACE (BlockOp) < Len) {\r
1077       return NULL;\r
1078     }\r
1079 \r
1080     BlockOp->Head   -= Len;\r
1081     BlockOp->Size   += Len;\r
1082     Nbuf->TotalSize += Len;\r
1083 \r
1084     return BlockOp->Head;\r
1085 \r
1086   } else {\r
1087     //\r
1088     // Allocate some space from the tail. If the buffer is empty,\r
1089     // allocate from the first block. If it isn't, allocate\r
1090     // from the last non-empty block, or the block after that.\r
1091     //\r
1092     if (Nbuf->TotalSize == 0) {\r
1093       Index = 0;\r
1094     } else {\r
1095       NetbufGetByte (Nbuf, Nbuf->TotalSize - 1, &Index);\r
1096 \r
1097       if ((NET_TAILSPACE(&(Nbuf->BlockOp[Index])) < Len) &&\r
1098           (Index < Nbuf->BlockOpNum - 1)) {\r
1099 \r
1100         Index++;\r
1101       }\r
1102     }\r
1103 \r
1104     BlockOp = &(Nbuf->BlockOp[Index]);\r
1105 \r
1106     if (NET_TAILSPACE (BlockOp) < Len) {\r
1107       return NULL;\r
1108     }\r
1109 \r
1110     SavedTail       = BlockOp->Tail;\r
1111 \r
1112     BlockOp->Tail   += Len;\r
1113     BlockOp->Size   += Len;\r
1114     Nbuf->TotalSize += Len;\r
1115 \r
1116     return SavedTail;\r
1117   }\r
1118 }\r
1119 \r
1120 \r
1121 /**\r
1122   Trim a single NET_BLOCK by Len bytes from the header or tail.\r
1123 \r
1124   @param[in, out]  BlockOp      Pointer to the NET_BLOCK.\r
1125   @param[in]       Len          The length of the data to be trimmed.\r
1126   @param[in]       FromHead     The flag to indicate whether trim data from head\r
1127                                 (TRUE) or tail (FALSE).\r
1128 \r
1129 **/\r
1130 VOID\r
1131 NetblockTrim (\r
1132   IN OUT NET_BLOCK_OP       *BlockOp,\r
1133   IN UINT32                 Len,\r
1134   IN BOOLEAN                FromHead\r
1135   )\r
1136 {\r
1137   ASSERT ((BlockOp != NULL) && (BlockOp->Size >= Len));\r
1138 \r
1139   BlockOp->Size -= Len;\r
1140 \r
1141   if (FromHead) {\r
1142     BlockOp->Head += Len;\r
1143   } else {\r
1144     BlockOp->Tail -= Len;\r
1145   }\r
1146 }\r
1147 \r
1148 \r
1149 /**\r
1150   Trim Len bytes from the header or tail of the net buffer.\r
1151 \r
1152   @param[in, out]  Nbuf         Pointer to the net buffer.\r
1153   @param[in]       Len          The length of the data to be trimmed.\r
1154   @param[in]      FromHead      The flag to indicate whether trim data from head\r
1155                                 (TRUE) or tail (FALSE).\r
1156 \r
1157   @return    Length of the actually trimmed data, which is possible to be less\r
1158              than Len because the TotalSize of Nbuf is less than Len.\r
1159 \r
1160 **/\r
1161 UINT32\r
1162 EFIAPI\r
1163 NetbufTrim (\r
1164   IN OUT NET_BUF            *Nbuf,\r
1165   IN UINT32                 Len,\r
1166   IN BOOLEAN                FromHead\r
1167   )\r
1168 {\r
1169   NET_BLOCK_OP              *BlockOp;\r
1170   UINT32                    Index;\r
1171   UINT32                    Trimmed;\r
1172 \r
1173   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
1174 \r
1175   if (Len > Nbuf->TotalSize) {\r
1176     Len = Nbuf->TotalSize;\r
1177   }\r
1178 \r
1179   //\r
1180   // If FromTail is true, iterate backward. That\r
1181   // is, init Index to NBuf->BlockNum - 1, and\r
1182   // decrease it by 1 during each loop. Otherwise,\r
1183   // iterate forward. That is, init Index to 0, and\r
1184   // increase it by 1 during each loop.\r
1185   //\r
1186   Trimmed          = 0;\r
1187   Nbuf->TotalSize -= Len;\r
1188 \r
1189   Index   = (FromHead ? 0 : Nbuf->BlockOpNum - 1);\r
1190   BlockOp = Nbuf->BlockOp;\r
1191 \r
1192   for (;;) {\r
1193     if (BlockOp[Index].Size == 0) {\r
1194       Index += (FromHead ? 1 : -1);\r
1195       continue;\r
1196     }\r
1197 \r
1198     if (Len > BlockOp[Index].Size) {\r
1199       Len     -= BlockOp[Index].Size;\r
1200       Trimmed += BlockOp[Index].Size;\r
1201       NetblockTrim (&BlockOp[Index], BlockOp[Index].Size, FromHead);\r
1202     } else {\r
1203       Trimmed += Len;\r
1204       NetblockTrim (&BlockOp[Index], Len, FromHead);\r
1205       break;\r
1206     }\r
1207 \r
1208     Index += (FromHead ? 1 : -1);\r
1209   }\r
1210 \r
1211   return Trimmed;\r
1212 }\r
1213 \r
1214 \r
1215 /**\r
1216   Copy Len bytes of data from the specific offset of the net buffer to the\r
1217   destination memory.\r
1218 \r
1219   The Len bytes of data may cross the several fragments of the net buffer.\r
1220 \r
1221   @param[in]   Nbuf         Pointer to the net buffer.\r
1222   @param[in]   Offset       The sequence number of the first byte to copy.\r
1223   @param[in]   Len          Length of the data to copy.\r
1224   @param[in]   Dest         The destination of the data to copy to.\r
1225 \r
1226   @return           The length of the actual copied data, or 0 if the offset\r
1227                     specified exceeds the total size of net buffer.\r
1228 \r
1229 **/\r
1230 UINT32\r
1231 EFIAPI\r
1232 NetbufCopy (\r
1233   IN NET_BUF                *Nbuf,\r
1234   IN UINT32                 Offset,\r
1235   IN UINT32                 Len,\r
1236   IN UINT8                  *Dest\r
1237   )\r
1238 {\r
1239   NET_BLOCK_OP              *BlockOp;\r
1240   UINT32                    Skip;\r
1241   UINT32                    Left;\r
1242   UINT32                    Copied;\r
1243   UINT32                    Index;\r
1244   UINT32                    Cur;\r
1245 \r
1246   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
1247   ASSERT (Dest);\r
1248 \r
1249   if ((Len == 0) || (Nbuf->TotalSize <= Offset)) {\r
1250     return 0;\r
1251   }\r
1252 \r
1253   if (Nbuf->TotalSize - Offset < Len) {\r
1254     Len = Nbuf->TotalSize - Offset;\r
1255   }\r
1256 \r
1257   BlockOp = Nbuf->BlockOp;\r
1258 \r
1259   //\r
1260   // Skip to the offset. Don't make "Offset-By-One" error here.\r
1261   // Cur + BLOCK.SIZE is the first sequence number of next block.\r
1262   // So, (Offset < Cur + BLOCK.SIZE) means that the  first byte\r
1263   // is in the current block. if (Offset == Cur + BLOCK.SIZE), the\r
1264   // first byte is the next block's first byte.\r
1265   //\r
1266   Cur = 0;\r
1267 \r
1268   for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {\r
1269     if (BlockOp[Index].Size == 0) {\r
1270       continue;\r
1271     }\r
1272 \r
1273     if (Offset < Cur + BlockOp[Index].Size) {\r
1274       break;\r
1275     }\r
1276 \r
1277     Cur += BlockOp[Index].Size;\r
1278   }\r
1279 \r
1280   //\r
1281   // Cur is the sequence number of the first byte in the block\r
1282   // Offset - Cur is the number of bytes before first byte to\r
1283   // to copy in the current block.\r
1284   //\r
1285   Skip  = Offset - Cur;\r
1286   Left  = BlockOp[Index].Size - Skip;\r
1287 \r
1288   if (Len <= Left) {\r
1289     CopyMem (Dest, BlockOp[Index].Head + Skip, Len);\r
1290     return Len;\r
1291   }\r
1292 \r
1293   CopyMem (Dest, BlockOp[Index].Head + Skip, Left);\r
1294 \r
1295   Dest  += Left;\r
1296   Len   -= Left;\r
1297   Copied = Left;\r
1298 \r
1299   Index++;\r
1300 \r
1301   for (; Index < Nbuf->BlockOpNum; Index++) {\r
1302     if (Len > BlockOp[Index].Size) {\r
1303       Len    -= BlockOp[Index].Size;\r
1304       Copied += BlockOp[Index].Size;\r
1305 \r
1306       CopyMem (Dest, BlockOp[Index].Head, BlockOp[Index].Size);\r
1307       Dest   += BlockOp[Index].Size;\r
1308     } else {\r
1309       Copied += Len;\r
1310       CopyMem (Dest, BlockOp[Index].Head, Len);\r
1311       break;\r
1312     }\r
1313   }\r
1314 \r
1315   return Copied;\r
1316 }\r
1317 \r
1318 \r
1319 /**\r
1320   Initiate the net buffer queue.\r
1321 \r
1322   @param[in, out]  NbufQue   Pointer to the net buffer queue to be initialized.\r
1323 \r
1324 **/\r
1325 VOID\r
1326 EFIAPI\r
1327 NetbufQueInit (\r
1328   IN OUT NET_BUF_QUEUE          *NbufQue\r
1329   )\r
1330 {\r
1331   NbufQue->Signature  = NET_QUE_SIGNATURE;\r
1332   NbufQue->RefCnt     = 1;\r
1333   InitializeListHead (&NbufQue->List);\r
1334 \r
1335   InitializeListHead (&NbufQue->BufList);\r
1336   NbufQue->BufSize  = 0;\r
1337   NbufQue->BufNum   = 0;\r
1338 }\r
1339 \r
1340 \r
1341 /**\r
1342   Allocate and initialize a net buffer queue.\r
1343 \r
1344   @return         Pointer to the allocated net buffer queue, or NULL if the\r
1345                   allocation failed due to resource limit.\r
1346 \r
1347 **/\r
1348 NET_BUF_QUEUE  *\r
1349 EFIAPI\r
1350 NetbufQueAlloc (\r
1351   VOID\r
1352   )\r
1353 {\r
1354   NET_BUF_QUEUE             *NbufQue;\r
1355 \r
1356   NbufQue = AllocatePool (sizeof (NET_BUF_QUEUE));\r
1357   if (NbufQue == NULL) {\r
1358     return NULL;\r
1359   }\r
1360 \r
1361   NetbufQueInit (NbufQue);\r
1362 \r
1363   return NbufQue;\r
1364 }\r
1365 \r
1366 \r
1367 /**\r
1368   Free a net buffer queue.\r
1369 \r
1370   Decrease the reference count of the net buffer queue by one. The real resource\r
1371   free operation isn't performed until the reference count of the net buffer\r
1372   queue is decreased to 0.\r
1373 \r
1374   @param[in]  NbufQue               Pointer to the net buffer queue to be freed.\r
1375 \r
1376 **/\r
1377 VOID\r
1378 EFIAPI\r
1379 NetbufQueFree (\r
1380   IN NET_BUF_QUEUE          *NbufQue\r
1381   )\r
1382 {\r
1383   ASSERT (NbufQue != NULL);\r
1384   NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);\r
1385 \r
1386   NbufQue->RefCnt--;\r
1387 \r
1388   if (NbufQue->RefCnt == 0) {\r
1389     NetbufQueFlush (NbufQue);\r
1390     FreePool (NbufQue);\r
1391   }\r
1392 }\r
1393 \r
1394 \r
1395 /**\r
1396   Append a net buffer to the net buffer queue.\r
1397 \r
1398   @param[in, out]  NbufQue            Pointer to the net buffer queue.\r
1399   @param[in, out]  Nbuf               Pointer to the net buffer to be appended.\r
1400 \r
1401 **/\r
1402 VOID\r
1403 EFIAPI\r
1404 NetbufQueAppend (\r
1405   IN OUT NET_BUF_QUEUE          *NbufQue,\r
1406   IN OUT NET_BUF                *Nbuf\r
1407   )\r
1408 {\r
1409   NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);\r
1410   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
1411 \r
1412   InsertTailList (&NbufQue->BufList, &Nbuf->List);\r
1413 \r
1414   NbufQue->BufSize += Nbuf->TotalSize;\r
1415   NbufQue->BufNum++;\r
1416 }\r
1417 \r
1418 \r
1419 /**\r
1420   Remove a net buffer from the head in the specific queue and return it.\r
1421 \r
1422   @param[in, out]  NbufQue               Pointer to the net buffer queue.\r
1423 \r
1424   @return           Pointer to the net buffer removed from the specific queue,\r
1425                     or NULL if there is no net buffer in the specific queue.\r
1426 \r
1427 **/\r
1428 NET_BUF  *\r
1429 EFIAPI\r
1430 NetbufQueRemove (\r
1431   IN OUT NET_BUF_QUEUE          *NbufQue\r
1432   )\r
1433 {\r
1434   NET_BUF                   *First;\r
1435 \r
1436   NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);\r
1437 \r
1438   if (NbufQue->BufNum == 0) {\r
1439     return NULL;\r
1440   }\r
1441 \r
1442   First = NET_LIST_USER_STRUCT (NbufQue->BufList.ForwardLink, NET_BUF, List);\r
1443 \r
1444   NetListRemoveHead (&NbufQue->BufList);\r
1445 \r
1446   NbufQue->BufSize -= First->TotalSize;\r
1447   NbufQue->BufNum--;\r
1448   return First;\r
1449 }\r
1450 \r
1451 \r
1452 /**\r
1453   Copy Len bytes of data from the net buffer queue at the specific offset to the\r
1454   destination memory.\r
1455 \r
1456   The copying operation is the same as NetbufCopy but applies to the net buffer\r
1457   queue instead of the net buffer.\r
1458 \r
1459   @param[in]   NbufQue         Pointer to the net buffer queue.\r
1460   @param[in]   Offset          The sequence number of the first byte to copy.\r
1461   @param[in]   Len             Length of the data to copy.\r
1462   @param[out]  Dest            The destination of the data to copy to.\r
1463 \r
1464   @return       The length of the actual copied data, or 0 if the offset\r
1465                 specified exceeds the total size of net buffer queue.\r
1466 \r
1467 **/\r
1468 UINT32\r
1469 EFIAPI\r
1470 NetbufQueCopy (\r
1471   IN NET_BUF_QUEUE          *NbufQue,\r
1472   IN UINT32                 Offset,\r
1473   IN UINT32                 Len,\r
1474   OUT UINT8                 *Dest\r
1475   )\r
1476 {\r
1477   LIST_ENTRY                *Entry;\r
1478   NET_BUF                   *Nbuf;\r
1479   UINT32                    Skip;\r
1480   UINT32                    Left;\r
1481   UINT32                    Cur;\r
1482   UINT32                    Copied;\r
1483 \r
1484   NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);\r
1485   ASSERT (Dest != NULL);\r
1486 \r
1487   if ((Len == 0) || (NbufQue->BufSize <= Offset)) {\r
1488     return 0;\r
1489   }\r
1490 \r
1491   if (NbufQue->BufSize - Offset < Len) {\r
1492     Len = NbufQue->BufSize - Offset;\r
1493   }\r
1494 \r
1495   //\r
1496   // skip to the Offset\r
1497   //\r
1498   Cur   = 0;\r
1499   Nbuf  = NULL;\r
1500 \r
1501   NET_LIST_FOR_EACH (Entry, &NbufQue->BufList) {\r
1502     Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
1503 \r
1504     if (Offset < Cur + Nbuf->TotalSize) {\r
1505       break;\r
1506     }\r
1507 \r
1508     Cur += Nbuf->TotalSize;\r
1509   }\r
1510 \r
1511   ASSERT (Nbuf != NULL);\r
1512 \r
1513   //\r
1514   // Copy the data in the first buffer.\r
1515   //\r
1516   Skip  = Offset - Cur;\r
1517   Left  = Nbuf->TotalSize - Skip;\r
1518 \r
1519   if (Len < Left) {\r
1520     return NetbufCopy (Nbuf, Skip, Len, Dest);\r
1521   }\r
1522 \r
1523   NetbufCopy (Nbuf, Skip, Left, Dest);\r
1524   Dest  += Left;\r
1525   Len   -= Left;\r
1526   Copied = Left;\r
1527 \r
1528   //\r
1529   // Iterate over the others\r
1530   //\r
1531   Entry = Entry->ForwardLink;\r
1532 \r
1533   while ((Len > 0) && (Entry != &NbufQue->BufList)) {\r
1534     Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
1535 \r
1536     if (Len > Nbuf->TotalSize) {\r
1537       Len -= Nbuf->TotalSize;\r
1538       Copied += Nbuf->TotalSize;\r
1539 \r
1540       NetbufCopy (Nbuf, 0, Nbuf->TotalSize, Dest);\r
1541       Dest += Nbuf->TotalSize;\r
1542 \r
1543     } else {\r
1544       NetbufCopy (Nbuf, 0, Len, Dest);\r
1545       Copied += Len;\r
1546       break;\r
1547     }\r
1548 \r
1549     Entry = Entry->ForwardLink;\r
1550   }\r
1551 \r
1552   return Copied;\r
1553 }\r
1554 \r
1555 \r
1556 /**\r
1557   Trim Len bytes of data from the queue header, release any of the net buffer\r
1558   whom is trimmed wholely.\r
1559 \r
1560   The trimming operation is the same as NetbufTrim but applies to the net buffer\r
1561   queue instead of the net buffer.\r
1562 \r
1563   @param[in, out]  NbufQue               Pointer to the net buffer queue.\r
1564   @param[in]       Len                   Length of the data to trim.\r
1565 \r
1566   @return   The actual length of the data trimmed.\r
1567 \r
1568 **/\r
1569 UINT32\r
1570 EFIAPI\r
1571 NetbufQueTrim (\r
1572   IN OUT NET_BUF_QUEUE      *NbufQue,\r
1573   IN UINT32                 Len\r
1574   )\r
1575 {\r
1576   LIST_ENTRY                *Entry;\r
1577   LIST_ENTRY                *Next;\r
1578   NET_BUF                   *Nbuf;\r
1579   UINT32                    Trimmed;\r
1580 \r
1581   NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);\r
1582 \r
1583   if (Len == 0) {\r
1584     return 0;\r
1585   }\r
1586 \r
1587   if (Len > NbufQue->BufSize) {\r
1588     Len = NbufQue->BufSize;\r
1589   }\r
1590 \r
1591   NbufQue->BufSize -= Len;\r
1592   Trimmed = 0;\r
1593 \r
1594   NET_LIST_FOR_EACH_SAFE (Entry, Next, &NbufQue->BufList) {\r
1595     Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
1596 \r
1597     if (Len >= Nbuf->TotalSize) {\r
1598       Trimmed += Nbuf->TotalSize;\r
1599       Len -= Nbuf->TotalSize;\r
1600 \r
1601       RemoveEntryList (Entry);\r
1602       NetbufFree (Nbuf);\r
1603 \r
1604       NbufQue->BufNum--;\r
1605 \r
1606       if (Len == 0) {\r
1607         break;\r
1608       }\r
1609 \r
1610     } else {\r
1611       Trimmed += NetbufTrim (Nbuf, Len, NET_BUF_HEAD);\r
1612       break;\r
1613     }\r
1614   }\r
1615 \r
1616   return Trimmed;\r
1617 }\r
1618 \r
1619 \r
1620 /**\r
1621   Flush the net buffer queue.\r
1622 \r
1623   @param[in, out]  NbufQue               Pointer to the queue to be flushed.\r
1624 \r
1625 **/\r
1626 VOID\r
1627 EFIAPI\r
1628 NetbufQueFlush (\r
1629   IN OUT NET_BUF_QUEUE          *NbufQue\r
1630   )\r
1631 {\r
1632   NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);\r
1633 \r
1634   NetbufFreeList (&NbufQue->BufList);\r
1635 \r
1636   NbufQue->BufNum   = 0;\r
1637   NbufQue->BufSize  = 0;\r
1638 }\r
1639 \r
1640 \r
1641 /**\r
1642   Compute the checksum for a bulk of data.\r
1643 \r
1644   @param[in]   Bulk                  Pointer to the data.\r
1645   @param[in]   Len                   Length of the data, in bytes.\r
1646 \r
1647   @return    The computed checksum.\r
1648 \r
1649 **/\r
1650 UINT16\r
1651 EFIAPI\r
1652 NetblockChecksum (\r
1653   IN UINT8                  *Bulk,\r
1654   IN UINT32                 Len\r
1655   )\r
1656 {\r
1657   register UINT32           Sum;\r
1658 \r
1659   Sum = 0;\r
1660 \r
1661   while (Len > 1) {\r
1662     Sum += *(UINT16 *) Bulk;\r
1663     Bulk += 2;\r
1664     Len -= 2;\r
1665   }\r
1666 \r
1667   //\r
1668   // Add left-over byte, if any\r
1669   //\r
1670   if (Len > 0) {\r
1671     Sum += *(UINT8 *) Bulk;\r
1672   }\r
1673 \r
1674   //\r
1675   // Fold 32-bit sum to 16 bits\r
1676   //\r
1677   while ((Sum >> 16) != 0) {\r
1678     Sum = (Sum & 0xffff) + (Sum >> 16);\r
1679 \r
1680   }\r
1681 \r
1682   return (UINT16) Sum;\r
1683 }\r
1684 \r
1685 \r
1686 /**\r
1687   Add two checksums.\r
1688 \r
1689   @param[in]   Checksum1             The first checksum to be added.\r
1690   @param[in]   Checksum2             The second checksum to be added.\r
1691 \r
1692   @return         The new checksum.\r
1693 \r
1694 **/\r
1695 UINT16\r
1696 EFIAPI\r
1697 NetAddChecksum (\r
1698   IN UINT16                 Checksum1,\r
1699   IN UINT16                 Checksum2\r
1700   )\r
1701 {\r
1702   UINT32                    Sum;\r
1703 \r
1704   Sum = Checksum1 + Checksum2;\r
1705 \r
1706   //\r
1707   // two UINT16 can only add up to a carry of 1.\r
1708   //\r
1709   if ((Sum >> 16) != 0) {\r
1710     Sum = (Sum & 0xffff) + 1;\r
1711 \r
1712   }\r
1713 \r
1714   return (UINT16) Sum;\r
1715 }\r
1716 \r
1717 \r
1718 /**\r
1719   Compute the checksum for a NET_BUF.\r
1720 \r
1721   @param[in]   Nbuf                  Pointer to the net buffer.\r
1722 \r
1723   @return    The computed checksum.\r
1724 \r
1725 **/\r
1726 UINT16\r
1727 EFIAPI\r
1728 NetbufChecksum (\r
1729   IN NET_BUF                *Nbuf\r
1730   )\r
1731 {\r
1732   NET_BLOCK_OP              *BlockOp;\r
1733   UINT32                    Offset;\r
1734   UINT16                    TotalSum;\r
1735   UINT16                    BlockSum;\r
1736   UINT32                    Index;\r
1737 \r
1738   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
1739 \r
1740   TotalSum  = 0;\r
1741   Offset    = 0;\r
1742   BlockOp   = Nbuf->BlockOp;\r
1743 \r
1744   for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {\r
1745     if (BlockOp[Index].Size == 0) {\r
1746       continue;\r
1747     }\r
1748 \r
1749     BlockSum = NetblockChecksum (BlockOp[Index].Head, BlockOp[Index].Size);\r
1750 \r
1751     if ((Offset & 0x01) != 0) {\r
1752       //\r
1753       // The checksum starts with an odd byte, swap\r
1754       // the checksum before added to total checksum\r
1755       //\r
1756       BlockSum = SwapBytes16 (BlockSum);\r
1757     }\r
1758 \r
1759     TotalSum = NetAddChecksum (BlockSum, TotalSum);\r
1760     Offset  += BlockOp[Index].Size;\r
1761   }\r
1762 \r
1763   return TotalSum;\r
1764 }\r
1765 \r
1766 \r
1767 /**\r
1768   Compute the checksum for TCP/UDP pseudo header.\r
1769 \r
1770   Src and Dst are in network byte order, and Len is in host byte order.\r
1771 \r
1772   @param[in]   Src                   The source address of the packet.\r
1773   @param[in]   Dst                   The destination address of the packet.\r
1774   @param[in]   Proto                 The protocol type of the packet.\r
1775   @param[in]   Len                   The length of the packet.\r
1776 \r
1777   @return   The computed checksum.\r
1778 \r
1779 **/\r
1780 UINT16\r
1781 EFIAPI\r
1782 NetPseudoHeadChecksum (\r
1783   IN IP4_ADDR               Src,\r
1784   IN IP4_ADDR               Dst,\r
1785   IN UINT8                  Proto,\r
1786   IN UINT16                 Len\r
1787   )\r
1788 {\r
1789   NET_PSEUDO_HDR            Hdr;\r
1790 \r
1791   //\r
1792   // Zero the memory to relieve align problems\r
1793   //\r
1794   ZeroMem (&Hdr, sizeof (Hdr));\r
1795 \r
1796   Hdr.SrcIp     = Src;\r
1797   Hdr.DstIp     = Dst;\r
1798   Hdr.Protocol  = Proto;\r
1799   Hdr.Len       = HTONS (Len);\r
1800 \r
1801   return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));\r
1802 }\r
1803 \r
1804 /**\r
1805   Compute the checksum for TCP6/UDP6 pseudo header.\r
1806 \r
1807   Src and Dst are in network byte order, and Len is in host byte order.\r
1808 \r
1809   @param[in]   Src                   The source address of the packet.\r
1810   @param[in]   Dst                   The destination address of the packet.\r
1811   @param[in]   NextHeader            The protocol type of the packet.\r
1812   @param[in]   Len                   The length of the packet.\r
1813 \r
1814   @return   The computed checksum.\r
1815 \r
1816 **/\r
1817 UINT16\r
1818 NetIp6PseudoHeadChecksum (\r
1819   IN EFI_IPv6_ADDRESS       *Src,\r
1820   IN EFI_IPv6_ADDRESS       *Dst,\r
1821   IN UINT8                  NextHeader,\r
1822   IN UINT32                 Len\r
1823   )\r
1824 {\r
1825   NET_IP6_PSEUDO_HDR        Hdr;\r
1826 \r
1827   //\r
1828   // Zero the memory to relieve align problems\r
1829   //\r
1830   ZeroMem (&Hdr, sizeof (Hdr));\r
1831 \r
1832   IP6_COPY_ADDRESS (&Hdr.SrcIp, Src);\r
1833   IP6_COPY_ADDRESS (&Hdr.DstIp, Dst);\r
1834 \r
1835   Hdr.NextHeader = NextHeader;\r
1836   Hdr.Len        = HTONL (Len);\r
1837 \r
1838   return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));\r
1839 }\r
1840 \r