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