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