Windows2003-3790/inetcore/wininet/apdetect/ipconfig.cxx
2020-09-30 16:53:55 +02:00

3440 lines
86 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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"
//
// 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;
//
// 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);
//
// WSOCK32 info - if the platform is Windows 95 then we use the WsControl entry
// point in WSOCK32.DLL to access the TCP/IP device driver. If we are running
// over non-MS Winsock or TCP/IP then we cannot get the IpConfig info (unless
// the same features are supported)
//
PRIVATE DWORD (PASCAL FAR * _I_WsControl)(DWORD,
DWORD,
LPVOID,
LPDWORD,
LPVOID,
LPDWORD
) = NULL;
PRIVATE DLL_ENTRY_POINT WsControlEntryPoint[] = {
DLL_ENTRY_POINT_ELEMENT(WsControl)
};
PRIVATE DLL_INFO WsControlInfo = DLL_INFO_INIT("WSOCK32.DLL", WsControlEntryPoint);
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 (PASCAL FAR * _I_DhcpRequestOptions)(LPWSTR,
BYTE *,
DWORD,
BYTE **,
DWORD *,
BYTE **,
DWORD *
) = NULL;
PRIVATE DLL_ENTRY_POINT DhcpcSvcEntryPoints[] = {
DLL_ENTRY_POINT_ELEMENT(DhcpRequestOptions)
};
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;
default:
//DhcpPrint(("Invalid HW Type, %ld.\n", IFE.if_type ));
INET_ASSERT( FALSE );
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(
IN OUT LPSTR lpszAutoProxyUrl,
IN DWORD dwAutoProxyUrlLength
)
/*++
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;
BYTE bRequestOptions[] = { OPTION_WPAD_URL, OPTION_SUBNET_MASK, OPTION_ROUTER_ADDRESS,
OPTION_DOMAIN_NAME_SERVERS, OPTION_HOST_NAME, OPTION_DOMAIN_NAME };
LPBYTE pbOptionList = NULL, pbReturnOptions = NULL;
DWORD dwOptionListSize, dwReturnOptionSize;
WCHAR wszAdapterName[(MAX_ADAPTER_NAME_LENGTH + 6)];
int len;
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_DhcpRequestOptions == NULL )
{
error = LoadDllEntryPoints(&DhcpcSvcDllInfo, 0);
if ( error != ERROR_SUCCESS ) {
return FALSE;
}
}
error = _I_DhcpRequestOptions(
wszAdapterName, // adapter name
bRequestOptions, // array of byte codes, each represnts an option
sizeof(bRequestOptions),// size of array above
&pbOptionList, // allocated array of option ids returned from server
&dwOptionListSize, // size of above allocated array
&pbReturnOptions, // allocated array of option values
&dwReturnOptionSize
);
if ( error == ERROR_SUCCESS )
{
DWORD dwNextInc = 0;
//
// option ids are returned as byte codes in an array while
// the option data contains a byte size descritor followed
// by the option data itself which is a second array.
//
// pbReturnedOptions = <OPTION_ID_1><OPTION_ID_2> ... <OPTION_ID_N>
// pbOptionValue = (<OPTION_LEN_1><OPTION_DATA_1>) ...
// (<OPTION_LEN_N><OPTION_DATA_N>)
//
// pbOptionId is the byte code of the option itself
// pbOptionValue points to the option length, or the data following it.
//
//
for ( LPBYTE pbOptionId = pbReturnOptions, pbOptionValue = pbOptionList;
(pbOptionId < (pbReturnOptions+dwReturnOptionSize) &&
pbOptionValue < (pbOptionList+dwOptionListSize));
pbOptionId++, pbOptionValue+=(dwNextInc+1) )
{
dwNextInc = *pbOptionValue;
pbOptionValue++; // advance past the size/length byte
if (*pbOptionId == OPTION_WPAD_URL &&
dwAutoProxyUrlLength > dwNextInc &&
lpszAutoProxyUrl)
{
strncpy(lpszAutoProxyUrl, (char *) pbOptionValue, dwNextInc);
return TRUE;
}
}
}
//
// BUGBUG [arthurbi] pbOptionList & pbReturnOptions - need to be freed
// but the documentation says it needs to be freed by DhcpFreeMemory?!?
//
return FALSE;
}
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;
m_Loaded = TRI_STATE_UNKNOWN;
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;
}
UnloadEntryPoints();
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
--*/
{
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
--*/
{
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
--*/
{
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(LMEM_FIXED, 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;
}
//
// get the gateway server IP address(es)
//
//
// We don't need this information any more
//
#if 0
if (info.ipsi_numroutes != 0) {
IPRouteEntry* pRoute;
memset(&req, 0, sizeof(req));
id.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
req.ID = id;
inputLen = sizeof(req);
//
// Warning: platform specifics; Win95 structure size is different
// than NT 4.0
//
//
// BUGBUG - this will probably have to be checked for version # on
// Memphis
//
int structLength = (GlobalPlatformType == PLATFORM_TYPE_WINNT)
? sizeof(IPRouteEntry) : sizeof(IPRouteEntry95);
outputLen = structLength * info.ipsi_numroutes;
//
// the route table may have grown since we got the SNMP stats
//
for (j = 0; j < 4; ++j) {
DWORD previousOutputLen = outputLen;
routeTable = (IPRouteEntry*)ResizeBuffer(routeTable,
outputLen,
FALSE
);
if (routeTable == NULL) {
goto error_exit;
}
status = WsControl(IPPROTO_TCP,
WSCNTL_TCPIP_QUERY_INFO,
(LPVOID)&req,
&inputLen,
(LPVOID)routeTable,
&outputLen
);
if (status != TDI_SUCCESS) {
//
// unexpected results - bail out
//
DEBUG_PRINT(UTIL,
ERROR,
("WsControl(IP_MIB_RTTABLE_ENTRY_ID): status = %d, outputLen = %d\n",
status,
outputLen
));
goto error_exit;
}
if (outputLen <= previousOutputLen) {
break;
}
}
UINT numberOfRoutes = (UINT)(outputLen / sizeof(IPRouteEntry));
for (j = 0, pRoute = routeTable; j < numberOfRoutes; ++j) {
//
// the gateway address has a destination of 0.0.0.0
//
if (pRoute->ire_dest == INADDR_ANY) {
CAdapterInterface * pInterface;
pInterface = FindInterface(pRoute->ire_index);
if (pInterface != NULL) {
DEBUG_PRINT(UTIL,
INFO,
("router address %d.%d.%d.%d, index %d\n",
((LPBYTE)&pRoute->ire_nexthop)[0] & 0xff,
((LPBYTE)&pRoute->ire_nexthop)[1] & 0xff,
((LPBYTE)&pRoute->ire_nexthop)[2] & 0xff,
((LPBYTE)&pRoute->ire_nexthop)[3] & 0xff,
pRoute->ire_index
));
CIpAddress * pIpAddress;
pIpAddress = pInterface->m_RouterList.Find(pRoute->ire_nexthop);
if (pIpAddress == NULL) {
pInterface->m_RouterList.Add(pRoute->ire_nexthop);
//
// added a router address - interface is changed
//
//dprintf("adding router address %d.%d.%d.%d - changed\n",
// ((LPBYTE)&pRoute->ire_nexthop)[0] & 0xff,
// ((LPBYTE)&pRoute->ire_nexthop)[1] & 0xff,
// ((LPBYTE)&pRoute->ire_nexthop)[2] & 0xff,
// ((LPBYTE)&pRoute->ire_nexthop)[3] & 0xff
// );
bChanged = TRUE;
} else {
pIpAddress->SetFound(TRUE);
}
}
} else {
DEBUG_PRINT(UTIL,
INFO,
("rejecting router address %d.%d.%d.%d, index %d\n",
((LPBYTE)&pRoute->ire_nexthop)[0] & 0xff,
((LPBYTE)&pRoute->ire_nexthop)[1] & 0xff,
((LPBYTE)&pRoute->ire_nexthop)[2] & 0xff,
((LPBYTE)&pRoute->ire_nexthop)[3] & 0xff,
pRoute->ire_index
));
}
pRoute = (IPRouteEntry *)((LPBYTE)pRoute + structLength);
}
INET_ASSERT(routeTable);
FREE_MEMORY(routeTable);
routeTable = NULL;
}
#endif // if 0, disable gathering of router addresses
}
//
// 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.
BUGBUG [arthurbi] - turned off for Win '98 because we were getting erronous
data values from the APIs (we currently fall back to old Win'95 code on '98).
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
));
DWORD status;
DWORD inputLen;
DWORD outputLen;
BOOL ok = FALSE;
UINT i; // major loop index
UINT j; // minor loop index
BOOL bChanged = FALSE;
int len;
IP_ADAPTER_INFO AdapterInfo[15];
PIP_ADAPTER_INFO pAdapterInfo;
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)*15;
pAdapterInfo = AdapterInfo;
dwError = _I_GetAdaptersInfo(pAdapterInfo, &uSize);
if ( dwError != ERROR_SUCCESS )
{
//
// BUGBUG [arthurbi] handle the case where we have more than 15 adapters,
// need to be brave and start allocating memory for a change.
//
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 = AdapterInfo; 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 )
{
CIpAddress * pDhcpAddress;
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:
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(
IN OUT LPSTR lpszAutoProxyUrl,
IN DWORD dwAutoProxyUrlLength
)
{
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(
lpszAutoProxyUrl,
dwAutoProxyUrlLength
);
}
else
{
fSuccess = DhcpDoInform( // send an inform packet if necessary
pEntry,
FALSE,
lpszAutoProxyUrl,
dwAutoProxyUrlLength
);
}
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 && (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;
BOOL found;
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 NTDLL.DLL entry points if Windows NT else (if Windows 95) loads
WsControl from WSOCK32.DLL
Arguments:
None.
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure -
--*/
{
DEBUG_ENTER((DBG_SOCKETS,
Dword,
"CIpConfig::LoadEntryPoints",
NULL
));
DWORD error = ERROR_SUCCESS;
if (m_Loaded == TRI_STATE_UNKNOWN) {
error = LoadDllEntryPoints((GlobalPlatformType == PLATFORM_TYPE_WINNT)
? &NtDllInfo : &WsControlInfo, 0);
m_Loaded = (error == ERROR_SUCCESS) ? TRI_STATE_TRUE : TRI_STATE_FALSE;
}
if (GlobalPlatformVersion5 && (_I_GetAdaptersInfo == NULL))
{
error = LoadDllEntryPoints(&IpHlpApiDllInfo, 0);
}
DEBUG_LEAVE(error);
return error;
}
PRIVATE
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 == TRI_STATE_TRUE) {
error = UnloadDllEntryPoints((GlobalPlatformType == PLATFORM_TYPE_WINNT)
? &NtDllInfo : &WsControlInfo, FALSE);
if (error == ERROR_SUCCESS) {
m_Loaded = TRI_STATE_UNKNOWN;
}
}
if (GlobalPlatformVersion5)
{
if (_I_GetAdaptersInfo != NULL) {
error = UnloadDllEntryPoints(&IpHlpApiDllInfo, FALSE);
}
if ( _I_DhcpRequestOptions != NULL ) {
error = UnloadDllEntryPoints(&DhcpcSvcDllInfo, FALSE);
}
}
DEBUG_LEAVE(error);
return error;
}
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 = _I_WsControl(dwProtocol,
dwRequest,
lpInputBuffer,
lpdwInputBufferLength,
lpOutputBuffer,
lpdwOutputBufferLength
);
}
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:
return "???";
}
return "???";
}
#endif