961 lines
23 KiB
C
961 lines
23 KiB
C
|
/*
|
||
|
|
||
|
Copyright (c) 1998, Microsoft Corporation, all rights reserved
|
||
|
|
||
|
Description:
|
||
|
Only the timer thread can call the following functions:
|
||
|
rasDhcpAllocateAddress, rasDhcpMonitorAddresses, rasDhcpRenewLease. This is
|
||
|
required to avoid race conditions in the timer queue (because these
|
||
|
functions call RasDhcpTimerSchedule). The only exception is that
|
||
|
RasDhcpInitialize can call RasDhcpTimerSchedule, but before the timer thread
|
||
|
is started. rasDhcpRenewLease leaves and enters the critical section in the
|
||
|
middle of the function. If pAddrInfo is freed in the meantime, there will be
|
||
|
an AV. However, only rasDhcpDeleteLists frees pAddrInfo's from the list.
|
||
|
Fortunately, only RasDhcpUninitialize (after stopping the timer thread) and
|
||
|
rasDhcpAllocateAddress (which belongs to the timer thread) call
|
||
|
rasDhcpDeleteLists.
|
||
|
|
||
|
If we get an EasyNet address, DHCP has already made sure that it is not
|
||
|
conflicting with anyone. We call SetProxyArp, so that no one else in the
|
||
|
future will take it (if they are well behaved).
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "rasdhcp_.h"
|
||
|
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
Notes:
|
||
|
There is no synchronization here, can be added easily but the assumption
|
||
|
here is that the initialization is a synchronous operation and till it
|
||
|
completes, no other code in this sub-system will be called.
|
||
|
|
||
|
*/
|
||
|
|
||
|
DWORD
|
||
|
RasDhcpInitialize(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
DWORD dwErr = NO_ERROR;
|
||
|
|
||
|
TraceHlp("RasDhcpInitialize");
|
||
|
|
||
|
EnterCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
RtlGetNtProductType(&RasDhcpNtProductType);
|
||
|
|
||
|
if (NtProductWinNt == RasDhcpNtProductType)
|
||
|
{
|
||
|
RasDhcpNumReqAddrs = 2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RasDhcpNumReqAddrs = HelperRegVal.dwChunkSize;
|
||
|
}
|
||
|
|
||
|
// This should be done before we start the timer thread. Once the timer
|
||
|
// thread starts, only it can call RasDhcpTimerSchedule (to avoid race
|
||
|
// conditions).
|
||
|
|
||
|
RasDhcpTimerSchedule(
|
||
|
&RasDhcpMonitorTimer,
|
||
|
0,
|
||
|
rasDhcpMonitorAddresses);
|
||
|
|
||
|
dwErr = RasDhcpTimerInitialize();
|
||
|
|
||
|
if (NO_ERROR != dwErr)
|
||
|
{
|
||
|
TraceHlp("RasDhcpInitTimer failed and returned %d", dwErr);
|
||
|
goto LDone;
|
||
|
}
|
||
|
|
||
|
LDone:
|
||
|
|
||
|
if (NO_ERROR != dwErr)
|
||
|
{
|
||
|
RasDhcpTimerUninitialize();
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
return(dwErr);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
VOID
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
*/
|
||
|
|
||
|
VOID
|
||
|
RasDhcpUninitialize(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
TraceHlp("RasDhcpUninitialize");
|
||
|
|
||
|
/*
|
||
|
Do not hold RasDhcpCriticalSection while calling this function. Otherwise,
|
||
|
the following deadlock can occur: The timer thread is blocked in
|
||
|
rasDhcpAllocateAddress, waiting for RasDhcpCriticalSection, and this thread
|
||
|
is blocked in RasDhcpTimerUninitialize, waiting for the timer thread to
|
||
|
stop.
|
||
|
*/
|
||
|
RasDhcpTimerUninitialize();
|
||
|
|
||
|
EnterCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
/*
|
||
|
To avoid a possible race condition in rasDhcpRenewLease (see the comments
|
||
|
in that function), it is important to call RasDhcpTimerUninitialize and
|
||
|
kill the timer thread before calling rasDhcpDeleteLists.
|
||
|
*/
|
||
|
rasDhcpDeleteLists();
|
||
|
|
||
|
RasDhcpUsingEasyNet = TRUE;
|
||
|
|
||
|
LeaveCriticalSection(&RasDhcpCriticalSection);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
*/
|
||
|
|
||
|
DWORD
|
||
|
RasDhcpAcquireAddress(
|
||
|
IN HPORT hPort,
|
||
|
OUT IPADDR* pnboIpAddr,
|
||
|
OUT IPADDR* pnboIpMask,
|
||
|
OUT BOOL* pfEasyNet
|
||
|
)
|
||
|
{
|
||
|
ADDR_INFO* pAddrInfo;
|
||
|
DWORD dwErr = ERROR_NOT_FOUND;
|
||
|
|
||
|
TraceHlp("RasDhcpAcquireAddress");
|
||
|
|
||
|
EnterCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
if (NULL == RasDhcpFreePool)
|
||
|
{
|
||
|
TraceHlp("Out of addresses");
|
||
|
goto LDone;
|
||
|
}
|
||
|
|
||
|
// Move from Free pool to Alloc pool
|
||
|
pAddrInfo = RasDhcpFreePool;
|
||
|
RasDhcpFreePool = RasDhcpFreePool->ai_Next;
|
||
|
pAddrInfo->ai_Next = RasDhcpAllocPool;
|
||
|
RasDhcpAllocPool = pAddrInfo;
|
||
|
|
||
|
TraceHlp("Acquired 0x%x", pAddrInfo->ai_LeaseInfo.IpAddress);
|
||
|
*pnboIpAddr = htonl(pAddrInfo->ai_LeaseInfo.IpAddress);
|
||
|
*pnboIpMask = htonl(pAddrInfo->ai_LeaseInfo.SubnetMask);
|
||
|
pAddrInfo->ai_hPort = hPort;
|
||
|
pAddrInfo->ai_Flags |= AI_FLAG_IN_USE;
|
||
|
|
||
|
if (NULL != pfEasyNet)
|
||
|
{
|
||
|
*pfEasyNet = RasDhcpUsingEasyNet;
|
||
|
}
|
||
|
|
||
|
if ( (NULL == RasDhcpFreePool)
|
||
|
&& (0 == RasDhcpNumReqAddrs))
|
||
|
{
|
||
|
// We don't have any more addresses to give out. Let us
|
||
|
// acquire another chunk of them.
|
||
|
|
||
|
if (NtProductWinNt == RasDhcpNtProductType)
|
||
|
{
|
||
|
RasDhcpNumReqAddrs += 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RasDhcpNumReqAddrs += HelperRegVal.dwChunkSize;
|
||
|
}
|
||
|
|
||
|
RasDhcpTimerRunNow();
|
||
|
}
|
||
|
|
||
|
dwErr = NO_ERROR;
|
||
|
|
||
|
LDone:
|
||
|
|
||
|
LeaveCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
return(dwErr);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
VOID
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
*/
|
||
|
|
||
|
VOID
|
||
|
RasDhcpReleaseAddress(
|
||
|
IN IPADDR nboIpAddr
|
||
|
)
|
||
|
{
|
||
|
ADDR_INFO* pAddrInfo;
|
||
|
ADDR_INFO** ppAddrInfo;
|
||
|
IPADDR hboIpAddr;
|
||
|
|
||
|
TraceHlp("RasDhcpReleaseAddress");
|
||
|
|
||
|
EnterCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
hboIpAddr = ntohl(nboIpAddr);
|
||
|
|
||
|
for (ppAddrInfo = &RasDhcpAllocPool;
|
||
|
(pAddrInfo = *ppAddrInfo) != NULL;
|
||
|
ppAddrInfo = &pAddrInfo->ai_Next)
|
||
|
{
|
||
|
if (pAddrInfo->ai_LeaseInfo.IpAddress == hboIpAddr)
|
||
|
{
|
||
|
TraceHlp("Released 0x%x", nboIpAddr);
|
||
|
|
||
|
// Unlink from alloc pool
|
||
|
*ppAddrInfo = pAddrInfo->ai_Next;
|
||
|
|
||
|
// Put at the end of the free pool, because we want to round-robin
|
||
|
// the addresses.
|
||
|
pAddrInfo->ai_Next = NULL;
|
||
|
|
||
|
ppAddrInfo = &RasDhcpFreePool;
|
||
|
while (NULL != *ppAddrInfo)
|
||
|
{
|
||
|
ppAddrInfo = &((*ppAddrInfo)->ai_Next);
|
||
|
}
|
||
|
*ppAddrInfo = pAddrInfo;
|
||
|
|
||
|
pAddrInfo->ai_Flags &= ~AI_FLAG_IN_USE;
|
||
|
goto LDone;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHlp("IpAddress 0x%x not present in alloc pool", nboIpAddr);
|
||
|
|
||
|
LDone:
|
||
|
|
||
|
LeaveCriticalSection(&RasDhcpCriticalSection);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
Notes:
|
||
|
Allocate an address from the DHCP server.
|
||
|
|
||
|
*/
|
||
|
|
||
|
DWORD
|
||
|
rasDhcpAllocateAddress(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
IPADDR nboIpAddress;
|
||
|
ADDR_INFO* pAddrInfo = NULL;
|
||
|
DHCP_OPTION_INFO* pOptionInfo = NULL;
|
||
|
DHCP_LEASE_INFO* pLeaseInfo = NULL;
|
||
|
AVAIL_INDEX* pAvailIndex;
|
||
|
time_t now = time(NULL);
|
||
|
BOOL fEasyNet = FALSE;
|
||
|
BOOL fPutInAvailList = FALSE;
|
||
|
BOOL fCSEntered = FALSE;
|
||
|
BYTE bAddress[MAX_ADAPTER_ADDRESS_LENGTH];
|
||
|
CHAR szIpAddress[MAXIPSTRLEN + 1];
|
||
|
CHAR* sz;
|
||
|
PPPE_MESSAGE PppMessage;
|
||
|
DWORD dwErr = NO_ERROR;
|
||
|
|
||
|
TraceHlp("rasDhcpAllocateAddress");
|
||
|
|
||
|
dwErr = GetPreferredAdapterInfo(&nboIpAddress, NULL, NULL, NULL, NULL,
|
||
|
bAddress);
|
||
|
|
||
|
if (NO_ERROR != dwErr)
|
||
|
{
|
||
|
// There is probably no NIC on the machine
|
||
|
nboIpAddress = htonl(INADDR_LOOPBACK);
|
||
|
}
|
||
|
|
||
|
pAddrInfo = LocalAlloc(LPTR, sizeof(ADDR_INFO));
|
||
|
|
||
|
if (pAddrInfo == NULL)
|
||
|
{
|
||
|
dwErr = GetLastError();
|
||
|
TraceHlp("LocalAlloc failed and returned %d", dwErr);
|
||
|
goto LDone;
|
||
|
}
|
||
|
|
||
|
// Initialize the structure.
|
||
|
|
||
|
rasDhcpInitializeAddrInfo(pAddrInfo, bAddress, &fPutInAvailList);
|
||
|
|
||
|
// Call DHCP to allocate an IP address.
|
||
|
|
||
|
dwErr = PDhcpLeaseIpAddress(
|
||
|
ntohl(nboIpAddress),
|
||
|
&pAddrInfo->ai_LeaseInfo.ClientUID,
|
||
|
0,
|
||
|
NULL,
|
||
|
&pLeaseInfo,
|
||
|
&pOptionInfo);
|
||
|
|
||
|
if (ERROR_SUCCESS != dwErr)
|
||
|
{
|
||
|
pLeaseInfo = NULL;
|
||
|
pOptionInfo = NULL;
|
||
|
TraceHlp("DhcpLeaseIpAddress failed and returned %d", dwErr);
|
||
|
goto LDone;
|
||
|
}
|
||
|
|
||
|
// Copy stuff into the pAddrInfo structure
|
||
|
|
||
|
pAddrInfo->ai_LeaseInfo.IpAddress = pLeaseInfo->IpAddress;
|
||
|
pAddrInfo->ai_LeaseInfo.SubnetMask = pLeaseInfo->SubnetMask;
|
||
|
pAddrInfo->ai_LeaseInfo.DhcpServerAddress = pLeaseInfo->DhcpServerAddress;
|
||
|
pAddrInfo->ai_LeaseInfo.Lease = pLeaseInfo->Lease;
|
||
|
pAddrInfo->ai_LeaseInfo.LeaseObtained = pLeaseInfo->LeaseObtained;
|
||
|
pAddrInfo->ai_LeaseInfo.T1Time = pLeaseInfo->T1Time;
|
||
|
pAddrInfo->ai_LeaseInfo.T2Time = pLeaseInfo->T2Time;
|
||
|
pAddrInfo->ai_LeaseInfo.LeaseExpires = pLeaseInfo->LeaseExpires;
|
||
|
|
||
|
EnterCriticalSection(&RasDhcpCriticalSection);
|
||
|
fCSEntered = TRUE;
|
||
|
|
||
|
if (-1 == (DWORD)(pLeaseInfo->DhcpServerAddress))
|
||
|
{
|
||
|
fEasyNet = TRUE;
|
||
|
|
||
|
if (!RasDhcpUsingEasyNet)
|
||
|
{
|
||
|
dwErr = E_FAIL;
|
||
|
TraceHlp("Not accepting any more EasyNet addresses");
|
||
|
goto LDone;
|
||
|
}
|
||
|
|
||
|
AbcdSzFromIpAddress(htonl(pLeaseInfo->IpAddress), szIpAddress);
|
||
|
sz = szIpAddress;
|
||
|
|
||
|
LogEvent(EVENTLOG_WARNING_TYPE, ROUTERLOG_AUTONET_ADDRESS, 1,
|
||
|
(CHAR**)&sz);
|
||
|
|
||
|
// We undo this call to RasTcpSetProxyArp in rasDhcpDeleteLists.
|
||
|
|
||
|
RasTcpSetProxyArp(htonl(pLeaseInfo->IpAddress), TRUE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (RasDhcpUsingEasyNet)
|
||
|
{
|
||
|
rasDhcpDeleteLists();
|
||
|
// We have already used up index 0 to get this address
|
||
|
RasDhcpNextIndex = 1;
|
||
|
RasDhcpUsingEasyNet = FALSE;
|
||
|
|
||
|
PppMessage.dwMsgId = PPPEMSG_IpAddressLeaseExpired;
|
||
|
PppMessage.ExtraInfo.IpAddressLeaseExpired.nboIpAddr = 0;
|
||
|
SendPPPMessageToEngine(&PppMessage);
|
||
|
}
|
||
|
|
||
|
if (NULL != PEnableDhcpInformServer)
|
||
|
{
|
||
|
// Redirect DHCP inform packets to this server.
|
||
|
PEnableDhcpInformServer(htonl(pLeaseInfo->DhcpServerAddress));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pAddrInfo->ai_Next = RasDhcpFreePool;
|
||
|
RasDhcpFreePool = pAddrInfo;
|
||
|
if (0 < RasDhcpNumReqAddrs)
|
||
|
{
|
||
|
// We need one less address now.
|
||
|
RasDhcpNumReqAddrs--;
|
||
|
}
|
||
|
|
||
|
RasDhcpNumAddrsAlloced++;
|
||
|
|
||
|
TraceHlp("Allocated address 0x%x using 0x%x, timer %ld%s",
|
||
|
pAddrInfo->ai_LeaseInfo.IpAddress,
|
||
|
nboIpAddress,
|
||
|
pAddrInfo->ai_LeaseInfo.T1Time - now,
|
||
|
fEasyNet ? ", EasyNet" : "");
|
||
|
|
||
|
if (!fEasyNet)
|
||
|
{
|
||
|
// Start timer for lease renewal
|
||
|
RasDhcpTimerSchedule(
|
||
|
&pAddrInfo->ai_Timer,
|
||
|
(LONG)(pAddrInfo->ai_LeaseInfo.T1Time - now),
|
||
|
rasDhcpRenewLease);
|
||
|
}
|
||
|
|
||
|
LDone:
|
||
|
|
||
|
if (fCSEntered)
|
||
|
{
|
||
|
LeaveCriticalSection(&RasDhcpCriticalSection);
|
||
|
}
|
||
|
|
||
|
if (NO_ERROR != dwErr)
|
||
|
{
|
||
|
if (fPutInAvailList)
|
||
|
{
|
||
|
pAvailIndex = LocalAlloc(LPTR, sizeof(AVAIL_INDEX));
|
||
|
|
||
|
if (NULL == pAvailIndex)
|
||
|
{
|
||
|
TraceHlp("Couldn't put index %d in the avail list. "
|
||
|
"Out of memory", pAddrInfo->ai_ClientUIDWords[3]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
EnterCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
pAvailIndex->dwIndex = pAddrInfo->ai_ClientUIDWords[3];
|
||
|
pAvailIndex->pNext = RasDhcpAvailIndexes;
|
||
|
RasDhcpAvailIndexes = pAvailIndex;
|
||
|
|
||
|
LeaveCriticalSection(&RasDhcpCriticalSection);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LocalFree(pAddrInfo);
|
||
|
}
|
||
|
|
||
|
LocalFree(pLeaseInfo);
|
||
|
LocalFree(pOptionInfo);
|
||
|
|
||
|
return(dwErr);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
VOID
|
||
|
|
||
|
Notes:
|
||
|
Renew the lease on an address with the DHCP server. This is also called by
|
||
|
the timer thread when the its time to renew the lease.
|
||
|
|
||
|
*/
|
||
|
|
||
|
VOID
|
||
|
rasDhcpRenewLease(
|
||
|
IN HANDLE rasDhcpTimerShutdown,
|
||
|
IN TIMERLIST* pTimer
|
||
|
)
|
||
|
{
|
||
|
IPADDR nboIpAddress;
|
||
|
ADDR_INFO* pAddrInfo;
|
||
|
ADDR_INFO** ppAddrInfo;
|
||
|
DHCP_OPTION_INFO* pOptionInfo = NULL;
|
||
|
AVAIL_INDEX* pAvailIndex;
|
||
|
time_t now = time(NULL);
|
||
|
IPADDR nboIpAddrTemp = 0;
|
||
|
PPPE_MESSAGE PppMessage;
|
||
|
BOOL fNeedToRenew;
|
||
|
DWORD dwErr;
|
||
|
|
||
|
TraceHlp("rasDhcpRenewLease");
|
||
|
|
||
|
dwErr = GetPreferredAdapterInfo(&nboIpAddress, NULL, NULL, NULL, NULL,
|
||
|
NULL);
|
||
|
|
||
|
if (NO_ERROR != dwErr)
|
||
|
{
|
||
|
TraceHlp("Couldn't get a NIC IP Address. Unable to renew lease");
|
||
|
goto LDone;
|
||
|
}
|
||
|
|
||
|
EnterCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
pAddrInfo = CONTAINING_RECORD(pTimer, ADDR_INFO, ai_Timer);
|
||
|
|
||
|
TraceHlp("address 0x%x", pAddrInfo->ai_LeaseInfo.IpAddress);
|
||
|
|
||
|
pAddrInfo->ai_Flags |= AI_FLAG_RENEW;
|
||
|
|
||
|
fNeedToRenew = rasDhcpNeedToRenewLease(pAddrInfo);
|
||
|
|
||
|
LeaveCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
/*
|
||
|
A race condition can occur if a thread other than this thread (the timer
|
||
|
thread) calls rasDhcpDeleteLists when we are here. rasDhcpAllocateAddress
|
||
|
calls rasDhcpDeleteLists, but only the timer thread calls
|
||
|
rasDhcpAllocateAddress. RasDhcpUninitialize also calls rasDhcpDeleteLists,
|
||
|
but it calls RasDhcpTimerUninitialize first. Before RasDhcpTimerUninitialize
|
||
|
returns, the timer thread exits, so it is impossible for us to be here.
|
||
|
|
||
|
In the worst case, DhcpRenewIpAddressLease might take up to 60 sec. In the
|
||
|
average case, it is 2-10 sec.
|
||
|
*/
|
||
|
|
||
|
if (fNeedToRenew)
|
||
|
{
|
||
|
dwErr = PDhcpRenewIpAddressLease(
|
||
|
ntohl(nboIpAddress),
|
||
|
&pAddrInfo->ai_LeaseInfo,
|
||
|
NULL,
|
||
|
&pOptionInfo);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Simulate not being able to renew
|
||
|
dwErr = ERROR_ACCESS_DENIED;
|
||
|
}
|
||
|
|
||
|
EnterCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
if (dwErr == ERROR_SUCCESS)
|
||
|
{
|
||
|
pAddrInfo->ai_Flags &= ~AI_FLAG_RENEW;
|
||
|
|
||
|
TraceHlp("success for address 0x%x, resched timer %ld",
|
||
|
pAddrInfo->ai_LeaseInfo.IpAddress,
|
||
|
pAddrInfo->ai_LeaseInfo.T1Time - now);
|
||
|
|
||
|
// Start timer to renew
|
||
|
|
||
|
RasDhcpTimerSchedule(
|
||
|
pTimer,
|
||
|
(LONG)(pAddrInfo->ai_LeaseInfo.T1Time - now),
|
||
|
rasDhcpRenewLease);
|
||
|
}
|
||
|
else if ( (ERROR_ACCESS_DENIED == dwErr)
|
||
|
|| (now > pAddrInfo->ai_LeaseInfo.T2Time))
|
||
|
{
|
||
|
TraceHlp("failed for address 0x%x", pAddrInfo->ai_LeaseInfo.IpAddress);
|
||
|
|
||
|
if (fNeedToRenew)
|
||
|
{
|
||
|
RasDhcpNumReqAddrs++;
|
||
|
}
|
||
|
|
||
|
if (RasDhcpNumAddrsAlloced > 0)
|
||
|
{
|
||
|
RasDhcpNumAddrsAlloced--;
|
||
|
}
|
||
|
|
||
|
// Cannot renew lease. Blow this away.
|
||
|
|
||
|
nboIpAddrTemp = htonl(pAddrInfo->ai_LeaseInfo.IpAddress);
|
||
|
|
||
|
// Unlink this structure from the list and cleanup
|
||
|
|
||
|
ppAddrInfo = (pAddrInfo->ai_Flags & AI_FLAG_IN_USE) ?
|
||
|
&RasDhcpAllocPool : &RasDhcpFreePool;
|
||
|
|
||
|
for (; *ppAddrInfo != NULL; ppAddrInfo = &(*ppAddrInfo)->ai_Next)
|
||
|
{
|
||
|
if (pAddrInfo == *ppAddrInfo)
|
||
|
{
|
||
|
pAvailIndex = LocalAlloc(LPTR, sizeof(AVAIL_INDEX));
|
||
|
|
||
|
if (NULL == pAvailIndex)
|
||
|
{
|
||
|
TraceHlp("Couldn't put index %d in the avail list. "
|
||
|
"Out of memory", pAddrInfo->ai_ClientUIDWords[3]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pAvailIndex->dwIndex = pAddrInfo->ai_ClientUIDWords[3];
|
||
|
pAvailIndex->pNext = RasDhcpAvailIndexes;
|
||
|
RasDhcpAvailIndexes = pAvailIndex;
|
||
|
}
|
||
|
|
||
|
*ppAddrInfo = pAddrInfo->ai_Next;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
rasDhcpFreeAddress(pAddrInfo);
|
||
|
LocalFree(pAddrInfo);
|
||
|
|
||
|
PppMessage.dwMsgId = PPPEMSG_IpAddressLeaseExpired;
|
||
|
PppMessage.ExtraInfo.IpAddressLeaseExpired.nboIpAddr = nboIpAddrTemp;
|
||
|
SendPPPMessageToEngine(&PppMessage);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceHlp("Error %d. Will try again later.", dwErr);
|
||
|
TraceHlp("Seconds left before expiry: %d",
|
||
|
pAddrInfo->ai_LeaseInfo.T2Time - now);
|
||
|
|
||
|
// Could not contact the Dhcp Server, retry in a little bit
|
||
|
RasDhcpTimerSchedule(pTimer, RETRY_TIME, rasDhcpRenewLease);
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
LDone:
|
||
|
|
||
|
LocalFree(pOptionInfo);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
|
||
|
Notes:
|
||
|
We call DHCP to release the address.
|
||
|
|
||
|
*/
|
||
|
|
||
|
VOID
|
||
|
rasDhcpFreeAddress(
|
||
|
IN ADDR_INFO* pAddrInfo
|
||
|
)
|
||
|
{
|
||
|
IPADDR nboIpAddress;
|
||
|
DWORD dwErr;
|
||
|
|
||
|
RTASSERT(NULL != pAddrInfo);
|
||
|
|
||
|
TraceHlp("rasDhcpFreeAddress 0x%x", pAddrInfo->ai_LeaseInfo.IpAddress);
|
||
|
|
||
|
dwErr = GetPreferredAdapterInfo(&nboIpAddress, NULL, NULL, NULL, NULL,
|
||
|
NULL);
|
||
|
|
||
|
if (NO_ERROR != dwErr)
|
||
|
{
|
||
|
TraceHlp("Couldn't get a NIC IP Address. Unable to release address");
|
||
|
goto LDone;
|
||
|
}
|
||
|
|
||
|
// Call DHCP to release the address.
|
||
|
|
||
|
dwErr = PDhcpReleaseIpAddressLease(ntohl(nboIpAddress),
|
||
|
&pAddrInfo->ai_LeaseInfo);
|
||
|
|
||
|
if (ERROR_SUCCESS != dwErr)
|
||
|
{
|
||
|
TraceHlp("DhcpReleaseIpAddressLease failed and returned %d", dwErr);
|
||
|
}
|
||
|
|
||
|
if (RasDhcpNumAddrsAlloced > 0)
|
||
|
{
|
||
|
RasDhcpNumAddrsAlloced--;
|
||
|
}
|
||
|
|
||
|
LDone:
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
VOID
|
||
|
|
||
|
Notes:
|
||
|
If we don't have enough addresses (because lease renewal failed or we were
|
||
|
unable to allocate), try to acquire some. The argument pTimer is not used.
|
||
|
|
||
|
*/
|
||
|
|
||
|
VOID
|
||
|
rasDhcpMonitorAddresses(
|
||
|
IN HANDLE rasDhcpTimerShutdown,
|
||
|
IN TIMERLIST* pTimer
|
||
|
)
|
||
|
{
|
||
|
DWORD dwErr;
|
||
|
|
||
|
while (TRUE)
|
||
|
{
|
||
|
EnterCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
if (0 == RasDhcpNumReqAddrs)
|
||
|
{
|
||
|
LeaveCriticalSection(&RasDhcpCriticalSection);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (RasDhcpNumAddrsAlloced >= rasDhcpMaxAddrsToAllocate())
|
||
|
{
|
||
|
RasDhcpNumReqAddrs = 0;
|
||
|
LeaveCriticalSection(&RasDhcpCriticalSection);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
dwErr = rasDhcpAllocateAddress();
|
||
|
|
||
|
if (NO_ERROR != dwErr)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (WaitForSingleObject(rasDhcpTimerShutdown, 10) != WAIT_TIMEOUT)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Start timer to monitor if we are running short on addresses etc.
|
||
|
|
||
|
RasDhcpTimerSchedule(
|
||
|
&RasDhcpMonitorTimer,
|
||
|
0,
|
||
|
rasDhcpMonitorAddresses);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
VOID
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
*/
|
||
|
|
||
|
VOID
|
||
|
rasDhcpInitializeAddrInfo(
|
||
|
IN OUT ADDR_INFO* pNewAddrInfo,
|
||
|
IN BYTE* pbAddress,
|
||
|
OUT BOOL* pfPutInAvailList
|
||
|
)
|
||
|
{
|
||
|
DWORD dwIndex;
|
||
|
AVAIL_INDEX* pAvailIndex;
|
||
|
|
||
|
RTASSERT(NULL != pNewAddrInfo);
|
||
|
|
||
|
TraceHlp("rasDhcpInitializeAddrInfo");
|
||
|
|
||
|
EnterCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
// ClientUIDBase is a combination of RAS_PREPEND (4 chars),
|
||
|
// MAC address (8 chars), Index (4 chars)
|
||
|
|
||
|
if (RasDhcpUsingEasyNet)
|
||
|
{
|
||
|
dwIndex = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*pfPutInAvailList = TRUE;
|
||
|
|
||
|
if (NULL != RasDhcpAvailIndexes)
|
||
|
{
|
||
|
pAvailIndex = RasDhcpAvailIndexes;
|
||
|
dwIndex = pAvailIndex->dwIndex;
|
||
|
RasDhcpAvailIndexes = RasDhcpAvailIndexes->pNext;
|
||
|
LocalFree(pAvailIndex);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwIndex = RasDhcpNextIndex++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHlp("dwIndex = %d", dwIndex);
|
||
|
|
||
|
strcpy(pNewAddrInfo->ai_ClientUIDBuf, RAS_PREPEND);
|
||
|
memcpy(pNewAddrInfo->ai_ClientUIDBuf + strlen(RAS_PREPEND),
|
||
|
pbAddress, MAX_ADAPTER_ADDRESS_LENGTH);
|
||
|
pNewAddrInfo->ai_ClientUIDWords[3] = dwIndex;
|
||
|
|
||
|
pNewAddrInfo->ai_LeaseInfo.ClientUID.ClientUID =
|
||
|
pNewAddrInfo->ai_ClientUIDBuf;
|
||
|
pNewAddrInfo->ai_LeaseInfo.ClientUID.ClientUIDLength =
|
||
|
sizeof(pNewAddrInfo->ai_ClientUIDBuf);
|
||
|
|
||
|
LeaveCriticalSection(&RasDhcpCriticalSection);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
VOID
|
||
|
|
||
|
Notes:
|
||
|
Delete proxy arp entries for easy net addresses.
|
||
|
|
||
|
*/
|
||
|
|
||
|
VOID
|
||
|
rasDhcpDeleteLists(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
ADDR_INFO* pAddrInfo;
|
||
|
ADDR_INFO* pTempAddrInfo;
|
||
|
ADDR_INFO* pList[2] = {RasDhcpAllocPool, RasDhcpFreePool};
|
||
|
AVAIL_INDEX* pAvailIndex;
|
||
|
AVAIL_INDEX* pTempAvailIndex;
|
||
|
DWORD dwIndex;
|
||
|
|
||
|
TraceHlp("rasDhcpDeleteLists");
|
||
|
|
||
|
EnterCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
for (dwIndex = 0; dwIndex < 2; dwIndex++)
|
||
|
{
|
||
|
pAddrInfo = pList[dwIndex];
|
||
|
while (pAddrInfo != NULL)
|
||
|
{
|
||
|
if (RasDhcpUsingEasyNet)
|
||
|
{
|
||
|
RasTcpSetProxyArp(htonl(pAddrInfo->ai_LeaseInfo.IpAddress),
|
||
|
FALSE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rasDhcpFreeAddress(pAddrInfo);
|
||
|
}
|
||
|
pTempAddrInfo = pAddrInfo;
|
||
|
pAddrInfo = pAddrInfo->ai_Next;
|
||
|
LocalFree(pTempAddrInfo);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (pAvailIndex = RasDhcpAvailIndexes; NULL != pAvailIndex;)
|
||
|
{
|
||
|
pTempAvailIndex = pAvailIndex;
|
||
|
pAvailIndex = pAvailIndex->pNext;
|
||
|
LocalFree(pTempAvailIndex);
|
||
|
}
|
||
|
|
||
|
RasDhcpAllocPool = NULL;
|
||
|
RasDhcpFreePool = NULL;
|
||
|
RasDhcpAvailIndexes = NULL;
|
||
|
if (NtProductWinNt == RasDhcpNtProductType)
|
||
|
{
|
||
|
RasDhcpNumReqAddrs = 2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RasDhcpNumReqAddrs = HelperRegVal.dwChunkSize;
|
||
|
}
|
||
|
RasDhcpNextIndex = 0;
|
||
|
RasDhcpNumAddrsAlloced = 0;
|
||
|
|
||
|
LeaveCriticalSection(&RasDhcpCriticalSection);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
VOID
|
||
|
|
||
|
Notes:
|
||
|
Should we bother to renew the lease?
|
||
|
|
||
|
*/
|
||
|
|
||
|
BOOL
|
||
|
rasDhcpNeedToRenewLease(
|
||
|
IN ADDR_INFO* pAddrInfo
|
||
|
)
|
||
|
{
|
||
|
BOOL fRet = TRUE;
|
||
|
DWORD dwCount = 0;
|
||
|
ADDR_INFO* pTemp;
|
||
|
|
||
|
TraceHlp("rasDhcpNeedToRenewLease");
|
||
|
|
||
|
EnterCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
if (pAddrInfo->ai_Flags & AI_FLAG_IN_USE)
|
||
|
{
|
||
|
goto LDone;
|
||
|
}
|
||
|
|
||
|
// How many free addresses do we have?
|
||
|
|
||
|
for (pTemp = RasDhcpFreePool; pTemp != NULL; pTemp = pTemp->ai_Next)
|
||
|
{
|
||
|
dwCount++;
|
||
|
}
|
||
|
|
||
|
if (dwCount > HelperRegVal.dwChunkSize)
|
||
|
{
|
||
|
fRet = FALSE;
|
||
|
}
|
||
|
|
||
|
LDone:
|
||
|
|
||
|
TraceHlp("Need to renew: %s", fRet ? "TRUE" : "FALSE");
|
||
|
|
||
|
LeaveCriticalSection(&RasDhcpCriticalSection);
|
||
|
|
||
|
return(fRet);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
The maximum number of addresses that we can get from the DHCP server.
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
*/
|
||
|
|
||
|
DWORD
|
||
|
rasDhcpMaxAddrsToAllocate(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
DWORD dwErr = NO_ERROR;
|
||
|
DWORD dwSize = 0;
|
||
|
DWORD dwNumEntries = 0;
|
||
|
DWORD dwRet = 0;
|
||
|
DWORD dw;
|
||
|
RASMAN_PORT* pRasmanPort = NULL;
|
||
|
|
||
|
dwErr = RasPortEnum(NULL, NULL, &dwSize, &dwNumEntries);
|
||
|
RTASSERT(ERROR_BUFFER_TOO_SMALL == dwErr);
|
||
|
|
||
|
pRasmanPort = (RASMAN_PORT*) LocalAlloc(LPTR, dwSize);
|
||
|
if (NULL == pRasmanPort)
|
||
|
{
|
||
|
// The server adapter also needs an address.
|
||
|
dwRet = dwNumEntries + 1;
|
||
|
goto LDone;
|
||
|
}
|
||
|
|
||
|
dwErr = RasPortEnum(NULL, (BYTE*)pRasmanPort, &dwSize, &dwNumEntries);
|
||
|
if (NO_ERROR != dwErr)
|
||
|
{
|
||
|
// The server adapter also needs an address.
|
||
|
dwRet = dwNumEntries + 1;
|
||
|
goto LDone;
|
||
|
}
|
||
|
|
||
|
for (dw = 0, dwRet = 0; dw < dwNumEntries; dw++)
|
||
|
{
|
||
|
if ( (pRasmanPort[dw].P_ConfiguredUsage & CALL_IN)
|
||
|
|| (pRasmanPort[dw].P_ConfiguredUsage & CALL_ROUTER))
|
||
|
{
|
||
|
dwRet++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// The server adapter also needs an address.
|
||
|
dwRet++;
|
||
|
|
||
|
LDone:
|
||
|
|
||
|
LocalFree(pRasmanPort);
|
||
|
return(dwRet);
|
||
|
}
|