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