v2:
* Update the MediaPresent detect declaring.

IP4 driver should re-initiate a DHCP if it detects that there is a network 
reconnection.
To fix this issue, we can implement the DHCP re-initiate policy while the media
change detected. The Ip4 driver should set a timer to signal the Ip4 to run the
DHCP configuration again(D.O.R.A). IP4 driver should free old IP address related
resource, then initiate a DHCP process to acquire new IP.

Cc: Ye Ting <ting...@intel.com>
Cc: Zhang Lubo <lubo.zh...@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiaxin Wu <jiaxin...@intel.com>
---
 .../Universal/Network/Ip4Dxe/Ip4Config2Impl.c      |   1 +
 MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c  |  10 ++
 MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c    | 121 ++++++++++++++++++++-
 MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.h    |   7 ++
 4 files changed, 133 insertions(+), 6 deletions(-)

diff --git a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.c 
b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.c
index fcb2bdd..caf84fb 100644
--- a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.c
+++ b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Config2Impl.c
@@ -490,10 +490,11 @@ Ip4Config2SetDefaultAddr (
   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
   IpIf = IpSb->DefaultInterface;
   ASSERT (IpIf != NULL);
 
   if ((IpIf->Ip == StationAddress) && (IpIf->SubnetMask == SubnetMask)) {
+    IpSb->State = IP4_SERVICE_CONFIGED;
     return EFI_SUCCESS;
   }
 
   //
   // The default address is changed, free the previous interface first.
diff --git a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c 
b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c
index 101390c..4d3ccec 100644
--- a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c
+++ b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c
@@ -208,10 +208,14 @@ Ip4CreateService (
 
   ZeroMem (&IpSb->SnpMode, sizeof (EFI_SIMPLE_NETWORK_MODE));
 
   IpSb->Timer = NULL;
 
+  IpSb->ReconfigEvent = NULL;
+  
+  IpSb->MediaPresent = TRUE;
+
   //
   // Create various resources. First create the route table, timer
   // event and MNP child. IGMP, interface's initialization depend
   // on the MNP child.
   //
@@ -384,10 +388,16 @@ Ip4CleanService (
     gBS->CloseEvent (IpSb->Timer);
 
     IpSb->Timer = NULL;
   }
 
+  if (IpSb->ReconfigEvent != NULL) {
+    gBS->CloseEvent (IpSb->ReconfigEvent);
+
+    IpSb->ReconfigEvent = NULL;
+  }
+
   if (IpSb->MacString != NULL) {
     FreePool (IpSb->MacString);
   }
 
   Ip4Config2CleanInstance (&IpSb->Ip4Config2Instance);
diff --git a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c 
b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
index 2fb4f4c..ac8fb1a 100644
--- a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
+++ b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
@@ -561,10 +561,58 @@ Ip4InitProtocol (
 
   EfiInitializeLock (&IpInstance->RecycleLock, TPL_NOTIFY);
 }
 
 
+/**
+  The event handle for IP4 auto reconfiguration. The original default
+  interface and route table will be removed as the default.
+
+  @param[in]  Context                The IP4 service binding instance.
+
+**/
+VOID
+EFIAPI
+Ip4AutoReconfigCallBackDpc (
+  IN VOID                   *Context
+  )
+{
+  IP4_SERVICE               *IpSb;
+
+  IpSb      = (IP4_SERVICE *) Context;
+  NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
+
+  if (IpSb->State > IP4_SERVICE_UNSTARTED) {
+    IpSb->State = IP4_SERVICE_UNSTARTED;
+  }
+
+  Ip4StartAutoConfig (&IpSb->Ip4Config2Instance);
+
+  return ;
+}
+
+
+/**
+  Request Ip4AutoReconfigCallBackDpc as a DPC at TPL_CALLBACK.
+
+  @param Event     The event that is signalled.
+  @param Context   The IP4 service binding instance.
+
+**/
+VOID
+EFIAPI
+Ip4AutoReconfigCallBack (
+  IN EFI_EVENT              Event,
+  IN VOID                   *Context
+  )
+{
+  //
+  // Request Ip4AutoReconfigCallBackDpc as a DPC at TPL_CALLBACK
+  //
+  QueueDpc (TPL_CALLBACK, Ip4AutoReconfigCallBackDpc, Context);
+}
+
 
 /**
   Configure the IP4 child. If the child is already configured,
   change the configuration parameter. Otherwise configure it
   for the first time. The caller should validate the configuration
@@ -676,14 +724,31 @@ Ip4ConfigProtocol (
     //
     // Use the default address. If the default configuration hasn't
     // been started, start it.
     //
     if (IpSb->State == IP4_SERVICE_UNSTARTED) {
+      //
+      // Create the ReconfigEvent to start the new configuration.
+      //
+      if (IpSb->ReconfigEvent == NULL) {
+        Status = gBS->CreateEvent (
+                        EVT_NOTIFY_SIGNAL,
+                        TPL_NOTIFY,
+                        Ip4AutoReconfigCallBack,
+                        IpSb,
+                        &IpSb->ReconfigEvent
+                        );
+
+        if (EFI_ERROR (Status)) {
+          goto ON_ERROR;
+        }
+      }
+      
       Status = Ip4StartAutoConfig (&IpSb->Ip4Config2Instance);
 
       if (EFI_ERROR (Status)) {
-        goto ON_ERROR;
+        goto CLOSE_RECONFIG_EVENT;
       }
     }
 
     IpIf = IpSb->DefaultInterface;
     NET_GET_REF (IpSb->DefaultInterface);
@@ -709,11 +774,11 @@ Ip4ConfigProtocol (
                     gIp4DriverBinding.DriverBindingHandle,
                     IpInstance->Handle,
                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
                     );
     if (EFI_ERROR (Status)) {
-      goto ON_ERROR;
+      goto CLOSE_RECONFIG_EVENT;
     }
   }
   InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);
 
   CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
@@ -728,10 +793,16 @@ Ip4ConfigProtocol (
     return EFI_NO_MAPPING;
   }
 
   return EFI_SUCCESS;
 
+CLOSE_RECONFIG_EVENT:
+  if (IpSb->ReconfigEvent != NULL) {
+    gBS->CloseEvent (IpSb->ReconfigEvent);
+    IpSb->ReconfigEvent = NULL;
+  }
+
 ON_ERROR:
   Ip4FreeRouteTable (IpInstance->RouteTable);
   IpInstance->RouteTable = NULL;
   return Status;
 }
@@ -2293,14 +2364,20 @@ Ip4SentPacketTicking (
   return EFI_SUCCESS;
 }
 
 
 /**
-  The heart beat timer of IP4 service instance. It times out
-  all of its IP4 children's received-but-not-delivered and
-  transmitted-but-not-recycle packets, and provides time input
-  for its IGMP protocol.
+  There are two steps for this the heart beat timer of IP4 service instance. 
+  First, it times out all of its IP4 children's received-but-not-delivered 
+  and transmitted-but-not-recycle packets, and provides time input for its 
+  IGMP protocol.
+  Second, a dedicated timer is used to poll underlying media status. In case 
+  of cable swap, a new round auto configuration will be initiated. The timer 
+  will signal the IP4 to run DHCP configuration again. IP4 driver will free
+  old IP address related resource, such as route table and Interface, then
+  initiate a DHCP process to acquire new IP, eventually create route table 
+  for new IP address.
 
   @param[in]  Event                  The IP4 service instance's heart beat 
timer.
   @param[in]  Context                The IP4 service instance.
 
 **/
@@ -2310,12 +2387,44 @@ Ip4TimerTicking (
   IN EFI_EVENT              Event,
   IN VOID                   *Context
   )
 {
   IP4_SERVICE               *IpSb;
+  BOOLEAN                   OldMediaPresent;
+  EFI_STATUS                Status;
+  EFI_SIMPLE_NETWORK_MODE   SnpModeData;
 
   IpSb = (IP4_SERVICE *) Context;
   NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
+  
+  OldMediaPresent = IpSb->MediaPresent;
 
   Ip4PacketTimerTicking (IpSb);
   Ip4IgmpTicking (IpSb);
+
+  //
+  // Get fresh mode data from MNP, since underlying media status may change. 
+  // Here, it needs to mention that the MediaPresent can also be checked even 
if 
+  // EFI_NOT_STARTED returned while this MNP child driver instance isn't 
configured.
+  //
+  Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &SnpModeData);
+  if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {
+    return;
+  }
+
+  IpSb->MediaPresent = SnpModeData.MediaPresent;
+  //
+  // Media transimit Unpresent to Present means new link movement is detected.
+  //
+  if (!OldMediaPresent && IpSb->MediaPresent) {
+    //
+    // Signal the IP4 to run the dhcp configuration again. IP4 driver will free
+    // old IP address related resource, such as route table and Interface, 
then 
+    // initiate a DHCP round to acquire new IP, eventually 
+    // create route table for new IP address.
+    //
+    if (IpSb->ReconfigEvent != NULL) {
+      Status = gBS->SignalEvent (IpSb->ReconfigEvent);
+      DispatchDpc ();
+    }
+  }
 }
diff --git a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.h 
b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.h
index 84dfa80..4bb0089 100644
--- a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.h
+++ b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.h
@@ -201,10 +201,17 @@ struct _IP4_SERVICE {
   EFI_MANAGED_NETWORK_CONFIG_DATA MnpConfigData;
   EFI_SIMPLE_NETWORK_MODE         SnpMode;
 
   EFI_EVENT                       Timer;
 
+  EFI_EVENT                       ReconfigEvent;
+
+  //
+  // Underlying media present status. 
+  //
+  BOOLEAN                         MediaPresent;
+
   //
   // IPv4 Configuration II Protocol instance
   //
   IP4_CONFIG2_INSTANCE            Ip4Config2Instance;
 
-- 
1.9.5.msysgit.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to