]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
Fix a bug in Ip4 driver that Ip4.Transmit() interface may return EFI_INVALID_PARAMETE...
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Impl.c
index 8974f5a5b7679916668488efaaf4e14ec4cab924..cd01685a304e5a6a4dc5940db0872e4d80dae7e2 100644 (file)
@@ -1,6 +1,6 @@
 /** @file\r
 \r
-Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include "Ip4Impl.h"\r
 \r
-EFI_IPSEC_PROTOCOL    *mIpSec = NULL;\r
+EFI_IPSEC2_PROTOCOL    *mIpSec = NULL;\r
 \r
 /**\r
   Gets the current operational settings for this instance of the EFI IPv4 Protocol driver.\r
@@ -562,6 +562,9 @@ Ip4AutoConfigCallBackDpc (
   IP4_ADDR                  SubnetMask;\r
   IP4_ADDR                  SubnetAddress;\r
   IP4_ADDR                  GatewayAddress;\r
+  IP4_PROTOCOL              *Ip4Instance;\r
+  EFI_ARP_PROTOCOL          *Arp;\r
+  LIST_ENTRY                *Entry;\r
 \r
   IpSb      = (IP4_SERVICE *) Context;\r
   NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);\r
@@ -650,11 +653,33 @@ Ip4AutoConfigCallBackDpc (
   StationAddress = EFI_NTOHL (Data->StationAddress);\r
   SubnetMask = EFI_NTOHL (Data->SubnetMask);\r
   Status = Ip4SetAddress (IpIf, StationAddress, SubnetMask);\r
-\r
   if (EFI_ERROR (Status)) {\r
     goto ON_EXIT;\r
   }\r
 \r
+  if (IpIf->Arp != NULL) {\r
+    //   \r
+    // A non-NULL IpIf->Arp here means a new ARP child is created when setting default address, \r
+    // but some IP children may have referenced the default interface before it is configured,\r
+    // these IP instances also consume this ARP protocol so they need to open it BY_CHILD_CONTROLLER.\r
+    //\r
+    Arp = NULL;\r
+    NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {\r
+      Ip4Instance = NET_LIST_USER_STRUCT_S (Entry, IP4_PROTOCOL, AddrLink, IP4_PROTOCOL_SIGNATURE);\r
+      Status = gBS->OpenProtocol (\r
+                      IpIf->ArpHandle,\r
+                      &gEfiArpProtocolGuid,\r
+                      (VOID **) &Arp,\r
+                      gIp4DriverBinding.DriverBindingHandle,\r
+                      Ip4Instance->Handle,\r
+                      EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        goto ON_EXIT;\r
+      }\r
+    }\r
+  }\r
+\r
   Ip4AddRoute (\r
     IpSb->DefaultRouteTable,\r
     StationAddress,\r
@@ -868,6 +893,7 @@ Ip4ConfigProtocol (
   EFI_STATUS                Status;\r
   IP4_ADDR                  Ip;\r
   IP4_ADDR                  Netmask;\r
+  EFI_ARP_PROTOCOL          *Arp;\r
 \r
   IpSb = IpInstance->Service;\r
 \r
@@ -972,6 +998,20 @@ Ip4ConfigProtocol (
   }\r
 \r
   IpInstance->Interface = IpIf;\r
+  if (IpIf->Arp != NULL) {\r
+    Arp = NULL;\r
+    Status = gBS->OpenProtocol (\r
+                    IpIf->ArpHandle,\r
+                    &gEfiArpProtocolGuid,\r
+                    (VOID **) &Arp,\r
+                    gIp4DriverBinding.DriverBindingHandle,\r
+                    IpInstance->Handle,\r
+                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+  }\r
   InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);\r
 \r
   CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));\r
@@ -1028,6 +1068,14 @@ Ip4CleanProtocol (
 \r
   if (IpInstance->Interface != NULL) {\r
     RemoveEntryList (&IpInstance->AddrLink);\r
+    if (IpInstance->Interface->Arp != NULL) {\r
+      gBS->CloseProtocol (\r
+             IpInstance->Interface->ArpHandle,\r
+             &gEfiArpProtocolGuid,\r
+             gIp4DriverBinding.DriverBindingHandle,\r
+             IpInstance->Handle\r
+             );\r
+    }\r
     Ip4FreeInterface (IpInstance->Interface, IpInstance);\r
     IpInstance->Interface = NULL;\r
   }\r
@@ -1193,14 +1241,6 @@ EfiIp4Configure (
   // Validate the configuration first.\r
   //\r
   if (IpConfigData != NULL) {\r
-    //\r
-    // This implementation doesn't support RawData\r
-    //\r
-    if (IpConfigData->RawData) {\r
-      Status = EFI_UNSUPPORTED;\r
-      goto ON_EXIT;\r
-    }\r
-\r
 \r
     CopyMem (&IpAddress, &IpConfigData->StationAddress, sizeof (IP4_ADDR));\r
     CopyMem (&SubnetMask, &IpConfigData->SubnetMask, sizeof (IP4_ADDR));\r
@@ -1256,7 +1296,7 @@ EfiIp4Configure (
     Status = Ip4CleanProtocol (IpInstance);\r
 \r
     //\r
-    // Don't change the state if it is DESTORY, consider the following\r
+    // Don't change the state if it is DESTROY, consider the following\r
     // valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,\r
     // Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,\r
     // the unload fails miserably.\r
@@ -1620,22 +1660,23 @@ Ip4TokenExist (
   return EFI_SUCCESS;\r
 }\r
 \r
-\r
 /**\r
   Validate the user's token against current station address.\r
 \r
-  @param[in]  Token                  User's token to validate\r
-  @param[in]  IpIf                   The IP4 child's interface.\r
+  @param[in]  Token              User's token to validate.\r
+  @param[in]  IpIf               The IP4 child's interface.\r
+  @param[in]  RawData            Set to TRUE to send unformatted packets.\r
 \r
-  @retval EFI_INVALID_PARAMETER  Some parameters are invalid\r
+  @retval EFI_INVALID_PARAMETER  Some parameters are invalid.\r
   @retval EFI_BAD_BUFFER_SIZE    The user's option/data is too long.\r
-  @retval EFI_SUCCESS            The token is OK\r
+  @retval EFI_SUCCESS            The token is valid.\r
 \r
 **/\r
 EFI_STATUS\r
 Ip4TxTokenValid (\r
   IN EFI_IP4_COMPLETION_TOKEN   *Token,\r
-  IN IP4_INTERFACE              *IpIf\r
+  IN IP4_INTERFACE              *IpIf,\r
+  IN BOOLEAN                    RawData\r
   )\r
 {\r
   EFI_IP4_TRANSMIT_DATA     *TxData;\r
@@ -1653,20 +1694,7 @@ Ip4TxTokenValid (
   TxData = Token->Packet.TxData;\r
 \r
   //\r
-  // Check the IP options: no more than 40 bytes and format is OK\r
-  //\r
-  if (TxData->OptionsLength != 0) {\r
-    if ((TxData->OptionsLength > 40) || (TxData->OptionsBuffer == NULL)) {\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
-\r
-    if (!Ip4OptionIsValid (TxData->OptionsBuffer, TxData->OptionsLength, FALSE)) {\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
-  }\r
-\r
-  //\r
-  // Check the fragment table: no empty fragment, and length isn't bogus\r
+  // Check the fragment table: no empty fragment, and length isn't bogus.\r
   //\r
   if ((TxData->TotalDataLength == 0) || (TxData->FragmentCount == 0)) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -1674,6 +1702,10 @@ Ip4TxTokenValid (
 \r
   Offset = TxData->TotalDataLength;\r
 \r
+  if (Offset > IP4_MAX_PACKET_SIZE) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
   for (Index = 0; Index < TxData->FragmentCount; Index++) {\r
     if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||\r
         (TxData->FragmentTable[Index].FragmentLength == 0)) {\r
@@ -1688,6 +1720,27 @@ Ip4TxTokenValid (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  //\r
+  // NOTE that OptionsLength/OptionsBuffer/OverrideData are ignored if RawData\r
+  // is TRUE.\r
+  //\r
+  if (RawData) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Check the IP options: no more than 40 bytes and format is OK\r
+  //\r
+  if (TxData->OptionsLength != 0) {\r
+    if ((TxData->OptionsLength > 40) || (TxData->OptionsBuffer == NULL)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (!Ip4OptionIsValid (TxData->OptionsBuffer, TxData->OptionsLength, FALSE)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
   //\r
   // Check the source and gateway: they must be a valid unicast.\r
   // Gateway must also be on the connected network.\r
@@ -1888,6 +1941,10 @@ EfiIp4Transmit (
   EFI_TPL                   OldTpl;\r
   BOOLEAN                   DontFragment;\r
   UINT32                    HeadLen;\r
+  UINT8                     RawHdrLen;\r
+  UINT32                    OptionsLength;\r
+  UINT8                     *OptionsBuffer;\r
+  VOID                      *FirstFragment;\r
 \r
   if (This == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -1913,7 +1970,7 @@ EfiIp4Transmit (
   //\r
   // make sure that token is properly formated\r
   //\r
-  Status = Ip4TxTokenValid (Token, IpIf);\r
+  Status = Ip4TxTokenValid (Token, IpIf, Config->RawData);\r
 \r
   if (EFI_ERROR (Status)) {\r
     goto ON_EXIT;\r
@@ -1933,32 +1990,84 @@ EfiIp4Transmit (
   //\r
   TxData = Token->Packet.TxData;\r
 \r
-  CopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));\r
-  Head.Dst = NTOHL (Head.Dst);\r
+  FirstFragment = NULL;\r
 \r
-  if (TxData->OverrideData != NULL) {\r
-    Override      = TxData->OverrideData;\r
-    Head.Protocol = Override->Protocol;\r
-    Head.Tos      = Override->TypeOfService;\r
-    Head.Ttl      = Override->TimeToLive;\r
-    DontFragment  = Override->DoNotFragment;\r
+  if (Config->RawData) {\r
+    //\r
+    // When RawData is TRUE, first buffer in FragmentTable points to a raw\r
+    // IPv4 fragment including IPv4 header and options.\r
+    //\r
+    FirstFragment = TxData->FragmentTable[0].FragmentBuffer;\r
+    CopyMem (&RawHdrLen, FirstFragment, sizeof (UINT8));\r
 \r
-    CopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));\r
-    CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));\r
+    RawHdrLen = (UINT8) (RawHdrLen & 0x0f);\r
+    if (RawHdrLen < 5) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    RawHdrLen = (UINT8) (RawHdrLen << 2);\r
+    \r
+    CopyMem (&Head, FirstFragment, IP4_MIN_HEADLEN);\r
+\r
+    Ip4NtohHead (&Head);\r
+    HeadLen      = 0;\r
+    DontFragment = IP4_DO_NOT_FRAGMENT (Head.Fragment);\r
+\r
+    if (!DontFragment) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    GateWay = IP4_ALLZERO_ADDRESS;\r
+\r
+    //\r
+    // Get IPv4 options from first fragment.\r
+    //\r
+    if (RawHdrLen == IP4_MIN_HEADLEN) {\r
+      OptionsLength = 0;\r
+      OptionsBuffer = NULL;\r
+    } else {\r
+      OptionsLength = RawHdrLen - IP4_MIN_HEADLEN;\r
+      OptionsBuffer = (UINT8 *) FirstFragment + IP4_MIN_HEADLEN;\r
+    }\r
 \r
-    Head.Src = NTOHL (Head.Src);\r
-    GateWay  = NTOHL (GateWay);\r
+    //\r
+    // Trim off IPv4 header and options from first fragment.\r
+    //\r
+    TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment + RawHdrLen;\r
+    TxData->FragmentTable[0].FragmentLength = TxData->FragmentTable[0].FragmentLength - RawHdrLen;\r
   } else {\r
-    Head.Src      = IpIf->Ip;\r
-    GateWay       = IP4_ALLZERO_ADDRESS;\r
-    Head.Protocol = Config->DefaultProtocol;\r
-    Head.Tos      = Config->TypeOfService;\r
-    Head.Ttl      = Config->TimeToLive;\r
-    DontFragment  = Config->DoNotFragment;\r
-  }\r
+    CopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));\r
+    Head.Dst = NTOHL (Head.Dst);\r
+\r
+    if (TxData->OverrideData != NULL) {\r
+      Override      = TxData->OverrideData;\r
+      Head.Protocol = Override->Protocol;\r
+      Head.Tos      = Override->TypeOfService;\r
+      Head.Ttl      = Override->TimeToLive;\r
+      DontFragment  = Override->DoNotFragment;\r
+\r
+      CopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));\r
+      CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));\r
+\r
+      Head.Src = NTOHL (Head.Src);\r
+      GateWay  = NTOHL (GateWay);\r
+    } else {\r
+      Head.Src      = IpIf->Ip;\r
+      GateWay       = IP4_ALLZERO_ADDRESS;\r
+      Head.Protocol = Config->DefaultProtocol;\r
+      Head.Tos      = Config->TypeOfService;\r
+      Head.Ttl      = Config->TimeToLive;\r
+      DontFragment  = Config->DoNotFragment;\r
+    }\r
+\r
+    Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);\r
+    HeadLen       = (TxData->OptionsLength + 3) & (~0x03);\r
 \r
-  Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);\r
-  HeadLen       = (TxData->OptionsLength + 3) & (~0x03);\r
+    OptionsLength = TxData->OptionsLength;\r
+    OptionsBuffer = (UINT8 *) (TxData->OptionsBuffer);\r
+  }\r
 \r
   //\r
   // If don't fragment and fragment needed, return error\r
@@ -2004,6 +2113,13 @@ EfiIp4Transmit (
     // free the IP4_TXTOKEN_WRAP. Now, the token wrap hasn't been\r
     // enqueued.\r
     //\r
+    if (Config->RawData) {\r
+      //\r
+      // Restore pointer of first fragment in RawData mode.\r
+      //\r
+      TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;\r
+    }\r
+\r
     NetbufFree (Wrap->Packet);\r
     goto ON_EXIT;\r
   }\r
@@ -2019,8 +2135,8 @@ EfiIp4Transmit (
              IpInstance,\r
              Wrap->Packet,\r
              &Head,\r
-             TxData->OptionsBuffer,\r
-             TxData->OptionsLength,\r
+             OptionsBuffer,\r
+             OptionsLength,\r
              GateWay,\r
              Ip4OnPacketSent,\r
              Wrap\r
@@ -2028,9 +2144,24 @@ EfiIp4Transmit (
 \r
   if (EFI_ERROR (Status)) {\r
     Wrap->Sent = FALSE;\r
+\r
+    if (Config->RawData) {\r
+      //\r
+      // Restore pointer of first fragment in RawData mode.\r
+      //\r
+      TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;\r
+    }\r
+\r
     NetbufFree (Wrap->Packet);\r
   }\r
 \r
+  if (Config->RawData) {\r
+    //\r
+    // Restore pointer of first fragment in RawData mode.\r
+    //\r
+    TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;\r
+  }\r
+\r
 ON_EXIT:\r
   gBS->RestoreTPL (OldTpl);\r
   return Status;\r