]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeNetLib/NetBuffer.c
Remove #include <Protocol/LoadedImage.h>
[mirror_edk2.git] / MdeModulePkg / Library / DxeNetLib / NetBuffer.c
CommitLineData
cbf316f2 1/** @file\r
3e7104c2 2 Network library.\r
3 \r
4Copyright (c) 2005 - 2006, Intel Corporation.<BR>\r
cbf316f2 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
cbf316f2 12**/\r
13\r
3e7104c2 14#include <Uefi.h>\r
f5acf5c6 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
cbf316f2 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
3e7104c2 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
cbf316f2 31\r
3e7104c2 32 @return Pointer to the allocated NET_BUF. If NULL, the\r
cbf316f2 33 allocation failed due to resource limit.\r
34\r
35**/\r
cbf316f2 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
e48e37fc 50 Nbuf = AllocateZeroPool (NET_BUF_SIZE (BlockOpNum));\r
cbf316f2 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
e48e37fc 59 InitializeListHead (&Nbuf->List);\r
cbf316f2 60\r
61 if (BlockNum != 0) {\r
e48e37fc 62 Vector = AllocateZeroPool (NET_VECTOR_SIZE (BlockNum));\r
cbf316f2 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
e48e37fc 78 gBS->FreePool (Nbuf);\r
cbf316f2 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
3e7104c2 87 @param[in] Len The length of the block.\r
cbf316f2 88\r
3e7104c2 89 @return Pointer to the allocated NET_BUF. If NULL the\r
cbf316f2 90 allocation failed due to resource limit.\r
91\r
92**/\r
93NET_BUF *\r
7b414b4e 94EFIAPI\r
cbf316f2 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
e48e37fc 111 Bulk = AllocatePool (Len);\r
cbf316f2 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
e48e37fc 133 gBS->FreePool (Nbuf);\r
cbf316f2 134 return NULL;\r
135}\r
136\r
137\r
138/**\r
3e7104c2 139 Free the vector.\r
cbf316f2 140\r
3e7104c2 141 @param[in] Vector Pointer to the NET_VECTOR to be freed.\r
cbf316f2 142\r
143**/\r
cbf316f2 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
e48e37fc 167 gBS->FreePool (Vector->Block[0].Bulk);\r
cbf316f2 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
e48e37fc 177 gBS->FreePool (Vector->Block[Index].Bulk);\r
cbf316f2 178 }\r
179 }\r
180\r
e48e37fc 181 gBS->FreePool (Vector);\r
cbf316f2 182}\r
183\r
184\r
185/**\r
186 Free the buffer and its associated NET_VECTOR.\r
187\r
3e7104c2 188 @param[in] Nbuf Pointer to the NET_BUF to be freed.\r
cbf316f2 189\r
190**/\r
191VOID\r
7b414b4e 192EFIAPI\r
cbf316f2 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
e48e37fc 208 gBS->FreePool (Nbuf);\r
cbf316f2 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
3e7104c2 216 @param[in] Nbuf Pointer to the net buffer to be cloned.\r
cbf316f2 217\r
3e7104c2 218 @return Pointer to the cloned net buffer.If NULL, the\r
219 allocation failed due to resource limit.\r
cbf316f2 220\r
221**/\r
222NET_BUF *\r
7b414b4e 223EFIAPI\r
cbf316f2 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
e48e37fc 232 Clone = AllocatePool (NET_BUF_SIZE (Nbuf->BlockOpNum));\r
cbf316f2 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
e48e37fc 240 InitializeListHead (&Clone->List);\r
cbf316f2 241\r
242 Clone->Ip = Nbuf->Ip;\r
243 Clone->Tcp = Nbuf->Tcp;\r
244\r
e48e37fc 245 CopyMem (Clone->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);\r
cbf316f2 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
e48e37fc 252 CopyMem (Clone->BlockOp, Nbuf->BlockOp, sizeof (NET_BLOCK_OP) * Nbuf->BlockOpNum);\r
cbf316f2 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
3e7104c2 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
cbf316f2 266\r
3e7104c2 267 @return Pointer to the duplicated net buffer.If NULL, the\r
268 allocation failed due to resource limit.\r
cbf316f2 269\r
270**/\r
271NET_BUF *\r
7b414b4e 272EFIAPI\r
cbf316f2 273NetbufDuplicate (\r
274 IN NET_BUF *Nbuf,\r
3e7104c2 275 IN OUT NET_BUF *Duplicate OPTIONAL,\r
cbf316f2 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
e48e37fc 295 CopyMem (Duplicate->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);\r
cbf316f2 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
3e7104c2 308 @param[in, out] Head Pointer to the head of linked net buffers.\r
cbf316f2 309\r
310**/\r
311VOID\r
7b414b4e 312EFIAPI\r
cbf316f2 313NetbufFreeList (\r
3e7104c2 314 IN OUT LIST_ENTRY *Head\r
cbf316f2 315 )\r
316{\r
e48e37fc 317 LIST_ENTRY *Entry;\r
318 LIST_ENTRY *Next;\r
cbf316f2 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
e48e37fc 327 RemoveEntryList (Entry);\r
cbf316f2 328 NetbufFree (Nbuf);\r
329 }\r
330\r
e48e37fc 331 ASSERT (IsListEmpty (Head));\r
cbf316f2 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
3e7104c2 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
cbf316f2 344\r
3e7104c2 345 @return * Pointer to the nth byte of data in the net buffer.\r
cbf316f2 346 If NULL, there is no such data in the net buffer.\r
347\r
348**/\r
349UINT8 *\r
7b414b4e 350EFIAPI\r
cbf316f2 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
3e7104c2 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
cbf316f2 401**/\r
cbf316f2 402VOID\r
403NetbufSetBlock (\r
3e7104c2 404 IN OUT NET_BUF *Nbuf,\r
cbf316f2 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
3e7104c2 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
cbf316f2 440\r
441**/\r
cbf316f2 442VOID\r
443NetbufSetBlockOp (\r
3e7104c2 444 IN OUT NET_BUF *Nbuf,\r
cbf316f2 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
3e7104c2 470 @param[in] Arg Point to the old NET_VECTOR.\r
cbf316f2 471\r
472**/\r
cbf316f2 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
3e7104c2 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
cbf316f2 498\r
3e7104c2 499 @return Pointer to the cloned net buffer.If NULL, the\r
500 allocation failed due to resource limit.\r
cbf316f2 501\r
502**/\r
503NET_BUF *\r
7b414b4e 504EFIAPI\r
cbf316f2 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
e48e37fc 597 FirstBulk = AllocatePool (HeadSpace);\r
cbf316f2 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
8d285ec0 641 for (Index = First + 1; Index <= Last - 1 ; Index++) {\r
cbf316f2 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
e48e37fc 659 CopyMem (Child->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);\r
cbf316f2 660 return Child;\r
661\r
662FreeChild:\r
663\r
e48e37fc 664 gBS->FreePool (Child);\r
cbf316f2 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
3e7104c2 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
cbf316f2 681\r
3e7104c2 682 @return Pointer to the net buffer built from the data blocks.\r
683 If NULL, the allocation failed due to resource limit.\r
cbf316f2 684\r
685**/\r
686NET_BUF *\r
7b414b4e 687EFIAPI\r
cbf316f2 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
e48e37fc 740 FirstBlock = AllocatePool (FirstBlockLen);\r
cbf316f2 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
e48e37fc 760 CopyMem (Header, ExtFragment[Index].Bulk, ExtFragment[Index].Len);\r
cbf316f2 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
e48e37fc 778 CopyMem (Header, ExtFragment[Index].Bulk, Len);\r
cbf316f2 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
3e7104c2 808 Vector->Flag = ((FirstBlockLen != 0) ? NET_VECTOR_OWN_FIRST : 0);\r
cbf316f2 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
3e7104c2 833 if (SavedIndex != 0) {\r
cbf316f2 834 ExtFragment[SavedIndex] = SavedFragment;\r
835 }\r
836\r
837 return Nbuf;\r
838\r
839FreeFirstBlock:\r
e48e37fc 840 gBS->FreePool (FirstBlock);\r
cbf316f2 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
3e7104c2 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
cbf316f2 852\r
3e7104c2 853 @retval EFI_BUFFER_TOO_SMALL The number of non-empty block is bigger than ExtNum.\r
cbf316f2 854 @retval EFI_SUCCESS Fragment table built.\r
855\r
856**/\r
857EFI_STATUS\r
7b414b4e 858EFIAPI\r
cbf316f2 859NetbufBuildExt (\r
860 IN NET_BUF *Nbuf,\r
3e7104c2 861 IN OUT NET_FRAGMENT *ExtFragment,\r
862 IN OUT UINT32 *ExtNum\r
cbf316f2 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
3e7104c2 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
cbf316f2 899\r
3e7104c2 900 @return Pointer to the net buffer built from the data\r
cbf316f2 901 blocks.\r
902\r
903**/\r
904NET_BUF *\r
7b414b4e 905EFIAPI\r
cbf316f2 906NetbufFromBufList (\r
e48e37fc 907 IN LIST_ENTRY *BufList,\r
cbf316f2 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
e48e37fc 916 LIST_ENTRY *Entry;\r
cbf316f2 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
e48e37fc 935 Fragment = AllocatePool (sizeof (NET_FRAGMENT) * FragmentNum);\r
cbf316f2 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
e48e37fc 957 gBS->FreePool (Fragment);\r
cbf316f2 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
3e7104c2 972 @param[in, out] Nbuf Pointer to the net buffer.\r
973 @param[in] Len The length of buffer to be reserverd.\r
cbf316f2 974\r
975**/\r
976VOID\r
7b414b4e 977EFIAPI\r
cbf316f2 978NetbufReserve (\r
3e7104c2 979 IN OUT NET_BUF *Nbuf,\r
cbf316f2 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
3e7104c2 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
cbf316f2 1004\r
3e7104c2 1005 @return Pointer to the first byte of the allocated buffer.\r
cbf316f2 1006\r
1007**/\r
1008UINT8 *\r
7b414b4e 1009EFIAPI\r
cbf316f2 1010NetbufAllocSpace (\r
3e7104c2 1011 IN OUT NET_BUF *Nbuf,\r
cbf316f2 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
3e7104c2 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
cbf316f2 1095\r
1096**/\r
cbf316f2 1097VOID\r
1098NetblockTrim (\r
3e7104c2 1099 IN OUT NET_BLOCK_OP *BlockOp,\r
cbf316f2 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
3e7104c2 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
cbf316f2 1123\r
3e7104c2 1124 @return Length of the actually trimmed data.\r
cbf316f2 1125\r
1126**/\r
1127UINT32\r
7b414b4e 1128EFIAPI\r
cbf316f2 1129NetbufTrim (\r
3e7104c2 1130 IN OUT NET_BUF *Nbuf,\r
cbf316f2 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
3e7104c2 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
cbf316f2 1188\r
1189 @retval UINTN The length of the copied data.\r
1190\r
1191**/\r
1192UINT32\r
7b414b4e 1193EFIAPI\r
cbf316f2 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
e48e37fc 1251 CopyMem (Dest, BlockOp[Index].Head + Skip, Len);\r
cbf316f2 1252 return Len;\r
1253 }\r
1254\r
e48e37fc 1255 CopyMem (Dest, BlockOp[Index].Head + Skip, Left);\r
cbf316f2 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
e48e37fc 1268 CopyMem (Dest, BlockOp[Index].Head, BlockOp[Index].Size);\r
cbf316f2 1269 Dest += BlockOp[Index].Size;\r
1270 } else {\r
1271 Copied += Len;\r
e48e37fc 1272 CopyMem (Dest, BlockOp[Index].Head, Len);\r
cbf316f2 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
3e7104c2 1284 @param[in, out] NbufQue Pointer to the net buffer queue to be initiated.\r
cbf316f2 1285\r
1286**/\r
1287VOID\r
7b414b4e 1288EFIAPI\r
cbf316f2 1289NetbufQueInit (\r
3e7104c2 1290 IN OUT NET_BUF_QUEUE *NbufQue\r
cbf316f2 1291 )\r
1292{\r
1293 NbufQue->Signature = NET_QUE_SIGNATURE;\r
1294 NbufQue->RefCnt = 1;\r
e48e37fc 1295 InitializeListHead (&NbufQue->List);\r
cbf316f2 1296\r
e48e37fc 1297 InitializeListHead (&NbufQue->BufList);\r
cbf316f2 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
3e7104c2 1306 @return Pointer to the allocated net buffer queue.If NULL, the\r
1307 allocation failed due to resource limit.\r
cbf316f2 1308\r
1309**/\r
1310NET_BUF_QUEUE *\r
7b414b4e 1311EFIAPI\r
cbf316f2 1312NetbufQueAlloc (\r
1313 VOID\r
1314 )\r
1315{\r
1316 NET_BUF_QUEUE *NbufQue;\r
1317\r
e48e37fc 1318 NbufQue = AllocatePool (sizeof (NET_BUF_QUEUE));\r
cbf316f2 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
3e7104c2 1332 @param[in] NbufQue Poitner to the net buffer queue to be freed.\r
cbf316f2 1333\r
1334**/\r
1335VOID\r
7b414b4e 1336EFIAPI\r
cbf316f2 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
e48e37fc 1347 gBS->FreePool (NbufQue);\r
cbf316f2 1348 }\r
1349}\r
1350\r
1351\r
1352/**\r
1353 Append a buffer to the end of the queue.\r
1354\r
3e7104c2 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
cbf316f2 1357\r
1358**/\r
1359VOID\r
7b414b4e 1360EFIAPI\r
cbf316f2 1361NetbufQueAppend (\r
3e7104c2 1362 IN OUT NET_BUF_QUEUE *NbufQue,\r
1363 IN OUT NET_BUF *Nbuf\r
cbf316f2 1364 )\r
1365{\r
1366 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);\r
1367 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
1368\r
e48e37fc 1369 InsertTailList (&NbufQue->BufList, &Nbuf->List);\r
cbf316f2 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
3e7104c2 1379 @param[in, out] NbufQue Pointer to the net buffer queue.\r
cbf316f2 1380\r
3e7104c2 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
cbf316f2 1383 queue.\r
1384\r
1385**/\r
1386NET_BUF *\r
7b414b4e 1387EFIAPI\r
cbf316f2 1388NetbufQueRemove (\r
3e7104c2 1389 IN OUT NET_BUF_QUEUE *NbufQue\r
cbf316f2 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
3e7104c2 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
cbf316f2 1417\r
3e7104c2 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
cbf316f2 1420\r
1421**/\r
1422UINT32\r
3e7104c2 1423EFIAPI\r
cbf316f2 1424NetbufQueCopy (\r
1425 IN NET_BUF_QUEUE *NbufQue,\r
1426 IN UINT32 Offset,\r
1427 IN UINT32 Len,\r
3e7104c2 1428 OUT UINT8 *Dest\r
cbf316f2 1429 )\r
1430{\r
e48e37fc 1431 LIST_ENTRY *Entry;\r
cbf316f2 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
3e7104c2 1512 @param[in, out] NbufQue Pointer to the net buffer queue.\r
1513 @param[in] Len Length of the data to trim.\r
cbf316f2 1514\r
3e7104c2 1515 @return The length of the data trimmed, or 0 if length of the data to trim is zero.\r
cbf316f2 1516\r
1517**/\r
1518UINT32\r
7b414b4e 1519EFIAPI\r
cbf316f2 1520NetbufQueTrim (\r
3e7104c2 1521 IN OUT NET_BUF_QUEUE *NbufQue,\r
cbf316f2 1522 IN UINT32 Len\r
1523 )\r
1524{\r
e48e37fc 1525 LIST_ENTRY *Entry;\r
1526 LIST_ENTRY *Next;\r
cbf316f2 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
e48e37fc 1550 RemoveEntryList (Entry);\r
cbf316f2 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
3e7104c2 1572 @param[in, out] NbufQue Pointer to the queue to be flushed.\r
cbf316f2 1573\r
1574**/\r
1575VOID\r
7b414b4e 1576EFIAPI\r
cbf316f2 1577NetbufQueFlush (\r
3e7104c2 1578 IN OUT NET_BUF_QUEUE *NbufQue\r
cbf316f2 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
3e7104c2 1593 @param[in] Bulk Pointer to the data.\r
1594 @param[in] Len Length of the data, in bytes.\r
cbf316f2 1595\r
3e7104c2 1596 @return The computed checksum.\r
cbf316f2 1597\r
1598**/\r
1599UINT16\r
7b414b4e 1600EFIAPI\r
cbf316f2 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
3e7104c2 1626 while ((Sum >> 16) != 0) {\r
cbf316f2 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
3e7104c2 1638 @param[in] Checksum1 The first checksum to be added.\r
1639 @param[in] Checksum2 The second checksum to be added.\r
cbf316f2 1640\r
3e7104c2 1641 @return The new checksum.\r
cbf316f2 1642\r
1643**/\r
1644UINT16\r
7b414b4e 1645EFIAPI\r
cbf316f2 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
3e7104c2 1658 if ((Sum >> 16) != 0) {\r
cbf316f2 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
3e7104c2 1670 @param[in] Nbuf Pointer to the net buffer.\r
cbf316f2 1671\r
3e7104c2 1672 @return The computed checksum.\r
cbf316f2 1673\r
1674**/\r
1675UINT16\r
7b414b4e 1676EFIAPI\r
cbf316f2 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
3e7104c2 1700 if ((Offset & 0x01) != 0) {\r
cbf316f2 1701 //\r
1702 // The checksum starts with an odd byte, swap\r
1703 // the checksum before added to total checksum\r
1704 //\r
4eb65aff 1705 BlockSum = (UINT16) NET_SWAP_SHORT (BlockSum);\r
cbf316f2 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
3e7104c2 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
cbf316f2 1725\r
3e7104c2 1726 @return The computed checksum.\r
cbf316f2 1727\r
1728**/\r
1729UINT16\r
7b414b4e 1730EFIAPI\r
cbf316f2 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
e48e37fc 1743 ZeroMem (&Hdr, sizeof (Hdr));\r
cbf316f2 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