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