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