3369 lines
81 KiB
C++
3369 lines
81 KiB
C++
/*++
|
||
|
||
Copyright (c) 1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ipconfig.cxx
|
||
|
||
Abstract:
|
||
|
||
CIpConfig class implementation
|
||
|
||
Contents:
|
||
CIpAddress::GetAddress
|
||
|
||
CIpAddressList::Find
|
||
CIpAddressList::Add(CIpAddress *)
|
||
CIpAddressList::Add(DWORD, DWORD, DWORD)
|
||
CIpAddressList::GetAddress
|
||
CIpAddressList::ThrowOutUnfoundEntries
|
||
|
||
CAdapterInterface::CAdapterInterface
|
||
CAdapterInterface::~CAdapterInterface
|
||
|
||
CIpConfig::CIpConfig
|
||
CIpConfig::~CIpConfig
|
||
CIpConfig::GetRouterAddress
|
||
CIpConfig::GetDnsAddress
|
||
CIpConfig::IsKnownIpAddress
|
||
CIpConfig::Refresh
|
||
(CIpConfig::GetAdapterList)
|
||
(CIpConfig::LoadEntryPoints)
|
||
(CIpConfig::UnloadEntryPoints)
|
||
(CIpConfig::FindOrCreateInterface)
|
||
(CIpConfig::FindInterface)
|
||
(CIpConfig::ThrowOutUnfoundEntries)
|
||
|
||
WsControl
|
||
(WinNtWsControl)
|
||
(OpenTcpipDriverHandle)
|
||
(CloseTcpipDriverHandle)
|
||
(GetEntityList)
|
||
[InternetMapEntity]
|
||
[InternetMapInterface]
|
||
|
||
Author:
|
||
|
||
Richard L Firth (rfirth) 29-Oct-1996
|
||
|
||
Environment:
|
||
|
||
Win32 user-mode DLL
|
||
|
||
Notes:
|
||
|
||
In order to operate correctly, we require the Microsoft Winsock implementation
|
||
(WSOCK32.DLL) and the Microsoft TCP/IP stack to be loaded
|
||
|
||
Revision History:
|
||
|
||
29-Oct-1996 rfirth
|
||
Created
|
||
|
||
15-Jul-1998 arthurbi
|
||
Resurrected from the dead
|
||
|
||
--*/
|
||
|
||
#include <wininetp.h>
|
||
#include "aproxp.h"
|
||
#include <dhcpcsdk.h>
|
||
|
||
//
|
||
// manifests
|
||
//
|
||
|
||
#define MAX_ADAPTER_DESCRIPTION_LENGTH 128 // arbitrary
|
||
//#define DEFAULT_MINIMUM_ENTITIES MAX_TDI_ENTITIES
|
||
|
||
//
|
||
// macros
|
||
//
|
||
|
||
//
|
||
// IS_INTERESTING_ADAPTER - TRUE if the type of this adapter (IFEntry) is NOT
|
||
// loopback. Loopback (corresponding to local host) is the only one we filter
|
||
// out right now
|
||
//
|
||
|
||
#define IS_INTERESTING_ADAPTER(p) (!((p)->if_type == IF_TYPE_LOOPBACK))
|
||
#define IS_INTERESTING_ADAPTER_NT5(p) (!((p)->Type == IF_TYPE_RFC877_X25))
|
||
|
||
//
|
||
// globals
|
||
//
|
||
|
||
const char SERVICES_KEY_NAME[] = "SYSTEM\\CurrentControlSet\\Services";
|
||
|
||
HKEY TcpipLinkageKey = NULL;// = INVALID_HANDLE_VALUE;
|
||
HKEY ServicesKey = NULL; // = INVALID_HANDLE_VALUE;
|
||
|
||
BOOL CIpConfig::m_Loaded;
|
||
|
||
|
||
//
|
||
// private prototypes
|
||
//
|
||
|
||
PRIVATE
|
||
DWORD
|
||
WinNtWsControl(
|
||
DWORD dwProtocol,
|
||
DWORD dwRequest,
|
||
LPVOID lpInputBuffer,
|
||
LPDWORD lpdwInputBufferLength,
|
||
LPVOID lpOutputBuffer,
|
||
LPDWORD lpdwOutputBufferLength
|
||
);
|
||
|
||
PRIVATE
|
||
DWORD
|
||
OpenTcpipDriverHandle(
|
||
VOID
|
||
);
|
||
|
||
PRIVATE
|
||
VOID
|
||
CloseTcpipDriverHandle(
|
||
VOID
|
||
);
|
||
|
||
PRIVATE
|
||
DWORD
|
||
GetEntityList(
|
||
OUT TDIEntityID * * lplpEntities
|
||
);
|
||
|
||
//
|
||
// private debug prototypes
|
||
//
|
||
|
||
PRIVATE
|
||
LPCSTR
|
||
InternetMapEntity(
|
||
IN INT EntityId
|
||
);
|
||
|
||
PRIVATE
|
||
LPCSTR
|
||
InternetMapInterface(
|
||
IN DWORD InterfaceType
|
||
);
|
||
|
||
PRIVATE
|
||
LPCSTR
|
||
InternetMapInterfaceOnNT5(
|
||
IN DWORD InterfaceType
|
||
);
|
||
|
||
|
||
//
|
||
// private data
|
||
//
|
||
|
||
//
|
||
// NTDLL info - if the platform is NT then we use the following entry points in
|
||
// NTDLL.DLL to talk to the TCP/IP device driver
|
||
//
|
||
|
||
PRIVATE VOID (* _I_RtlInitUnicodeString)(PUNICODE_STRING, PCWSTR) = NULL;
|
||
PRIVATE NTSTATUS (* _I_NtCreateFile)(PHANDLE,
|
||
ACCESS_MASK,
|
||
POBJECT_ATTRIBUTES,
|
||
PIO_STATUS_BLOCK,
|
||
PLARGE_INTEGER,
|
||
ULONG,
|
||
ULONG,
|
||
ULONG,
|
||
ULONG,
|
||
PVOID,
|
||
ULONG
|
||
) = NULL;
|
||
PRIVATE ULONG (* _I_RtlNtStatusToDosError)(NTSTATUS) = NULL;
|
||
|
||
PRIVATE DLL_ENTRY_POINT NtDllEntryPoints[] = {
|
||
DLL_ENTRY_POINT_ELEMENT(RtlInitUnicodeString),
|
||
DLL_ENTRY_POINT_ELEMENT(NtCreateFile),
|
||
DLL_ENTRY_POINT_ELEMENT(RtlNtStatusToDosError)
|
||
};
|
||
|
||
PRIVATE DLL_INFO NtDllInfo = DLL_INFO_INIT("NTDLL.DLL", NtDllEntryPoints);
|
||
|
||
PRIVATE HANDLE TcpipDriverHandle = INVALID_HANDLE_VALUE;
|
||
|
||
//
|
||
// Iphlpapi - Ip Helper APIs only found on NT 5 and Win 98, must dynaload,
|
||
// Used to gather information on what adapters are avaible on the machine
|
||
//
|
||
|
||
PRIVATE DWORD (PASCAL FAR * _I_GetAdaptersInfo)(PIP_ADAPTER_INFO,
|
||
PULONG
|
||
) = NULL;
|
||
|
||
PRIVATE DLL_ENTRY_POINT IpHlpApiEntryPoints[] = {
|
||
DLL_ENTRY_POINT_ELEMENT(GetAdaptersInfo)
|
||
};
|
||
|
||
PRIVATE DLL_INFO IpHlpApiDllInfo = DLL_INFO_INIT("IPHLPAPI.DLL", IpHlpApiEntryPoints);
|
||
|
||
//
|
||
// DhcpcSvc - DHCP dll, Only found on Win'98 and NT 5. This function does almost all the
|
||
// work for us using the native DHCP services found on these cool new OSes.
|
||
//
|
||
|
||
PRIVATE DWORD (__stdcall * _I_DhcpRequestParams)(DWORD,
|
||
LPVOID,
|
||
LPWSTR,
|
||
LPDHCPCAPI_CLASSID,
|
||
DHCPCAPI_PARAMS_ARRAY,
|
||
DHCPCAPI_PARAMS_ARRAY,
|
||
LPBYTE,
|
||
LPDWORD,
|
||
LPWSTR
|
||
) = NULL;
|
||
|
||
PRIVATE DLL_ENTRY_POINT DhcpcSvcEntryPoints[] = {
|
||
DLL_ENTRY_POINT_ELEMENT(DhcpRequestParams)
|
||
};
|
||
|
||
PRIVATE DLL_INFO DhcpcSvcDllInfo = DLL_INFO_INIT("DHCPCSVC.DLL", DhcpcSvcEntryPoints);
|
||
|
||
|
||
//
|
||
// global data
|
||
//
|
||
|
||
// none.
|
||
|
||
//
|
||
// methods
|
||
//
|
||
|
||
//
|
||
// public CIpAddress methods
|
||
//
|
||
|
||
|
||
BOOL
|
||
CIpAddress::GetAddress(
|
||
OUT LPBYTE lpbAddress,
|
||
IN OUT LPDWORD lpdwAddressLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the IP address from this CIpAddress
|
||
|
||
Arguments:
|
||
|
||
lpbAddress - pointer to returned address
|
||
|
||
lpdwAddressLength - size of IP address
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - address copied
|
||
|
||
FALSE - address not copied (buffer not large enough)
|
||
|
||
--*/
|
||
|
||
{
|
||
if (*lpdwAddressLength >= sizeof(DWORD)) {
|
||
*(LPDWORD)lpbAddress = m_dwIpAddress;
|
||
*lpdwAddressLength = sizeof(DWORD);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
//
|
||
// public CIpAddressList methods
|
||
//
|
||
|
||
BOOL
|
||
CIpAddressList::IsContextInList(
|
||
IN DWORD dwContext
|
||
)
|
||
{
|
||
for (CIpAddress * pEntry = m_List; pEntry != NULL; pEntry = pEntry->m_Next) {
|
||
if (pEntry->Context() == dwContext) {
|
||
return TRUE;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
|
||
CIpAddress *
|
||
CIpAddressList::Find(
|
||
IN DWORD dwIpAddress,
|
||
IN DWORD dwIpMask
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Finds the CIpAddress object corresponding to (dwIpAddress, dwIpMask)
|
||
|
||
Arguments:
|
||
|
||
dwIpAddress - IP address to find
|
||
|
||
dwIpMask - IP address mask, or INADDR_ANY (0) if we don't care
|
||
|
||
Return Value:
|
||
|
||
CIpAddress *
|
||
Success - pointer to found object
|
||
|
||
Failure - NULL
|
||
|
||
--*/
|
||
|
||
{
|
||
for (CIpAddress * pEntry = m_List; pEntry != NULL; pEntry = pEntry->m_Next) {
|
||
if ((pEntry->IpAddress() == dwIpAddress)
|
||
&& ((dwIpMask == INADDR_ANY) || (pEntry->IpMask() == dwIpMask))) {
|
||
break;
|
||
}
|
||
}
|
||
return pEntry;
|
||
}
|
||
|
||
|
||
VOID
|
||
CIpAddressList::Add(
|
||
IN CIpAddress * pAddress
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Adds an IP address entry to the list
|
||
|
||
Arguments:
|
||
|
||
pAddress - pointer to CIpAddress to add
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
INET_ASSERT(pAddress->m_Next == NULL);
|
||
|
||
CIpAddress * pEntry = (CIpAddress *)&m_List;
|
||
|
||
while (pEntry->m_Next != NULL) {
|
||
pEntry = pEntry->m_Next;
|
||
}
|
||
pEntry->m_Next = pAddress;
|
||
}
|
||
|
||
|
||
BOOL
|
||
CIpAddressList::Add(
|
||
IN DWORD dwIpAddress,
|
||
IN DWORD dwIpMask,
|
||
IN DWORD dwContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Adds an IP address entry to the list
|
||
|
||
Arguments:
|
||
|
||
dwIpAddress - IP address to add
|
||
|
||
dwIpMask - IP subnet mask
|
||
|
||
dwContext - unique interface context value
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - item added
|
||
|
||
FALSE - out of memory
|
||
|
||
--*/
|
||
|
||
{
|
||
CIpAddress * pIpAddress = new CIpAddress(dwIpAddress, dwIpMask, dwContext);
|
||
|
||
if (pIpAddress != NULL) {
|
||
Add(pIpAddress);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
CIpAddressList::GetAddress(
|
||
IN OUT LPDWORD lpdwIndex,
|
||
OUT LPBYTE lpbAddress,
|
||
IN OUT LPDWORD lpdwAddressLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the *lpdwIndex'th address from the list
|
||
|
||
Arguments:
|
||
|
||
lpdwIndex - which address to return. Updated on output
|
||
|
||
lpbAddress - pointer to returned address
|
||
|
||
lpdwAddressLength - pointer to returned address length
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - address returned
|
||
|
||
FALSE - address not returned
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Bool,
|
||
"CIpAddressList::GetAddress",
|
||
"%#x [%d], %#x, %#x [%d]",
|
||
lpdwIndex,
|
||
*lpdwIndex,
|
||
lpbAddress,
|
||
lpdwAddressLength,
|
||
*lpdwAddressLength
|
||
));
|
||
|
||
CIpAddress * p = m_List;
|
||
|
||
for (DWORD i = 0; (i < *lpdwIndex) && (p != NULL); ++i) {
|
||
p = p->m_Next;
|
||
}
|
||
|
||
BOOL found;
|
||
|
||
if (p != NULL) {
|
||
found = p->GetAddress(lpbAddress, lpdwAddressLength);
|
||
if (found) {
|
||
++*lpdwIndex;
|
||
}
|
||
} else {
|
||
found = FALSE;
|
||
}
|
||
|
||
DEBUG_LEAVE(found);
|
||
|
||
return found;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
BOOL
|
||
CIpAddressList::ThrowOutUnfoundEntries(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Throws out (deletes) any addresses that are marked not-found
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - interfaces thrown out
|
||
|
||
FALSE - " not " "
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Bool,
|
||
"CIpAddressList::ThrowOutUnfoundEntries",
|
||
NULL
|
||
));
|
||
|
||
CIpAddress * pLast = (CIpAddress *)&m_List;
|
||
CIpAddress * pEntry;
|
||
BOOL bThrownOut = FALSE;
|
||
|
||
for (pEntry = m_List; pEntry != NULL; pEntry = pEntry->m_Next) {
|
||
if (!pEntry->IsFound()) {
|
||
pLast->m_Next = pEntry->m_Next;
|
||
delete pEntry;
|
||
bThrownOut = TRUE;
|
||
pEntry = pLast;
|
||
} else {
|
||
pLast = pEntry;
|
||
}
|
||
}
|
||
|
||
DEBUG_LEAVE(bThrownOut);
|
||
|
||
return bThrownOut;
|
||
}
|
||
|
||
//
|
||
// public CAdapterInterface methods
|
||
//
|
||
|
||
|
||
CAdapterInterface::CAdapterInterface(
|
||
IN DWORD dwIndex,
|
||
IN DWORD dwType,
|
||
IN DWORD dwSpeed,
|
||
IN LPSTR lpszDescription,
|
||
IN DWORD dwDescriptionLength,
|
||
IN LPBYTE lpPhysicalAddress,
|
||
IN DWORD dwPhysicalAddressLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
CAdapterInterface constructor
|
||
|
||
Arguments:
|
||
|
||
dwIndex - unique adapter interface index
|
||
|
||
dwType - type of interface
|
||
|
||
dwSpeed - speed of interface
|
||
|
||
lpszDescription - pointer to descriptive name of adapter
|
||
|
||
dwDescriptionLength - length of lpszDescription
|
||
|
||
lpPhysicalAddress -
|
||
dwPhysicalAddressLength -
|
||
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
if ((lpszDescription != NULL) && (dwDescriptionLength != 0)) {
|
||
m_lpszDescription = new char[dwDescriptionLength + 1];
|
||
if (m_lpszDescription != NULL) {
|
||
memcpy(m_lpszDescription, lpszDescription, dwDescriptionLength);
|
||
} else {
|
||
dwDescriptionLength = 0;
|
||
}
|
||
}
|
||
|
||
if ((lpPhysicalAddress != NULL) && (dwPhysicalAddressLength != 0)) {
|
||
m_lpPhysicalAddress = new BYTE[dwPhysicalAddressLength];
|
||
if ( m_lpPhysicalAddress != NULL ) {
|
||
memcpy(m_lpPhysicalAddress, lpPhysicalAddress, dwPhysicalAddressLength);
|
||
}
|
||
else {
|
||
dwPhysicalAddressLength = 0;
|
||
}
|
||
}
|
||
|
||
switch( dwType )
|
||
{
|
||
case IF_TYPE_ETHERNET:
|
||
m_dwPhysicalAddressType = HARDWARE_TYPE_10MB_EITHERNET;
|
||
break;
|
||
|
||
case IF_TYPE_TOKENRING:
|
||
case IF_TYPE_FDDI:
|
||
m_dwPhysicalAddressType = HARDWARE_TYPE_IEEE_802;
|
||
break;
|
||
|
||
case IF_TYPE_OTHER:
|
||
m_dwPhysicalAddressType = HARDWARE_ARCNET;
|
||
break;
|
||
|
||
case IF_TYPE_PPP:
|
||
m_dwPhysicalAddressType = HARDWARE_PPP;
|
||
break;
|
||
|
||
case IF_TYPE_IEEE1394:
|
||
m_dwPhysicalAddressType = HARDWARE_IEEE1394;
|
||
break;
|
||
|
||
default:
|
||
m_dwPhysicalAddressType = HARDWARE_ARCNET;
|
||
break;
|
||
}
|
||
|
||
m_dwPhysicalAddressLength = dwPhysicalAddressLength;
|
||
m_dwDescriptionLength = dwDescriptionLength;
|
||
m_lpszAdapterName = NULL;
|
||
m_dwIndex = dwIndex;
|
||
m_dwType = dwType;
|
||
m_dwSpeed = dwSpeed;
|
||
m_Flags.Word = 0;
|
||
SetFound(TRUE);
|
||
}
|
||
|
||
|
||
CAdapterInterface::~CAdapterInterface(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
CAdapterInterface destructor
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
if (m_lpszDescription != NULL) {
|
||
delete m_lpszDescription;
|
||
}
|
||
|
||
if (m_lpPhysicalAddress != NULL) {
|
||
delete m_lpPhysicalAddress;
|
||
}
|
||
|
||
if ( m_lpszAdapterName != NULL) {
|
||
FREE_MEMORY(m_lpszAdapterName);
|
||
}
|
||
}
|
||
|
||
|
||
BOOL
|
||
CAdapterInterface::DhcpDoInformNT5(
|
||
OUT LPSTR * ppszAutoProxyUrl
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
For a given Interface, this nifly little method uses the new wizbang NT 5/Win'98 specific API
|
||
to do the DHCP Inform request and determine an auto-proxy Url that we can use.
|
||
|
||
Kinda of nice when we're on NT 5, otherwise we need to pull in the kitchen sink equivlent of
|
||
DHCP code that has been ripped off from the NT 4/Win'95 code base
|
||
|
||
Arguments:
|
||
|
||
lpszAutoProxyUrl - a piece of memory where we can stuff our new auto-proxy URL
|
||
|
||
dwAutoProxyUrlLength - size of the space to store the string above
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - successfully talked to server and got Url
|
||
|
||
FALSE - failed to allocate memory or failure talking to TCP/IP or failure to get an Url needed to continue
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD error;
|
||
WCHAR wszAdapterName[(MAX_ADAPTER_NAME_LENGTH + 6)];
|
||
int len;
|
||
LPSTR lpszAutoProxyUrl = NULL;
|
||
|
||
len = MultiByteToWideChar(
|
||
CP_ACP,
|
||
0, // flags
|
||
GetAdapterName(),
|
||
-1, // assume null-terminated
|
||
wszAdapterName,
|
||
(MAX_ADAPTER_NAME_LENGTH + 6)
|
||
);
|
||
|
||
if ( len == 0 ) {
|
||
return FALSE; // failed to convert string
|
||
}
|
||
|
||
if (_I_DhcpRequestParams == NULL)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
DHCPCAPI_PARAMS_ARRAY SendParams;
|
||
DHCPCAPI_PARAMS_ARRAY RecvParams;
|
||
DHCPAPI_PARAMS WpadParam;
|
||
BYTE * pBuffer = NULL;
|
||
BYTE Buffer[400];
|
||
DWORD dwBufferSize = sizeof(Buffer);
|
||
|
||
ZeroMemory(&WpadParam, sizeof(WpadParam));
|
||
WpadParam.OptionId = OPTION_WPAD_URL;
|
||
WpadParam.IsVendor = FALSE;
|
||
|
||
SendParams.nParams = 0;
|
||
SendParams.Params = NULL;
|
||
|
||
RecvParams.nParams = 1;
|
||
RecvParams.Params = &WpadParam;
|
||
|
||
error = _I_DhcpRequestParams(
|
||
DHCPCAPI_REQUEST_SYNCHRONOUS,
|
||
NULL,
|
||
wszAdapterName,
|
||
NULL,
|
||
SendParams,
|
||
RecvParams,
|
||
Buffer,
|
||
&dwBufferSize,
|
||
NULL
|
||
);
|
||
|
||
if (error == ERROR_MORE_DATA)
|
||
{
|
||
dwBufferSize += 400;
|
||
|
||
pBuffer = new BYTE[dwBufferSize];
|
||
|
||
if (pBuffer != NULL)
|
||
{
|
||
ZeroMemory(&WpadParam, sizeof(WpadParam));
|
||
|
||
WpadParam.OptionId = OPTION_WPAD_URL;
|
||
WpadParam.IsVendor = FALSE;
|
||
|
||
SendParams.nParams = 0;
|
||
SendParams.Params = NULL;
|
||
|
||
RecvParams.nParams = 1;
|
||
RecvParams.Params = &WpadParam;
|
||
|
||
error = _I_DhcpRequestParams(
|
||
DHCPCAPI_REQUEST_SYNCHRONOUS,
|
||
NULL,
|
||
wszAdapterName,
|
||
NULL,
|
||
SendParams,
|
||
RecvParams,
|
||
pBuffer,
|
||
&dwBufferSize,
|
||
NULL
|
||
);
|
||
}
|
||
else
|
||
{
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
}
|
||
|
||
if (error == ERROR_SUCCESS && WpadParam.Data != NULL && WpadParam.nBytesData != 0)
|
||
{
|
||
lpszAutoProxyUrl = NewString((LPCSTR)WpadParam.Data, WpadParam.nBytesData);
|
||
|
||
if (lpszAutoProxyUrl)
|
||
{
|
||
*ppszAutoProxyUrl = lpszAutoProxyUrl;
|
||
}
|
||
|
||
}
|
||
|
||
if (pBuffer)
|
||
delete [] pBuffer;
|
||
|
||
return (lpszAutoProxyUrl != NULL);
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
CAdapterInterface::CopyAdapterInfoToDhcpContext(
|
||
PDHCP_CONTEXT pDhcpContext
|
||
)
|
||
{
|
||
memset ((void *) pDhcpContext, 0, sizeof(DHCP_CONTEXT));
|
||
|
||
// hardware address, length, and type
|
||
pDhcpContext->HardwareAddressType = m_dwPhysicalAddressType;
|
||
pDhcpContext->HardwareAddress = m_lpPhysicalAddress;
|
||
pDhcpContext->HardwareAddressLength = m_dwPhysicalAddressLength;
|
||
|
||
if (m_IpList.m_List) {
|
||
// Selected IpAddress, NetworkOrder. htonl
|
||
// note: assumed to be in network order
|
||
pDhcpContext->IpAddress = ((m_IpList.m_List)->IpAddress());
|
||
pDhcpContext->IpInterfaceContext = ((m_IpList.m_List)->Context());
|
||
}
|
||
|
||
if (m_DhcpList.m_List) {
|
||
// Selected DHCP server address. Network Order. htonl
|
||
// note: assumed to be in network order
|
||
pDhcpContext->DhcpServerAddress = ((m_DhcpList.m_List)->IpAddress());
|
||
}
|
||
|
||
pDhcpContext->ClientIdentifier.fSpecified = FALSE;
|
||
pDhcpContext->T2Time = 0;
|
||
// when was the last time an inform was sent?
|
||
pDhcpContext->LastInformSent = 0;
|
||
// seconds passed since boot.
|
||
pDhcpContext->SecondsSinceBoot = 0;
|
||
|
||
// the list of options to send and the list of options received
|
||
InitializeListHead(&pDhcpContext->RecdOptionsList);
|
||
InitializeListHead(&pDhcpContext->SendOptionsList);
|
||
|
||
// the class this adapter belongs to
|
||
|
||
if ( m_lpszAdapterName )
|
||
{
|
||
pDhcpContext->ClassId = (unsigned char *) m_lpszAdapterName;
|
||
pDhcpContext->ClassIdLength = lstrlen(m_lpszAdapterName);
|
||
}
|
||
else
|
||
{
|
||
pDhcpContext->ClassId = NULL;
|
||
pDhcpContext->ClassIdLength = 0;
|
||
}
|
||
|
||
// Message buffer to send and receive DHCP message.
|
||
pDhcpContext->MessageBuffer = (PDHCP_MESSAGE) pDhcpContext->szMessageBuffer;
|
||
memset(pDhcpContext->szMessageBuffer, 0, sizeof(pDhcpContext->szMessageBuffer));
|
||
|
||
//LocalInfo = (PLOCAL_CONTEXT_INFO)((*pDhcpContext)->LocalInformation);
|
||
//LocalInfo->IpInterfaceContext = IpInterfaceContext;
|
||
//LocalInfo->IpInterfaceInstance = IpInterfaceInstance;
|
||
// IpInterfaceInstance is filled in make context
|
||
|
||
pDhcpContext->Socket = INVALID_SOCKET;
|
||
pDhcpContext->State.Plumbed = TRUE;
|
||
pDhcpContext->State.ServerReached = FALSE;
|
||
pDhcpContext->State.AutonetEnabled= FALSE;
|
||
pDhcpContext->State.HasBeenLooked = FALSE;
|
||
pDhcpContext->State.DhcpEnabled = FALSE;
|
||
pDhcpContext->State.AutoMode = FALSE;
|
||
pDhcpContext->State.MediaState = FALSE;
|
||
pDhcpContext->State.MDhcp = FALSE;
|
||
pDhcpContext->State.PowerResumed = FALSE;
|
||
pDhcpContext->State.Broadcast = FALSE;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// public CIpConfig methods
|
||
//
|
||
|
||
|
||
CIpConfig::CIpConfig(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
CIpConfig constructor - initializes the object & loads the requird DLLs if
|
||
not already loaded
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_OBJECTS,
|
||
None,
|
||
"CIpConfig::CIpConfig",
|
||
NULL
|
||
));
|
||
|
||
InitializeListHead(&m_List);
|
||
m_dwNumberOfInterfaces = 0;
|
||
|
||
DWORD error = LoadEntryPoints();
|
||
|
||
if (error == ERROR_SUCCESS) {
|
||
#ifndef unix
|
||
GetAdapterList();
|
||
#endif /* unix */
|
||
}
|
||
|
||
DEBUG_LEAVE(0);
|
||
}
|
||
|
||
|
||
CIpConfig::~CIpConfig()
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
CIpConfig destructor - destroys this object and unloads (or reduces the
|
||
reference count on) the DLLs
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_OBJECTS,
|
||
None,
|
||
"CIpConfig::~CIpConfig",
|
||
NULL
|
||
));
|
||
|
||
while (!IsListEmpty(&m_List)) {
|
||
|
||
PLIST_ENTRY pEntry = RemoveHeadList(&m_List);
|
||
|
||
//
|
||
// BUGBUG - need CONTAINING_RECORD() if m_List is not @ start of
|
||
// CAdapterInterface
|
||
//
|
||
|
||
CAdapterInterface * pInterface = (CAdapterInterface *)pEntry;
|
||
|
||
delete pInterface;
|
||
}
|
||
|
||
CloseTcpipDriverHandle();
|
||
|
||
DEBUG_LEAVE(0);
|
||
}
|
||
|
||
|
||
BOOL
|
||
CIpConfig::GetRouterAddress(
|
||
IN LPBYTE lpbInterfaceAddress OPTIONAL,
|
||
IN DWORD dwInterfaceAddressLength,
|
||
IN OUT LPDWORD lpdwIndex,
|
||
OUT LPBYTE lpbAddress,
|
||
IN OUT LPDWORD lpdwAddressLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the *lpdwIndex'th router address belonging to the interface
|
||
corresponding to the address in lpbInterfaceAddress
|
||
|
||
Arguments:
|
||
|
||
lpbInterfaceAddress - pointer to interface address
|
||
|
||
dwInterfaceAddressLength - length of interface address
|
||
|
||
lpdwIndex - index of router address to return
|
||
|
||
lpbAddress - returned router address
|
||
|
||
lpdwAddressLength - length of router address
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - *lpdwIndex'th router address returned for requested interface
|
||
|
||
FALSE - requested address not returned
|
||
|
||
--*/
|
||
|
||
{
|
||
UNREFERENCED_PARAMETER(lpbInterfaceAddress);
|
||
UNREFERENCED_PARAMETER(dwInterfaceAddressLength);
|
||
UNREFERENCED_PARAMETER(lpdwIndex);
|
||
UNREFERENCED_PARAMETER(lpbAddress);
|
||
UNREFERENCED_PARAMETER(lpdwAddressLength);
|
||
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Bool,
|
||
"CIpConfig::GetRouterAddress",
|
||
"%#x, %d, %#x [%d], %#x, %#x [%d]",
|
||
lpbInterfaceAddress,
|
||
dwInterfaceAddressLength,
|
||
lpdwIndex,
|
||
*lpdwIndex,
|
||
lpbAddress,
|
||
lpdwAddressLength,
|
||
*lpdwAddressLength
|
||
));
|
||
|
||
//
|
||
// for now, we default to 1st interface
|
||
//
|
||
|
||
INET_ASSERT(lpbInterfaceAddress == NULL);
|
||
INET_ASSERT(dwInterfaceAddressLength == sizeof(DWORD));
|
||
|
||
BOOL found;
|
||
|
||
//
|
||
// no one uses this any more
|
||
//
|
||
|
||
INET_ASSERT(FALSE);
|
||
|
||
//if (!IsListEmpty(&m_List)) {
|
||
// found = ((CAdapterInterface *)m_List.Flink)->m_RouterList.GetAddress(
|
||
// lpdwIndex,
|
||
// lpbAddress,
|
||
// lpdwAddressLength
|
||
// );
|
||
//} else {
|
||
found = FALSE;
|
||
//}
|
||
|
||
DEBUG_LEAVE(found);
|
||
|
||
return found;
|
||
}
|
||
|
||
|
||
BOOL
|
||
CIpConfig::GetDnsAddress(
|
||
IN LPBYTE lpbInterfaceAddress OPTIONAL,
|
||
IN DWORD dwInterfaceAddressLength,
|
||
IN OUT LPDWORD lpdwIndex,
|
||
OUT LPBYTE lpbAddress,
|
||
IN OUT LPDWORD lpdwAddressLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the *lpdwIndex'th DNS address belonging to the interface
|
||
corresponding to the address in lpbInterfaceAddress
|
||
|
||
Arguments:
|
||
|
||
lpbInterfaceAddress - pointer to interface address
|
||
|
||
dwInterfaceAddressLength - length of interface address
|
||
|
||
lpdwIndex - index of DNS address to return
|
||
|
||
lpbAddress - returned DNS address
|
||
|
||
lpdwAddressLength - length of DNS address
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - *lpdwIndex'th DNS address returned for requested interface
|
||
|
||
FALSE - requested address not returned
|
||
|
||
--*/
|
||
|
||
{
|
||
UNREFERENCED_PARAMETER(lpbInterfaceAddress);
|
||
UNREFERENCED_PARAMETER(dwInterfaceAddressLength);
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Bool,
|
||
"CIpConfig::GetDnsAddress",
|
||
"%#x, %d, %#x [%d], %#x, %#x [%d]",
|
||
lpbInterfaceAddress,
|
||
dwInterfaceAddressLength,
|
||
lpdwIndex,
|
||
*lpdwIndex,
|
||
lpbAddress,
|
||
lpdwAddressLength,
|
||
*lpdwAddressLength
|
||
));
|
||
|
||
//
|
||
// for now, we only return the global DNS info
|
||
//
|
||
|
||
INET_ASSERT(lpbInterfaceAddress == NULL);
|
||
INET_ASSERT(dwInterfaceAddressLength == sizeof(DWORD));
|
||
|
||
BOOL found;
|
||
|
||
if (!m_DnsList.IsEmpty()) {
|
||
found = m_DnsList.GetAddress(lpdwIndex,
|
||
lpbAddress,
|
||
lpdwAddressLength
|
||
);
|
||
} else {
|
||
found = FALSE;
|
||
}
|
||
|
||
DEBUG_LEAVE(found);
|
||
|
||
return found;
|
||
}
|
||
|
||
|
||
BOOL
|
||
CIpConfig::IsKnownIpAddress(
|
||
IN LPBYTE lpbInterfaceAddress OPTIONAL,
|
||
IN DWORD dwInterfaceAddressLength,
|
||
IN LPBYTE lpbAddress,
|
||
IN DWORD dwAddressLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Return TRUE if lpbAddress is a known interface address
|
||
|
||
Arguments:
|
||
|
||
lpbInterfaceAddress - pointer to interface address
|
||
|
||
dwInterfaceAddressLength - length of interface address
|
||
|
||
lpbAddress - pointer to address to check
|
||
|
||
dwAddressLength - length of address
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
|
||
--*/
|
||
|
||
{
|
||
UNREFERENCED_PARAMETER(lpbInterfaceAddress);
|
||
UNREFERENCED_PARAMETER(dwInterfaceAddressLength);
|
||
UNREFERENCED_PARAMETER(dwAddressLength);
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Bool,
|
||
"CIpConfig::IsKnownIpAddress",
|
||
"%#x, %d, %#x, %d",
|
||
lpbInterfaceAddress,
|
||
dwInterfaceAddressLength,
|
||
lpbAddress,
|
||
dwAddressLength
|
||
));
|
||
|
||
BOOL found = FALSE;
|
||
|
||
for (CAdapterInterface * pEntry = (CAdapterInterface *)m_List.Flink;
|
||
pEntry != (CAdapterInterface *)&m_List.Flink;
|
||
pEntry = (CAdapterInterface *)pEntry->m_List.Flink) {
|
||
|
||
if (pEntry->FindIpAddress(*(LPDWORD)lpbAddress)) {
|
||
found = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
DEBUG_LEAVE(found);
|
||
|
||
return found;
|
||
}
|
||
|
||
|
||
BOOL
|
||
CIpConfig::Refresh(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Refreshes the interface information - re-reads the interfaces and IP
|
||
addresses
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - interfaces or IP address changed
|
||
|
||
FALSE - nothing changed
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Bool,
|
||
"CIpConfig::Refresh",
|
||
NULL
|
||
));
|
||
|
||
BOOL bChanged;
|
||
|
||
GetAdapterList(&bChanged);
|
||
|
||
if (bChanged) {
|
||
//dprintf("flushing hostent cache\n");
|
||
// FlushHostentCache();
|
||
}
|
||
|
||
DEBUG_LEAVE(bChanged);
|
||
|
||
return bChanged;
|
||
}
|
||
|
||
//
|
||
// private CIpConfig methods
|
||
//
|
||
|
||
|
||
PRIVATE
|
||
BOOL
|
||
CIpConfig::GetAdapterList(
|
||
OUT LPBOOL lpbChanged
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Builds a list of interfaces corresponding to physical and logical adapters,
|
||
Uses Win'95 and NT 4 private VxD driver/registry entry points to get this data.
|
||
|
||
Arguments:
|
||
|
||
lpbChanged - if present, returns interface changed state
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - successfully built list
|
||
|
||
FALSE - failed to allocate memory or failure talking to TCP/IP
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Bool,
|
||
"CIpConfig::GetAdapterList",
|
||
"%#x",
|
||
lpbChanged
|
||
));
|
||
|
||
TCP_REQUEST_QUERY_INFORMATION_EX req;
|
||
TDIObjectID id;
|
||
UINT numberOfEntities;
|
||
TDIEntityID* pEntity;
|
||
TDIEntityID* entityList = NULL;
|
||
IPRouteEntry* routeTable = NULL;
|
||
LPVOID buffer = NULL;
|
||
DWORD status;
|
||
DWORD inputLen;
|
||
DWORD outputLen;
|
||
BOOL ok = FALSE;
|
||
UINT i; // major loop index
|
||
UINT j; // minor loop index
|
||
BOOL bChanged = FALSE;
|
||
|
||
//
|
||
// default is interfaces unchanged
|
||
//
|
||
|
||
if (lpbChanged) {
|
||
*lpbChanged = FALSE;
|
||
}
|
||
|
||
//
|
||
// On NT 5 we override and use a different method for
|
||
// getting network settings.
|
||
//
|
||
|
||
if ( GlobalPlatformVersion5 ) {
|
||
return GetAdapterListOnNT5();
|
||
}
|
||
|
||
//
|
||
// get the list of entities supported by TCP/IP then make 2 passes on the
|
||
// list. Pass 1 scans for IF_ENTITY's (interface entities perhaps?) which
|
||
// describe adapter instances (physical and virtual). Once we have our list
|
||
// of adapters, on pass 2 we look for CL_NL_ENTITY's (connection-less
|
||
// network layer entities peut-etre?) which will give us the list of IP
|
||
// addresses for the adapters we found in pass 1
|
||
//
|
||
|
||
numberOfEntities = GetEntityList(&entityList);
|
||
if (numberOfEntities == 0) {
|
||
|
||
INET_ASSERT(entityList == NULL);
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
ERROR,
|
||
("GetAdapterList: failed to get entity list\n"
|
||
));
|
||
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// first off, mark all the current interfaces (if any), including current
|
||
// IP addresses, as not found
|
||
//
|
||
|
||
SetNotFound();
|
||
|
||
//
|
||
// pass 1
|
||
//
|
||
|
||
for (i = 0, pEntity = entityList; i < numberOfEntities; ++i, ++pEntity) {
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
INFO,
|
||
("Pass 1: Entity %#x (%s) Instance #%d\n",
|
||
pEntity->tei_entity,
|
||
InternetMapEntity(pEntity->tei_entity),
|
||
pEntity->tei_instance
|
||
));
|
||
|
||
if (pEntity->tei_entity != IF_ENTITY) {
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
INFO,
|
||
("Entity %#x (%s) Instance #%d not IF_ENTITY - skipping\n",
|
||
pEntity->tei_entity,
|
||
InternetMapEntity(pEntity->tei_entity),
|
||
pEntity->tei_instance
|
||
));
|
||
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// IF_ENTITY: this entity/instance describes an adapter
|
||
//
|
||
|
||
DWORD isMib;
|
||
BYTE info[sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1];
|
||
IFEntry* pIfEntry = (IFEntry*)info;
|
||
int len;
|
||
|
||
//
|
||
// find out if this entity supports MIB requests
|
||
//
|
||
|
||
memset(&req, 0, sizeof(req));
|
||
|
||
id.toi_entity = *pEntity;
|
||
id.toi_class = INFO_CLASS_GENERIC;
|
||
id.toi_type = INFO_TYPE_PROVIDER;
|
||
id.toi_id = ENTITY_TYPE_ID;
|
||
|
||
req.ID = id;
|
||
|
||
inputLen = sizeof(req);
|
||
outputLen = sizeof(isMib);
|
||
|
||
status = WsControl(IPPROTO_TCP,
|
||
WSCNTL_TCPIP_QUERY_INFO,
|
||
(LPVOID)&req,
|
||
&inputLen,
|
||
(LPVOID)&isMib,
|
||
&outputLen
|
||
);
|
||
|
||
//
|
||
// BUGBUG - this returns 0 as outputLen
|
||
//
|
||
|
||
// if ((status != TDI_SUCCESS) || (outputLen != sizeof(isMib))) {
|
||
if (status != TDI_SUCCESS) {
|
||
|
||
//
|
||
// unexpected results - bail out
|
||
//
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
ERROR,
|
||
("WsControl(ENTITY_TYPE_ID): status = %d, outputLen = %d\n",
|
||
status,
|
||
outputLen
|
||
));
|
||
|
||
goto error_exit;
|
||
}
|
||
if (isMib != IF_MIB) {
|
||
|
||
//
|
||
// entity doesn't support MIB requests - try another
|
||
//
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
WARNING,
|
||
("Entity %#x, Instance #%d doesn't support MIB (%#x)\n",
|
||
id.toi_entity.tei_entity,
|
||
id.toi_entity.tei_instance,
|
||
isMib
|
||
));
|
||
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// MIB requests supported - query the adapter info
|
||
//
|
||
|
||
id.toi_class = INFO_CLASS_PROTOCOL;
|
||
id.toi_id = IF_MIB_STATS_ID;
|
||
|
||
memset(&req, 0, sizeof(req));
|
||
req.ID = id;
|
||
|
||
inputLen = sizeof(req);
|
||
outputLen = sizeof(info);
|
||
|
||
status = WsControl(IPPROTO_TCP,
|
||
WSCNTL_TCPIP_QUERY_INFO,
|
||
(LPVOID)&req,
|
||
&inputLen,
|
||
(LPVOID)&info,
|
||
&outputLen
|
||
);
|
||
if (status != TDI_SUCCESS) {
|
||
|
||
//
|
||
// unexpected results - bail out
|
||
//
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
ERROR,
|
||
("WsControl(IF_MIB_STATS_ID) returns %d\n",
|
||
status
|
||
));
|
||
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// we only want physical adapters
|
||
//
|
||
|
||
if (!IS_INTERESTING_ADAPTER(pIfEntry)) {
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
INFO,
|
||
("ignoring adapter #%d [%s]\n",
|
||
pIfEntry->if_index,
|
||
InternetMapInterface(pIfEntry->if_type)
|
||
));
|
||
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// got this adapter info ok. Find or create an interface object and fill
|
||
// in what we can
|
||
//
|
||
|
||
CAdapterInterface * pInterface;
|
||
|
||
len = min(MAX_ADAPTER_ADDRESS_LENGTH, (size_t)pIfEntry->if_physaddrlen);
|
||
|
||
pInterface = FindOrCreateInterface(pIfEntry->if_index,
|
||
pIfEntry->if_type,
|
||
pIfEntry->if_speed,
|
||
(LPSTR)pIfEntry->if_descr,
|
||
pIfEntry->if_descrlen,
|
||
(LPBYTE)pIfEntry->if_physaddr,
|
||
(DWORD) len
|
||
);
|
||
if (pInterface == NULL) {
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
ERROR,
|
||
("failed to allocate memory for CAdapterInterface\n"
|
||
));
|
||
|
||
goto error_exit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// pass 2
|
||
//
|
||
|
||
for (i = 0, pEntity = entityList; i < numberOfEntities; ++i, ++pEntity) {
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
INFO,
|
||
("Pass 2: Entity %#x (%s) Instance %d\n",
|
||
pEntity->tei_entity,
|
||
InternetMapEntity(pEntity->tei_entity),
|
||
pEntity->tei_instance
|
||
));
|
||
|
||
if (pEntity->tei_entity != CL_NL_ENTITY) {
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
INFO,
|
||
("Entity %#x (%s) Instance %d - not CL_NL_ENTITY - skipping\n",
|
||
pEntity->tei_entity,
|
||
InternetMapEntity(pEntity->tei_entity),
|
||
pEntity->tei_instance
|
||
));
|
||
|
||
continue;
|
||
}
|
||
|
||
IPSNMPInfo info;
|
||
DWORD type;
|
||
|
||
//
|
||
// first off, see if this network layer entity supports IP
|
||
//
|
||
|
||
memset(&req, 0, sizeof(req));
|
||
|
||
id.toi_entity = *pEntity;
|
||
id.toi_class = INFO_CLASS_GENERIC;
|
||
id.toi_type = INFO_TYPE_PROVIDER;
|
||
id.toi_id = ENTITY_TYPE_ID;
|
||
|
||
req.ID = id;
|
||
|
||
inputLen = sizeof(req);
|
||
outputLen = sizeof(type);
|
||
|
||
status = WsControl(IPPROTO_TCP,
|
||
WSCNTL_TCPIP_QUERY_INFO,
|
||
(LPVOID)&req,
|
||
&inputLen,
|
||
(LPVOID)&type,
|
||
&outputLen
|
||
);
|
||
|
||
//
|
||
// BUGBUG - this returns 0 as outputLen
|
||
//
|
||
|
||
// if ((status != TDI_SUCCESS) || (outputLen != sizeof(type))) {
|
||
if (status != TDI_SUCCESS) {
|
||
|
||
//
|
||
// unexpected results - bail out
|
||
//
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
ERROR,
|
||
("WsControl(ENTITY_TYPE_ID): status = %d, outputLen = %d\n",
|
||
status,
|
||
outputLen
|
||
));
|
||
|
||
goto error_exit;
|
||
}
|
||
if (type != CL_NL_IP) {
|
||
|
||
//
|
||
// nope, not IP - try next one
|
||
//
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
INFO,
|
||
("CL_NL_ENTITY #%d not CL_NL_IP - skipping\n",
|
||
pEntity->tei_instance
|
||
));
|
||
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// okay, this NL provider supports IP. Let's get them addresses: First
|
||
// we find out how many by getting the SNMP stats and looking at the
|
||
// number of addresses supported by this interface
|
||
//
|
||
|
||
memset(&req, 0, sizeof(req));
|
||
|
||
id.toi_class = INFO_CLASS_PROTOCOL;
|
||
id.toi_id = IP_MIB_STATS_ID;
|
||
|
||
req.ID = id;
|
||
|
||
inputLen = sizeof(req);
|
||
outputLen = sizeof(info);
|
||
|
||
status = WsControl(IPPROTO_TCP,
|
||
WSCNTL_TCPIP_QUERY_INFO,
|
||
(LPVOID)&req,
|
||
&inputLen,
|
||
(LPVOID)&info,
|
||
&outputLen
|
||
);
|
||
if ((status != TDI_SUCCESS) || (outputLen != sizeof(info))) {
|
||
|
||
//
|
||
// unexpected results - bail out
|
||
//
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
ERROR,
|
||
("WsControl(IP_MIB_STATS_ID): status = %d, outputLen = %d\n",
|
||
status,
|
||
outputLen
|
||
));
|
||
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// get the IP addresses & subnet masks
|
||
//
|
||
|
||
if (info.ipsi_numaddr != 0) {
|
||
|
||
//
|
||
// this interface has some addresses. What are they?
|
||
//
|
||
|
||
UINT numberOfAddresses;
|
||
IPAddrEntry* pAddr;
|
||
|
||
outputLen = info.ipsi_numaddr * sizeof(IPAddrEntry);
|
||
buffer = (LPVOID)ALLOCATE_MEMORY(outputLen);
|
||
if (buffer == NULL) {
|
||
|
||
//
|
||
// unexpected results - bail out
|
||
//
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
ERROR,
|
||
("failed to allocate %d bytes\n",
|
||
outputLen
|
||
));
|
||
|
||
goto error_exit;
|
||
}
|
||
|
||
memset(&req, 0, sizeof(req));
|
||
|
||
id.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
|
||
|
||
req.ID = id;
|
||
|
||
inputLen = sizeof(req);
|
||
|
||
status = WsControl(IPPROTO_TCP,
|
||
WSCNTL_TCPIP_QUERY_INFO,
|
||
(LPVOID)&req,
|
||
&inputLen,
|
||
(LPVOID)buffer,
|
||
&outputLen
|
||
);
|
||
if (status != TDI_SUCCESS) {
|
||
|
||
//
|
||
// unexpected results - bail out
|
||
//
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
ERROR,
|
||
("WsControl(IP_MIB_ADDRTABLE_ENTRY_ID): status = %d, outputLen = %d\n",
|
||
status,
|
||
outputLen
|
||
));
|
||
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// now loop through this list of IP addresses, applying them
|
||
// to the correct adapter
|
||
//
|
||
|
||
numberOfAddresses = min((UINT)(outputLen / sizeof(IPAddrEntry)),
|
||
(UINT)info.ipsi_numaddr
|
||
);
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
INFO,
|
||
("%d IP addresses\n",
|
||
numberOfAddresses
|
||
));
|
||
|
||
pAddr = (IPAddrEntry *)buffer;
|
||
for (j = 0; j < numberOfAddresses; ++j, ++pAddr) {
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
INFO,
|
||
("IP address %d.%d.%d.%d, index %d, context %d\n",
|
||
((LPBYTE)&pAddr->iae_addr)[0] & 0xff,
|
||
((LPBYTE)&pAddr->iae_addr)[1] & 0xff,
|
||
((LPBYTE)&pAddr->iae_addr)[2] & 0xff,
|
||
((LPBYTE)&pAddr->iae_addr)[3] & 0xff,
|
||
pAddr->iae_index,
|
||
pAddr->iae_context
|
||
));
|
||
|
||
CAdapterInterface * pInterface = FindInterface(pAddr->iae_index);
|
||
|
||
if (pInterface != NULL) {
|
||
|
||
CIpAddress * pIpAddress;
|
||
|
||
pIpAddress = pInterface->m_IpList.Find(pAddr->iae_addr,
|
||
pAddr->iae_mask
|
||
);
|
||
if (pIpAddress == NULL) {
|
||
pInterface->m_IpList.Add(pAddr->iae_addr,
|
||
pAddr->iae_mask,
|
||
pAddr->iae_context
|
||
);
|
||
|
||
//
|
||
// added an address - interface is changed
|
||
//
|
||
//dprintf("adding IP address %d.%d.%d.%d - changed\n",
|
||
// ((LPBYTE)&pAddr->iae_addr)[0] & 0xff,
|
||
// ((LPBYTE)&pAddr->iae_addr)[1] & 0xff,
|
||
// ((LPBYTE)&pAddr->iae_addr)[2] & 0xff,
|
||
// ((LPBYTE)&pAddr->iae_addr)[3] & 0xff
|
||
// );
|
||
bChanged = TRUE;
|
||
} else {
|
||
|
||
INET_ASSERT(pAddr->iae_context == pIpAddress->Context());
|
||
|
||
pIpAddress->SetFound(TRUE);
|
||
}
|
||
}
|
||
}
|
||
|
||
INET_ASSERT(buffer);
|
||
|
||
FREE_MEMORY(buffer);
|
||
|
||
buffer = NULL;
|
||
}
|
||
}
|
||
|
||
//
|
||
// add the DNS servers, read from registry or DHCP depending on platform.
|
||
// Even if we don't get any DNS servers, we deem that this function has
|
||
// succeeded
|
||
//
|
||
|
||
char dnsBuffer[1024]; // arbitrary (how many DNS entries?)
|
||
UINT error;
|
||
|
||
error = SockGetSingleValue(CONFIG_NAME_SERVER,
|
||
(LPBYTE)dnsBuffer,
|
||
sizeof(dnsBuffer)
|
||
);
|
||
if (error == ERROR_SUCCESS) {
|
||
//m_DnsList.Clear();
|
||
|
||
char ipString[4 * 4];
|
||
LPSTR p = dnsBuffer;
|
||
DWORD buflen = (DWORD)lstrlen(dnsBuffer);
|
||
|
||
do {
|
||
if (SkipWhitespace(&p, &buflen)) {
|
||
|
||
int i = 0;
|
||
|
||
while ((*p != '\0')
|
||
&& (*p != ',')
|
||
&& (buflen != 0)
|
||
&& (i < sizeof(ipString))
|
||
&& !isspace(*p)) {
|
||
ipString[i++] = *p++;
|
||
--buflen;
|
||
}
|
||
ipString[i] = '\0';
|
||
|
||
DWORD ipAddress = _I_inet_addr(ipString);
|
||
|
||
if (IS_VALID_NON_LOOPBACK_IP_ADDRESS(ipAddress)) {
|
||
|
||
CIpAddress * pIpAddress;
|
||
|
||
pIpAddress = m_DnsList.Find(ipAddress);
|
||
if (pIpAddress == NULL) {
|
||
m_DnsList.Add(ipAddress);
|
||
|
||
//
|
||
// added a DNS address - interface is changed
|
||
//
|
||
|
||
//dprintf("adding DNS address %d.%d.%d.%d - changed\n",
|
||
// ((LPBYTE)&ipAddress)[0] & 0xff,
|
||
// ((LPBYTE)&ipAddress)[1] & 0xff,
|
||
// ((LPBYTE)&ipAddress)[2] & 0xff,
|
||
// ((LPBYTE)&ipAddress)[3] & 0xff
|
||
// );
|
||
bChanged = TRUE;
|
||
} else {
|
||
pIpAddress->SetFound(TRUE);
|
||
}
|
||
}
|
||
while ((*p == ',') && (buflen != 0)) {
|
||
++p;
|
||
--buflen;
|
||
}
|
||
} else {
|
||
break;
|
||
}
|
||
} while (TRUE);
|
||
}
|
||
|
||
//
|
||
// Refresh registry settings of DHCP server stuff
|
||
// and figure out what DHCP server we have
|
||
//
|
||
|
||
GetAdapterInfo();
|
||
|
||
//
|
||
// throw out any adapter interfaces which were not found this time. This may
|
||
// happen if we support PnP devices that are unplugged
|
||
//
|
||
|
||
BOOL bThrownOut;
|
||
|
||
bThrownOut = ThrowOutUnfoundEntries();
|
||
if (!bChanged) {
|
||
bChanged = bThrownOut;
|
||
}
|
||
|
||
INET_ASSERT(entityList != NULL);
|
||
|
||
FREE_MEMORY(entityList);
|
||
|
||
ok = TRUE;
|
||
|
||
//
|
||
// return the change state of the interfaces, if required
|
||
//
|
||
|
||
if (lpbChanged) {
|
||
*lpbChanged = bChanged;
|
||
}
|
||
|
||
quit:
|
||
|
||
if (routeTable != NULL) {
|
||
FREE_MEMORY(routeTable);
|
||
}
|
||
|
||
if (buffer != NULL) {
|
||
FREE_MEMORY(buffer);
|
||
}
|
||
|
||
DEBUG_LEAVE(ok);
|
||
|
||
return ok;
|
||
|
||
error_exit:
|
||
|
||
//
|
||
// here because of an error. Throw out all interfaces
|
||
//
|
||
|
||
SetNotFound();
|
||
ThrowOutUnfoundEntries();
|
||
|
||
INET_ASSERT(!ok);
|
||
|
||
goto quit;
|
||
}
|
||
|
||
|
||
|
||
PRIVATE
|
||
BOOL
|
||
CIpConfig::GetAdapterListOnNT5(
|
||
OUT LPBOOL lpbChanged
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Builds a list of interfaces corresponding to physical and logical adapters
|
||
using the new NT 5 and Win98 APIs.
|
||
|
||
Arguments:
|
||
|
||
lpbChanged - if present, returns interface changed state
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - successfully built list
|
||
|
||
FALSE - failed to allocate memory or failure talking to TCP/IP
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Bool,
|
||
"CIpConfig::GetAdapterListOnNT5",
|
||
"%#x",
|
||
lpbChanged
|
||
));
|
||
|
||
BOOL ok = FALSE;
|
||
BOOL bChanged = FALSE;
|
||
int len;
|
||
|
||
PIP_ADAPTER_INFO pAdapterInfo = NULL;
|
||
PIP_ADAPTER_INFO pAdapterInfoAllocation = NULL;
|
||
DWORD dwError;
|
||
ULONG uSize;
|
||
|
||
//
|
||
// Load the IPHLPAPI DLL, cause we need this function find adapter info on NT 5/Win98
|
||
//
|
||
|
||
if (_I_GetAdaptersInfo == NULL )
|
||
{
|
||
DEBUG_PRINT(UTIL,
|
||
ERROR,
|
||
("GetAdapterListOnNT5: IPHLPAPI dll could not be found with correct entry point\n"
|
||
));
|
||
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// get the list of adapters supported by TCP/IP
|
||
//
|
||
|
||
uSize = sizeof(IP_ADAPTER_INFO) * 5;
|
||
|
||
pAdapterInfoAllocation = (IP_ADAPTER_INFO *) ALLOCATE_FIXED_MEMORY(uSize);
|
||
|
||
// Alias the pAdapterInfoAllocation pointer. pAdapterInfo will be used
|
||
// to traverse the list of adapter info records. We need the
|
||
// pAdapterInfoAllocation pointer in order to free the memory block at
|
||
// the end of this function.
|
||
pAdapterInfo = pAdapterInfoAllocation;
|
||
|
||
if (pAdapterInfo == NULL)
|
||
{
|
||
goto quit;
|
||
}
|
||
|
||
dwError = _I_GetAdaptersInfo(pAdapterInfo, &uSize);
|
||
|
||
if (dwError == ERROR_BUFFER_OVERFLOW)
|
||
{
|
||
pAdapterInfoAllocation = (IP_ADAPTER_INFO *) ResizeBuffer(pAdapterInfoAllocation, uSize, FALSE);
|
||
|
||
pAdapterInfo = pAdapterInfoAllocation;
|
||
|
||
if (pAdapterInfo == NULL)
|
||
{
|
||
goto quit;
|
||
}
|
||
|
||
dwError = _I_GetAdaptersInfo(pAdapterInfo, &uSize);
|
||
}
|
||
|
||
if ( dwError != ERROR_SUCCESS )
|
||
{
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
ERROR,
|
||
("GetAdapterListOnNT5: failed to get adapters list\n"
|
||
));
|
||
|
||
goto quit;
|
||
}
|
||
|
||
//
|
||
// first off, mark all the current interfaces (if any), including current
|
||
// IP addresses, as not found
|
||
//
|
||
|
||
SetNotFound();
|
||
|
||
//
|
||
// pass 1
|
||
//
|
||
|
||
for (; pAdapterInfo; pAdapterInfo = pAdapterInfo->Next)
|
||
{
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
INFO,
|
||
("Adapter Pass: [#%u] Adapter name=%s, description=%s\n",
|
||
pAdapterInfo->Index,
|
||
pAdapterInfo->AdapterName,
|
||
pAdapterInfo->Description
|
||
));
|
||
|
||
//
|
||
// we only want physical adapters
|
||
//
|
||
|
||
if (!IS_INTERESTING_ADAPTER_NT5(pAdapterInfo)) {
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
INFO,
|
||
("ignoring adapter #%u [%s]\n",
|
||
pAdapterInfo->Index,
|
||
InternetMapInterfaceOnNT5(pAdapterInfo->Type)
|
||
));
|
||
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// got this adapter info ok. Find or create an interface object and fill
|
||
// in what we can
|
||
//
|
||
|
||
CAdapterInterface * pInterface;
|
||
|
||
len = min(MAX_ADAPTER_ADDRESS_LENGTH, (size_t)pAdapterInfo->AddressLength);
|
||
|
||
|
||
pInterface = FindOrCreateInterface(pAdapterInfo->Index,
|
||
pAdapterInfo->Type,
|
||
0, // speed
|
||
pAdapterInfo->Description,
|
||
lstrlen(pAdapterInfo->Description),
|
||
pAdapterInfo->Address,
|
||
(DWORD) len
|
||
);
|
||
if (pInterface == NULL) {
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
ERROR,
|
||
("failed to allocate memory for CAdapterInterface\n"
|
||
));
|
||
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// Update the Adapter Name, this is the critical glue to make the new NT 5 DHCP Apis work,
|
||
// as they need this Adapter name as an ID to work.
|
||
//
|
||
|
||
if ( pInterface->GetAdapterName() == NULL ) {
|
||
pInterface->SetAdapterName(pAdapterInfo->AdapterName);
|
||
} else {
|
||
INET_ASSERT(lstrcmpi(pInterface->GetAdapterName(), pAdapterInfo->AdapterName) == 0 );
|
||
}
|
||
|
||
//
|
||
// Update the IP address found in the structure, as we're not getting anything back with this filled in.
|
||
//
|
||
|
||
if ( pAdapterInfo->CurrentIpAddress == NULL )
|
||
{
|
||
pAdapterInfo->CurrentIpAddress = &pAdapterInfo->IpAddressList;
|
||
}
|
||
else
|
||
{
|
||
INET_ASSERT(FALSE); // want to know about this case.
|
||
}
|
||
|
||
//
|
||
// Gather the IP addresses from the structure, doing all the necessary,
|
||
// IP string to network-ordered DWORD thingie usable for winsock.
|
||
//
|
||
// BUGBUG [arthurbi] do we really need to do this anymore? As the
|
||
// the new NT 5 APIs can handle themselves without IP addresses...
|
||
//
|
||
|
||
|
||
if ( pAdapterInfo->CurrentIpAddress->IpAddress.String &&
|
||
pAdapterInfo->CurrentIpAddress->IpMask.String )
|
||
{
|
||
DWORD dwAddress = _I_inet_addr(pAdapterInfo->CurrentIpAddress->IpAddress.String);
|
||
DWORD dwMask = _I_inet_addr(pAdapterInfo->CurrentIpAddress->IpMask.String);
|
||
DWORD dwContext = pAdapterInfo->CurrentIpAddress->Context;
|
||
|
||
if ( dwAddress != INADDR_NONE &&
|
||
dwMask != INADDR_NONE )
|
||
{
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
INFO,
|
||
("IP address %d.%d.%d.%d, index %d, context %d\n",
|
||
((LPBYTE)&dwAddress)[0] & 0xff,
|
||
((LPBYTE)&dwAddress)[1] & 0xff,
|
||
((LPBYTE)&dwAddress)[2] & 0xff,
|
||
((LPBYTE)&dwAddress)[3] & 0xff,
|
||
pAdapterInfo->Index,
|
||
dwContext
|
||
));
|
||
|
||
INET_ASSERT(pInterface != NULL);
|
||
|
||
CIpAddress * pIpAddress;
|
||
|
||
pIpAddress = pInterface->m_IpList.Find(dwAddress,
|
||
dwMask
|
||
);
|
||
if (pIpAddress == NULL) {
|
||
pInterface->m_IpList.Add(dwAddress,
|
||
dwMask,
|
||
dwContext
|
||
);
|
||
|
||
//
|
||
// added an address - interface is changed
|
||
//
|
||
|
||
bChanged = TRUE;
|
||
} else {
|
||
|
||
INET_ASSERT(dwContext == pIpAddress->Context());
|
||
|
||
pIpAddress->SetFound(TRUE);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Gather DHCP server addresses to use, once again do we need this info on NT 5?
|
||
//
|
||
|
||
if ( pAdapterInfo->DhcpEnabled )
|
||
{
|
||
PIP_ADDR_STRING pDhcpServer;
|
||
INET_ASSERT(pInterface != NULL);
|
||
|
||
for ( pDhcpServer = &pAdapterInfo->DhcpServer; pDhcpServer; pDhcpServer = pDhcpServer->Next )
|
||
{
|
||
|
||
DWORD dwAddress = _I_inet_addr(pDhcpServer->IpAddress.String);
|
||
DWORD dwMask = _I_inet_addr(pDhcpServer->IpMask.String);
|
||
DWORD dwContext = pDhcpServer->Context;
|
||
|
||
if ( dwAddress != INADDR_NONE )
|
||
{
|
||
CIpAddress * pIpAddress;
|
||
|
||
pInterface->SetDhcp();
|
||
|
||
pIpAddress = pInterface->m_DhcpList.Find(dwAddress,
|
||
dwMask
|
||
);
|
||
if (pIpAddress == NULL)
|
||
{
|
||
pInterface->m_DhcpList.Add(dwAddress,
|
||
dwMask,
|
||
dwContext
|
||
);
|
||
|
||
//
|
||
// added an address - interface is changed
|
||
//
|
||
|
||
bChanged = TRUE;
|
||
} else {
|
||
|
||
INET_ASSERT(dwContext == pIpAddress->Context());
|
||
|
||
pIpAddress->SetFound(TRUE);
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// add the DNS servers, read from registry or DHCP depending on platform.
|
||
// Even if we don't get any DNS servers, we deem that this function has
|
||
// succeeded
|
||
//
|
||
|
||
char dnsBuffer[1024]; // arbitrary (how many DNS entries?)
|
||
UINT error;
|
||
|
||
error = SockGetSingleValue(CONFIG_NAME_SERVER,
|
||
(LPBYTE)dnsBuffer,
|
||
sizeof(dnsBuffer)
|
||
);
|
||
if (error == ERROR_SUCCESS) {
|
||
//m_DnsList.Clear();
|
||
|
||
char ipString[4 * 4];
|
||
LPSTR p = dnsBuffer;
|
||
DWORD buflen = (DWORD)lstrlen(dnsBuffer);
|
||
|
||
do {
|
||
if (SkipWhitespace(&p, &buflen)) {
|
||
|
||
int i = 0;
|
||
|
||
while ((*p != '\0')
|
||
&& (*p != ',')
|
||
&& (buflen != 0)
|
||
&& (i < sizeof(ipString))
|
||
&& !isspace(*p)) {
|
||
ipString[i++] = *p++;
|
||
--buflen;
|
||
}
|
||
ipString[i] = '\0';
|
||
|
||
DWORD ipAddress = _I_inet_addr(ipString);
|
||
|
||
if (IS_VALID_NON_LOOPBACK_IP_ADDRESS(ipAddress)) {
|
||
|
||
CIpAddress * pIpAddress;
|
||
|
||
pIpAddress = m_DnsList.Find(ipAddress);
|
||
if (pIpAddress == NULL) {
|
||
m_DnsList.Add(ipAddress);
|
||
|
||
//
|
||
// added a DNS address - interface is changed
|
||
//
|
||
|
||
bChanged = TRUE;
|
||
} else {
|
||
pIpAddress->SetFound(TRUE);
|
||
}
|
||
}
|
||
while ((*p == ',') && (buflen != 0)) {
|
||
++p;
|
||
--buflen;
|
||
}
|
||
} else {
|
||
break;
|
||
}
|
||
} while (TRUE);
|
||
}
|
||
|
||
//
|
||
// throw out any adapter interfaces which were not found this time. This may
|
||
// happen if we support PnP devices that are unplugged
|
||
//
|
||
// Do we need to still do this ???
|
||
//
|
||
|
||
BOOL bThrownOut;
|
||
|
||
bThrownOut = ThrowOutUnfoundEntries();
|
||
if (!bChanged) {
|
||
bChanged = bThrownOut;
|
||
}
|
||
|
||
ok = TRUE;
|
||
|
||
//
|
||
// return the change state of the interfaces, if required
|
||
//
|
||
|
||
if (lpbChanged) {
|
||
*lpbChanged = bChanged;
|
||
}
|
||
|
||
quit:
|
||
|
||
if (pAdapterInfoAllocation)
|
||
{
|
||
FREE_MEMORY(pAdapterInfoAllocation);
|
||
}
|
||
|
||
DEBUG_LEAVE(ok);
|
||
|
||
return ok;
|
||
|
||
error_exit:
|
||
|
||
//
|
||
// here because of an error. Throw out all interfaces
|
||
//
|
||
|
||
SetNotFound();
|
||
ThrowOutUnfoundEntries();
|
||
|
||
INET_ASSERT(!ok);
|
||
|
||
goto quit;
|
||
}
|
||
|
||
|
||
BOOL
|
||
CIpConfig::DoInformsOnEachInterface(
|
||
OUT LPSTR * ppszAutoProxyUrl
|
||
)
|
||
{
|
||
for (CAdapterInterface * pEntry = (CAdapterInterface *)m_List.Flink;
|
||
pEntry != (CAdapterInterface *)&m_List.Flink;
|
||
pEntry = (CAdapterInterface *)pEntry->m_List.Flink)
|
||
{
|
||
if ( pEntry->IsDhcp() )
|
||
{
|
||
BOOL fSuccess;
|
||
|
||
if ( GlobalPlatformVersion5 )
|
||
{
|
||
fSuccess = pEntry->DhcpDoInformNT5(ppszAutoProxyUrl);
|
||
}
|
||
else
|
||
{
|
||
fSuccess = DhcpDoInform( // send an inform packet if necessary
|
||
pEntry,
|
||
FALSE,
|
||
ppszAutoProxyUrl
|
||
);
|
||
}
|
||
|
||
if ( fSuccess ) {
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
/*******************************************************************************
|
||
*
|
||
* GetAdapterInfo
|
||
*
|
||
* Gets a list of all adapters to which TCP/IP is bound and reads the per-
|
||
* adapter information that we want to display. Most of the information now
|
||
* comes from the TCP/IP stack itself. In order to keep the 'short' names that
|
||
* exist in the registry to refer to the individual adapters, we read the names
|
||
* from the registry then match them to the adapters returned by TCP/IP by
|
||
* matching the IPInterfaceContext value with the adapter which owns the IP
|
||
* address with that context value
|
||
*
|
||
* ENTRY nothing
|
||
*
|
||
* EXIT nothing
|
||
*
|
||
* RETURNS pointer to linked list of ADAPTER_INFO structures
|
||
*
|
||
* ASSUMES
|
||
*
|
||
******************************************************************************/
|
||
|
||
VOID
|
||
CIpConfig::GetAdapterInfo()
|
||
{
|
||
LPSTR* boundAdapterNames = NULL;
|
||
DWORD err = ERROR_SUCCESS;
|
||
|
||
if (GlobalPlatformType == PLATFORM_TYPE_WINNT)
|
||
{
|
||
if ( ServicesKey == NULL )
|
||
{
|
||
err = REGOPENKEY(HKEY_LOCAL_MACHINE,
|
||
SERVICES_KEY_NAME,
|
||
&ServicesKey
|
||
);
|
||
}
|
||
|
||
if ( err == ERROR_SUCCESS && TcpipLinkageKey == NULL )
|
||
{
|
||
err = REGOPENKEY(ServicesKey,
|
||
"Tcpip\\Linkage",
|
||
//"Tcpip\\Parameters\\Interfaces",
|
||
&TcpipLinkageKey
|
||
);
|
||
}
|
||
|
||
if (err == ERROR_SUCCESS && (NULL != (boundAdapterNames = GetBoundAdapterList(TcpipLinkageKey))))
|
||
{
|
||
int i;
|
||
|
||
//
|
||
// apply the short name to the right adapter info by comparing
|
||
// the IPInterfaceContext value in the adapter\Parameters\Tcpip
|
||
// section with the context values read from the stack for the
|
||
// IP addresses
|
||
//
|
||
|
||
for (i = 0; boundAdapterNames[i]; ++i) {
|
||
|
||
LPSTR name;
|
||
DWORD context;
|
||
HKEY key;
|
||
|
||
name = boundAdapterNames[i];
|
||
|
||
if (!OpenAdapterKey(KEY_TCP, name, &key)) {
|
||
DEBUG_PRINT(UTIL, ERROR, ("GetAdapterInfo cannot open %s\n",
|
||
name ));
|
||
|
||
goto quit;
|
||
}
|
||
if (!ReadRegistryDword(key,
|
||
"IPInterfaceContext",
|
||
&context
|
||
)) {
|
||
DEBUG_PRINT(UTIL, ERROR, ("GetAdapterInfo: IPInterfaceContext failed\n"));
|
||
goto quit;
|
||
}
|
||
REGCLOSEKEY(key);
|
||
|
||
//
|
||
// now search through the list of adapters, looking for the one
|
||
// that has the IP address with the same context value as that
|
||
// just read. When found, apply the short name to that adapter
|
||
//
|
||
|
||
for (CAdapterInterface * pEntry = (CAdapterInterface *)m_List.Flink;
|
||
pEntry != (CAdapterInterface *)&m_List.Flink;
|
||
pEntry = (CAdapterInterface *)pEntry->m_List.Flink)
|
||
{
|
||
if ( pEntry->IsContextInIPAddrList(context) )
|
||
{
|
||
pEntry->SetAdapterName(name);
|
||
GetDhcpServerFromDhcp(pEntry);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
} else {
|
||
DEBUG_PRINT(UTIL, ERROR, ("GetAdapterInfo failed\n"));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Win95: search through the list of adapters, gather DHCP server names
|
||
// for each.
|
||
//
|
||
|
||
for (CAdapterInterface * pEntry = (CAdapterInterface *)m_List.Flink;
|
||
pEntry != (CAdapterInterface *)&m_List.Flink;
|
||
pEntry = (CAdapterInterface *)pEntry->m_List.Flink)
|
||
{
|
||
GetDhcpServerFromDhcp(pEntry);
|
||
}
|
||
|
||
}
|
||
|
||
quit:
|
||
|
||
if (boundAdapterNames != NULL )
|
||
{
|
||
FREE_MEMORY(boundAdapterNames);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
PRIVATE
|
||
DWORD
|
||
CIpConfig::LoadEntryPoints(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Loads IPHLPAPI.DLL and DHCPCSVC.DLL entry points if platform is
|
||
Windows 2000 (or later), or NTDLL.DLL entry points if Windows NT.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure -
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Dword,
|
||
"CIpConfig::LoadEntryPoints",
|
||
NULL
|
||
));
|
||
|
||
DWORD error = ERROR_SUCCESS;
|
||
|
||
if (!m_Loaded)
|
||
{
|
||
if (GlobalDataInitCritSec.Lock())
|
||
{
|
||
if (!m_Loaded)
|
||
{
|
||
INET_ASSERT(GlobalPlatformType == PLATFORM_TYPE_WINNT);
|
||
|
||
if (GlobalPlatformVersion5)
|
||
{
|
||
INET_ASSERT(_I_GetAdaptersInfo == NULL);
|
||
|
||
error = LoadDllEntryPoints(&IpHlpApiDllInfo, 0);
|
||
|
||
if (error == ERROR_SUCCESS)
|
||
{
|
||
error = LoadDllEntryPoints(&DhcpcSvcDllInfo, 0);
|
||
}
|
||
|
||
}
|
||
else
|
||
{ INET_ASSERT(_I_RtlInitUnicodeString == NULL);
|
||
error = LoadDllEntryPoints(&NtDllInfo, 0);
|
||
}
|
||
|
||
m_Loaded = (error == ERROR_SUCCESS);
|
||
}
|
||
|
||
GlobalDataInitCritSec.Unlock();
|
||
}
|
||
else
|
||
{
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
}
|
||
|
||
DEBUG_LEAVE(error);
|
||
|
||
return error;
|
||
}
|
||
|
||
|
||
DWORD
|
||
CIpConfig::UnloadEntryPoints(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Unloads NTDLL.DLL if platform is Windows NT
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Dword,
|
||
"CIpConfig::UnloadEntryPoints",
|
||
NULL
|
||
));
|
||
|
||
DWORD error = ERROR_SUCCESS;
|
||
|
||
if (m_Loaded)
|
||
{
|
||
if (GlobalDataInitCritSec.Lock())
|
||
{
|
||
if (m_Loaded)
|
||
{
|
||
if (GlobalPlatformVersion5)
|
||
{
|
||
if (_I_GetAdaptersInfo != NULL)
|
||
{
|
||
error = UnloadDllEntryPoints(&IpHlpApiDllInfo, FALSE);
|
||
}
|
||
|
||
if (_I_DhcpRequestParams != NULL)
|
||
{
|
||
error = UnloadDllEntryPoints(&DhcpcSvcDllInfo, FALSE);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
error = UnloadDllEntryPoints(&NtDllInfo, FALSE);
|
||
}
|
||
|
||
m_Loaded = FALSE;
|
||
}
|
||
|
||
GlobalDataInitCritSec.Unlock();
|
||
}
|
||
else
|
||
{
|
||
error = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
}
|
||
|
||
DEBUG_LEAVE(error);
|
||
|
||
return error;
|
||
}
|
||
|
||
|
||
//
|
||
// UnloadAutoProxy()
|
||
//
|
||
// Called from GlobalDataTerminate to unload IPHLPAPI.DLL & DHCPCSVC.DLL (Win2K+)
|
||
// or NTDLL.DLL (NT4) if necessary.
|
||
//
|
||
void UnloadAutoProxy()
|
||
{
|
||
CIpConfig::UnloadEntryPoints();
|
||
}
|
||
|
||
|
||
|
||
PRIVATE
|
||
CAdapterInterface *
|
||
CIpConfig::FindOrCreateInterface(
|
||
IN DWORD dwIndex,
|
||
IN DWORD dwType,
|
||
IN DWORD dwSpeed,
|
||
IN LPSTR lpszDescription,
|
||
IN DWORD dwDescriptionLength,
|
||
IN LPBYTE lpPhysicalAddress,
|
||
IN DWORD dwPhysicalAddressLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns a pointer to the CAdapterInterface object corresponding to dwIndex.
|
||
If none found in the list, a new entry is created
|
||
|
||
Arguments:
|
||
|
||
dwIndex - unique interface identifier to find or create
|
||
|
||
dwType - type of adapter
|
||
|
||
dwSpeed - adapter media speed
|
||
|
||
lpszDescription - name of this interface
|
||
|
||
dwDescriptionLength - length of the name
|
||
|
||
Return Value:
|
||
|
||
CAdapterInterface *
|
||
Success - pointer to found or created object
|
||
|
||
Failure - NULL
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Pointer,
|
||
"CIpConfig::FindOrCreateInterface",
|
||
"%d, %s (%d), %d, %.*q, %d, %x, (%u)",
|
||
dwIndex,
|
||
InternetMapInterface(dwType),
|
||
dwType,
|
||
dwSpeed,
|
||
dwDescriptionLength,
|
||
lpszDescription,
|
||
dwDescriptionLength,
|
||
lpPhysicalAddress,
|
||
dwPhysicalAddressLength
|
||
));
|
||
|
||
CAdapterInterface * pInterface = FindInterface(dwIndex);
|
||
|
||
if (pInterface == NULL) {
|
||
pInterface = new CAdapterInterface(dwIndex,
|
||
dwType,
|
||
dwSpeed,
|
||
lpszDescription,
|
||
dwDescriptionLength,
|
||
lpPhysicalAddress,
|
||
dwPhysicalAddressLength
|
||
);
|
||
if (pInterface != NULL) {
|
||
InsertHeadList(&m_List, &pInterface->m_List);
|
||
++m_dwNumberOfInterfaces;
|
||
}
|
||
}
|
||
|
||
DEBUG_LEAVE(pInterface);
|
||
|
||
return pInterface;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
CAdapterInterface *
|
||
CIpConfig::FindInterface(
|
||
IN DWORD dwIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns a pointer to the CAdapterInterface object corresponding to dwIndex
|
||
|
||
Arguments:
|
||
|
||
dwIndex - unique interface identifier to find
|
||
|
||
Return Value:
|
||
|
||
CAdapterInterface *
|
||
Success - pointer to found object
|
||
|
||
Failure - NULL
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Pointer,
|
||
"CIpConfig::FindInterface",
|
||
"%d",
|
||
dwIndex
|
||
));
|
||
|
||
CAdapterInterface * pInterface = NULL;
|
||
|
||
for (PLIST_ENTRY pEntry = m_List.Flink;
|
||
pEntry != (PLIST_ENTRY)&m_List;
|
||
pEntry = pEntry->Flink) {
|
||
|
||
if (((CAdapterInterface *)pEntry)->m_dwIndex == dwIndex) {
|
||
((CAdapterInterface *)pEntry)->SetFound(TRUE);
|
||
|
||
//
|
||
// ASSUMES: pEntry == &CAdapterInterface
|
||
//
|
||
|
||
pInterface = (CAdapterInterface *)pEntry;
|
||
break;
|
||
}
|
||
}
|
||
|
||
DEBUG_LEAVE(pInterface);
|
||
|
||
return pInterface;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
BOOL
|
||
CIpConfig::ThrowOutUnfoundEntries(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Throws out (deletes) any entries that are marked not-found
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
BOOL
|
||
TRUE - interfaces thrown out
|
||
|
||
FALSE - " not " "
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Bool,
|
||
"CIpConfig::ThrowOutUnfoundEntries",
|
||
NULL
|
||
));
|
||
|
||
//
|
||
// ASSUMES: CAdapterInterface.m_List.Flink is first element in structure
|
||
//
|
||
|
||
PLIST_ENTRY pPrevious = (PLIST_ENTRY)&m_List.Flink;
|
||
PLIST_ENTRY pEntry = m_List.Flink;
|
||
BOOL bThrownOut = FALSE;
|
||
|
||
while (pEntry != (PLIST_ENTRY)&m_List) {
|
||
|
||
CAdapterInterface * pInterface = (CAdapterInterface *)pEntry;
|
||
|
||
if (!pInterface->IsFound()) {
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
WARNING,
|
||
("adapter index %d (%q) not located in list\n",
|
||
pInterface->m_dwIndex,
|
||
pInterface->m_lpszDescription
|
||
));
|
||
|
||
RemoveEntryList(&pInterface->m_List);
|
||
--m_dwNumberOfInterfaces;
|
||
|
||
INET_ASSERT((int)m_dwNumberOfInterfaces >= 0);
|
||
|
||
delete pInterface;
|
||
bThrownOut = TRUE;
|
||
} else {
|
||
|
||
//
|
||
// throw out any IP addresses
|
||
//
|
||
|
||
bThrownOut |= pInterface->m_IpList.ThrowOutUnfoundEntries();
|
||
//bThrownOut |= pInterface->m_RouterList.ThrowOutUnfoundEntries();
|
||
//bThrownOut |= pInterface->m_DnsList.ThrowOutUnfoundEntries();
|
||
pPrevious = pEntry;
|
||
}
|
||
pEntry = pPrevious->Flink;
|
||
}
|
||
|
||
DEBUG_LEAVE(bThrownOut);
|
||
|
||
return bThrownOut;
|
||
}
|
||
|
||
//
|
||
// public functions
|
||
//
|
||
|
||
|
||
DWORD
|
||
WsControl(
|
||
IN DWORD dwProtocol,
|
||
IN DWORD dwRequest,
|
||
IN LPVOID lpInputBuffer,
|
||
IN OUT LPDWORD lpdwInputBufferLength,
|
||
OUT LPVOID lpOutputBuffer,
|
||
IN OUT LPDWORD lpdwOutputBufferLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Makes device-dependent driver call based on O/S
|
||
|
||
Arguments:
|
||
|
||
dwProtocol - ignored
|
||
|
||
dwRequest - ignored
|
||
|
||
lpInputBuffer - pointer to request buffer
|
||
|
||
lpdwInputBufferLength - pointer to DWORD: IN = request buffer length
|
||
|
||
lpOutputBuffer - pointer to output buffer
|
||
|
||
lpdwOutputBufferLength - pointer to DWORD: IN = length of output buffer;
|
||
OUT = length of returned data
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure -
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Dword,
|
||
"WsControl",
|
||
"%d, %d, %#x, %#x [%d], %#x, %#x [%d]",
|
||
dwProtocol,
|
||
dwRequest,
|
||
lpInputBuffer,
|
||
lpdwInputBufferLength,
|
||
*lpdwInputBufferLength,
|
||
lpOutputBuffer,
|
||
lpdwOutputBufferLength,
|
||
*lpdwOutputBufferLength
|
||
));
|
||
|
||
DWORD error;
|
||
|
||
if (GlobalPlatformType == PLATFORM_TYPE_WINNT)
|
||
{
|
||
error = WinNtWsControl(dwProtocol,
|
||
dwRequest,
|
||
lpInputBuffer,
|
||
lpdwInputBufferLength,
|
||
lpOutputBuffer,
|
||
lpdwOutputBufferLength
|
||
);
|
||
}
|
||
else
|
||
{
|
||
error = ERROR_NOT_SUPPORTED;
|
||
}
|
||
|
||
DEBUG_LEAVE(error);
|
||
|
||
return error;
|
||
}
|
||
|
||
//
|
||
// private functions
|
||
//
|
||
|
||
|
||
PRIVATE
|
||
DWORD
|
||
WinNtWsControl(
|
||
DWORD dwProtocol,
|
||
DWORD dwRequest,
|
||
LPVOID lpInputBuffer,
|
||
LPDWORD lpdwInputBufferLength,
|
||
LPVOID lpOutputBuffer,
|
||
LPDWORD lpdwOutputBufferLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handles WsControl() functionality on NT platform. Assumes NTDLL.DLL has
|
||
already been loaded
|
||
|
||
Arguments:
|
||
|
||
dwProtocol - unused
|
||
|
||
dwRequest - unused
|
||
|
||
lpInputBuffer - contains driver request structure
|
||
|
||
lpdwInputBufferLength - pointer to length of InputBuffer
|
||
|
||
lpOutputBuffer - pointer to buffer where results written
|
||
|
||
lpdwOutputBufferLength - pointer to length of OutputBuffer. Updated with
|
||
returned data length on successful return
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure -
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Dword,
|
||
"WinNtWsControl",
|
||
"%d, %d, %#x, %#x [%d], %#x, %#x [%d]",
|
||
dwProtocol,
|
||
dwRequest,
|
||
lpInputBuffer,
|
||
lpdwInputBufferLength,
|
||
*lpdwInputBufferLength,
|
||
lpOutputBuffer,
|
||
lpdwOutputBufferLength,
|
||
*lpdwOutputBufferLength
|
||
));
|
||
|
||
UNREFERENCED_PARAMETER(dwProtocol);
|
||
UNREFERENCED_PARAMETER(dwRequest);
|
||
|
||
DWORD error;
|
||
|
||
if (TcpipDriverHandle == INVALID_HANDLE_VALUE) {
|
||
error = OpenTcpipDriverHandle();
|
||
if (error != ERROR_SUCCESS) {
|
||
goto quit;
|
||
}
|
||
}
|
||
|
||
DWORD bytesReturned;
|
||
BOOL ok;
|
||
|
||
ok = DeviceIoControl(TcpipDriverHandle,
|
||
IOCTL_TCP_QUERY_INFORMATION_EX,
|
||
lpInputBuffer,
|
||
*lpdwInputBufferLength,
|
||
lpOutputBuffer,
|
||
*lpdwOutputBufferLength,
|
||
&bytesReturned,
|
||
NULL
|
||
);
|
||
if (!ok) {
|
||
error = GetLastError();
|
||
} else {
|
||
*lpdwOutputBufferLength = bytesReturned;
|
||
error = ERROR_SUCCESS;
|
||
}
|
||
|
||
quit:
|
||
|
||
DEBUG_LEAVE(error);
|
||
|
||
return error;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
DWORD
|
||
OpenTcpipDriverHandle(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Opens handle to TCP/IP device driver
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
DWORD
|
||
Success - ERROR_SUCCESS
|
||
|
||
Failure -
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD error = ERROR_SUCCESS;
|
||
|
||
if (TcpipDriverHandle == INVALID_HANDLE_VALUE) {
|
||
|
||
OBJECT_ATTRIBUTES objectAttributes;
|
||
IO_STATUS_BLOCK iosb;
|
||
UNICODE_STRING string;
|
||
NTSTATUS status;
|
||
|
||
_I_RtlInitUnicodeString(&string, DD_TCP_DEVICE_NAME);
|
||
|
||
InitializeObjectAttributes(&objectAttributes,
|
||
&string,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
status = _I_NtCreateFile(&TcpipDriverHandle,
|
||
SYNCHRONIZE | GENERIC_EXECUTE,
|
||
&objectAttributes,
|
||
&iosb,
|
||
NULL,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
FILE_OPEN_IF,
|
||
FILE_SYNCHRONOUS_IO_NONALERT,
|
||
NULL,
|
||
0
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
error = _I_RtlNtStatusToDosError(status);
|
||
}
|
||
}
|
||
return error;
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
VOID
|
||
CloseTcpipDriverHandle(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Closes TCP/IP device driver handle
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
if (TcpipDriverHandle != INVALID_HANDLE_VALUE) {
|
||
CloseHandle(TcpipDriverHandle);
|
||
TcpipDriverHandle = INVALID_HANDLE_VALUE;
|
||
}
|
||
}
|
||
|
||
|
||
PRIVATE
|
||
DWORD
|
||
GetEntityList(
|
||
OUT TDIEntityID * * lplpEntities
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocates a buffer for, and retrieves, the list of entities supported by the
|
||
TCP/IP device driver
|
||
|
||
Arguments:
|
||
|
||
lplpEntities - pointer to allocated returned list of entities. Caller
|
||
must free
|
||
|
||
Return Value:
|
||
|
||
UINT - number of entities returned
|
||
|
||
--*/
|
||
|
||
{
|
||
DEBUG_ENTER((DBG_SOCKETS,
|
||
Int,
|
||
"GetEntityList",
|
||
"%#x",
|
||
lplpEntities
|
||
));
|
||
|
||
TCP_REQUEST_QUERY_INFORMATION_EX req;
|
||
|
||
memset(&req, 0, sizeof(req));
|
||
|
||
req.ID.toi_entity.tei_entity = GENERIC_ENTITY;
|
||
req.ID.toi_entity.tei_instance = 0;
|
||
req.ID.toi_class = INFO_CLASS_GENERIC;
|
||
req.ID.toi_type = INFO_TYPE_PROVIDER;
|
||
req.ID.toi_id = ENTITY_LIST_ID;
|
||
|
||
DWORD inputLen = sizeof(req);
|
||
DWORD outputLen = sizeof(TDIEntityID) * DEFAULT_MINIMUM_ENTITIES;
|
||
TDIEntityID * pEntity = NULL;
|
||
DWORD status = TDI_SUCCESS;
|
||
|
||
//
|
||
// this is over-engineered - its very unlikely that we'll ever get >32
|
||
// entities returned, never mind >64K's worth
|
||
//
|
||
// Go round this loop a maximum of 4 times - length of list shouldn't
|
||
// change between calls. Stops us getting stuck in infinite loop if
|
||
// something bad happens with outputLen
|
||
//
|
||
|
||
for (int i = 0; i < 4; ++i) {
|
||
|
||
DWORD previousOutputLen = outputLen;
|
||
|
||
pEntity = (TDIEntityID *)ResizeBuffer(pEntity, outputLen, FALSE);
|
||
if (pEntity == NULL) {
|
||
outputLen = 0;
|
||
break;
|
||
}
|
||
|
||
status = WsControl(IPPROTO_TCP,
|
||
WSCNTL_TCPIP_QUERY_INFO,
|
||
(LPVOID)&req,
|
||
&inputLen,
|
||
(LPVOID)pEntity,
|
||
&outputLen
|
||
);
|
||
|
||
//
|
||
// TDI_SUCCESS is returned if all data is not returned: driver
|
||
// communicates all/partial data via outputLen
|
||
//
|
||
|
||
if (status == TDI_SUCCESS) {
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
INFO,
|
||
("GENERIC_ENTITY required length = %d\n",
|
||
outputLen
|
||
));
|
||
|
||
if (outputLen && (outputLen <= previousOutputLen)) {
|
||
break;
|
||
}
|
||
} else {
|
||
outputLen = 0;
|
||
}
|
||
}
|
||
|
||
if ((status != TDI_SUCCESS) && (pEntity != NULL)) {
|
||
ResizeBuffer(pEntity, 0, FALSE);
|
||
}
|
||
|
||
DEBUG_PRINT(UTIL,
|
||
INFO,
|
||
("%d entities returned in %#x\n",
|
||
(outputLen / sizeof(TDIEntityID)),
|
||
pEntity
|
||
));
|
||
|
||
*lplpEntities = pEntity;
|
||
|
||
DEBUG_LEAVE((UINT)(outputLen / sizeof(TDIEntityID)));
|
||
|
||
return (UINT)(outputLen / sizeof(TDIEntityID));
|
||
}
|
||
|
||
//
|
||
// private debug functions
|
||
//
|
||
|
||
#if INET_DEBUG
|
||
|
||
PRIVATE
|
||
LPCSTR
|
||
InternetMapEntity(
|
||
IN INT EntityId
|
||
) {
|
||
switch (EntityId) {
|
||
case CO_TL_ENTITY:
|
||
return "CO_TL_ENTITY";
|
||
|
||
case CL_TL_ENTITY:
|
||
return "CL_TL_ENTITY";
|
||
|
||
case ER_ENTITY:
|
||
return "ER_ENTITY";
|
||
|
||
case CO_NL_ENTITY:
|
||
return "CO_NL_ENTITY";
|
||
|
||
case CL_NL_ENTITY:
|
||
return "CL_NL_ENTITY";
|
||
|
||
case AT_ENTITY:
|
||
return "AT_ENTITY";
|
||
|
||
case IF_ENTITY:
|
||
return "IF_ENTITY";
|
||
|
||
}
|
||
return "*** UNKNOWN ENTITY ***";
|
||
}
|
||
|
||
PRIVATE
|
||
LPCSTR
|
||
InternetMapInterface(
|
||
IN DWORD InterfaceType
|
||
) {
|
||
switch (InterfaceType) {
|
||
case IF_TYPE_OTHER:
|
||
return "other";
|
||
|
||
case IF_TYPE_ETHERNET:
|
||
return "ethernet";
|
||
|
||
case IF_TYPE_TOKENRING:
|
||
return "token ring";
|
||
|
||
case IF_TYPE_FDDI:
|
||
return "FDDI";
|
||
|
||
case IF_TYPE_PPP:
|
||
return "PPP";
|
||
|
||
case IF_TYPE_LOOPBACK:
|
||
return "loopback";
|
||
}
|
||
return "???";
|
||
}
|
||
|
||
PRIVATE
|
||
LPCSTR
|
||
InternetMapInterfaceOnNT5(
|
||
IN DWORD InterfaceType
|
||
) {
|
||
switch (InterfaceType) {
|
||
case IF_TYPE_OTHER:
|
||
return "other";
|
||
|
||
case IF_TYPE_ETHERNET_CSMACD:
|
||
return "ethernet";
|
||
|
||
case IF_TYPE_ISO88025_TOKENRING:
|
||
return "token ring";
|
||
|
||
case IF_TYPE_FDDI:
|
||
return "FDDI";
|
||
|
||
case IF_TYPE_PPP:
|
||
return "PPP";
|
||
|
||
case IF_TYPE_SOFTWARE_LOOPBACK:
|
||
return "loopback";
|
||
|
||
case IF_TYPE_SLIP:
|
||
return "SLIP";
|
||
|
||
default:
|
||
break;
|
||
}
|
||
return "???";
|
||
}
|
||
|
||
|
||
#endif
|
||
|
||
|
||
|