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