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