[DHCPCSVC]
authorCameron Gutman <aicommander@gmail.com>
Fri, 13 Jan 2012 10:03:38 +0000 (10:03 +0000)
committerCameron Gutman <aicommander@gmail.com>
Fri, 13 Jan 2012 10:03:38 +0000 (10:03 +0000)
- Fix an issue assigning a private address after the IpReleaseAddress API was used prior to IpRenewAddress
- Move the IP refresh hack into dhcpcsvc so it now properly refresh IP information after an adapter is disconnected and reconnected (wired and wireless)
- When a state change occurs (connecting to a different wireless network or unplugging and plugging in the Ethernet cable), TCP/IP will flush routes and the neighbor cache then set the IP address to 0.0.0.0. DHCP will detect that IP address (that part is the hack since we do it via polling instead of events) then send a DHCP discover packet out via the new network connection. No more ipconfig /renew to get a new DHCP lease after network changes. It's all seamless now :D

svn path=/branches/wlan-bringup/; revision=54933

dll/win32/dhcpcsvc/dhcp/adapter.c
dll/win32/dhcpcsvc/dhcp/api.c
dll/win32/dhcpcsvc/dhcp/dhclient.c

index d79b76b..41b94d3 100644 (file)
@@ -200,6 +200,84 @@ InterfaceConnected(const MIB_IFROW* IfEntry)
     return 0;
 }
 
+BOOL
+IsReconnectHackNeeded(PDHCP_ADAPTER Adapter, const MIB_IFROW* IfEntry)
+{
+    struct protocol *proto;
+    PIP_ADAPTER_INFO AdapterInfo, Orig;
+    DWORD Size, Ret;
+    char *ZeroAddress = "0.0.0.0";
+
+    proto = find_protocol_by_adapter(&Adapter->DhclientInfo);
+
+    if (!proto)
+        return FALSE;
+
+    if (Adapter->DhclientInfo.client->state != S_BOUND)
+        return FALSE;
+    
+    ApiUnlock();
+
+    Orig = AdapterInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(IP_ADAPTER_INFO));
+    Size = sizeof(IP_ADAPTER_INFO);
+    if (!AdapterInfo)
+    {
+        ApiLock();
+        return FALSE;
+    }
+
+    Ret = GetAdaptersInfo(AdapterInfo, &Size);
+    if (Ret == ERROR_BUFFER_OVERFLOW)
+    {
+        HeapFree(GetProcessHeap(), 0, AdapterInfo);
+        AdapterInfo = HeapAlloc(GetProcessHeap(), 0, Size);
+        if (!AdapterInfo)
+        {
+            ApiLock();
+            return FALSE;
+        }
+
+        if (GetAdaptersInfo(AdapterInfo, &Size) != NO_ERROR)
+        {
+            ApiLock();
+            return FALSE;
+        }
+
+        Orig = AdapterInfo;
+        for (; AdapterInfo != NULL; AdapterInfo = AdapterInfo->Next)
+        {
+            if (AdapterInfo->Index == IfEntry->dwIndex)
+                break;
+        }
+
+        if (AdapterInfo == NULL)
+        {
+            HeapFree(GetProcessHeap(), 0, Orig);
+            ApiLock();
+            return FALSE;
+        }
+    }
+    else if (Ret != NO_ERROR)
+    {
+        HeapFree(GetProcessHeap(), 0, Orig);
+        ApiLock();
+        return FALSE;
+    }
+
+    if (!strcmp(AdapterInfo->IpAddressList.IpAddress.String, ZeroAddress))
+    {
+        HeapFree(GetProcessHeap(), 0, Orig);
+        ApiLock();
+        return TRUE;
+    }
+    else
+    {
+        HeapFree(GetProcessHeap(), 0, Orig);
+        ApiLock();
+        return FALSE;
+    }
+}
+
 /*
  * XXX Figure out the way to bind a specific adapter to a socket.
  */
@@ -241,12 +319,34 @@ DWORD WINAPI AdapterDiscoveryThread(LPVOID Context) {
 
             if ((Adapter = AdapterFindByHardwareAddress(Table->table[i].bPhysAddr, Table->table[i].dwPhysAddrLen)))
             {
+                proto = find_protocol_by_adapter(&Adapter->DhclientInfo);
+
                 /* This is an existing adapter */
                 if (InterfaceConnected(&Table->table[i])) {
                     /* We're still active so we stay in the list */
                     ifi = &Adapter->DhclientInfo;
+
+                    /* This is a hack because IP helper API sucks */
+                    if (IsReconnectHackNeeded(Adapter, &Table->table[i]))
+                    {
+                        /* This handles a disconnect/reconnect */
+
+                        remove_protocol(proto);
+                        Adapter->DhclientInfo.client->state = S_INIT;
+
+                        /* These are already invalid since the media state change */
+                        Adapter->RouterMib.dwForwardNextHop = 0;
+                        Adapter->NteContext = 0;
+
+                        add_protocol(Adapter->DhclientInfo.name,
+                                     Adapter->DhclientInfo.rfdesc,
+                                     got_one, &Adapter->DhclientInfo);
+                        state_init(&Adapter->DhclientInfo);
+
+                        SetEvent(AdapterStateChangedEvent);
+                    }
+
                 } else {
-                    proto = find_protocol_by_adapter(&Adapter->DhclientInfo);
                     if (proto)
                         remove_protocol(proto);
 
index 26723f9..2a9ba0f 100644 (file)
@@ -101,9 +101,15 @@ DWORD DSReleaseIpAddressLease( PipeSendFunc Send, COMM_DHCP_REQ *Req ) {
 
     if( Adapter ) {
         if (Adapter->NteContext)
+        {
             DeleteIPAddress( Adapter->NteContext );
+            Adapter->NteContext = 0;
+        }
         if (Adapter->RouterMib.dwForwardNextHop)
+        {
             DeleteIpForwardEntry( &Adapter->RouterMib );
+            Adapter->RouterMib.dwForwardNextHop = 0;
+        }
 
         proto = find_protocol_by_adapter( &Adapter->DhclientInfo );
         if (proto)
@@ -171,9 +177,15 @@ DWORD DSStaticRefreshParams( PipeSendFunc Send, COMM_DHCP_REQ *Req ) {
 
     if( Adapter ) {
         if (Adapter->NteContext)
+        {
             DeleteIPAddress( Adapter->NteContext );
+            Adapter->NteContext = 0;
+        }
         if (Adapter->RouterMib.dwForwardNextHop)
+        {
             DeleteIpForwardEntry( &Adapter->RouterMib );
+            Adapter->RouterMib.dwForwardNextHop = 0;
+        }
         
         Adapter->DhclientState.state = S_STATIC;
         proto = find_protocol_by_adapter( &Adapter->DhclientInfo );
index cbdb4fe..b8a49f4 100644 (file)
@@ -548,7 +548,10 @@ void setup_adapter( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) {
 
 
     if( Adapter->NteContext )
+    {
         DeleteIPAddress( Adapter->NteContext );
+        Adapter->NteContext = 0;
+    }
 
     /* Set up our default router if we got one from the DHCP server */
     if( new_lease->options[DHO_SUBNET_MASK].len ) {
@@ -1007,7 +1010,7 @@ send_discover(void *ipp)
           we haven't found anything for this interface yet. */
        if (interval > ip->client->config->timeout) {
                state_panic(ip);
-               return;
+        ip->client->first_sending = cur_time;
        }
 
        /* If we're selecting media, try the whole list before doing
@@ -1100,17 +1103,9 @@ state_panic(void *ipp)
 {
        struct interface_info *ip = ipp;
         PDHCP_ADAPTER Adapter = AdapterFindInfo(ip);
-       time_t cur_time;
-
-       time(&cur_time);
 
        note("No DHCPOFFERS received.");
 
-       note("No working leases in persistent database - sleeping.\n");
-       ip->client->state = S_INIT;
-       add_timeout(cur_time + ip->client->config->retry_interval, state_init,
-           ip);
-
         if (!Adapter->NteContext)
         {
             /* Generate an automatic private address */
@@ -1181,7 +1176,10 @@ send_request(void *ipp)
                discover a new address. */
 
             if( Adapter )
+            {
                 DeleteIPAddress( Adapter->NteContext );
+                Adapter->NteContext = 0;
+            }
 
             ip->client->state = S_INIT;
             state_init(ip);