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