]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Ip4Dxe/Ip4Input.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / NetworkPkg / Ip4Dxe / Ip4Input.c
CommitLineData
772db4bb 1/** @file\r
3e8c18da 2 IP4 input process.\r
d1102dba 3\r
578bcdc2 4Copyright (c) 2005 - 2020, Intel Corporation. All rights reserved.<BR>\r
c79de074
SEHM
5(C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
6\r
9d510e61 7SPDX-License-Identifier: BSD-2-Clause-Patent\r
772db4bb 8\r
772db4bb 9**/\r
10\r
11#include "Ip4Impl.h"\r
12\r
772db4bb 13/**\r
96e1079f 14 Create an empty assemble entry for the packet identified by\r
772db4bb 15 (Dst, Src, Id, Protocol). The default life for the packet is\r
16 120 seconds.\r
17\r
3e8c18da 18 @param[in] Dst The destination address\r
19 @param[in] Src The source address\r
20 @param[in] Id The ID field in IP header\r
21 @param[in] Protocol The protocol field in IP header\r
772db4bb 22\r
23 @return NULL if failed to allocate memory for the entry, otherwise\r
3e8c18da 24 the point to just created reassemble entry.\r
772db4bb 25\r
26**/\r
772db4bb 27IP4_ASSEMBLE_ENTRY *\r
28Ip4CreateAssembleEntry (\r
d1050b9d
MK
29 IN IP4_ADDR Dst,\r
30 IN IP4_ADDR Src,\r
31 IN UINT16 Id,\r
32 IN UINT8 Protocol\r
772db4bb 33 )\r
34{\r
d1050b9d 35 IP4_ASSEMBLE_ENTRY *Assemble;\r
772db4bb 36\r
e48e37fc 37 Assemble = AllocatePool (sizeof (IP4_ASSEMBLE_ENTRY));\r
772db4bb 38\r
39 if (Assemble == NULL) {\r
40 return NULL;\r
41 }\r
42\r
e48e37fc 43 InitializeListHead (&Assemble->Link);\r
44 InitializeListHead (&Assemble->Fragments);\r
772db4bb 45\r
46 Assemble->Dst = Dst;\r
47 Assemble->Src = Src;\r
48 Assemble->Id = Id;\r
49 Assemble->Protocol = Protocol;\r
50 Assemble->TotalLen = 0;\r
51 Assemble->CurLen = 0;\r
52 Assemble->Head = NULL;\r
53 Assemble->Info = NULL;\r
54 Assemble->Life = IP4_FRAGMENT_LIFE;\r
55\r
56 return Assemble;\r
57}\r
58\r
772db4bb 59/**\r
96e1079f 60 Release all the fragments of a packet, then free the assemble entry.\r
772db4bb 61\r
3e8c18da 62 @param[in] Assemble The assemble entry to free\r
772db4bb 63\r
64**/\r
772db4bb 65VOID\r
66Ip4FreeAssembleEntry (\r
d1050b9d 67 IN IP4_ASSEMBLE_ENTRY *Assemble\r
772db4bb 68 )\r
69{\r
d1050b9d
MK
70 LIST_ENTRY *Entry;\r
71 LIST_ENTRY *Next;\r
72 NET_BUF *Fragment;\r
772db4bb 73\r
74 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Assemble->Fragments) {\r
75 Fragment = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
76\r
e48e37fc 77 RemoveEntryList (Entry);\r
772db4bb 78 NetbufFree (Fragment);\r
79 }\r
80\r
766c7483 81 FreePool (Assemble);\r
772db4bb 82}\r
83\r
772db4bb 84/**\r
85 Initialize an already allocated assemble table. This is generally\r
86 the assemble table embedded in the IP4 service instance.\r
87\r
3e8c18da 88 @param[in, out] Table The assemble table to initialize.\r
772db4bb 89\r
90**/\r
91VOID\r
92Ip4InitAssembleTable (\r
d1050b9d 93 IN OUT IP4_ASSEMBLE_TABLE *Table\r
772db4bb 94 )\r
95{\r
d1050b9d 96 UINT32 Index;\r
772db4bb 97\r
98 for (Index = 0; Index < IP4_ASSEMLE_HASH_SIZE; Index++) {\r
e48e37fc 99 InitializeListHead (&Table->Bucket[Index]);\r
772db4bb 100 }\r
101}\r
102\r
772db4bb 103/**\r
104 Clean up the assemble table: remove all the fragments\r
105 and assemble entries.\r
106\r
3e8c18da 107 @param[in] Table The assemble table to clean up\r
772db4bb 108\r
109**/\r
110VOID\r
111Ip4CleanAssembleTable (\r
d1050b9d 112 IN IP4_ASSEMBLE_TABLE *Table\r
772db4bb 113 )\r
114{\r
d1050b9d
MK
115 LIST_ENTRY *Entry;\r
116 LIST_ENTRY *Next;\r
117 IP4_ASSEMBLE_ENTRY *Assemble;\r
118 UINT32 Index;\r
772db4bb 119\r
120 for (Index = 0; Index < IP4_ASSEMLE_HASH_SIZE; Index++) {\r
121 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Table->Bucket[Index]) {\r
122 Assemble = NET_LIST_USER_STRUCT (Entry, IP4_ASSEMBLE_ENTRY, Link);\r
123\r
e48e37fc 124 RemoveEntryList (Entry);\r
772db4bb 125 Ip4FreeAssembleEntry (Assemble);\r
126 }\r
127 }\r
128}\r
129\r
772db4bb 130/**\r
131 Trim the packet to fit in [Start, End), and update the per\r
132 packet information.\r
133\r
134 @param Packet Packet to trim\r
135 @param Start The sequence of the first byte to fit in\r
136 @param End One beyond the sequence of last byte to fit in.\r
137\r
772db4bb 138**/\r
772db4bb 139VOID\r
140Ip4TrimPacket (\r
d1050b9d
MK
141 IN OUT NET_BUF *Packet,\r
142 IN INTN Start,\r
143 IN INTN End\r
772db4bb 144 )\r
145{\r
d1050b9d
MK
146 IP4_CLIP_INFO *Info;\r
147 INTN Len;\r
772db4bb 148\r
149 Info = IP4_GET_CLIP_INFO (Packet);\r
150\r
151 ASSERT (Info->Start + Info->Length == Info->End);\r
152 ASSERT ((Info->Start < End) && (Start < Info->End));\r
153\r
d1050b9d 154 if (Info->Start < Start) {\r
772db4bb 155 Len = Start - Info->Start;\r
156\r
d1050b9d 157 NetbufTrim (Packet, (UINT32)Len, NET_BUF_HEAD);\r
772db4bb 158 Info->Start = Start;\r
159 Info->Length -= Len;\r
160 }\r
161\r
162 if (End < Info->End) {\r
163 Len = End - Info->End;\r
164\r
d1050b9d 165 NetbufTrim (Packet, (UINT32)Len, NET_BUF_TAIL);\r
772db4bb 166 Info->End = End;\r
167 Info->Length -= Len;\r
168 }\r
169}\r
170\r
772db4bb 171/**\r
172 Release all the fragments of the packet. This is the callback for\r
173 the assembled packet's OnFree. It will free the assemble entry,\r
174 which in turn will free all the fragments of the packet.\r
175\r
3e8c18da 176 @param[in] Arg The assemble entry to free\r
772db4bb 177\r
178**/\r
772db4bb 179VOID\r
e798cd87 180EFIAPI\r
772db4bb 181Ip4OnFreeFragments (\r
d1050b9d 182 IN VOID *Arg\r
772db4bb 183 )\r
184{\r
d1050b9d 185 Ip4FreeAssembleEntry ((IP4_ASSEMBLE_ENTRY *)Arg);\r
772db4bb 186}\r
187\r
772db4bb 188/**\r
189 Reassemble the IP fragments. If all the fragments of the packet\r
190 have been received, it will wrap the packet in a net buffer then\r
191 return it to caller. If the packet can't be assembled, NULL is\r
192 return.\r
193\r
96e1079f 194 @param Table The assemble table used. New assemble entry will be created\r
195 if the Packet is from a new chain of fragments.\r
196 @param Packet The fragment to assemble. It might be freed if the fragment\r
197 can't be re-assembled.\r
772db4bb 198\r
199 @return NULL if the packet can't be reassemble. The point to just assembled\r
96e1079f 200 packet if all the fragments of the packet have arrived.\r
772db4bb 201\r
202**/\r
772db4bb 203NET_BUF *\r
204Ip4Reassemble (\r
d1050b9d
MK
205 IN OUT IP4_ASSEMBLE_TABLE *Table,\r
206 IN OUT NET_BUF *Packet\r
772db4bb 207 )\r
208{\r
d1050b9d
MK
209 IP4_HEAD *IpHead;\r
210 IP4_CLIP_INFO *This;\r
211 IP4_CLIP_INFO *Node;\r
212 IP4_ASSEMBLE_ENTRY *Assemble;\r
213 LIST_ENTRY *Head;\r
214 LIST_ENTRY *Prev;\r
215 LIST_ENTRY *Cur;\r
216 NET_BUF *Fragment;\r
217 NET_BUF *NewPacket;\r
218 INTN Index;\r
219\r
220 IpHead = Packet->Ip.Ip4;\r
221 This = IP4_GET_CLIP_INFO (Packet);\r
772db4bb 222\r
223 ASSERT (IpHead != NULL);\r
224\r
225 //\r
226 // First: find the related assemble entry\r
227 //\r
d1050b9d
MK
228 Assemble = NULL;\r
229 Index = IP4_ASSEMBLE_HASH (IpHead->Dst, IpHead->Src, IpHead->Id, IpHead->Protocol);\r
772db4bb 230\r
231 NET_LIST_FOR_EACH (Cur, &Table->Bucket[Index]) {\r
232 Assemble = NET_LIST_USER_STRUCT (Cur, IP4_ASSEMBLE_ENTRY, Link);\r
233\r
234 if ((Assemble->Dst == IpHead->Dst) && (Assemble->Src == IpHead->Src) &&\r
d1050b9d
MK
235 (Assemble->Id == IpHead->Id) && (Assemble->Protocol == IpHead->Protocol))\r
236 {\r
772db4bb 237 break;\r
238 }\r
239 }\r
240\r
241 //\r
242 // Create a new assemble entry if no assemble entry is related to this packet\r
243 //\r
244 if (Cur == &Table->Bucket[Index]) {\r
245 Assemble = Ip4CreateAssembleEntry (\r
246 IpHead->Dst,\r
247 IpHead->Src,\r
248 IpHead->Id,\r
249 IpHead->Protocol\r
250 );\r
251\r
252 if (Assemble == NULL) {\r
253 goto DROP;\r
254 }\r
255\r
e48e37fc 256 InsertHeadList (&Table->Bucket[Index], &Assemble->Link);\r
772db4bb 257 }\r
d1050b9d 258\r
894d038a 259 //\r
260 // Assemble shouldn't be NULL here\r
261 //\r
262 ASSERT (Assemble != NULL);\r
772db4bb 263\r
264 //\r
265 // Find the point to insert the packet: before the first\r
266 // fragment with THIS.Start < CUR.Start. the previous one\r
267 // has PREV.Start <= THIS.Start < CUR.Start.\r
268 //\r
269 Head = &Assemble->Fragments;\r
270\r
271 NET_LIST_FOR_EACH (Cur, Head) {\r
272 Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
273\r
274 if (This->Start < IP4_GET_CLIP_INFO (Fragment)->Start) {\r
275 break;\r
276 }\r
277 }\r
278\r
279 //\r
280 // Check whether the current fragment overlaps with the previous one.\r
281 // It holds that: PREV.Start <= THIS.Start < THIS.End. Only need to\r
282 // check whether THIS.Start < PREV.End for overlap. If two fragments\r
283 // overlaps, trim the overlapped part off THIS fragment.\r
284 //\r
cc0b145e 285 if ((Prev = Cur->BackLink) != Head) {\r
d1050b9d
MK
286 Fragment = NET_LIST_USER_STRUCT (Prev, NET_BUF, List);\r
287 Node = IP4_GET_CLIP_INFO (Fragment);\r
772db4bb 288\r
289 if (This->Start < Node->End) {\r
290 if (This->End <= Node->End) {\r
291 NetbufFree (Packet);\r
292 return NULL;\r
293 }\r
294\r
295 Ip4TrimPacket (Packet, Node->End, This->End);\r
296 }\r
297 }\r
298\r
299 //\r
300 // Insert the fragment into the packet. The fragment may be removed\r
301 // from the list by the following checks.\r
302 //\r
303 NetListInsertBefore (Cur, &Packet->List);\r
304\r
305 //\r
306 // Check the packets after the insert point. It holds that:\r
307 // THIS.Start <= NODE.Start < NODE.End. The equality holds\r
308 // if PREV and NEXT are continuous. THIS fragment may fill\r
309 // several holes. Remove the completely overlapped fragments\r
310 //\r
311 while (Cur != Head) {\r
312 Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
313 Node = IP4_GET_CLIP_INFO (Fragment);\r
314\r
315 //\r
316 // Remove fragments completely overlapped by this fragment\r
317 //\r
318 if (Node->End <= This->End) {\r
319 Cur = Cur->ForwardLink;\r
320\r
e48e37fc 321 RemoveEntryList (&Fragment->List);\r
772db4bb 322 Assemble->CurLen -= Node->Length;\r
323\r
324 NetbufFree (Fragment);\r
325 continue;\r
326 }\r
327\r
328 //\r
329 // The conditions are: THIS.Start <= NODE.Start, and THIS.End <\r
330 // NODE.End. Two fragments overlaps if NODE.Start < THIS.End.\r
331 // If two fragments start at the same offset, remove THIS fragment\r
332 // because ((THIS.Start == NODE.Start) && (THIS.End < NODE.End)).\r
333 //\r
334 if (Node->Start < This->End) {\r
335 if (This->Start == Node->Start) {\r
e48e37fc 336 RemoveEntryList (&Packet->List);\r
772db4bb 337 goto DROP;\r
338 }\r
339\r
340 Ip4TrimPacket (Packet, This->Start, Node->Start);\r
341 }\r
342\r
343 break;\r
344 }\r
345\r
346 //\r
347 // Update the assemble info: increase the current length. If it is\r
348 // the frist fragment, update the packet's IP head and per packet\r
349 // info. If it is the last fragment, update the total length.\r
350 //\r
351 Assemble->CurLen += This->Length;\r
352\r
353 if (This->Start == 0) {\r
354 //\r
355 // Once the first fragment is enqueued, it can't be removed\r
356 // from the fragment list. So, Assemble->Head always point\r
357 // to valid memory area.\r
358 //\r
359 ASSERT (Assemble->Head == NULL);\r
360\r
d1050b9d
MK
361 Assemble->Head = IpHead;\r
362 Assemble->Info = IP4_GET_CLIP_INFO (Packet);\r
772db4bb 363 }\r
364\r
365 //\r
366 // Don't update the length more than once.\r
367 //\r
368 if (IP4_LAST_FRAGMENT (IpHead->Fragment) && (Assemble->TotalLen == 0)) {\r
369 Assemble->TotalLen = This->End;\r
370 }\r
371\r
372 //\r
373 // Deliver the whole packet if all the fragments received.\r
374 // All fragments received if:\r
96e1079f 375 // 1. received the last one, so, the total length is know\r
772db4bb 376 // 2. received all the data. If the last fragment on the\r
377 // queue ends at the total length, all data is received.\r
378 //\r
379 if ((Assemble->TotalLen != 0) && (Assemble->CurLen >= Assemble->TotalLen)) {\r
e48e37fc 380 RemoveEntryList (&Assemble->Link);\r
772db4bb 381\r
382 //\r
6c585b52 383 // If the packet is properly formatted, the last fragment's End\r
772db4bb 384 // equals to the packet's total length. Otherwise, the packet\r
385 // is a fake, drop it now.\r
386 //\r
387 Fragment = NET_LIST_USER_STRUCT (Head->BackLink, NET_BUF, List);\r
388\r
389 if (IP4_GET_CLIP_INFO (Fragment)->End != Assemble->TotalLen) {\r
390 Ip4FreeAssembleEntry (Assemble);\r
391 return NULL;\r
392 }\r
393\r
394 //\r
395 // Wrap the packet in a net buffer then deliver it up\r
396 //\r
397 NewPacket = NetbufFromBufList (\r
398 &Assemble->Fragments,\r
399 0,\r
400 0,\r
401 Ip4OnFreeFragments,\r
402 Assemble\r
403 );\r
404\r
405 if (NewPacket == NULL) {\r
406 Ip4FreeAssembleEntry (Assemble);\r
407 return NULL;\r
408 }\r
409\r
f6b7393c 410 NewPacket->Ip.Ip4 = Assemble->Head;\r
04eb20aa
ED
411\r
412 ASSERT (Assemble->Info != NULL);\r
413\r
414 CopyMem (\r
415 IP4_GET_CLIP_INFO (NewPacket),\r
416 Assemble->Info,\r
417 sizeof (*IP4_GET_CLIP_INFO (NewPacket))\r
418 );\r
419\r
772db4bb 420 return NewPacket;\r
421 }\r
422\r
423 return NULL;\r
424\r
425DROP:\r
426 NetbufFree (Packet);\r
427 return NULL;\r
428}\r
429\r
a1503a32 430/**\r
d1102dba
LG
431 The callback function for the net buffer which wraps the packet processed by\r
432 IPsec. It releases the wrap packet and also signals IPsec to free the resources.\r
a1503a32 433\r
434 @param[in] Arg The wrap context\r
435\r
436**/\r
437VOID\r
e798cd87 438EFIAPI\r
a1503a32 439Ip4IpSecFree (\r
d1050b9d 440 IN VOID *Arg\r
a1503a32 441 )\r
442{\r
d1050b9d 443 IP4_IPSEC_WRAP *Wrap;\r
a1503a32 444\r
d1050b9d 445 Wrap = (IP4_IPSEC_WRAP *)Arg;\r
a1503a32 446\r
447 if (Wrap->IpSecRecycleSignal != NULL) {\r
448 gBS->SignalEvent (Wrap->IpSecRecycleSignal);\r
449 }\r
450\r
451 NetbufFree (Wrap->Packet);\r
452\r
453 FreePool (Wrap);\r
454\r
455 return;\r
456}\r
457\r
458/**\r
d1102dba 459 The work function to locate IPsec protocol to process the inbound or\r
a1503a32 460 outbound IP packets. The process routine handls the packet with following\r
d1102dba 461 actions: bypass the packet, discard the packet, or protect the packet.\r
a1503a32 462\r
705f53a9 463 @param[in] IpSb The IP4 service instance.\r
6c585b52 464 @param[in, out] Head The caller supplied IP4 header.\r
705f53a9 465 @param[in, out] Netbuf The IP4 packet to be processed by IPsec.\r
466 @param[in, out] Options The caller supplied options.\r
467 @param[in, out] OptionsLen The length of the option.\r
d1102dba 468 @param[in] Direction The directionality in an SPD entry,\r
705f53a9 469 EfiIPsecInBound or EfiIPsecOutBound.\r
470 @param[in] Context The token's wrap.\r
a1503a32 471\r
472 @retval EFI_SUCCESS The IPsec protocol is not available or disabled.\r
473 @retval EFI_SUCCESS The packet was bypassed and all buffers remain the same.\r
474 @retval EFI_SUCCESS The packet was protected.\r
d1102dba 475 @retval EFI_ACCESS_DENIED The packet was discarded.\r
6c585b52 476 @retval EFI_OUT_OF_RESOURCES There is no sufficient resource to complete the operation.\r
d1102dba 477 @retval EFI_BUFFER_TOO_SMALL The number of non-empty block is bigger than the\r
a1503a32 478 number of input data blocks when build a fragment table.\r
479\r
480**/\r
481EFI_STATUS\r
482Ip4IpSecProcessPacket (\r
705f53a9 483 IN IP4_SERVICE *IpSb,\r
484 IN OUT IP4_HEAD **Head,\r
485 IN OUT NET_BUF **Netbuf,\r
486 IN OUT UINT8 **Options,\r
487 IN OUT UINT32 *OptionsLen,\r
488 IN EFI_IPSEC_TRAFFIC_DIR Direction,\r
489 IN VOID *Context\r
a1503a32 490 )\r
491{\r
d1050b9d
MK
492 NET_FRAGMENT *FragmentTable;\r
493 NET_FRAGMENT *OriginalFragmentTable;\r
494 UINT32 FragmentCount;\r
495 UINT32 OriginalFragmentCount;\r
496 EFI_EVENT RecycleEvent;\r
497 NET_BUF *Packet;\r
498 IP4_TXTOKEN_WRAP *TxWrap;\r
499 IP4_IPSEC_WRAP *IpSecWrap;\r
500 EFI_STATUS Status;\r
501 IP4_HEAD ZeroHead;\r
502\r
503 Status = EFI_SUCCESS;\r
c79de074
SEHM
504\r
505 if (!mIpSec2Installed) {\r
506 goto ON_EXIT;\r
507 }\r
d1050b9d 508\r
5aae2d35 509 ASSERT (mIpSec != NULL);\r
d1102dba 510\r
a1503a32 511 Packet = *Netbuf;\r
512 RecycleEvent = NULL;\r
513 IpSecWrap = NULL;\r
514 FragmentTable = NULL;\r
d1050b9d 515 TxWrap = (IP4_TXTOKEN_WRAP *)Context;\r
a1503a32 516 FragmentCount = Packet->BlockOpNum;\r
705f53a9 517\r
518 ZeroMem (&ZeroHead, sizeof (IP4_HEAD));\r
a1503a32 519\r
a1503a32 520 //\r
521 // Check whether the IPsec enable variable is set.\r
522 //\r
523 if (mIpSec->DisabledFlag) {\r
524 //\r
525 // If IPsec is disabled, restore the original MTU\r
d1102dba 526 //\r
a1503a32 527 IpSb->MaxPacketSize = IpSb->OldMaxPacketSize;\r
528 goto ON_EXIT;\r
529 } else {\r
530 //\r
d1102dba 531 // If IPsec is enabled, use the MTU which reduce the IPsec header length.\r
a1503a32 532 //\r
d1102dba 533 IpSb->MaxPacketSize = IpSb->OldMaxPacketSize - IP4_MAX_IPSEC_HEADLEN;\r
a1503a32 534 }\r
535\r
536 //\r
537 // Rebuild fragment table from netbuf to ease IPsec process.\r
538 //\r
539 FragmentTable = AllocateZeroPool (FragmentCount * sizeof (NET_FRAGMENT));\r
540\r
541 if (FragmentTable == NULL) {\r
542 Status = EFI_OUT_OF_RESOURCES;\r
543 goto ON_EXIT;\r
544 }\r
d1102dba 545\r
a1503a32 546 Status = NetbufBuildExt (Packet, FragmentTable, &FragmentCount);\r
d1102dba 547\r
705f53a9 548 //\r
549 // Record the original FragmentTable and count.\r
550 //\r
551 OriginalFragmentTable = FragmentTable;\r
552 OriginalFragmentCount = FragmentCount;\r
a1503a32 553\r
554 if (EFI_ERROR (Status)) {\r
555 FreePool (FragmentTable);\r
556 goto ON_EXIT;\r
557 }\r
558\r
559 //\r
560 // Convert host byte order to network byte order\r
561 //\r
705f53a9 562 Ip4NtohHead (*Head);\r
d1102dba 563\r
705f53a9 564 Status = mIpSec->ProcessExt (\r
a1503a32 565 mIpSec,\r
566 IpSb->Controller,\r
567 IP_VERSION_4,\r
d1050b9d 568 (VOID *)(*Head),\r
705f53a9 569 &(*Head)->Protocol,\r
d1050b9d 570 (VOID **)Options,\r
705f53a9 571 OptionsLen,\r
d1050b9d 572 (EFI_IPSEC_FRAGMENT_DATA **)(&FragmentTable),\r
a1503a32 573 &FragmentCount,\r
574 Direction,\r
575 &RecycleEvent\r
576 );\r
577 //\r
578 // Convert back to host byte order\r
579 //\r
705f53a9 580 Ip4NtohHead (*Head);\r
d1102dba 581\r
a1503a32 582 if (EFI_ERROR (Status)) {\r
94b928ca 583 FreePool (OriginalFragmentTable);\r
a1503a32 584 goto ON_EXIT;\r
585 }\r
586\r
d1050b9d 587 if ((OriginalFragmentTable == FragmentTable) && (OriginalFragmentCount == FragmentCount)) {\r
94b928ca 588 //\r
589 // For ByPass Packet\r
590 //\r
591 FreePool (FragmentTable);\r
705f53a9 592 goto ON_EXIT;\r
94b928ca 593 } else {\r
594 //\r
595 // Free the FragmentTable which allocated before calling the IPsec.\r
596 //\r
597 FreePool (OriginalFragmentTable);\r
705f53a9 598 }\r
599\r
d1050b9d 600 if ((Direction == EfiIPsecOutBound) && (TxWrap != NULL)) {\r
a1503a32 601 TxWrap->IpSecRecycleSignal = RecycleEvent;\r
602 TxWrap->Packet = NetbufFromExt (\r
603 FragmentTable,\r
604 FragmentCount,\r
605 IP4_MAX_HEADLEN,\r
606 0,\r
607 Ip4FreeTxToken,\r
608 TxWrap\r
609 );\r
610 if (TxWrap->Packet == NULL) {\r
94b928ca 611 //\r
612 // Recover the TxWrap->Packet, if meet a error, and the caller will free\r
613 // the TxWrap.\r
614 //\r
615 TxWrap->Packet = *Netbuf;\r
d1050b9d 616 Status = EFI_OUT_OF_RESOURCES;\r
a1503a32 617 goto ON_EXIT;\r
618 }\r
619\r
705f53a9 620 //\r
6c585b52 621 // Free original Netbuf.\r
705f53a9 622 //\r
623 NetIpSecNetbufFree (*Netbuf);\r
a1503a32 624 *Netbuf = TxWrap->Packet;\r
a1503a32 625 } else {\r
a1503a32 626 IpSecWrap = AllocateZeroPool (sizeof (IP4_IPSEC_WRAP));\r
d1102dba 627\r
a1503a32 628 if (IpSecWrap == NULL) {\r
94b928ca 629 Status = EFI_OUT_OF_RESOURCES;\r
630 gBS->SignalEvent (RecycleEvent);\r
a1503a32 631 goto ON_EXIT;\r
632 }\r
d1102dba 633\r
a1503a32 634 IpSecWrap->IpSecRecycleSignal = RecycleEvent;\r
635 IpSecWrap->Packet = Packet;\r
636 Packet = NetbufFromExt (\r
d1102dba
LG
637 FragmentTable,\r
638 FragmentCount,\r
639 IP4_MAX_HEADLEN,\r
640 0,\r
641 Ip4IpSecFree,\r
a1503a32 642 IpSecWrap\r
643 );\r
d1102dba 644\r
a1503a32 645 if (Packet == NULL) {\r
94b928ca 646 Packet = IpSecWrap->Packet;\r
647 gBS->SignalEvent (RecycleEvent);\r
648 FreePool (IpSecWrap);\r
a1503a32 649 Status = EFI_OUT_OF_RESOURCES;\r
650 goto ON_EXIT;\r
651 }\r
652\r
d1050b9d 653 if ((Direction == EfiIPsecInBound) && (0 != CompareMem (*Head, &ZeroHead, sizeof (IP4_HEAD)))) {\r
705f53a9 654 Ip4PrependHead (Packet, *Head, *Options, *OptionsLen);\r
a1503a32 655 Ip4NtohHead (Packet->Ip.Ip4);\r
705f53a9 656 NetbufTrim (Packet, ((*Head)->HeadLen << 2), TRUE);\r
a1503a32 657\r
658 CopyMem (\r
659 IP4_GET_CLIP_INFO (Packet),\r
660 IP4_GET_CLIP_INFO (IpSecWrap->Packet),\r
661 sizeof (IP4_CLIP_INFO)\r
662 );\r
663 }\r
d1050b9d 664\r
a1503a32 665 *Netbuf = Packet;\r
666 }\r
667\r
668ON_EXIT:\r
669 return Status;\r
670}\r
772db4bb 671\r
672/**\r
705f53a9 673 Pre-process the IPv4 packet. First validates the IPv4 packet, and\r
674 then reassembles packet if it is necessary.\r
d1102dba 675\r
705f53a9 676 @param[in] IpSb Pointer to IP4_SERVICE.\r
677 @param[in, out] Packet Pointer to the Packet to be processed.\r
678 @param[in] Head Pointer to the IP4_HEAD.\r
679 @param[in] Option Pointer to a buffer which contains the IPv4 option.\r
680 @param[in] OptionLen The length of Option in bytes.\r
681 @param[in] Flag The link layer flag for the packet received, such\r
682 as multicast.\r
772db4bb 683\r
6c585b52
AC
684 @retval EFI_SUCCESS The received packet is in well form.\r
685 @retval EFI_INVALID_PARAMETER The received packet is malformed.\r
772db4bb 686\r
687**/\r
705f53a9 688EFI_STATUS\r
689Ip4PreProcessPacket (\r
d1050b9d
MK
690 IN IP4_SERVICE *IpSb,\r
691 IN OUT NET_BUF **Packet,\r
692 IN IP4_HEAD *Head,\r
693 IN UINT8 *Option,\r
694 IN UINT32 OptionLen,\r
695 IN UINT32 Flag\r
d1102dba 696 )\r
772db4bb 697{\r
d1050b9d
MK
698 IP4_CLIP_INFO *Info;\r
699 UINT32 HeadLen;\r
700 UINT32 TotalLen;\r
701 UINT16 Checksum;\r
772db4bb 702\r
703 //\r
216f7970 704 // Check if the IP4 header is correctly formatted.\r
772db4bb 705 //\r
772db4bb 706 HeadLen = (Head->HeadLen << 2);\r
707 TotalLen = NTOHS (Head->TotalLen);\r
708\r
709 //\r
710 // Mnp may deliver frame trailer sequence up, trim it off.\r
711 //\r
705f53a9 712 if (TotalLen < (*Packet)->TotalSize) {\r
713 NetbufTrim (*Packet, (*Packet)->TotalSize - TotalLen, FALSE);\r
772db4bb 714 }\r
715\r
716 if ((Head->Ver != 4) || (HeadLen < IP4_MIN_HEADLEN) ||\r
d1050b9d
MK
717 (TotalLen < HeadLen) || (TotalLen != (*Packet)->TotalSize))\r
718 {\r
705f53a9 719 return EFI_INVALID_PARAMETER;\r
772db4bb 720 }\r
721\r
722 //\r
723 // Some OS may send IP packets without checksum.\r
724 //\r
d1050b9d 725 Checksum = (UINT16)(~NetblockChecksum ((UINT8 *)Head, HeadLen));\r
772db4bb 726\r
727 if ((Head->Checksum != 0) && (Checksum != 0)) {\r
705f53a9 728 return EFI_INVALID_PARAMETER;\r
772db4bb 729 }\r
730\r
731 //\r
732 // Convert the IP header to host byte order, then get the per packet info.\r
733 //\r
d1050b9d 734 (*Packet)->Ip.Ip4 = Ip4NtohHead (Head);\r
772db4bb 735\r
d1050b9d
MK
736 Info = IP4_GET_CLIP_INFO (*Packet);\r
737 Info->LinkFlag = Flag;\r
738 Info->CastType = Ip4GetHostCast (IpSb, Head->Dst, Head->Src);\r
739 Info->Start = (Head->Fragment & IP4_HEAD_OFFSET_MASK) << 3;\r
740 Info->Length = Head->TotalLen - HeadLen;\r
741 Info->End = Info->Start + Info->Length;\r
742 Info->Status = EFI_SUCCESS;\r
772db4bb 743\r
744 //\r
745 // The packet is destinated to us if the CastType is non-zero.\r
746 //\r
747 if ((Info->CastType == 0) || (Info->End > IP4_MAX_PACKET_SIZE)) {\r
705f53a9 748 return EFI_INVALID_PARAMETER;\r
772db4bb 749 }\r
750\r
751 //\r
752 // Validate the options. Don't call the Ip4OptionIsValid if\r
753 // there is no option to save some CPU process.\r
754 //\r
d1102dba 755\r
705f53a9 756 if ((OptionLen > 0) && !Ip4OptionIsValid (Option, OptionLen, TRUE)) {\r
757 return EFI_INVALID_PARAMETER;\r
772db4bb 758 }\r
759\r
760 //\r
216f7970 761 // Trim the head off, after this point, the packet is headless,\r
772db4bb 762 // and Packet->TotalLen == Info->Length.\r
763 //\r
705f53a9 764 NetbufTrim (*Packet, HeadLen, TRUE);\r
772db4bb 765\r
766 //\r
767 // Reassemble the packet if this is a fragment. The packet is a\r
768 // fragment if its head has MF (more fragment) set, or it starts\r
769 // at non-zero byte.\r
770 //\r
b2c0a175 771 if (((Head->Fragment & IP4_HEAD_MF_MASK) != 0) || (Info->Start != 0)) {\r
772db4bb 772 //\r
773 // Drop the fragment if DF is set but it is fragmented. Gateway\r
774 // need to send a type 4 destination unreache ICMP message here.\r
775 //\r
b2c0a175 776 if ((Head->Fragment & IP4_HEAD_DF_MASK) != 0) {\r
705f53a9 777 return EFI_INVALID_PARAMETER;\r
772db4bb 778 }\r
779\r
780 //\r
781 // The length of all but the last fragments is in the unit of 8 bytes.\r
782 //\r
b2c0a175 783 if (((Head->Fragment & IP4_HEAD_MF_MASK) != 0) && (Info->Length % 8 != 0)) {\r
705f53a9 784 return EFI_INVALID_PARAMETER;\r
772db4bb 785 }\r
786\r
705f53a9 787 *Packet = Ip4Reassemble (&IpSb->Assemble, *Packet);\r
772db4bb 788\r
789 //\r
790 // Packet assembly isn't complete, start receive more packet.\r
791 //\r
705f53a9 792 if (*Packet == NULL) {\r
793 return EFI_INVALID_PARAMETER;\r
772db4bb 794 }\r
795 }\r
d1102dba 796\r
705f53a9 797 return EFI_SUCCESS;\r
798}\r
799\r
578bcdc2
JW
800/**\r
801 This function checks the IPv4 packet length.\r
802\r
803 @param[in] Packet Pointer to the IPv4 Packet to be checked.\r
804\r
805 @retval TRUE The input IPv4 packet length is valid.\r
806 @retval FALSE The input IPv4 packet length is invalid.\r
807\r
808**/\r
809BOOLEAN\r
810Ip4IsValidPacketLength (\r
d1050b9d 811 IN NET_BUF *Packet\r
578bcdc2
JW
812 )\r
813{\r
814 //\r
815 // Check the IP4 packet length.\r
816 //\r
817 if (Packet->TotalSize < IP4_MIN_HEADLEN) {\r
818 return FALSE;\r
819 }\r
820\r
821 return TRUE;\r
822}\r
823\r
705f53a9 824/**\r
825 The IP4 input routine. It is called by the IP4_INTERFACE when a\r
826 IP4 fragment is received from MNP.\r
827\r
828 @param[in] Ip4Instance The IP4 child that request the receive, most like\r
829 it is NULL.\r
830 @param[in] Packet The IP4 packet received.\r
831 @param[in] IoStatus The return status of receive request.\r
832 @param[in] Flag The link layer flag for the packet received, such\r
833 as multicast.\r
834 @param[in] Context The IP4 service instance that own the MNP.\r
835\r
836**/\r
837VOID\r
838Ip4AccpetFrame (\r
d1050b9d
MK
839 IN IP4_PROTOCOL *Ip4Instance,\r
840 IN NET_BUF *Packet,\r
841 IN EFI_STATUS IoStatus,\r
842 IN UINT32 Flag,\r
843 IN VOID *Context\r
705f53a9 844 )\r
845{\r
d1050b9d
MK
846 IP4_SERVICE *IpSb;\r
847 IP4_HEAD *Head;\r
848 EFI_STATUS Status;\r
849 IP4_HEAD ZeroHead;\r
850 UINT8 *Option;\r
851 UINT32 OptionLen;\r
852\r
853 IpSb = (IP4_SERVICE *)Context;\r
705f53a9 854 Option = NULL;\r
855\r
75dce340 856 if (EFI_ERROR (IoStatus) || (IpSb->State == IP4_SERVICE_DESTROY)) {\r
705f53a9 857 goto DROP;\r
858 }\r
859\r
578bcdc2
JW
860 if (!Ip4IsValidPacketLength (Packet)) {\r
861 goto RESTART;\r
862 }\r
863\r
d1050b9d 864 Head = (IP4_HEAD *)NetbufGetByte (Packet, 0, NULL);\r
a56b6e03 865 ASSERT (Head != NULL);\r
705f53a9 866 OptionLen = (Head->HeadLen << 2) - IP4_MIN_HEADLEN;\r
867 if (OptionLen > 0) {\r
d1050b9d 868 Option = (UINT8 *)(Head + 1);\r
705f53a9 869 }\r
870\r
871 //\r
872 // Validate packet format and reassemble packet if it is necessary.\r
873 //\r
874 Status = Ip4PreProcessPacket (\r
d1102dba
LG
875 IpSb,\r
876 &Packet,\r
877 Head,\r
705f53a9 878 Option,\r
d1102dba 879 OptionLen,\r
705f53a9 880 Flag\r
881 );\r
882\r
883 if (EFI_ERROR (Status)) {\r
884 goto RESTART;\r
885 }\r
772db4bb 886\r
887 //\r
a1503a32 888 // After trim off, the packet is a esp/ah/udp/tcp/icmp6 net buffer,\r
889 // and no need consider any other ahead ext headers.\r
890 //\r
891 Status = Ip4IpSecProcessPacket (\r
94b928ca 892 IpSb,\r
893 &Head,\r
894 &Packet,\r
705f53a9 895 &Option,\r
94b928ca 896 &OptionLen,\r
a1503a32 897 EfiIPsecInBound,\r
898 NULL\r
899 );\r
900\r
705f53a9 901 if (EFI_ERROR (Status)) {\r
a1503a32 902 goto RESTART;\r
903 }\r
d1102dba 904\r
705f53a9 905 //\r
906 // If the packet is protected by tunnel mode, parse the inner Ip Packet.\r
907 //\r
908 ZeroMem (&ZeroHead, sizeof (IP4_HEAD));\r
909 if (0 == CompareMem (Head, &ZeroHead, sizeof (IP4_HEAD))) {\r
578bcdc2
JW
910 // Packet may have been changed. Head, HeadLen, TotalLen, and\r
911 // info must be reloaded before use. The ownership of the packet\r
912 // is transferred to the packet process logic.\r
913 //\r
914 if (!Ip4IsValidPacketLength (Packet)) {\r
915 goto RESTART;\r
916 }\r
917\r
d1050b9d 918 Head = (IP4_HEAD *)NetbufGetByte (Packet, 0, NULL);\r
a56b6e03 919 ASSERT (Head != NULL);\r
705f53a9 920 Status = Ip4PreProcessPacket (\r
94b928ca 921 IpSb,\r
922 &Packet,\r
923 Head,\r
705f53a9 924 Option,\r
94b928ca 925 OptionLen,\r
705f53a9 926 Flag\r
927 );\r
928 if (EFI_ERROR (Status)) {\r
929 goto RESTART;\r
930 }\r
931 }\r
d1102dba 932\r
fbe12b79 933 ASSERT (Packet != NULL);\r
d1050b9d 934 Head = Packet->Ip.Ip4;\r
772db4bb 935 IP4_GET_CLIP_INFO (Packet)->Status = EFI_SUCCESS;\r
936\r
937 switch (Head->Protocol) {\r
d1050b9d
MK
938 case EFI_IP_PROTO_ICMP:\r
939 Ip4IcmpHandle (IpSb, Head, Packet);\r
940 break;\r
772db4bb 941\r
d1050b9d
MK
942 case IP4_PROTO_IGMP:\r
943 Ip4IgmpHandle (IpSb, Head, Packet);\r
944 break;\r
772db4bb 945\r
d1050b9d
MK
946 default:\r
947 Ip4Demultiplex (IpSb, Head, Packet, Option, OptionLen);\r
772db4bb 948 }\r
949\r
950 Packet = NULL;\r
951\r
36ee91ca 952 //\r
953 // Dispatch the DPCs queued by the NotifyFunction of the rx token's events\r
954 // which are signaled with received data.\r
955 //\r
d8d26fb2 956 DispatchDpc ();\r
36ee91ca 957\r
772db4bb 958RESTART:\r
959 Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);\r
960\r
961DROP:\r
962 if (Packet != NULL) {\r
963 NetbufFree (Packet);\r
964 }\r
965\r
d1050b9d 966 return;\r
772db4bb 967}\r
968\r
772db4bb 969/**\r
970 Check whether this IP child accepts the packet.\r
971\r
3e8c18da 972 @param[in] IpInstance The IP child to check\r
973 @param[in] Head The IP header of the packet\r
974 @param[in] Packet The data of the packet\r
772db4bb 975\r
96e1079f 976 @retval TRUE If the child wants to receive the packet.\r
977 @retval FALSE Otherwise.\r
772db4bb 978\r
979**/\r
980BOOLEAN\r
981Ip4InstanceFrameAcceptable (\r
d1050b9d
MK
982 IN IP4_PROTOCOL *IpInstance,\r
983 IN IP4_HEAD *Head,\r
984 IN NET_BUF *Packet\r
772db4bb 985 )\r
986{\r
d1050b9d
MK
987 IP4_ICMP_ERROR_HEAD Icmp;\r
988 EFI_IP4_CONFIG_DATA *Config;\r
989 IP4_CLIP_INFO *Info;\r
990 UINT16 Proto;\r
991 UINT32 Index;\r
772db4bb 992\r
993 Config = &IpInstance->ConfigData;\r
994\r
995 //\r
6c585b52 996 // Dirty trick for the Tiano UEFI network stack implementation. If\r
772db4bb 997 // ReceiveTimeout == -1, the receive of the packet for this instance\r
96e1079f 998 // is disabled. The UEFI spec don't have such capability. We add\r
772db4bb 999 // this to improve the performance because IP will make a copy of\r
1000 // the received packet for each accepting instance. Some IP instances\r
1001 // used by UDP/TCP only send packets, they don't wants to receive.\r
1002 //\r
1003 if (Config->ReceiveTimeout == (UINT32)(-1)) {\r
1004 return FALSE;\r
1005 }\r
1006\r
1007 if (Config->AcceptPromiscuous) {\r
1008 return TRUE;\r
1009 }\r
1010\r
1011 //\r
1012 // Use protocol from the IP header embedded in the ICMP error\r
1013 // message to filter, instead of ICMP itself. ICMP handle will\r
9899d8b6 1014 // call Ip4Demultiplex to deliver ICMP errors.\r
772db4bb 1015 //\r
1016 Proto = Head->Protocol;\r
1017\r
9899d8b6 1018 if ((Proto == EFI_IP_PROTO_ICMP) && (!Config->AcceptAnyProtocol) && (Proto != Config->DefaultProtocol)) {\r
d1050b9d 1019 NetbufCopy (Packet, 0, sizeof (Icmp.Head), (UINT8 *)&Icmp.Head);\r
772db4bb 1020\r
1021 if (mIcmpClass[Icmp.Head.Type].IcmpClass == ICMP_ERROR_MESSAGE) {\r
1022 if (!Config->AcceptIcmpErrors) {\r
1023 return FALSE;\r
1024 }\r
1025\r
d1050b9d 1026 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *)&Icmp);\r
772db4bb 1027 Proto = Icmp.IpHead.Protocol;\r
1028 }\r
1029 }\r
1030\r
1031 //\r
1032 // Match the protocol\r
1033 //\r
1034 if (!Config->AcceptAnyProtocol && (Proto != Config->DefaultProtocol)) {\r
1035 return FALSE;\r
1036 }\r
1037\r
1038 //\r
1039 // Check for broadcast, the caller has computed the packet's\r
1040 // cast type for this child's interface.\r
1041 //\r
1042 Info = IP4_GET_CLIP_INFO (Packet);\r
1043\r
1044 if (IP4_IS_BROADCAST (Info->CastType)) {\r
1045 return Config->AcceptBroadcast;\r
1046 }\r
1047\r
1048 //\r
1049 // If it is a multicast packet, check whether we are in the group.\r
1050 //\r
1051 if (Info->CastType == IP4_MULTICAST) {\r
1052 //\r
1053 // Receive the multicast if the instance wants to receive all packets.\r
1054 //\r
1055 if (!IpInstance->ConfigData.UseDefaultAddress && (IpInstance->Interface->Ip == 0)) {\r
1056 return TRUE;\r
1057 }\r
1058\r
1059 for (Index = 0; Index < IpInstance->GroupCount; Index++) {\r
1060 if (IpInstance->Groups[Index] == HTONL (Head->Dst)) {\r
1061 break;\r
1062 }\r
1063 }\r
1064\r
1065 return (BOOLEAN)(Index < IpInstance->GroupCount);\r
1066 }\r
1067\r
1068 return TRUE;\r
1069}\r
1070\r
772db4bb 1071/**\r
1072 Enqueue a shared copy of the packet to the IP4 child if the\r
1073 packet is acceptable to it. Here the data of the packet is\r
1074 shared, but the net buffer isn't.\r
1075\r
3e8c18da 1076 @param[in] IpInstance The IP4 child to enqueue the packet to\r
1077 @param[in] Head The IP header of the received packet\r
1078 @param[in] Packet The data of the received packet\r
772db4bb 1079\r
1080 @retval EFI_NOT_STARTED The IP child hasn't been configured.\r
1081 @retval EFI_INVALID_PARAMETER The child doesn't want to receive the packet\r
1082 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resource\r
1083 @retval EFI_SUCCESS A shared copy the packet is enqueued to the child.\r
1084\r
1085**/\r
1086EFI_STATUS\r
1087Ip4InstanceEnquePacket (\r
d1050b9d
MK
1088 IN IP4_PROTOCOL *IpInstance,\r
1089 IN IP4_HEAD *Head,\r
1090 IN NET_BUF *Packet\r
772db4bb 1091 )\r
1092{\r
d1050b9d
MK
1093 IP4_CLIP_INFO *Info;\r
1094 NET_BUF *Clone;\r
772db4bb 1095\r
1096 //\r
1097 // Check whether the packet is acceptable to this instance.\r
1098 //\r
1099 if (IpInstance->State != IP4_STATE_CONFIGED) {\r
1100 return EFI_NOT_STARTED;\r
1101 }\r
1102\r
1103 if (!Ip4InstanceFrameAcceptable (IpInstance, Head, Packet)) {\r
1104 return EFI_INVALID_PARAMETER;\r
1105 }\r
1106\r
1107 //\r
6c585b52 1108 // Enqueue a shared copy of the packet.\r
772db4bb 1109 //\r
1110 Clone = NetbufClone (Packet);\r
1111\r
1112 if (Clone == NULL) {\r
1113 return EFI_OUT_OF_RESOURCES;\r
1114 }\r
1115\r
1116 //\r
1117 // Set the receive time out for the assembled packet. If it expires,\r
1118 // packet will be removed from the queue.\r
1119 //\r
d1050b9d
MK
1120 Info = IP4_GET_CLIP_INFO (Clone);\r
1121 Info->Life = IP4_US_TO_SEC (IpInstance->ConfigData.ReceiveTimeout);\r
772db4bb 1122\r
e48e37fc 1123 InsertTailList (&IpInstance->Received, &Clone->List);\r
772db4bb 1124 return EFI_SUCCESS;\r
1125}\r
1126\r
772db4bb 1127/**\r
1128 The signal handle of IP4's recycle event. It is called back\r
1129 when the upper layer release the packet.\r
1130\r
3e8c18da 1131 @param Event The IP4's recycle event.\r
1132 @param Context The context of the handle, which is a\r
1133 IP4_RXDATA_WRAP\r
772db4bb 1134\r
1135**/\r
772db4bb 1136VOID\r
1137EFIAPI\r
1138Ip4OnRecyclePacket (\r
d1050b9d
MK
1139 IN EFI_EVENT Event,\r
1140 IN VOID *Context\r
772db4bb 1141 )\r
1142{\r
d1050b9d 1143 IP4_RXDATA_WRAP *Wrap;\r
772db4bb 1144\r
d1050b9d 1145 Wrap = (IP4_RXDATA_WRAP *)Context;\r
772db4bb 1146\r
e48e37fc 1147 EfiAcquireLockOrFail (&Wrap->IpInstance->RecycleLock);\r
1148 RemoveEntryList (&Wrap->Link);\r
1149 EfiReleaseLock (&Wrap->IpInstance->RecycleLock);\r
772db4bb 1150\r
1151 ASSERT (!NET_BUF_SHARED (Wrap->Packet));\r
1152 NetbufFree (Wrap->Packet);\r
1153\r
1154 gBS->CloseEvent (Wrap->RxData.RecycleSignal);\r
766c7483 1155 FreePool (Wrap);\r
772db4bb 1156}\r
1157\r
772db4bb 1158/**\r
1159 Wrap the received packet to a IP4_RXDATA_WRAP, which will be\r
1160 delivered to the upper layer. Each IP4 child that accepts the\r
1161 packet will get a not-shared copy of the packet which is wrapped\r
1162 in the IP4_RXDATA_WRAP. The IP4_RXDATA_WRAP->RxData is passed\r
1163 to the upper layer. Upper layer will signal the recycle event in\r
1164 it when it is done with the packet.\r
1165\r
216f7970 1166 @param[in] IpInstance The IP4 child to receive the packet.\r
1167 @param[in] Packet The packet to deliver up.\r
772db4bb 1168\r
3e8c18da 1169 @retval Wrap if warp the packet succeed.\r
1170 @retval NULL failed to wrap the packet .\r
772db4bb 1171\r
1172**/\r
1173IP4_RXDATA_WRAP *\r
1174Ip4WrapRxData (\r
d1050b9d
MK
1175 IN IP4_PROTOCOL *IpInstance,\r
1176 IN NET_BUF *Packet\r
772db4bb 1177 )\r
1178{\r
d1050b9d
MK
1179 IP4_RXDATA_WRAP *Wrap;\r
1180 EFI_IP4_RECEIVE_DATA *RxData;\r
1181 EFI_STATUS Status;\r
1182 BOOLEAN RawData;\r
772db4bb 1183\r
e48e37fc 1184 Wrap = AllocatePool (IP4_RXDATA_WRAP_SIZE (Packet->BlockOpNum));\r
772db4bb 1185\r
1186 if (Wrap == NULL) {\r
1187 return NULL;\r
1188 }\r
1189\r
e48e37fc 1190 InitializeListHead (&Wrap->Link);\r
772db4bb 1191\r
d1050b9d
MK
1192 Wrap->IpInstance = IpInstance;\r
1193 Wrap->Packet = Packet;\r
1194 RxData = &Wrap->RxData;\r
772db4bb 1195\r
216f7970 1196 ZeroMem (RxData, sizeof (EFI_IP4_RECEIVE_DATA));\r
772db4bb 1197\r
1198 Status = gBS->CreateEvent (\r
1199 EVT_NOTIFY_SIGNAL,\r
e48e37fc 1200 TPL_NOTIFY,\r
772db4bb 1201 Ip4OnRecyclePacket,\r
1202 Wrap,\r
1203 &RxData->RecycleSignal\r
1204 );\r
1205\r
1206 if (EFI_ERROR (Status)) {\r
766c7483 1207 FreePool (Wrap);\r
772db4bb 1208 return NULL;\r
1209 }\r
1210\r
f6b7393c 1211 ASSERT (Packet->Ip.Ip4 != NULL);\r
772db4bb 1212\r
216f7970 1213 ASSERT (IpInstance != NULL);\r
1214 RawData = IpInstance->ConfigData.RawData;\r
1215\r
772db4bb 1216 //\r
1217 // The application expects a network byte order header.\r
1218 //\r
216f7970 1219 if (!RawData) {\r
1220 RxData->HeaderLength = (Packet->Ip.Ip4->HeadLen << 2);\r
d1050b9d 1221 RxData->Header = (EFI_IP4_HEADER *)Ip4NtohHead (Packet->Ip.Ip4);\r
216f7970 1222 RxData->OptionsLength = RxData->HeaderLength - IP4_MIN_HEADLEN;\r
1223 RxData->Options = NULL;\r
772db4bb 1224\r
216f7970 1225 if (RxData->OptionsLength != 0) {\r
d1050b9d 1226 RxData->Options = (VOID *)(RxData->Header + 1);\r
216f7970 1227 }\r
772db4bb 1228 }\r
1229\r
d1050b9d 1230 RxData->DataLength = Packet->TotalSize;\r
772db4bb 1231\r
1232 //\r
1233 // Build the fragment table to be delivered up.\r
1234 //\r
1235 RxData->FragmentCount = Packet->BlockOpNum;\r
d1050b9d 1236 NetbufBuildExt (Packet, (NET_FRAGMENT *)RxData->FragmentTable, &RxData->FragmentCount);\r
772db4bb 1237\r
1238 return Wrap;\r
1239}\r
1240\r
772db4bb 1241/**\r
1242 Deliver the received packets to upper layer if there are both received\r
1243 requests and enqueued packets. If the enqueued packet is shared, it will\r
1244 duplicate it to a non-shared packet, release the shared packet, then\r
1245 deliver the non-shared packet up.\r
1246\r
3e8c18da 1247 @param[in] IpInstance The IP child to deliver the packet up.\r
772db4bb 1248\r
1249 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to deliver the\r
1250 packets.\r
1251 @retval EFI_SUCCESS All the enqueued packets that can be delivered\r
1252 are delivered up.\r
1253\r
1254**/\r
1255EFI_STATUS\r
1256Ip4InstanceDeliverPacket (\r
d1050b9d 1257 IN IP4_PROTOCOL *IpInstance\r
772db4bb 1258 )\r
1259{\r
1260 EFI_IP4_COMPLETION_TOKEN *Token;\r
1261 IP4_RXDATA_WRAP *Wrap;\r
1262 NET_BUF *Packet;\r
1263 NET_BUF *Dup;\r
1264 UINT8 *Head;\r
216f7970 1265 UINT32 HeadLen;\r
772db4bb 1266\r
1267 //\r
1268 // Deliver a packet if there are both a packet and a receive token.\r
1269 //\r
e48e37fc 1270 while (!IsListEmpty (&IpInstance->Received) &&\r
d1050b9d
MK
1271 !NetMapIsEmpty (&IpInstance->RxTokens))\r
1272 {\r
772db4bb 1273 Packet = NET_LIST_HEAD (&IpInstance->Received, NET_BUF, List);\r
1274\r
1275 if (!NET_BUF_SHARED (Packet)) {\r
1276 //\r
1277 // If this is the only instance that wants the packet, wrap it up.\r
1278 //\r
1279 Wrap = Ip4WrapRxData (IpInstance, Packet);\r
1280\r
1281 if (Wrap == NULL) {\r
1282 return EFI_OUT_OF_RESOURCES;\r
1283 }\r
1284\r
e48e37fc 1285 RemoveEntryList (&Packet->List);\r
772db4bb 1286 } else {\r
1287 //\r
1288 // Create a duplicated packet if this packet is shared\r
1289 //\r
216f7970 1290 if (IpInstance->ConfigData.RawData) {\r
1291 HeadLen = 0;\r
1292 } else {\r
1293 HeadLen = IP4_MAX_HEADLEN;\r
1294 }\r
1295\r
1296 Dup = NetbufDuplicate (Packet, NULL, HeadLen);\r
772db4bb 1297\r
1298 if (Dup == NULL) {\r
1299 return EFI_OUT_OF_RESOURCES;\r
1300 }\r
1301\r
216f7970 1302 if (!IpInstance->ConfigData.RawData) {\r
1303 //\r
1304 // Copy the IP head over. The packet to deliver up is\r
1305 // headless. Trim the head off after copy. The IP head\r
1306 // may be not continuous before the data.\r
1307 //\r
1308 Head = NetbufAllocSpace (Dup, IP4_MAX_HEADLEN, NET_BUF_HEAD);\r
1309 ASSERT (Head != NULL);\r
d1102dba 1310\r
d1050b9d 1311 Dup->Ip.Ip4 = (IP4_HEAD *)Head;\r
216f7970 1312\r
1313 CopyMem (Head, Packet->Ip.Ip4, Packet->Ip.Ip4->HeadLen << 2);\r
1314 NetbufTrim (Dup, IP4_MAX_HEADLEN, TRUE);\r
1315 }\r
772db4bb 1316\r
1317 Wrap = Ip4WrapRxData (IpInstance, Dup);\r
1318\r
1319 if (Wrap == NULL) {\r
1320 NetbufFree (Dup);\r
1321 return EFI_OUT_OF_RESOURCES;\r
1322 }\r
1323\r
e48e37fc 1324 RemoveEntryList (&Packet->List);\r
772db4bb 1325 NetbufFree (Packet);\r
1326\r
1327 Packet = Dup;\r
1328 }\r
1329\r
1330 //\r
1331 // Insert it into the delivered packet, then get a user's\r
1332 // receive token, pass the wrapped packet up.\r
1333 //\r
e48e37fc 1334 EfiAcquireLockOrFail (&IpInstance->RecycleLock);\r
1335 InsertHeadList (&IpInstance->Delivered, &Wrap->Link);\r
1336 EfiReleaseLock (&IpInstance->RecycleLock);\r
772db4bb 1337\r
1338 Token = NetMapRemoveHead (&IpInstance->RxTokens, NULL);\r
1339 Token->Status = IP4_GET_CLIP_INFO (Packet)->Status;\r
1340 Token->Packet.RxData = &Wrap->RxData;\r
1341\r
1342 gBS->SignalEvent (Token->Event);\r
1343 }\r
1344\r
1345 return EFI_SUCCESS;\r
1346}\r
1347\r
772db4bb 1348/**\r
1349 Enqueue a received packet to all the IP children that share\r
1350 the same interface.\r
1351\r
216f7970 1352 @param[in] IpSb The IP4 service instance that receive the packet.\r
1353 @param[in] Head The header of the received packet.\r
1354 @param[in] Packet The data of the received packet.\r
1355 @param[in] Option Point to the IP4 packet header options.\r
d1102dba 1356 @param[in] OptionLen Length of the IP4 packet header options.\r
216f7970 1357 @param[in] IpIf The interface to enqueue the packet to.\r
772db4bb 1358\r
1359 @return The number of the IP4 children that accepts the packet\r
1360\r
1361**/\r
1362INTN\r
1363Ip4InterfaceEnquePacket (\r
d1050b9d
MK
1364 IN IP4_SERVICE *IpSb,\r
1365 IN IP4_HEAD *Head,\r
1366 IN NET_BUF *Packet,\r
1367 IN UINT8 *Option,\r
1368 IN UINT32 OptionLen,\r
1369 IN IP4_INTERFACE *IpIf\r
772db4bb 1370 )\r
1371{\r
d1050b9d
MK
1372 IP4_PROTOCOL *IpInstance;\r
1373 IP4_CLIP_INFO *Info;\r
1374 LIST_ENTRY *Entry;\r
1375 INTN Enqueued;\r
1376 INTN LocalType;\r
1377 INTN SavedType;\r
772db4bb 1378\r
1379 //\r
1380 // First, check that the packet is acceptable to this interface\r
1381 // and find the local cast type for the interface. A packet sent\r
6c585b52 1382 // to say 192.168.1.1 should NOT be deliver to 10.0.0.1 unless\r
772db4bb 1383 // promiscuous receiving.\r
1384 //\r
1385 LocalType = 0;\r
1386 Info = IP4_GET_CLIP_INFO (Packet);\r
1387\r
1388 if ((Info->CastType == IP4_MULTICAST) || (Info->CastType == IP4_LOCAL_BROADCAST)) {\r
1389 //\r
1390 // If the CastType is multicast, don't need to filter against\r
1391 // the group address here, Ip4InstanceFrameAcceptable will do\r
1392 // that later.\r
1393 //\r
1394 LocalType = Info->CastType;\r
772db4bb 1395 } else {\r
1396 //\r
6c585b52 1397 // Check the destination against local IP. If the station\r
772db4bb 1398 // address is 0.0.0.0, it means receiving all the IP destined\r
1399 // to local non-zero IP. Otherwise, it is necessary to compare\r
1400 // the destination to the interface's IP address.\r
1401 //\r
1402 if (IpIf->Ip == IP4_ALLZERO_ADDRESS) {\r
1403 LocalType = IP4_LOCAL_HOST;\r
772db4bb 1404 } else {\r
1405 LocalType = Ip4GetNetCast (Head->Dst, IpIf);\r
1406\r
1407 if ((LocalType == 0) && IpIf->PromiscRecv) {\r
1408 LocalType = IP4_PROMISCUOUS;\r
1409 }\r
1410 }\r
1411 }\r
1412\r
1413 if (LocalType == 0) {\r
1414 return 0;\r
1415 }\r
1416\r
1417 //\r
1418 // Iterate through the ip instances on the interface, enqueue\r
1419 // the packet if filter passed. Save the original cast type,\r
1420 // and pass the local cast type to the IP children on the\r
1421 // interface. The global cast type will be restored later.\r
1422 //\r
d1050b9d
MK
1423 SavedType = Info->CastType;\r
1424 Info->CastType = LocalType;\r
772db4bb 1425\r
d1050b9d 1426 Enqueued = 0;\r
772db4bb 1427\r
1428 NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {\r
1429 IpInstance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);\r
1430 NET_CHECK_SIGNATURE (IpInstance, IP4_PROTOCOL_SIGNATURE);\r
1431\r
216f7970 1432 //\r
1433 // In RawData mode, add IPv4 headers and options back to packet.\r
1434 //\r
d1050b9d 1435 if ((IpInstance->ConfigData.RawData) && (Option != NULL) && (OptionLen != 0)) {\r
216f7970 1436 Ip4PrependHead (Packet, Head, Option, OptionLen);\r
1437 }\r
1438\r
772db4bb 1439 if (Ip4InstanceEnquePacket (IpInstance, Head, Packet) == EFI_SUCCESS) {\r
1440 Enqueued++;\r
1441 }\r
1442 }\r
1443\r
1444 Info->CastType = SavedType;\r
1445 return Enqueued;\r
1446}\r
1447\r
772db4bb 1448/**\r
1449 Deliver the packet for each IP4 child on the interface.\r
1450\r
3e8c18da 1451 @param[in] IpSb The IP4 service instance that received the packet\r
1452 @param[in] IpIf The IP4 interface to deliver the packet.\r
772db4bb 1453\r
1454 @retval EFI_SUCCESS It always returns EFI_SUCCESS now\r
1455\r
1456**/\r
1457EFI_STATUS\r
1458Ip4InterfaceDeliverPacket (\r
d1050b9d
MK
1459 IN IP4_SERVICE *IpSb,\r
1460 IN IP4_INTERFACE *IpIf\r
772db4bb 1461 )\r
1462{\r
d1050b9d
MK
1463 IP4_PROTOCOL *Ip4Instance;\r
1464 LIST_ENTRY *Entry;\r
772db4bb 1465\r
1466 NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {\r
1467 Ip4Instance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);\r
1468 Ip4InstanceDeliverPacket (Ip4Instance);\r
1469 }\r
1470\r
1471 return EFI_SUCCESS;\r
1472}\r
1473\r
772db4bb 1474/**\r
1475 Demultiple the packet. the packet delivery is processed in two\r
6c585b52 1476 passes. The first pass will enqueue a shared copy of the packet\r
772db4bb 1477 to each IP4 child that accepts the packet. The second pass will\r
1478 deliver a non-shared copy of the packet to each IP4 child that\r
1479 has pending receive requests. Data is copied if more than one\r
96e1079f 1480 child wants to consume the packet because each IP child needs\r
772db4bb 1481 its own copy of the packet to make changes.\r
1482\r
216f7970 1483 @param[in] IpSb The IP4 service instance that received the packet.\r
1484 @param[in] Head The header of the received packet.\r
1485 @param[in] Packet The data of the received packet.\r
1486 @param[in] Option Point to the IP4 packet header options.\r
1487 @param[in] OptionLen Length of the IP4 packet header options.\r
772db4bb 1488\r
216f7970 1489 @retval EFI_NOT_FOUND No IP child accepts the packet.\r
772db4bb 1490 @retval EFI_SUCCESS The packet is enqueued or delivered to some IP\r
1491 children.\r
1492\r
1493**/\r
1494EFI_STATUS\r
1495Ip4Demultiplex (\r
d1050b9d
MK
1496 IN IP4_SERVICE *IpSb,\r
1497 IN IP4_HEAD *Head,\r
1498 IN NET_BUF *Packet,\r
1499 IN UINT8 *Option,\r
1500 IN UINT32 OptionLen\r
772db4bb 1501 )\r
1502{\r
d1050b9d
MK
1503 LIST_ENTRY *Entry;\r
1504 IP4_INTERFACE *IpIf;\r
1505 INTN Enqueued;\r
772db4bb 1506\r
1507 //\r
6c585b52 1508 // Two pass delivery: first, enqueue a shared copy of the packet\r
772db4bb 1509 // to each instance that accept the packet.\r
1510 //\r
1511 Enqueued = 0;\r
1512\r
1513 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
1514 IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
1515\r
1516 if (IpIf->Configured) {\r
216f7970 1517 Enqueued += Ip4InterfaceEnquePacket (\r
1518 IpSb,\r
1519 Head,\r
1520 Packet,\r
1521 Option,\r
1522 OptionLen,\r
1523 IpIf\r
1524 );\r
772db4bb 1525 }\r
1526 }\r
1527\r
1528 //\r
1529 // Second: deliver a duplicate of the packet to each instance.\r
1530 // Release the local reference first, so that the last instance\r
1531 // getting the packet will not copy the data.\r
1532 //\r
1533 NetbufFree (Packet);\r
1534\r
1535 if (Enqueued == 0) {\r
1536 return EFI_NOT_FOUND;\r
1537 }\r
1538\r
1539 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
1540 IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
1541\r
1542 if (IpIf->Configured) {\r
1543 Ip4InterfaceDeliverPacket (IpSb, IpIf);\r
1544 }\r
1545 }\r
1546\r
1547 return EFI_SUCCESS;\r
1548}\r
1549\r
772db4bb 1550/**\r
1551 Timeout the fragment and enqueued packets.\r
1552\r
3e8c18da 1553 @param[in] IpSb The IP4 service instance to timeout\r
772db4bb 1554\r
1555**/\r
1556VOID\r
1557Ip4PacketTimerTicking (\r
d1050b9d 1558 IN IP4_SERVICE *IpSb\r
772db4bb 1559 )\r
1560{\r
d1050b9d
MK
1561 LIST_ENTRY *InstanceEntry;\r
1562 LIST_ENTRY *Entry;\r
1563 LIST_ENTRY *Next;\r
1564 IP4_PROTOCOL *IpInstance;\r
1565 IP4_ASSEMBLE_ENTRY *Assemble;\r
1566 NET_BUF *Packet;\r
1567 IP4_CLIP_INFO *Info;\r
1568 UINT32 Index;\r
772db4bb 1569\r
1570 //\r
1571 // First, time out the fragments. The packet's life is counting down\r
1572 // once the first-arrived fragment was received.\r
1573 //\r
1574 for (Index = 0; Index < IP4_ASSEMLE_HASH_SIZE; Index++) {\r
1575 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->Assemble.Bucket[Index]) {\r
1576 Assemble = NET_LIST_USER_STRUCT (Entry, IP4_ASSEMBLE_ENTRY, Link);\r
1577\r
1578 if ((Assemble->Life > 0) && (--Assemble->Life == 0)) {\r
e48e37fc 1579 RemoveEntryList (Entry);\r
772db4bb 1580 Ip4FreeAssembleEntry (Assemble);\r
1581 }\r
1582 }\r
1583 }\r
1584\r
1585 NET_LIST_FOR_EACH (InstanceEntry, &IpSb->Children) {\r
1586 IpInstance = NET_LIST_USER_STRUCT (InstanceEntry, IP4_PROTOCOL, Link);\r
1587\r
1588 //\r
1589 // Second, time out the assembled packets enqueued on each IP child.\r
1590 //\r
1591 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpInstance->Received) {\r
1592 Packet = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
1593 Info = IP4_GET_CLIP_INFO (Packet);\r
1594\r
1595 if ((Info->Life > 0) && (--Info->Life == 0)) {\r
e48e37fc 1596 RemoveEntryList (Entry);\r
772db4bb 1597 NetbufFree (Packet);\r
1598 }\r
1599 }\r
1600\r
1601 //\r
1602 // Third: time out the transmitted packets.\r
1603 //\r
1604 NetMapIterate (&IpInstance->TxTokens, Ip4SentPacketTicking, NULL);\r
1605 }\r
1606}\r