]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Impl.c
index 37e2114d01c90ab21fd45fcefe37f04758629439..ec6f0370772b003ec1b79b230655571034f0b747 100644 (file)
@@ -1,19 +1,13 @@
 /** @file\r
 \r
-Copyright (c) 2005 - 2010, 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
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \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
@@ -530,280 +524,6 @@ Ip4ServiceConfigMnp (
 }\r
 \r
 \r
-/**\r
-  The event handle for IP4 auto configuration. If IP is asked\r
-  to reconfigure the default address. The original default\r
-  interface and route table are removed as the default. If there\r
-  is active IP children using the default address, the interface\r
-  will remain valid until all the children have freed their\r
-  references. If IP is signalled when auto configuration is done,\r
-  it will configure the default interface and default route table\r
-  with the configuration information retrieved by IP4_CONFIGURE.\r
-\r
-  @param[in]  Context                The IP4 service binding instance.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-Ip4AutoConfigCallBackDpc (\r
-  IN VOID                   *Context\r
-  )\r
-{\r
-  EFI_IP4_CONFIG_PROTOCOL   *Ip4Config;\r
-  EFI_IP4_IPCONFIG_DATA     *Data;\r
-  EFI_IP4_ROUTE_TABLE       *RouteEntry;\r
-  IP4_SERVICE               *IpSb;\r
-  IP4_ROUTE_TABLE           *RouteTable;\r
-  IP4_INTERFACE             *IpIf;\r
-  EFI_STATUS                Status;\r
-  UINTN                     Len;\r
-  UINT32                    Index;\r
-  IP4_ADDR                  StationAddress;\r
-  IP4_ADDR                  SubnetMask;\r
-  IP4_ADDR                  SubnetAddress;\r
-  IP4_ADDR                  GatewayAddress;\r
-\r
-  IpSb      = (IP4_SERVICE *) Context;\r
-  NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);\r
-\r
-  Ip4Config = IpSb->Ip4Config;\r
-\r
-  //\r
-  // IP is asked to do the reconfiguration. If the default interface\r
-  // has been configured, release the default interface and route\r
-  // table, then create a new one. If there are some IP children\r
-  // using it, the interface won't be physically freed until all the\r
-  // children have released their reference to it. Also remember to\r
-  // restart the receive on the default address. IP4 driver only receive\r
-  // frames on the default address, and when the default interface is\r
-  // freed, Ip4AcceptFrame won't be informed.\r
-  //\r
-  if (IpSb->ActiveEvent == IpSb->ReconfigEvent) {\r
-\r
-    if (IpSb->DefaultInterface->Configured) {\r
-      IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);\r
-\r
-      if (IpIf == NULL) {\r
-        return;\r
-      }\r
-\r
-      RouteTable = Ip4CreateRouteTable ();\r
-\r
-      if (RouteTable == NULL) {\r
-        Ip4FreeInterface (IpIf, NULL);\r
-        return;\r
-      }\r
-\r
-      Ip4CancelReceive (IpSb->DefaultInterface);\r
-      Ip4FreeInterface (IpSb->DefaultInterface, NULL);\r
-      Ip4FreeRouteTable (IpSb->DefaultRouteTable);\r
-\r
-      IpSb->DefaultInterface  = IpIf;\r
-      InsertHeadList (&IpSb->Interfaces, &IpIf->Link);\r
-\r
-      IpSb->DefaultRouteTable = RouteTable;\r
-      Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);\r
-    }\r
-\r
-    Ip4Config->Stop (Ip4Config);\r
-    Ip4Config->Start (Ip4Config, IpSb->DoneEvent, IpSb->ReconfigEvent);\r
-    return ;\r
-  }\r
-\r
-  //\r
-  // Get the configure data in two steps: get the length then the data.\r
-  //\r
-  Len = 0;\r
-\r
-  if (Ip4Config->GetData (Ip4Config, &Len, NULL) != EFI_BUFFER_TOO_SMALL) {\r
-    return ;\r
-  }\r
-\r
-  Data = AllocatePool (Len);\r
-\r
-  if (Data == NULL) {\r
-    return ;\r
-  }\r
-\r
-  Status = Ip4Config->GetData (Ip4Config, &Len, Data);\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  IpIf = IpSb->DefaultInterface;\r
-\r
-  //\r
-  // If the default address has been configured don't change it.\r
-  // This is unlikely to happen if EFI_IP4_CONFIG protocol has\r
-  // informed us to reconfigure each time it wants to change the\r
-  // configuration parameters.\r
-  //\r
-  if (IpIf->Configured) {\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  //\r
-  // Set the default interface's address, then add a directed\r
-  // route for it, that is, the route whose nexthop is zero.\r
-  //\r
-  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
-  Ip4AddRoute (\r
-    IpSb->DefaultRouteTable,\r
-    StationAddress,\r
-    SubnetMask,\r
-    IP4_ALLZERO_ADDRESS\r
-    );\r
-\r
-  //\r
-  // Add routes returned by EFI_IP4_CONFIG protocol.\r
-  //\r
-  for (Index = 0; Index < Data->RouteTableSize; Index++) {\r
-    RouteEntry = &Data->RouteTable[Index];\r
-\r
-    SubnetAddress = EFI_NTOHL (RouteEntry->SubnetAddress);\r
-    SubnetMask = EFI_NTOHL (RouteEntry->SubnetMask);\r
-    GatewayAddress = EFI_NTOHL (RouteEntry->GatewayAddress);\r
-    Ip4AddRoute (IpSb->DefaultRouteTable, SubnetAddress, SubnetMask, GatewayAddress);\r
-  }\r
-\r
-  IpSb->State = IP4_SERVICE_CONFIGED;\r
-\r
-  Ip4SetVariableData (IpSb);\r
-\r
-ON_EXIT:\r
-  FreePool (Data);\r
-}\r
-\r
-/**\r
-  Request Ip4AutoConfigCallBackDpc as a DPC at TPL_CALLBACK.\r
-\r
-  @param Event     The event that is signalled.\r
-  @param Context   The IP4 service binding instance.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-Ip4AutoConfigCallBack (\r
-  IN EFI_EVENT              Event,\r
-  IN VOID                   *Context\r
-  )\r
-{\r
-  IP4_SERVICE  *IpSb;\r
-\r
-  IpSb              = (IP4_SERVICE *) Context;\r
-  IpSb->ActiveEvent = Event;\r
-\r
-  //\r
-  // Request Ip4AutoConfigCallBackDpc as a DPC at TPL_CALLBACK\r
-  //\r
-  QueueDpc (TPL_CALLBACK, Ip4AutoConfigCallBackDpc, Context);\r
-}\r
-\r
-\r
-/**\r
-  Start the auto configuration for this IP service instance.\r
-  It will locates the EFI_IP4_CONFIG_PROTOCOL, then start the\r
-  auto configuration.\r
-\r
-  @param[in]  IpSb               The IP4 service instance to configure\r
-\r
-  @retval EFI_SUCCESS            The auto configuration is successfull started\r
-  @retval Others                 Failed to start auto configuration.\r
-\r
-**/\r
-EFI_STATUS\r
-Ip4StartAutoConfig (\r
-  IN IP4_SERVICE            *IpSb\r
-  )\r
-{\r
-  EFI_IP4_CONFIG_PROTOCOL   *Ip4Config;\r
-  EFI_STATUS                Status;\r
-\r
-  if (IpSb->State > IP4_SERVICE_UNSTARTED) {\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
-  //\r
-  // Create the DoneEvent and ReconfigEvent to call EFI_IP4_CONFIG\r
-  //\r
-  Status = gBS->CreateEvent (\r
-                  EVT_NOTIFY_SIGNAL,\r
-                  TPL_CALLBACK,\r
-                  Ip4AutoConfigCallBack,\r
-                  IpSb,\r
-                  &IpSb->DoneEvent\r
-                  );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
-  Status = gBS->CreateEvent (\r
-                  EVT_NOTIFY_SIGNAL,\r
-                  TPL_NOTIFY,\r
-                  Ip4AutoConfigCallBack,\r
-                  IpSb,\r
-                  &IpSb->ReconfigEvent\r
-                  );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    goto CLOSE_DONE_EVENT;\r
-  }\r
-\r
-  //\r
-  // Open the EFI_IP4_CONFIG protocol then start auto configure\r
-  //\r
-  Status = gBS->OpenProtocol (\r
-                  IpSb->Controller,\r
-                  &gEfiIp4ConfigProtocolGuid,\r
-                  (VOID **) &Ip4Config,\r
-                  IpSb->Image,\r
-                  IpSb->Controller,\r
-                  EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE\r
-                  );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    Status = EFI_UNSUPPORTED;\r
-    goto CLOSE_RECONFIG_EVENT;\r
-  }\r
-\r
-  Status = Ip4Config->Start (Ip4Config, IpSb->DoneEvent, IpSb->ReconfigEvent);\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    gBS->CloseProtocol (\r
-           IpSb->Controller,\r
-           &gEfiIp4ConfigProtocolGuid,\r
-           IpSb->Image,\r
-           IpSb->Controller\r
-           );\r
-\r
-    goto CLOSE_RECONFIG_EVENT;\r
-  }\r
-\r
-  IpSb->Ip4Config = Ip4Config;\r
-  IpSb->State     = IP4_SERVICE_STARTED;\r
-  return Status;\r
-\r
-CLOSE_RECONFIG_EVENT:\r
-  gBS->CloseEvent (IpSb->ReconfigEvent);\r
-  IpSb->ReconfigEvent = NULL;\r
-\r
-CLOSE_DONE_EVENT:\r
-  gBS->CloseEvent (IpSb->DoneEvent);\r
-  IpSb->DoneEvent = NULL;\r
-\r
-  return Status;\r
-}\r
-\r
-\r
 /**\r
   Intiialize the IP4_PROTOCOL structure to the unconfigured states.\r
 \r
@@ -824,6 +544,7 @@ Ip4InitProtocol (
   IpInstance->Signature = IP4_PROTOCOL_SIGNATURE;\r
   CopyMem (&IpInstance->Ip4Proto, &mEfiIp4ProtocolTemplete, sizeof (IpInstance->Ip4Proto));\r
   IpInstance->State     = IP4_STATE_UNCONFIGED;\r
+  IpInstance->InDestroy   = FALSE;\r
   IpInstance->Service   = IpSb;\r
 \r
   InitializeListHead (&IpInstance->Link);\r
@@ -868,9 +589,14 @@ Ip4ConfigProtocol (
   EFI_STATUS                Status;\r
   IP4_ADDR                  Ip;\r
   IP4_ADDR                  Netmask;\r
+  EFI_ARP_PROTOCOL          *Arp;\r
+  EFI_IP4_CONFIG2_PROTOCOL  *Ip4Config2;\r
+  EFI_IP4_CONFIG2_POLICY    Policy;\r
 \r
   IpSb = IpInstance->Service;\r
 \r
+  Ip4Config2  = NULL;\r
+\r
   //\r
   // User is changing packet filters. It must be stopped\r
   // before the station address can be changed.\r
@@ -940,20 +666,36 @@ Ip4ConfigProtocol (
     }\r
 \r
     //\r
-    // Add a route to this connected network in the route table\r
+    // Add a route to this connected network in the instance route table.\r
     //\r
-    Ip4AddRoute (IpInstance->RouteTable, Ip, Netmask, IP4_ALLZERO_ADDRESS);\r
-\r
+    Ip4AddRoute (\r
+      IpInstance->RouteTable,\r
+      Ip & Netmask,\r
+      Netmask,\r
+      IP4_ALLZERO_ADDRESS\r
+      );\r
   } else {\r
     //\r
-    // Use the default address. If the default configuration hasn't\r
-    // been started, start it.\r
+    // Use the default address. Check the state.\r
     //\r
     if (IpSb->State == IP4_SERVICE_UNSTARTED) {\r
-      Status = Ip4StartAutoConfig (IpSb);\r
-\r
-      if (EFI_ERROR (Status)) {\r
-        goto ON_ERROR;\r
+      //\r
+      // Trigger the EFI_IP4_CONFIG2_PROTOCOL to retrieve the\r
+      // default IPv4 address if it is not available yet.\r
+      //\r
+      Policy = IpSb->Ip4Config2Instance.Policy;\r
+      if (Policy != Ip4Config2PolicyDhcp) {\r
+        Ip4Config2 = &IpSb->Ip4Config2Instance.Ip4Config2;\r
+        Policy = Ip4Config2PolicyDhcp;\r
+        Status= Ip4Config2->SetData (\r
+                              Ip4Config2,\r
+                              Ip4Config2DataTypePolicy,\r
+                              sizeof (EFI_IP4_CONFIG2_POLICY),\r
+                              &Policy\r
+                              );\r
+        if (EFI_ERROR (Status)) {\r
+          goto ON_ERROR;\r
+        }\r
       }\r
     }\r
 \r
@@ -972,6 +714,21 @@ 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
+      Ip4FreeInterface (IpIf, IpInstance);\r
+      goto ON_ERROR;\r
+    }\r
+  }\r
   InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);\r
 \r
   CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));\r
@@ -1000,8 +757,8 @@ ON_ERROR:
 \r
   @param[in]  IpInstance         The IP4 child to clean up.\r
 \r
-  @retval EFI_SUCCESS            The IP4 child is cleaned up\r
-  @retval EFI_DEVICE_ERROR       Some resources failed to be released\r
+  @retval EFI_SUCCESS            The IP4 child is cleaned up.\r
+  @retval EFI_DEVICE_ERROR       Some resources failed to be released.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -1028,6 +785,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
@@ -1061,66 +826,6 @@ Ip4CleanProtocol (
 }\r
 \r
 \r
-/**\r
-  Validate that Ip/Netmask pair is OK to be used as station\r
-  address. Only continuous netmasks are supported. and check\r
-  that StationAddress is a unicast address on the newtwork.\r
-\r
-  @param[in]  Ip                 The IP address to validate\r
-  @param[in]  Netmask            The netmaks of the IP\r
-\r
-  @retval TRUE                   The Ip/Netmask pair is valid\r
-  @retval FALSE                  The Ip/Netmask pair is invalid\r
-\r
-**/\r
-BOOLEAN\r
-Ip4StationAddressValid (\r
-  IN IP4_ADDR               Ip,\r
-  IN IP4_ADDR               Netmask\r
-  )\r
-{\r
-  IP4_ADDR                  NetBrdcastMask;\r
-  INTN                      Len;\r
-  INTN                      Type;\r
-\r
-  //\r
-  // Only support the station address with 0.0.0.0/0 to enable DHCP client.\r
-  //\r
-  if (Netmask == IP4_ALLZERO_ADDRESS) {\r
-    return (BOOLEAN) (Ip == IP4_ALLZERO_ADDRESS);\r
-  }\r
-\r
-  //\r
-  // Only support the continuous net masks\r
-  //\r
-  if ((Len = NetGetMaskLength (Netmask)) == IP4_MASK_NUM) {\r
-    return FALSE;\r
-  }\r
-\r
-  //\r
-  // Station address can't be class D or class E address\r
-  //\r
-  if ((Type = NetGetIpClass (Ip)) > IP4_ADDR_CLASSC) {\r
-    return FALSE;\r
-  }\r
-\r
-  //\r
-  // Station address can't be subnet broadcast/net broadcast address\r
-  //\r
-  if ((Ip == (Ip & Netmask)) || (Ip == (Ip | ~Netmask))) {\r
-    return FALSE;\r
-  }\r
-\r
-  NetBrdcastMask = gIp4AllMasks[MIN (Len, Type << 3)];\r
-\r
-  if (Ip == (Ip | ~NetBrdcastMask)) {\r
-    return FALSE;\r
-  }\r
-\r
-  return TRUE;\r
-}\r
-\r
-\r
 /**\r
   Assigns an IPv4 address and subnet mask to this EFI IPv4 Protocol driver instance.\r
 \r
@@ -1193,14 +898,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
@@ -1241,7 +938,8 @@ EfiIp4Configure (
       }\r
 \r
       if (Current->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
-        return EFI_NO_MAPPING;\r
+        Status = EFI_NO_MAPPING;\r
+        goto ON_EXIT;\r
       }\r
     }\r
   }\r
@@ -1255,8 +953,7 @@ EfiIp4Configure (
     Status = Ip4CleanProtocol (IpInstance);\r
 \r
     //\r
-    // Don't change the state if it is DESTORY, consider the following\r
-    // valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,\r
+    // Consider the following 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
     //\r
@@ -1271,11 +968,6 @@ EfiIp4Configure (
   //\r
   Ip4ServiceConfigMnp (IpInstance->Service, FALSE);\r
 \r
-  //\r
-  // Update the variable data.\r
-  //\r
-  Ip4SetVariableData (IpInstance->Service);\r
-\r
 ON_EXIT:\r
   gBS->RestoreTPL (OldTpl);\r
   return Status;\r
@@ -1288,12 +980,12 @@ ON_EXIT:
   should make sure that the parameters is valid.\r
 \r
   @param[in]  IpInstance             The IP4 child to change the setting.\r
-  @param[in]  JoinFlag               TRUE to join the group, otherwise leave it\r
-  @param[in]  GroupAddress           The target group address\r
+  @param[in]  JoinFlag               TRUE to join the group, otherwise leave it.\r
+  @param[in]  GroupAddress           The target group address.\r
 \r
-  @retval EFI_ALREADY_STARTED    Want to join the group, but already a member of it\r
+  @retval EFI_ALREADY_STARTED    Want to join the group, but already a member of it.\r
   @retval EFI_OUT_OF_RESOURCES   Failed to allocate some resources.\r
-  @retval EFI_DEVICE_ERROR       Failed to set the group configuraton\r
+  @retval EFI_DEVICE_ERROR       Failed to set the group configuraton.\r
   @retval EFI_SUCCESS            Successfully updated the group setting.\r
   @retval EFI_NOT_FOUND          Try to leave the group which it isn't a member.\r
 \r
@@ -1354,8 +1046,8 @@ Ip4Groups (
   // is decreamented each time an address is removed..\r
   //\r
   for (Index = IpInstance->GroupCount; Index > 0 ; Index--) {\r
+    ASSERT (IpInstance->Groups != NULL);\r
     Group = IpInstance->Groups[Index - 1];\r
-\r
     if ((GroupAddress == NULL) || EFI_IP4_EQUAL (&Group, GroupAddress)) {\r
       if (EFI_ERROR (Ip4LeaveGroup (IpInstance, NTOHL (Group)))) {\r
         return EFI_DEVICE_ERROR;\r
@@ -1565,7 +1257,7 @@ EfiIp4Routes (
   // the gateway address must be a unicast on the connected network if not zero.\r
   //\r
   if ((Nexthop != IP4_ALLZERO_ADDRESS) &&\r
-      (!IP4_NET_EQUAL (Nexthop, IpIf->Ip, IpIf->SubnetMask) ||\r
+      ((IpIf->SubnetMask != IP4_ALLONE_ADDRESS && !IP4_NET_EQUAL (Nexthop, IpIf->Ip, IpIf->SubnetMask)) ||\r
         IP4_IS_BROADCAST (Ip4GetNetCast (Nexthop, IpIf)))) {\r
 \r
     Status = EFI_INVALID_PARAMETER;\r
@@ -1590,10 +1282,10 @@ ON_EXIT:
 \r
   @param[in]  Map                    The container of either user's transmit or receive\r
                                      token.\r
-  @param[in]  Item                   Current item to check against\r
+  @param[in]  Item                   Current item to check against.\r
   @param[in]  Context                The Token to check againist.\r
 \r
-  @retval EFI_ACCESS_DENIED      The token or event has already been enqueued in IP\r
+  @retval EFI_ACCESS_DENIED      The token or event has already been enqueued in IP.\r
   @retval EFI_SUCCESS            The current item isn't the same token/event as the\r
                                  context.\r
 \r
@@ -1619,22 +1311,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
@@ -1652,20 +1345,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
@@ -1673,6 +1353,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
@@ -1687,6 +1371,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
@@ -1753,7 +1458,7 @@ Ip4TxTokenValid (
   are bound together. Check the comments in Ip4Output for information\r
   about IP fragmentation.\r
 \r
-  @param[in]  Context                The token's wrap\r
+  @param[in]  Context                The token's wrap.\r
 \r
 **/\r
 VOID\r
@@ -1801,9 +1506,9 @@ Ip4FreeTxToken (
   The callback function to Ip4Output to update the transmit status.\r
 \r
   @param  Ip4Instance            The Ip4Instance that request the transmit.\r
-  @param  Packet                 The user's transmit request\r
-  @param  IoStatus               The result of the transmission\r
-  @param  Flag                   Not used during transmission\r
+  @param  Packet                 The user's transmit request.\r
+  @param  IoStatus               The result of the transmission.\r
+  @param  Flag                   Not used during transmission.\r
   @param  Context                The token's wrap.\r
 \r
 **/\r
@@ -1864,7 +1569,7 @@ Ip4OnPacketSent (
   @retval  EFI_BAD_BUFFER_SIZE   The length of the IPv4 header + option length + total data length is\r
                                  greater than MTU (or greater than the maximum packet size if\r
                                  Token.Packet.TxData.OverrideData.\r
-                                 DoNotFragment is TRUE.)\r
+                                 DoNotFragment is TRUE).\r
 \r
 **/\r
 EFI_STATUS\r
@@ -1887,6 +1592,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
@@ -1912,7 +1621,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
@@ -1932,32 +1641,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
+    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.Src, &Override->SourceAddress, sizeof (IP4_ADDR));\r
-    CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));\r
+    CopyMem (&Head, FirstFragment, IP4_MIN_HEADLEN);\r
 \r
-    Head.Src = NTOHL (Head.Src);\r
-    GateWay  = NTOHL (GateWay);\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
+    //\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
-  Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);\r
-  HeadLen       = (TxData->OptionsLength + 3) & (~0x03);\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
+    OptionsLength = TxData->OptionsLength;\r
+    OptionsBuffer = (UINT8 *) (TxData->OptionsBuffer);\r
+  }\r
 \r
   //\r
   // If don't fragment and fragment needed, return error\r
@@ -2003,6 +1764,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
@@ -2018,8 +1786,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
@@ -2027,9 +1795,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
@@ -2137,9 +1920,9 @@ ON_EXIT:
   Because Ip4CancelPacket and other functions are all called in\r
   line, so, after Ip4CancelPacket returns, the Item has been freed.\r
 \r
-  @param[in]  Map                    The IP4 child's transmit queue\r
-  @param[in]  Item                   The current transmitted packet to test.\r
-  @param[in]  Context                The user's token to cancel.\r
+  @param[in]  Map                The IP4 child's transmit queue.\r
+  @param[in]  Item               The current transmitted packet to test.\r
+  @param[in]  Context            The user's token to cancel.\r
 \r
   @retval EFI_SUCCESS            Continue to check the next Item.\r
   @retval EFI_ABORTED            The user's Token (Token != NULL) is cancelled.\r
@@ -2191,9 +1974,9 @@ Ip4CancelTxTokens (
   Cancel the receive request. This is quiet simple, because\r
   it is only enqueued in our local receive map.\r
 \r
-  @param[in]  Map                    The IP4 child's receive queue\r
-  @param[in]  Item                   Current receive request to cancel.\r
-  @param[in]  Context                The user's token to cancel\r
+  @param[in]  Map                The IP4 child's receive queue.\r
+  @param[in]  Item               Current receive request to cancel.\r
+  @param[in]  Context            The user's token to cancel.\r
 \r
   @retval EFI_SUCCESS            Continue to check the next receive request on the\r
                                  queue.\r
@@ -2236,13 +2019,13 @@ Ip4CancelRxTokens (
 /**\r
   Cancel the user's receive/transmit request.\r
 \r
-  @param[in]  IpInstance         The IP4 child\r
+  @param[in]  IpInstance         The IP4 child.\r
   @param[in]  Token              The token to cancel. If NULL, all token will be\r
                                  cancelled.\r
 \r
-  @retval EFI_SUCCESS            The token is cancelled\r
+  @retval EFI_SUCCESS            The token is cancelled.\r
   @retval EFI_NOT_FOUND          The token isn't found on either the\r
-                                 transmit/receive queue\r
+                                 transmit/receive queue.\r
   @retval EFI_DEVICE_ERROR       Not all token is cancelled when Token is NULL.\r
 \r
 **/\r
@@ -2438,10 +2221,10 @@ EfiIp4Poll (
   packets.\r
 \r
   @param[in]  Map                    The IP4 child's transmit map.\r
-  @param[in]  Item                   Current transmitted packet\r
+  @param[in]  Item                   Current transmitted packet.\r
   @param[in]  Context                Not used.\r
 \r
-  @retval EFI_SUCCESS            Always returns EFI_SUCCESS\r
+  @retval EFI_SUCCESS            Always returns EFI_SUCCESS.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -2464,12 +2247,10 @@ Ip4SentPacketTicking (
   return EFI_SUCCESS;\r
 }\r
 \r
-\r
 /**\r
-  The heart beat timer of IP4 service instance. It times out\r
-  all of its IP4 children's received-but-not-delivered and\r
-  transmitted-but-not-recycle packets, and provides time input\r
-  for its IGMP protocol.\r
+  This heart beat timer of IP4 service instance times out all of its IP4 children's\r
+  received-but-not-delivered and transmitted-but-not-recycle packets, and provides\r
+  time input for its IGMP protocol.\r
 \r
   @param[in]  Event                  The IP4 service instance's heart beat timer.\r
   @param[in]  Context                The IP4 service instance.\r
@@ -2490,3 +2271,60 @@ Ip4TimerTicking (
   Ip4PacketTimerTicking (IpSb);\r
   Ip4IgmpTicking (IpSb);\r
 }\r
+\r
+/**\r
+  This dedicated timer is used to poll underlying network media status. In case\r
+  of cable swap or wireless network switch, a new round auto configuration will\r
+  be initiated. The timer will signal the IP4 to run DHCP configuration again.\r
+  IP4 driver will free old IP address related resource, such as route table and\r
+  Interface, then initiate a DHCP process to acquire new IP, eventually create\r
+  route table for new IP address.\r
+\r
+  @param[in]  Event                  The IP4 service instance's heart beat timer.\r
+  @param[in]  Context                The IP4 service instance.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ip4TimerReconfigChecking (\r
+  IN EFI_EVENT              Event,\r
+  IN VOID                   *Context\r
+  )\r
+{\r
+  IP4_SERVICE               *IpSb;\r
+  BOOLEAN                   OldMediaPresent;\r
+  EFI_STATUS                Status;\r
+  EFI_SIMPLE_NETWORK_MODE   SnpModeData;\r
+\r
+  IpSb = (IP4_SERVICE *) Context;\r
+  NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);\r
+\r
+  OldMediaPresent = IpSb->MediaPresent;\r
+\r
+  //\r
+  // Get fresh mode data from MNP, since underlying media status may change.\r
+  // Here, it needs to mention that the MediaPresent can also be checked even if\r
+  // EFI_NOT_STARTED returned while this MNP child driver instance isn't configured.\r
+  //\r
+  Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &SnpModeData);\r
+  if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {\r
+    return;\r
+  }\r
+\r
+  IpSb->MediaPresent = SnpModeData.MediaPresent;\r
+  //\r
+  // Media transimit Unpresent to Present means new link movement is detected.\r
+  //\r
+  if (!OldMediaPresent && IpSb->MediaPresent && (IpSb->Ip4Config2Instance.Policy == Ip4Config2PolicyDhcp)) {\r
+    //\r
+    // Signal the IP4 to run the dhcp configuration again. IP4 driver will free\r
+    // old IP address related resource, such as route table and Interface, then\r
+    // initiate a DHCP round to acquire new IP, eventually\r
+    // create route table for new IP address.\r
+    //\r
+    if (IpSb->ReconfigEvent != NULL) {\r
+      Status = gBS->SignalEvent (IpSb->ReconfigEvent);\r
+      DispatchDpc ();\r
+    }\r
+  }\r
+}\r