]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Library/DxeNetLib/NetBuffer.c
add security check.
[mirror_edk2.git] / MdeModulePkg / Library / DxeNetLib / NetBuffer.c
... / ...
CommitLineData
1/** @file\r
2 Network library functions providing net buffer operation support.\r
3 \r
4Copyright (c) 2005 - 2009, Intel Corporation.<BR>\r
5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12**/\r
13\r
14#include <Uefi.h>\r
15\r
16#include <Library/NetLib.h>\r
17#include <Library/BaseLib.h>\r
18#include <Library/DebugLib.h>\r
19#include <Library/BaseMemoryLib.h>\r
20#include <Library/UefiBootServicesTableLib.h>\r
21#include <Library/MemoryAllocationLib.h>\r
22\r
23\r
24/**\r
25 Allocate and build up the sketch for a NET_BUF. \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
30\r
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
33\r
34 @return Pointer to the allocated NET_BUF, or NULL if the \r
35 allocation failed due to resource limit.\r
36\r
37**/\r
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
52 Nbuf = AllocateZeroPool (NET_BUF_SIZE (BlockOpNum));\r
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
61 InitializeListHead (&Nbuf->List);\r
62\r
63 if (BlockNum != 0) {\r
64 Vector = AllocateZeroPool (NET_VECTOR_SIZE (BlockNum));\r
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
80 gBS->FreePool (Nbuf);\r
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
89 @param[in] Len The length of the block.\r
90\r
91 @return Pointer to the allocated NET_BUF, or NULL if the \r
92 allocation failed due to resource limit.\r
93\r
94**/\r
95NET_BUF *\r
96EFIAPI\r
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
113 Bulk = AllocatePool (Len);\r
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
135 gBS->FreePool (Nbuf);\r
136 return NULL;\r
137}\r
138\r
139/**\r
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
145\r
146 @param[in] Vector Pointer to the NET_VECTOR to be freed.\r
147\r
148**/\r
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
171 if ((Vector->Flag & NET_VECTOR_OWN_FIRST) != 0) {\r
172 gBS->FreePool (Vector->Block[0].Bulk);\r
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
182 gBS->FreePool (Vector->Block[Index].Bulk);\r
183 }\r
184 }\r
185\r
186 gBS->FreePool (Vector);\r
187}\r
188\r
189\r
190/**\r
191 Free the net buffer and its associated NET_VECTOR.\r
192 \r
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
198 \r
199 @param[in] Nbuf Pointer to the NET_BUF to be freed.\r
200\r
201**/\r
202VOID\r
203EFIAPI\r
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
219 gBS->FreePool (Nbuf);\r
220 }\r
221}\r
222\r
223\r
224/**\r
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
229\r
230 @param[in] Nbuf Pointer to the net buffer to be cloned.\r
231\r
232 @return Pointer to the cloned net buffer, or NULL if the\r
233 allocation failed due to resource limit.\r
234\r
235**/\r
236NET_BUF *\r
237EFIAPI\r
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
246 Clone = AllocatePool (NET_BUF_SIZE (Nbuf->BlockOpNum));\r
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
254 InitializeListHead (&Clone->List);\r
255\r
256 Clone->Ip = Nbuf->Ip;\r
257 Clone->Tcp = Nbuf->Tcp;\r
258\r
259 CopyMem (Clone->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);\r
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
266 CopyMem (Clone->BlockOp, Nbuf->BlockOp, sizeof (NET_BLOCK_OP) * Nbuf->BlockOpNum);\r
267\r
268 return Clone;\r
269}\r
270\r
271\r
272/**\r
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
286\r
287**/\r
288NET_BUF *\r
289EFIAPI\r
290NetbufDuplicate (\r
291 IN NET_BUF *Nbuf,\r
292 IN OUT NET_BUF *Duplicate OPTIONAL,\r
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
312 CopyMem (Duplicate->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);\r
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
325 @param[in, out] Head Pointer to the head of linked net buffers.\r
326\r
327**/\r
328VOID\r
329EFIAPI\r
330NetbufFreeList (\r
331 IN OUT LIST_ENTRY *Head\r
332 )\r
333{\r
334 LIST_ENTRY *Entry;\r
335 LIST_ENTRY *Next;\r
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
344 RemoveEntryList (Entry);\r
345 NetbufFree (Nbuf);\r
346 }\r
347\r
348 ASSERT (IsListEmpty (Head));\r
349}\r
350\r
351\r
352/**\r
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
359\r
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
364\r
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
367\r
368**/\r
369UINT8 *\r
370EFIAPI\r
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
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
423**/\r
424VOID\r
425NetbufSetBlock (\r
426 IN OUT NET_BUF *Nbuf,\r
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
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
464\r
465**/\r
466VOID\r
467NetbufSetBlockOp (\r
468 IN OUT NET_BUF *Nbuf,\r
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
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
493\r
494 @param[in] Arg Point to the old NET_VECTOR.\r
495\r
496**/\r
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
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
523 @return Pointer to the cloned net buffer, or NULL if the \r
524 allocation failed due to resource limit.\r
525\r
526**/\r
527NET_BUF *\r
528EFIAPI\r
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
621 FirstBulk = AllocatePool (HeadSpace);\r
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
634 // Reserve the head space in the first block\r
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
665 for (Index = First + 1; Index <= Last - 1 ; Index++) {\r
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
683 CopyMem (Child->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);\r
684 return Child;\r
685\r
686FreeChild:\r
687\r
688 gBS->FreePool (Child);\r
689 return NULL;\r
690}\r
691\r
692\r
693\r
694/**\r
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
701\r
702 @param[in] ExtFragment Pointer to the data block.\r
703 @param[in] ExtNum The number of the data blocks.\r
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
710\r
711 @return Pointer to the net buffer built from the data blocks, \r
712 or NULL if the allocation failed due to resource\r
713 limit.\r
714\r
715**/\r
716NET_BUF *\r
717EFIAPI\r
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
770 FirstBlock = AllocatePool (FirstBlockLen);\r
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
790 CopyMem (Header, ExtFragment[Index].Bulk, ExtFragment[Index].Len);\r
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
808 CopyMem (Header, ExtFragment[Index].Bulk, Len);\r
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
838 Vector->Flag = ((FirstBlockLen != 0) ? NET_VECTOR_OWN_FIRST : 0);\r
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
863 if (SavedIndex != 0) {\r
864 ExtFragment[SavedIndex] = SavedFragment;\r
865 }\r
866\r
867 return Nbuf;\r
868\r
869FreeFirstBlock:\r
870 gBS->FreePool (FirstBlock);\r
871 return NULL;\r
872}\r
873\r
874\r
875/**\r
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
879 @param[in] Nbuf Point to the net buffer.\r
880 @param[in, out] ExtFragment Pointer to the data block.\r
881 @param[in, out] ExtNum The number of the data blocks.\r
882\r
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
886\r
887**/\r
888EFI_STATUS\r
889EFIAPI\r
890NetbufBuildExt (\r
891 IN NET_BUF *Nbuf,\r
892 IN OUT NET_FRAGMENT *ExtFragment,\r
893 IN OUT UINT32 *ExtNum\r
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
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
935\r
936**/\r
937NET_BUF *\r
938EFIAPI\r
939NetbufFromBufList (\r
940 IN LIST_ENTRY *BufList,\r
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
949 LIST_ENTRY *Entry;\r
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
968 Fragment = AllocatePool (sizeof (NET_FRAGMENT) * FragmentNum);\r
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
981 if (Nbuf->BlockOp[Index].Size != 0) {\r
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
990 gBS->FreePool (Fragment);\r
991\r
992 return Nbuf;\r
993}\r
994\r
995\r
996/**\r
997 Reserve some space in the header room of the net buffer.\r
998\r
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
1006\r
1007**/\r
1008VOID\r
1009EFIAPI\r
1010NetbufReserve (\r
1011 IN OUT NET_BUF *Nbuf,\r
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
1029 Allocate Len bytes of space from the header or tail of the buffer. \r
1030\r
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
1035\r
1036 @return Pointer to the first byte of the allocated buffer, \r
1037 or NULL if there is no sufficient space.\r
1038\r
1039**/\r
1040UINT8*\r
1041EFIAPI\r
1042NetbufAllocSpace (\r
1043 IN OUT NET_BUF *Nbuf,\r
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
1121 Trim a single NET_BLOCK by Len bytes from the header or tail.\r
1122\r
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
1127\r
1128**/\r
1129VOID\r
1130NetblockTrim (\r
1131 IN OUT NET_BLOCK_OP *BlockOp,\r
1132 IN UINT32 Len,\r
1133 IN BOOLEAN FromHead\r
1134 )\r
1135{\r
1136 ASSERT ((BlockOp != NULL) && (BlockOp->Size >= Len));\r
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
1149 Trim Len bytes from the header or tail of the net buffer. \r
1150\r
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
1155\r
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
1158\r
1159**/\r
1160UINT32\r
1161EFIAPI\r
1162NetbufTrim (\r
1163 IN OUT NET_BUF *Nbuf,\r
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
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
1226 specified exceeds the total size of net buffer.\r
1227\r
1228**/\r
1229UINT32\r
1230EFIAPI\r
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
1288 CopyMem (Dest, BlockOp[Index].Head + Skip, Len);\r
1289 return Len;\r
1290 }\r
1291\r
1292 CopyMem (Dest, BlockOp[Index].Head + Skip, Left);\r
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
1305 CopyMem (Dest, BlockOp[Index].Head, BlockOp[Index].Size);\r
1306 Dest += BlockOp[Index].Size;\r
1307 } else {\r
1308 Copied += Len;\r
1309 CopyMem (Dest, BlockOp[Index].Head, Len);\r
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
1321 @param[in, out] NbufQue Pointer to the net buffer queue to be initialized.\r
1322\r
1323**/\r
1324VOID\r
1325EFIAPI\r
1326NetbufQueInit (\r
1327 IN OUT NET_BUF_QUEUE *NbufQue\r
1328 )\r
1329{\r
1330 NbufQue->Signature = NET_QUE_SIGNATURE;\r
1331 NbufQue->RefCnt = 1;\r
1332 InitializeListHead (&NbufQue->List);\r
1333\r
1334 InitializeListHead (&NbufQue->BufList);\r
1335 NbufQue->BufSize = 0;\r
1336 NbufQue->BufNum = 0;\r
1337}\r
1338\r
1339\r
1340/**\r
1341 Allocate and initialize a net buffer queue.\r
1342\r
1343 @return Pointer to the allocated net buffer queue, or NULL if the\r
1344 allocation failed due to resource limit.\r
1345\r
1346**/\r
1347NET_BUF_QUEUE *\r
1348EFIAPI\r
1349NetbufQueAlloc (\r
1350 VOID\r
1351 )\r
1352{\r
1353 NET_BUF_QUEUE *NbufQue;\r
1354\r
1355 NbufQue = AllocatePool (sizeof (NET_BUF_QUEUE));\r
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
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
1372\r
1373 @param[in] NbufQue Pointer to the net buffer queue to be freed.\r
1374\r
1375**/\r
1376VOID\r
1377EFIAPI\r
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
1388 gBS->FreePool (NbufQue);\r
1389 }\r
1390}\r
1391\r
1392\r
1393/**\r
1394 Append a net buffer to the net buffer queue.\r
1395\r
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
1398\r
1399**/\r
1400VOID\r
1401EFIAPI\r
1402NetbufQueAppend (\r
1403 IN OUT NET_BUF_QUEUE *NbufQue,\r
1404 IN OUT NET_BUF *Nbuf\r
1405 )\r
1406{\r
1407 NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);\r
1408 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
1409\r
1410 InsertTailList (&NbufQue->BufList, &Nbuf->List);\r
1411\r
1412 NbufQue->BufSize += Nbuf->TotalSize;\r
1413 NbufQue->BufNum++;\r
1414}\r
1415\r
1416\r
1417/**\r
1418 Remove a net buffer from the head in the specific queue and return it.\r
1419\r
1420 @param[in, out] NbufQue Pointer to the net buffer queue.\r
1421\r
1422 @return Pointer to the net buffer removed from the specific queue, \r
1423 or NULL if there is no net buffer in the specific queue.\r
1424\r
1425**/\r
1426NET_BUF *\r
1427EFIAPI\r
1428NetbufQueRemove (\r
1429 IN OUT NET_BUF_QUEUE *NbufQue\r
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
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
1462 @return The length of the actual copied data, or 0 if the offset \r
1463 specified exceeds the total size of net buffer queue.\r
1464\r
1465**/\r
1466UINT32\r
1467EFIAPI\r
1468NetbufQueCopy (\r
1469 IN NET_BUF_QUEUE *NbufQue,\r
1470 IN UINT32 Offset,\r
1471 IN UINT32 Len,\r
1472 OUT UINT8 *Dest\r
1473 )\r
1474{\r
1475 LIST_ENTRY *Entry;\r
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
1509 ASSERT (Nbuf != NULL);\r
1510\r
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
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
1560\r
1561 @param[in, out] NbufQue Pointer to the net buffer queue.\r
1562 @param[in] Len Length of the data to trim.\r
1563\r
1564 @return The actual length of the data trimmed.\r
1565\r
1566**/\r
1567UINT32\r
1568EFIAPI\r
1569NetbufQueTrim (\r
1570 IN OUT NET_BUF_QUEUE *NbufQue,\r
1571 IN UINT32 Len\r
1572 )\r
1573{\r
1574 LIST_ENTRY *Entry;\r
1575 LIST_ENTRY *Next;\r
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
1599 RemoveEntryList (Entry);\r
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
1621 @param[in, out] NbufQue Pointer to the queue to be flushed.\r
1622\r
1623**/\r
1624VOID\r
1625EFIAPI\r
1626NetbufQueFlush (\r
1627 IN OUT NET_BUF_QUEUE *NbufQue\r
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
1640 Compute the checksum for a bulk of data.\r
1641\r
1642 @param[in] Bulk Pointer to the data.\r
1643 @param[in] Len Length of the data, in bytes.\r
1644\r
1645 @return The computed checksum.\r
1646\r
1647**/\r
1648UINT16\r
1649EFIAPI\r
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
1675 while ((Sum >> 16) != 0) {\r
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
1687 @param[in] Checksum1 The first checksum to be added.\r
1688 @param[in] Checksum2 The second checksum to be added.\r
1689\r
1690 @return The new checksum.\r
1691\r
1692**/\r
1693UINT16\r
1694EFIAPI\r
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
1707 if ((Sum >> 16) != 0) {\r
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
1719 @param[in] Nbuf Pointer to the net buffer.\r
1720\r
1721 @return The computed checksum.\r
1722\r
1723**/\r
1724UINT16\r
1725EFIAPI\r
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
1749 if ((Offset & 0x01) != 0) {\r
1750 //\r
1751 // The checksum starts with an odd byte, swap\r
1752 // the checksum before added to total checksum\r
1753 //\r
1754 BlockSum = (UINT16) NET_SWAP_SHORT (BlockSum);\r
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
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
1769\r
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
1774\r
1775 @return The computed checksum.\r
1776\r
1777**/\r
1778UINT16\r
1779EFIAPI\r
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
1792 ZeroMem (&Hdr, sizeof (Hdr));\r
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