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