From e8b08a9dd89f4cc44c725b1b0d3230da7daf56f0 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Fri, 13 Jan 2012 10:03:38 +0000 Subject: [PATCH] [DHCPCSVC] - 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 | 102 ++++++++++++++++++++++++++++- dll/win32/dhcpcsvc/dhcp/api.c | 12 ++++ dll/win32/dhcpcsvc/dhcp/dhclient.c | 16 ++--- 3 files changed, 120 insertions(+), 10 deletions(-) diff --git a/dll/win32/dhcpcsvc/dhcp/adapter.c b/dll/win32/dhcpcsvc/dhcp/adapter.c index d79b76b112b..41b94d332c0 100644 --- a/dll/win32/dhcpcsvc/dhcp/adapter.c +++ b/dll/win32/dhcpcsvc/dhcp/adapter.c @@ -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); diff --git a/dll/win32/dhcpcsvc/dhcp/api.c b/dll/win32/dhcpcsvc/dhcp/api.c index 26723f9c38e..2a9ba0fd5e3 100644 --- a/dll/win32/dhcpcsvc/dhcp/api.c +++ b/dll/win32/dhcpcsvc/dhcp/api.c @@ -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 ); diff --git a/dll/win32/dhcpcsvc/dhcp/dhclient.c b/dll/win32/dhcpcsvc/dhcp/dhclient.c index cbdb4fef4c9..b8a49f4ccdd 100644 --- a/dll/win32/dhcpcsvc/dhcp/dhclient.c +++ b/dll/win32/dhcpcsvc/dhcp/dhclient.c @@ -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); -- 2.17.1