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