]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeNetLib/NetBuffer.c
1. Fix the potential issue in NetbufGetFragment() when Last is zero in Line 53.
[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
1053 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
1054 NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);\r
1055\r
1056 ASSERT (Len > 0);\r
1057\r
1058 if (FromHead) {\r
1059 //\r
1060 // Allocate some space from head. If the buffer is empty,\r
1061 // allocate from the first block. If it isn't, allocate\r
1062 // from the first non-empty block, or the block before that.\r
1063 //\r
1064 if (Nbuf->TotalSize == 0) {\r
1065 Index = 0;\r
1066 } else {\r
1067 NetbufGetByte (Nbuf, 0, &Index);\r
1068\r
1069 if ((NET_HEADSPACE(&(Nbuf->BlockOp[Index])) < Len) && (Index > 0)) {\r
1070 Index--;\r
1071 }\r
1072 }\r
1073\r
1074 BlockOp = &(Nbuf->BlockOp[Index]);\r
1075\r
1076 if (NET_HEADSPACE (BlockOp) < Len) {\r
1077 return NULL;\r
1078 }\r
1079\r
1080 BlockOp->Head -= Len;\r
1081 BlockOp->Size += Len;\r
1082 Nbuf->TotalSize += Len;\r
1083\r
1084 return BlockOp->Head;\r
1085\r
1086 } else {\r
1087 //\r
1088 // Allocate some space from the tail. If the buffer is empty,\r
1089 // allocate from the first block. If it isn't, allocate\r
1090 // from the last non-empty block, or the block after that.\r
1091 //\r
1092 if (Nbuf->TotalSize == 0) {\r
1093 Index = 0;\r
1094 } else {\r
1095 NetbufGetByte (Nbuf, Nbuf->TotalSize - 1, &Index);\r
1096\r
1097 if ((NET_TAILSPACE(&(Nbuf->BlockOp[Index])) < Len) &&\r
1098 (Index < Nbuf->BlockOpNum - 1)) {\r
1099\r
1100 Index++;\r
1101 }\r
1102 }\r
1103\r
1104 BlockOp = &(Nbuf->BlockOp[Index]);\r
1105\r
1106 if (NET_TAILSPACE (BlockOp) < Len) {\r
1107 return NULL;\r
1108 }\r
1109\r
1110 SavedTail = BlockOp->Tail;\r
1111\r
1112 BlockOp->Tail += Len;\r
1113 BlockOp->Size += Len;\r
1114 Nbuf->TotalSize += Len;\r
1115\r
1116 return SavedTail;\r
1117 }\r
1118}\r
1119\r
1120\r
1121/**\r
32cf7c73 1122 Trim a single NET_BLOCK by Len bytes from the header or tail.\r
cbf316f2 1123\r
32cf7c73 1124 @param[in, out] BlockOp Pointer to the NET_BLOCK.\r
1125 @param[in] Len The length of the data to be trimmed.\r
1204fe83 1126 @param[in] FromHead The flag to indicate whether trim data from head\r
32cf7c73 1127 (TRUE) or tail (FALSE).\r
cbf316f2 1128\r
1129**/\r
cbf316f2 1130VOID\r
1131NetblockTrim (\r
3e7104c2 1132 IN OUT NET_BLOCK_OP *BlockOp,\r
cbf316f2 1133 IN UINT32 Len,\r
1134 IN BOOLEAN FromHead\r
1135 )\r
1136{\r
32cf7c73 1137 ASSERT ((BlockOp != NULL) && (BlockOp->Size >= Len));\r
cbf316f2 1138\r
1139 BlockOp->Size -= Len;\r
1140\r
1141 if (FromHead) {\r
1142 BlockOp->Head += Len;\r
1143 } else {\r
1144 BlockOp->Tail -= Len;\r
1145 }\r
1146}\r
1147\r
1148\r
1149/**\r
1204fe83 1150 Trim Len bytes from the header or tail of the net buffer.\r
cbf316f2 1151\r
32cf7c73 1152 @param[in, out] Nbuf Pointer to the net buffer.\r
1153 @param[in] Len The length of the data to be trimmed.\r
1204fe83 1154 @param[in] FromHead The flag to indicate whether trim data from head\r
32cf7c73 1155 (TRUE) or tail (FALSE).\r
cbf316f2 1156\r
1204fe83 1157 @return Length of the actually trimmed data, which is possible to be less\r
32cf7c73 1158 than Len because the TotalSize of Nbuf is less than Len.\r
cbf316f2 1159\r
1160**/\r
1161UINT32\r
7b414b4e 1162EFIAPI\r
cbf316f2 1163NetbufTrim (\r
3e7104c2 1164 IN OUT NET_BUF *Nbuf,\r
cbf316f2 1165 IN UINT32 Len,\r
1166 IN BOOLEAN FromHead\r
1167 )\r
1168{\r
1169 NET_BLOCK_OP *BlockOp;\r
1170 UINT32 Index;\r
1171 UINT32 Trimmed;\r
1172\r
1173 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
1174\r
1175 if (Len > Nbuf->TotalSize) {\r
1176 Len = Nbuf->TotalSize;\r
1177 }\r
1178\r
1179 //\r
1180 // If FromTail is true, iterate backward. That\r
1181 // is, init Index to NBuf->BlockNum - 1, and\r
1182 // decrease it by 1 during each loop. Otherwise,\r
1183 // iterate forward. That is, init Index to 0, and\r
1184 // increase it by 1 during each loop.\r
1185 //\r
1186 Trimmed = 0;\r
1187 Nbuf->TotalSize -= Len;\r
1188\r
1189 Index = (FromHead ? 0 : Nbuf->BlockOpNum - 1);\r
1190 BlockOp = Nbuf->BlockOp;\r
1191\r
1192 for (;;) {\r
1193 if (BlockOp[Index].Size == 0) {\r
1194 Index += (FromHead ? 1 : -1);\r
1195 continue;\r
1196 }\r
1197\r
1198 if (Len > BlockOp[Index].Size) {\r
1199 Len -= BlockOp[Index].Size;\r
1200 Trimmed += BlockOp[Index].Size;\r
1201 NetblockTrim (&BlockOp[Index], BlockOp[Index].Size, FromHead);\r
1202 } else {\r
1203 Trimmed += Len;\r
1204 NetblockTrim (&BlockOp[Index], Len, FromHead);\r
1205 break;\r
1206 }\r
1207\r
1208 Index += (FromHead ? 1 : -1);\r
1209 }\r
1210\r
1211 return Trimmed;\r
1212}\r
1213\r
1214\r
1215/**\r
1204fe83 1216 Copy Len bytes of data from the specific offset of the net buffer to the\r
32cf7c73 1217 destination memory.\r
1204fe83 1218\r
32cf7c73 1219 The Len bytes of data may cross the several fragments of the net buffer.\r
1204fe83 1220\r
32cf7c73 1221 @param[in] Nbuf Pointer to the net buffer.\r
1222 @param[in] Offset The sequence number of the first byte to copy.\r
1223 @param[in] Len Length of the data to copy.\r
1224 @param[in] Dest The destination of the data to copy to.\r
1225\r
1226 @return The length of the actual copied data, or 0 if the offset\r
e3c8c68a 1227 specified exceeds the total size of net buffer.\r
cbf316f2 1228\r
1229**/\r
1230UINT32\r
7b414b4e 1231EFIAPI\r
cbf316f2 1232NetbufCopy (\r
1233 IN NET_BUF *Nbuf,\r
1234 IN UINT32 Offset,\r
1235 IN UINT32 Len,\r
1236 IN UINT8 *Dest\r
1237 )\r
1238{\r
1239 NET_BLOCK_OP *BlockOp;\r
1240 UINT32 Skip;\r
1241 UINT32 Left;\r
1242 UINT32 Copied;\r
1243 UINT32 Index;\r
1244 UINT32 Cur;\r
1245\r
1246 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
1247 ASSERT (Dest);\r
1248\r
1249 if ((Len == 0) || (Nbuf->TotalSize <= Offset)) {\r
1250 return 0;\r
1251 }\r
1252\r
1253 if (Nbuf->TotalSize - Offset < Len) {\r
1254 Len = Nbuf->TotalSize - Offset;\r
1255 }\r
1256\r
1257 BlockOp = Nbuf->BlockOp;\r
1258\r
1259 //\r
1260 // Skip to the offset. Don't make "Offset-By-One" error here.\r
1261 // Cur + BLOCK.SIZE is the first sequence number of next block.\r
1262 // So, (Offset < Cur + BLOCK.SIZE) means that the first byte\r
1263 // is in the current block. if (Offset == Cur + BLOCK.SIZE), the\r
1264 // first byte is the next block's first byte.\r
1265 //\r
1266 Cur = 0;\r
1267\r
1268 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {\r
1269 if (BlockOp[Index].Size == 0) {\r
1270 continue;\r
1271 }\r
1272\r
1273 if (Offset < Cur + BlockOp[Index].Size) {\r
1274 break;\r
1275 }\r
1276\r
1277 Cur += BlockOp[Index].Size;\r
1278 }\r
1279\r
1280 //\r
1281 // Cur is the sequence number of the first byte in the block\r
1282 // Offset - Cur is the number of bytes before first byte to\r
1283 // to copy in the current block.\r
1284 //\r
1285 Skip = Offset - Cur;\r
1286 Left = BlockOp[Index].Size - Skip;\r
1287\r
1288 if (Len <= Left) {\r
e48e37fc 1289 CopyMem (Dest, BlockOp[Index].Head + Skip, Len);\r
cbf316f2 1290 return Len;\r
1291 }\r
1292\r
e48e37fc 1293 CopyMem (Dest, BlockOp[Index].Head + Skip, Left);\r
cbf316f2 1294\r
1295 Dest += Left;\r
1296 Len -= Left;\r
1297 Copied = Left;\r
1298\r
1299 Index++;\r
1300\r
1301 for (; Index < Nbuf->BlockOpNum; Index++) {\r
1302 if (Len > BlockOp[Index].Size) {\r
1303 Len -= BlockOp[Index].Size;\r
1304 Copied += BlockOp[Index].Size;\r
1305\r
e48e37fc 1306 CopyMem (Dest, BlockOp[Index].Head, BlockOp[Index].Size);\r
cbf316f2 1307 Dest += BlockOp[Index].Size;\r
1308 } else {\r
1309 Copied += Len;\r
e48e37fc 1310 CopyMem (Dest, BlockOp[Index].Head, Len);\r
cbf316f2 1311 break;\r
1312 }\r
1313 }\r
1314\r
1315 return Copied;\r
1316}\r
1317\r
1318\r
1319/**\r
1320 Initiate the net buffer queue.\r
1321\r
32cf7c73 1322 @param[in, out] NbufQue Pointer to the net buffer queue to be initialized.\r
cbf316f2 1323\r
1324**/\r
1325VOID\r
7b414b4e 1326EFIAPI\r
cbf316f2 1327NetbufQueInit (\r
3e7104c2 1328 IN OUT NET_BUF_QUEUE *NbufQue\r
cbf316f2 1329 )\r
1330{\r
1331 NbufQue->Signature = NET_QUE_SIGNATURE;\r
1332 NbufQue->RefCnt = 1;\r
e48e37fc 1333 InitializeListHead (&NbufQue->List);\r
cbf316f2 1334\r
e48e37fc 1335 InitializeListHead (&NbufQue->BufList);\r
cbf316f2 1336 NbufQue->BufSize = 0;\r
1337 NbufQue->BufNum = 0;\r
1338}\r
1339\r
1340\r
1341/**\r
32cf7c73 1342 Allocate and initialize a net buffer queue.\r
cbf316f2 1343\r
32cf7c73 1344 @return Pointer to the allocated net buffer queue, or NULL if the\r
1345 allocation failed due to resource limit.\r
cbf316f2 1346\r
1347**/\r
1348NET_BUF_QUEUE *\r
7b414b4e 1349EFIAPI\r
cbf316f2 1350NetbufQueAlloc (\r
1351 VOID\r
1352 )\r
1353{\r
1354 NET_BUF_QUEUE *NbufQue;\r
1355\r
e48e37fc 1356 NbufQue = AllocatePool (sizeof (NET_BUF_QUEUE));\r
cbf316f2 1357 if (NbufQue == NULL) {\r
1358 return NULL;\r
1359 }\r
1360\r
1361 NetbufQueInit (NbufQue);\r
1362\r
1363 return NbufQue;\r
1364}\r
1365\r
1366\r
1367/**\r
1204fe83 1368 Free a net buffer queue.\r
1369\r
32cf7c73 1370 Decrease the reference count of the net buffer queue by one. The real resource\r
1204fe83 1371 free operation isn't performed until the reference count of the net buffer\r
32cf7c73 1372 queue is decreased to 0.\r
cbf316f2 1373\r
32cf7c73 1374 @param[in] NbufQue Pointer to the net buffer queue to be freed.\r
cbf316f2 1375\r
1376**/\r
1377VOID\r
7b414b4e 1378EFIAPI\r
cbf316f2 1379NetbufQueFree (\r
1380 IN NET_BUF_QUEUE *NbufQue\r
1381 )\r
1382{\r
7b0ae7e8 1383 ASSERT (NbufQue != NULL);\r
cbf316f2 1384 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);\r
1385\r
1386 NbufQue->RefCnt--;\r
1387\r
1388 if (NbufQue->RefCnt == 0) {\r
1389 NetbufQueFlush (NbufQue);\r
7b0ae7e8 1390 FreePool (NbufQue);\r
cbf316f2 1391 }\r
1392}\r
1393\r
1394\r
1395/**\r
32cf7c73 1396 Append a net buffer to the net buffer queue.\r
cbf316f2 1397\r
32cf7c73 1398 @param[in, out] NbufQue Pointer to the net buffer queue.\r
1399 @param[in, out] Nbuf Pointer to the net buffer to be appended.\r
cbf316f2 1400\r
1401**/\r
1402VOID\r
7b414b4e 1403EFIAPI\r
cbf316f2 1404NetbufQueAppend (\r
3e7104c2 1405 IN OUT NET_BUF_QUEUE *NbufQue,\r
1406 IN OUT NET_BUF *Nbuf\r
cbf316f2 1407 )\r
1408{\r
1409 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);\r
1410 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
1411\r
e48e37fc 1412 InsertTailList (&NbufQue->BufList, &Nbuf->List);\r
cbf316f2 1413\r
1414 NbufQue->BufSize += Nbuf->TotalSize;\r
1415 NbufQue->BufNum++;\r
1416}\r
1417\r
1418\r
1419/**\r
32cf7c73 1420 Remove a net buffer from the head in the specific queue and return it.\r
cbf316f2 1421\r
3e7104c2 1422 @param[in, out] NbufQue Pointer to the net buffer queue.\r
cbf316f2 1423\r
1204fe83 1424 @return Pointer to the net buffer removed from the specific queue,\r
9bc4edf2 1425 or NULL if there is no net buffer in the specific queue.\r
cbf316f2 1426\r
1427**/\r
1428NET_BUF *\r
7b414b4e 1429EFIAPI\r
cbf316f2 1430NetbufQueRemove (\r
3e7104c2 1431 IN OUT NET_BUF_QUEUE *NbufQue\r
cbf316f2 1432 )\r
1433{\r
1434 NET_BUF *First;\r
1435\r
1436 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);\r
1437\r
1438 if (NbufQue->BufNum == 0) {\r
1439 return NULL;\r
1440 }\r
1441\r
1442 First = NET_LIST_USER_STRUCT (NbufQue->BufList.ForwardLink, NET_BUF, List);\r
1443\r
1444 NetListRemoveHead (&NbufQue->BufList);\r
1445\r
1446 NbufQue->BufSize -= First->TotalSize;\r
1447 NbufQue->BufNum--;\r
1448 return First;\r
1449}\r
1450\r
1451\r
1452/**\r
32cf7c73 1453 Copy Len bytes of data from the net buffer queue at the specific offset to the\r
1454 destination memory.\r
1204fe83 1455\r
32cf7c73 1456 The copying operation is the same as NetbufCopy but applies to the net buffer\r
1457 queue instead of the net buffer.\r
1204fe83 1458\r
32cf7c73 1459 @param[in] NbufQue Pointer to the net buffer queue.\r
1460 @param[in] Offset The sequence number of the first byte to copy.\r
1461 @param[in] Len Length of the data to copy.\r
1462 @param[out] Dest The destination of the data to copy to.\r
1463\r
1204fe83 1464 @return The length of the actual copied data, or 0 if the offset\r
32cf7c73 1465 specified exceeds the total size of net buffer queue.\r
cbf316f2 1466\r
1467**/\r
1468UINT32\r
3e7104c2 1469EFIAPI\r
cbf316f2 1470NetbufQueCopy (\r
1471 IN NET_BUF_QUEUE *NbufQue,\r
1472 IN UINT32 Offset,\r
1473 IN UINT32 Len,\r
3e7104c2 1474 OUT UINT8 *Dest\r
cbf316f2 1475 )\r
1476{\r
e48e37fc 1477 LIST_ENTRY *Entry;\r
cbf316f2 1478 NET_BUF *Nbuf;\r
1479 UINT32 Skip;\r
1480 UINT32 Left;\r
1481 UINT32 Cur;\r
1482 UINT32 Copied;\r
1483\r
1484 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);\r
1485 ASSERT (Dest != NULL);\r
1486\r
1487 if ((Len == 0) || (NbufQue->BufSize <= Offset)) {\r
1488 return 0;\r
1489 }\r
1490\r
1491 if (NbufQue->BufSize - Offset < Len) {\r
1492 Len = NbufQue->BufSize - Offset;\r
1493 }\r
1494\r
1495 //\r
1496 // skip to the Offset\r
1497 //\r
1498 Cur = 0;\r
1499 Nbuf = NULL;\r
1500\r
1501 NET_LIST_FOR_EACH (Entry, &NbufQue->BufList) {\r
1502 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
1503\r
1504 if (Offset < Cur + Nbuf->TotalSize) {\r
1505 break;\r
1506 }\r
1507\r
1508 Cur += Nbuf->TotalSize;\r
1509 }\r
1510\r
894d038a 1511 ASSERT (Nbuf != NULL);\r
1512\r
cbf316f2 1513 //\r
1514 // Copy the data in the first buffer.\r
1515 //\r
1516 Skip = Offset - Cur;\r
1517 Left = Nbuf->TotalSize - Skip;\r
1518\r
1519 if (Len < Left) {\r
1520 return NetbufCopy (Nbuf, Skip, Len, Dest);\r
1521 }\r
1522\r
1523 NetbufCopy (Nbuf, Skip, Left, Dest);\r
1524 Dest += Left;\r
1525 Len -= Left;\r
1526 Copied = Left;\r
1527\r
1528 //\r
1529 // Iterate over the others\r
1530 //\r
1531 Entry = Entry->ForwardLink;\r
1532\r
1533 while ((Len > 0) && (Entry != &NbufQue->BufList)) {\r
1534 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
1535\r
1536 if (Len > Nbuf->TotalSize) {\r
1537 Len -= Nbuf->TotalSize;\r
1538 Copied += Nbuf->TotalSize;\r
1539\r
1540 NetbufCopy (Nbuf, 0, Nbuf->TotalSize, Dest);\r
1541 Dest += Nbuf->TotalSize;\r
1542\r
1543 } else {\r
1544 NetbufCopy (Nbuf, 0, Len, Dest);\r
1545 Copied += Len;\r
1546 break;\r
1547 }\r
1548\r
1549 Entry = Entry->ForwardLink;\r
1550 }\r
1551\r
1552 return Copied;\r
1553}\r
1554\r
1555\r
1556/**\r
1204fe83 1557 Trim Len bytes of data from the queue header, release any of the net buffer\r
32cf7c73 1558 whom is trimmed wholely.\r
1204fe83 1559\r
32cf7c73 1560 The trimming operation is the same as NetbufTrim but applies to the net buffer\r
1561 queue instead of the net buffer.\r
cbf316f2 1562\r
3e7104c2 1563 @param[in, out] NbufQue Pointer to the net buffer queue.\r
1564 @param[in] Len Length of the data to trim.\r
cbf316f2 1565\r
32cf7c73 1566 @return The actual length of the data trimmed.\r
cbf316f2 1567\r
1568**/\r
1569UINT32\r
7b414b4e 1570EFIAPI\r
cbf316f2 1571NetbufQueTrim (\r
3e7104c2 1572 IN OUT NET_BUF_QUEUE *NbufQue,\r
cbf316f2 1573 IN UINT32 Len\r
1574 )\r
1575{\r
e48e37fc 1576 LIST_ENTRY *Entry;\r
1577 LIST_ENTRY *Next;\r
cbf316f2 1578 NET_BUF *Nbuf;\r
1579 UINT32 Trimmed;\r
1580\r
1581 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);\r
1582\r
1583 if (Len == 0) {\r
1584 return 0;\r
1585 }\r
1586\r
1587 if (Len > NbufQue->BufSize) {\r
1588 Len = NbufQue->BufSize;\r
1589 }\r
1590\r
1591 NbufQue->BufSize -= Len;\r
1592 Trimmed = 0;\r
1593\r
1594 NET_LIST_FOR_EACH_SAFE (Entry, Next, &NbufQue->BufList) {\r
1595 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
1596\r
1597 if (Len >= Nbuf->TotalSize) {\r
1598 Trimmed += Nbuf->TotalSize;\r
1599 Len -= Nbuf->TotalSize;\r
1600\r
e48e37fc 1601 RemoveEntryList (Entry);\r
cbf316f2 1602 NetbufFree (Nbuf);\r
1603\r
1604 NbufQue->BufNum--;\r
1605\r
1606 if (Len == 0) {\r
1607 break;\r
1608 }\r
1609\r
1610 } else {\r
1611 Trimmed += NetbufTrim (Nbuf, Len, NET_BUF_HEAD);\r
1612 break;\r
1613 }\r
1614 }\r
1615\r
1616 return Trimmed;\r
1617}\r
1618\r
1619\r
1620/**\r
1621 Flush the net buffer queue.\r
1622\r
3e7104c2 1623 @param[in, out] NbufQue Pointer to the queue to be flushed.\r
cbf316f2 1624\r
1625**/\r
1626VOID\r
7b414b4e 1627EFIAPI\r
cbf316f2 1628NetbufQueFlush (\r
3e7104c2 1629 IN OUT NET_BUF_QUEUE *NbufQue\r
cbf316f2 1630 )\r
1631{\r
1632 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);\r
1633\r
1634 NetbufFreeList (&NbufQue->BufList);\r
1635\r
1636 NbufQue->BufNum = 0;\r
1637 NbufQue->BufSize = 0;\r
1638}\r
1639\r
1640\r
1641/**\r
32cf7c73 1642 Compute the checksum for a bulk of data.\r
cbf316f2 1643\r
3e7104c2 1644 @param[in] Bulk Pointer to the data.\r
1645 @param[in] Len Length of the data, in bytes.\r
cbf316f2 1646\r
3e7104c2 1647 @return The computed checksum.\r
cbf316f2 1648\r
1649**/\r
1650UINT16\r
7b414b4e 1651EFIAPI\r
cbf316f2 1652NetblockChecksum (\r
1653 IN UINT8 *Bulk,\r
1654 IN UINT32 Len\r
1655 )\r
1656{\r
1657 register UINT32 Sum;\r
1658\r
1659 Sum = 0;\r
1660\r
1661 while (Len > 1) {\r
1662 Sum += *(UINT16 *) Bulk;\r
1663 Bulk += 2;\r
1664 Len -= 2;\r
1665 }\r
1666\r
1667 //\r
1668 // Add left-over byte, if any\r
1669 //\r
1670 if (Len > 0) {\r
1671 Sum += *(UINT8 *) Bulk;\r
1672 }\r
1673\r
1674 //\r
1675 // Fold 32-bit sum to 16 bits\r
1676 //\r
3e7104c2 1677 while ((Sum >> 16) != 0) {\r
cbf316f2 1678 Sum = (Sum & 0xffff) + (Sum >> 16);\r
1679\r
1680 }\r
1681\r
1682 return (UINT16) Sum;\r
1683}\r
1684\r
1685\r
1686/**\r
1687 Add two checksums.\r
1688\r
3e7104c2 1689 @param[in] Checksum1 The first checksum to be added.\r
1690 @param[in] Checksum2 The second checksum to be added.\r
cbf316f2 1691\r
3e7104c2 1692 @return The new checksum.\r
cbf316f2 1693\r
1694**/\r
1695UINT16\r
7b414b4e 1696EFIAPI\r
cbf316f2 1697NetAddChecksum (\r
1698 IN UINT16 Checksum1,\r
1699 IN UINT16 Checksum2\r
1700 )\r
1701{\r
1702 UINT32 Sum;\r
1703\r
1704 Sum = Checksum1 + Checksum2;\r
1705\r
1706 //\r
1707 // two UINT16 can only add up to a carry of 1.\r
1708 //\r
3e7104c2 1709 if ((Sum >> 16) != 0) {\r
cbf316f2 1710 Sum = (Sum & 0xffff) + 1;\r
1711\r
1712 }\r
1713\r
1714 return (UINT16) Sum;\r
1715}\r
1716\r
1717\r
1718/**\r
1719 Compute the checksum for a NET_BUF.\r
1720\r
3e7104c2 1721 @param[in] Nbuf Pointer to the net buffer.\r
cbf316f2 1722\r
3e7104c2 1723 @return The computed checksum.\r
cbf316f2 1724\r
1725**/\r
1726UINT16\r
7b414b4e 1727EFIAPI\r
cbf316f2 1728NetbufChecksum (\r
1729 IN NET_BUF *Nbuf\r
1730 )\r
1731{\r
1732 NET_BLOCK_OP *BlockOp;\r
1733 UINT32 Offset;\r
1734 UINT16 TotalSum;\r
1735 UINT16 BlockSum;\r
1736 UINT32 Index;\r
1737\r
1738 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
1739\r
1740 TotalSum = 0;\r
1741 Offset = 0;\r
1742 BlockOp = Nbuf->BlockOp;\r
1743\r
1744 for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {\r
1745 if (BlockOp[Index].Size == 0) {\r
1746 continue;\r
1747 }\r
1748\r
1749 BlockSum = NetblockChecksum (BlockOp[Index].Head, BlockOp[Index].Size);\r
1750\r
3e7104c2 1751 if ((Offset & 0x01) != 0) {\r
cbf316f2 1752 //\r
1753 // The checksum starts with an odd byte, swap\r
1754 // the checksum before added to total checksum\r
1755 //\r
1204fe83 1756 BlockSum = SwapBytes16 (BlockSum);\r
cbf316f2 1757 }\r
1758\r
1759 TotalSum = NetAddChecksum (BlockSum, TotalSum);\r
1760 Offset += BlockOp[Index].Size;\r
1761 }\r
1762\r
1763 return TotalSum;\r
1764}\r
1765\r
1766\r
1767/**\r
1204fe83 1768 Compute the checksum for TCP/UDP pseudo header.\r
1769\r
32cf7c73 1770 Src and Dst are in network byte order, and Len is in host byte order.\r
cbf316f2 1771\r
3e7104c2 1772 @param[in] Src The source address of the packet.\r
1773 @param[in] Dst The destination address of the packet.\r
1774 @param[in] Proto The protocol type of the packet.\r
1775 @param[in] Len The length of the packet.\r
cbf316f2 1776\r
3e7104c2 1777 @return The computed checksum.\r
cbf316f2 1778\r
1779**/\r
1780UINT16\r
7b414b4e 1781EFIAPI\r
cbf316f2 1782NetPseudoHeadChecksum (\r
1783 IN IP4_ADDR Src,\r
1784 IN IP4_ADDR Dst,\r
1785 IN UINT8 Proto,\r
1786 IN UINT16 Len\r
1787 )\r
1788{\r
1789 NET_PSEUDO_HDR Hdr;\r
1790\r
1791 //\r
1792 // Zero the memory to relieve align problems\r
1793 //\r
e48e37fc 1794 ZeroMem (&Hdr, sizeof (Hdr));\r
cbf316f2 1795\r
1796 Hdr.SrcIp = Src;\r
1797 Hdr.DstIp = Dst;\r
1798 Hdr.Protocol = Proto;\r
1799 Hdr.Len = HTONS (Len);\r
1800\r
1801 return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));\r
1802}\r
f6b7393c 1803\r
1804/**\r
1204fe83 1805 Compute the checksum for TCP6/UDP6 pseudo header.\r
1806\r
f6b7393c 1807 Src and Dst are in network byte order, and Len is in host byte order.\r
1808\r
1809 @param[in] Src The source address of the packet.\r
1810 @param[in] Dst The destination address of the packet.\r
1811 @param[in] NextHeader The protocol type of the packet.\r
1812 @param[in] Len The length of the packet.\r
1813\r
1814 @return The computed checksum.\r
1815\r
1816**/\r
1817UINT16\r
1818NetIp6PseudoHeadChecksum (\r
1819 IN EFI_IPv6_ADDRESS *Src,\r
1820 IN EFI_IPv6_ADDRESS *Dst,\r
1821 IN UINT8 NextHeader,\r
1822 IN UINT32 Len\r
1823 )\r
1824{\r
1825 NET_IP6_PSEUDO_HDR Hdr;\r
1826\r
1827 //\r
1828 // Zero the memory to relieve align problems\r
1829 //\r
1830 ZeroMem (&Hdr, sizeof (Hdr));\r
1831\r
1832 IP6_COPY_ADDRESS (&Hdr.SrcIp, Src);\r
1833 IP6_COPY_ADDRESS (&Hdr.DstIp, Dst);\r
1834\r
1835 Hdr.NextHeader = NextHeader;\r
1204fe83 1836 Hdr.Len = HTONL (Len);\r
f6b7393c 1837\r
1838 return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));\r
1839}\r
1840\r