Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

5907 lines
181 KiB

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name: //KERNEL/RAZZLE3/src/sockets/tcpcmd/ipconfigext/ipcfgdll/ipconfig.c
SYNOPSIS: IPCFGDLL.DLL exports routines
Abstract:
Author: Richard L Firth (rfirth) 05-Feb-1994
Revision History:
05-Feb-1994 rfirth
Created
04-Mar-1994 rfirth
* Pick non-Dhcp registry values if DHCP not enabled
* TCP and IP have been consolidated
27-Apr-1994 rfirth
* added /release and /renew
06-Aug-1994 rfirth
* Get IP address values from TCP/IP stack, not registry
30-Apr-97 MohsinA
* Cleaning up for NT50.
17-Jan-98 RameshV
* Removed ScopeId display as new UI does not have this...
* Made ReadRegistryIpAddrString read both MULTI_SZ and REG_SZ
* Changed domainname and Dns server list from global to per-adapter
* Display DhcpServer only if address is NOT autoconfigured..
* AutoconfigEnabled is decided based on regval "AddressType"
* Friendly names stubs are used....
* Error codes are converted first thru system library..
06-Mar-98 chunye
* Made this a DLL for support IPHLPAPI etc.
--*/
#include "precomp.h"
#include "ipcfgmsg.h"
#include <iprtrmib.h>
#include <ws2tcpip.h> // for in6addr_any
#include <ntddip.h>
#include <ntddip6.h>
#include <iphlpstk.h>
#include <nhapi.h>
#pragma warning(push)
#pragma warning(disable:4200)
#pragma warning(disable:4201)
#pragma warning(disable:4214)
#include <netconp.h>
#pragma warning(pop)
//
// manifests
//
#define DEVICE_PREFIX "\\Device\\"
#define TCPIP_DEVICE_PREFIX "\\Device\\Tcpip_"
const CHAR c_szDevice[] = "\\Device\\";
const CHAR c_szDeviceTcpip[] = "\\Device\\Tcpip_";
const WCHAR c_szDeviceNdiswanIp[] = L"\\Device\\NdiswanIp";
#define INITIAL_CAPABILITY 0x00000001
#define TCPIP_CAPABILITY 0x00000002
#define NETBT_CAPABILITY 0x00000004
#define STRING_ARRAY_DELIMITERS " \t,;"
#define MSG_NO_MESSAGE 0
#define KEY_TCP 1
#define KEY_NBT 2
#define KEY_TCP6 3
#define BNODE BROADCAST_NODETYPE
#define PNODE PEER_TO_PEER_NODETYPE
#define MNODE MIXED_NODETYPE
#define HNODE HYBRID_NODETYPE
#ifdef DBG
#define SET_DHCP_MODE 1
#define SET_AUTO_MODE 2
#endif
// ========================================================================
// macros
// ========================================================================
#define REG_OPEN_KEY(_hKey, _lpSubKey, _phkResult) \
RegOpenKeyEx(_hKey, _lpSubKey, 0, KEY_READ, _phkResult)
#define ALIGN_DOWN(length, type) \
((ULONG)(length) & ~(sizeof(type) - 1))
#define ALIGN_UP(length, type) \
(ALIGN_DOWN(((ULONG)(length) + sizeof(type) - 1), type))
#define ALIGN_DOWN_PTR(length, type) \
((ULONG_PTR)(length) & ~(sizeof(type) - 1))
#define ALIGN_UP_PTR(length, type) \
(ALIGN_DOWN_PTR(((ULONG_PTR)(length) + sizeof(type) - 1), type))
// ========================================================================
// types
// ========================================================================
typedef struct {
DWORD Message;
LPSTR String;
} MESSAGE_STRING, *PMESSAGE_STRING;
#define MAX_STRING_LIST_LENGTH 32 // arbitrary
// ========================================================================
// macros
// ========================================================================
// #define IS_ARG(c) (((c) == '-') || ((c) == '/'))
// #define ReleaseMemory(p) LocalFree((HLOCAL)(p))
// #define MAP_YES_NO(i) ((i) ? MISC_MESSAGE(MI_YES) : MISC_MESSAGE(MI_NO))
#define ZERO_IP_ADDRESS(a) !strcmp((a), "0.0.0.0")
// ========================================================================
// prototypes
// ========================================================================
BOOL Initialize(PDWORD);
VOID LoadMessages(VOID);
VOID LoadMessageTable(PMESSAGE_STRING, UINT);
BOOL ConvertOemToUnicode(LPSTR, LPWSTR);
BOOL WriteRegistryDword(HKEY hKey, LPSTR szParameter, DWORD *pdwValue );
BOOL WriteRegistryMultiString(HKEY, LPSTR, LPSTR);
static
BOOL OpenAdapterKey(DWORD, const LPSTR, REGSAM, PHKEY);
BOOL MyReadRegistryDword(HKEY, LPSTR, LPDWORD);
BOOL ReadRegistryString(HKEY, LPSTR, LPSTR, LPDWORD);
BOOL ReadRegistryOemString(HKEY, LPWSTR, LPSTR, LPDWORD);
BOOL ReadRegistryIpAddrString(HKEY, LPSTR, PIP_ADDR_STRING);
BOOL GetDnsServerList(PIP_ADDR_STRING);
LPSTR* GetBoundAdapterList(HKEY);
LPSTR MapNodeType(UINT);
LPSTR MapNodeTypeEx(UINT);
LPSTR MapAdapterType(UINT);
LPSTR MapAdapterTypeEx(UINT);
LPSTR MapAdapterAddress(PIP_ADAPTER_INFO, LPSTR);
LPSTR MapTime(PIP_ADAPTER_INFO, DWORD_PTR);
LPSTR MapTimeEx(PIP_ADAPTER_INFO, DWORD_PTR);
LPSTR MapScopeId(PVOID);
VOID KillFixedInfo(PFIXED_INFO);
VOID KillPerAdapterInfo(PIP_PER_ADAPTER_INFO);
VOID KillAdapterAddresses(PIP_ADAPTER_ADDRESSES);
VOID Terminate(VOID);
LPVOID GrabMemory(DWORD);
VOID DisplayMessage(BOOL, DWORD, ...);
BOOL IsIncluded(DWORD Context, DWORD contextlist[], int len_contextlist);
BOOL ReadRegistryList(HKEY Key, LPSTR ParameterName,
DWORD NumList[], int *MaxList);
DWORD GetIgmpList(DWORD NTEAddr, DWORD *pIgmpList, PULONG dwOutBufLen);
DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE, PULONG, BOOL);
// ========================================================================
// data
// ========================================================================
HKEY TcpipLinkageKey = INVALID_HANDLE_VALUE;
HKEY TcpipParametersKey = INVALID_HANDLE_VALUE;
HKEY NetbtParametersKey = INVALID_HANDLE_VALUE;
HKEY NetbtInterfacesKey = INVALID_HANDLE_VALUE;
// PHRLANCONNECTIONNAMEFROMGUIDORPATH HrLanConnectionNameFromGuid = NULL;
// HANDLE hNetMan = NULL;
//
// Note: The following variable caches whether IPv6 was installed and running
// at the time GetAdaptersAddresses() was called. If multiple threads
// are calling GetAdaptersAddresses() during an install/uninstall, its
// value may change. However, this is not really a problem. The set of
// IPv6 DNS server addresses may or may not be present on an interface,
// but this is the same as the behavior of the set of IPv6 addresses, which
// doesn't use this variable.
//
BOOL bIp6DriverInstalled;
#ifdef DBG
UINT uChangeMode = 0;
#endif
#define FIELD_JUSTIFICATION_TEXT " "
// ========================================================================
// MESSAGE_STRING arrays - contain internationalizable strings loaded from this
// module. If a load error occurs, we use the English language defaults
// ========================================================================
LPSTR NodeTypesEx[] = {
"",
"Broadcast",
"Peer-Peer",
"Mixed",
"Hybrid"
};
MESSAGE_STRING NodeTypes[] =
{
MSG_NO_MESSAGE, TEXT(""),
MSG_BNODE, TEXT("Broadcast"),
MSG_PNODE, TEXT("Peer-Peer"),
MSG_MNODE, TEXT("Mixed"),
MSG_HNODE, TEXT("Hybrid")
};
#define NUMBER_OF_NODE_TYPES (sizeof(NodeTypes)/sizeof(NodeTypes[0]))
#define FIRST_NODE_TYPE 1
#define LAST_NODE_TYPE 4
LPSTR AdapterTypesEx[] = {
"Other",
"Ethernet",
"Token Ring",
"FDDI",
"PPP",
"Loopback",
"SLIP"
};
MESSAGE_STRING AdapterTypes[] =
{
MSG_IF_TYPE_OTHER, TEXT("Other"),
MSG_IF_TYPE_ETHERNET, TEXT("Ethernet"),
MSG_IF_TYPE_TOKEN_RING, TEXT("Token Ring"),
MSG_IF_TYPE_FDDI, TEXT("FDDI"),
MSG_IF_TYPE_PPP, TEXT("PPP"),
MSG_IF_TYPE_LOOPBACK, TEXT("Loopback"),
MSG_IF_TYPE_SLIP, TEXT("SLIP")
};
#define NUMBER_OF_ADAPTER_TYPES (sizeof(AdapterTypes)/sizeof(AdapterTypes[0]))
MESSAGE_STRING MiscMessages[] =
{
MSG_YES, TEXT("Yes"),
MSG_NO, TEXT("No"),
MSG_INIT_FAILED, TEXT("Failed to initialize"),
MSG_TCP_NOT_RUNNING, TEXT("TCP/IP is not running on this system"),
MSG_REG_BINDINGS_ERROR, TEXT("Cannot access adapter bindings registry key"),
MSG_REG_INCONSISTENT_ERROR, TEXT("Inconsistent registry contents"),
MSG_TCP_BINDING_ERROR, TEXT("TCP/IP not bound to any adapters"),
MSG_MEMORY_ERROR, TEXT("Allocating memory"),
MSG_ALL, TEXT("all"),
MSG_RELEASE, TEXT("Release"),
MSG_RENEW, TEXT("Renew"),
MSG_ACCESS_DENIED, TEXT("Access Denied"),
MSG_SERVER_UNAVAILABLE, TEXT("DHCP Server Unavailable"),
MSG_ADDRESS_CONFLICT, TEXT("The DHCP client obtained an address that is already in use on the network.")
};
#define NUMBER_OF_MISC_MESSAGES (sizeof(MiscMessages)/sizeof(MiscMessages[0]))
#define MISC_MESSAGE(i) MiscMessages[i].String
#define ADAPTER_TYPE(i) AdapterTypes[i].String
#define ADAPTER_TYPE_EX(i) AdapterTypesEx[i]
#define MI_IF_OTHER 0
#define MI_IF_ETHERNET 1
#define MI_IF_TOKEN_RING 2
#define MI_IF_FDDI 3
#define MI_IF_PPP 4
#define MI_IF_LOOPBACK 5
#define MI_IF_SLIP 6
#define MI_YES 0
#define MI_NO 1
#define MI_INIT_FAILED 2
#define MI_TCP_NOT_RUNNING 3
#define MI_REG_BINDINGS_ERROR 4
#define MI_REG_INCONSISTENT_ERROR 5
#define MI_TCP_BINDINGS_ERROR 6
#define MI_MEMORY_ERROR 7
#define MI_ALL 8
#define MI_RELEASE 9
#define MI_RENEW 10
#define MI_ACCESS_DENIED 11
#define MI_SERVER_UNAVAILABLE 12
#define MI_ADDRESS_CONFLICT 13
//
// Debugging
//
#if defined(DEBUG)
BOOL Debugging = FALSE;
int MyTrace = 0;
#endif
// ========================================================================
// functions
// ========================================================================
BOOL
IpcfgdllInit(
HINSTANCE hInstDll,
DWORD fdwReason,
LPVOID pReserved
)
{
DWORD capability;
UNREFERENCED_PARAMETER(hInstDll);
UNREFERENCED_PARAMETER(pReserved);
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
// DisableThreadLibraryCalls(hInstDll);
//
// load all possible internationalizable strings
//
LoadMessages();
//
// what debug version is this?
//
DEBUG_PRINT(("IpcfgdllInit" __DATE__ " " __TIME__ "\n"));
//
// opens all the required registry keys
//
if (!Initialize(&capability)) {
LPSTR str = NULL;
//
// exit if we couldn't open the registry services key or
// IP or TCP keys.
// We will continue if the NetBT key couldn't be opened
//
if (!(capability & INITIAL_CAPABILITY)) {
str = MISC_MESSAGE(MI_INIT_FAILED);
} else if (!(capability & TCPIP_CAPABILITY)) {
str = MISC_MESSAGE(MI_TCP_NOT_RUNNING);
}
if (str) {
//DisplayMessage(FALSE, MSG_ERROR_STRING, str);
Terminate();
return FALSE;
}
}
break;
case DLL_PROCESS_DETACH:
Terminate();
break;
default:
break;
}
return TRUE;
}
/*******************************************************************************
*
* Initialize
*
* Opens all the required registry keys
*
* ENTRY Capability
* Pointer to returned set of capabilities (bitmap)
*
* EXIT *Capability
* INITIAL_CAPABILITY
*
* TCPIP_CAPABILITY
* we could open the Tcpip\Linkage and Tcpip\Parameters keys
* TcpipLinkageKey and TcpipParametersKey contain the open handles
*
* NETBT_CAPABILITY
* we could open the NetBT\Parameters key
* NetbtInterfacesKey contains the open handle
*
*
* RETURNS TRUE = success
* FALSE = failure
*
* ASSUMES
*
******************************************************************************/
#define TCPIP_LINKAGE_KEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Linkage"
#define TCPIP_PARAMS_KEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\"
#define TCPIP_PARAMS_INTER_KEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"
#define TCPIP6_PARAMS_INTER_KEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces\\"
#define NETBT_PARAMS_KEY "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters"
#define NETBT_INTERFACE_KEY "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters\\Interfaces"
#define NETBT_ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Adapters\\"
BOOL Initialize(PDWORD Capability)
{
LONG err;
char * name;
*Capability = INITIAL_CAPABILITY;
name = TCPIP_LINKAGE_KEY;
TRACE_PRINT(("Initialize: RegOpenKey TcpipLinkageKey %s\n", name ));
err = REG_OPEN_KEY(HKEY_LOCAL_MACHINE, name, &TcpipLinkageKey );
if (err == ERROR_SUCCESS) {
*Capability |= TCPIP_CAPABILITY;
name = TCPIP_PARAMS_KEY;
TRACE_PRINT(("Initialize: RegOpenKey TcpipParametersKey %s\n",
name ));
err = REG_OPEN_KEY(HKEY_LOCAL_MACHINE, name, &TcpipParametersKey );
if (err == ERROR_SUCCESS) {
name = NETBT_INTERFACE_KEY;
TRACE_PRINT(("Initialize: RegOpenKey NetbtInterfacesKey %s\n",
name ));
err = REG_OPEN_KEY(HKEY_LOCAL_MACHINE, name, &NetbtInterfacesKey );
if (err == ERROR_SUCCESS) {
*Capability |= NETBT_CAPABILITY;
} else {
NetbtInterfacesKey = INVALID_HANDLE_VALUE;
}
} else {
*Capability &= ~TCPIP_CAPABILITY;
TcpipParametersKey = INVALID_HANDLE_VALUE;
}
} else {
TcpipLinkageKey = INVALID_HANDLE_VALUE;
}
// =======================================================
name = NETBT_PARAMS_KEY;
TRACE_PRINT(("Initialize: RegOpenKey NetbtParametersKey %s.\n", name ));
err = REG_OPEN_KEY(HKEY_LOCAL_MACHINE, name, &NetbtParametersKey );
// ======================================================
if( err != ERROR_SUCCESS ){
DEBUG_PRINT(("Initialize: RegOpenKey %s failed, err=%d\n",
name, GetLastError() ));
}
TRACE_PRINT(("Initialize RegOpenKey ok: \n"
" TcpipLinkageKey = %p\n"
" TcpipParametersKey = %p\n"
" NetbtInterfacesKey = %p\n"
" NetbtParametersKey = %p\n",
TcpipLinkageKey,
TcpipParametersKey,
NetbtInterfacesKey,
NetbtParametersKey
));
return err == ERROR_SUCCESS;
}
/*******************************************************************************
*
* LoadMessages
*
* Loads all internationalizable messages into the various tables
*
* ENTRY
*
* EXIT AdapterTypes, MiscMessages updated
*
* RETURNS
*
* ASSUMES
*
* COHESION Temporal
*
******************************************************************************/
VOID LoadMessages()
{
LoadMessageTable(NodeTypes, NUMBER_OF_NODE_TYPES);
LoadMessageTable(AdapterTypes, NUMBER_OF_ADAPTER_TYPES);
LoadMessageTable(MiscMessages, NUMBER_OF_MISC_MESSAGES);
}
/*******************************************************************************
*
* LoadMessageTable
*
* Loads internationalizable strings into a table, replacing the default for
* each. If an error occurs, the English language default is left in place
*
* ENTRY Table
* Pointer to table containing message ID and pointer to string
*
* MessageCount
* Number of messages in Table
*
* EXIT Table updated
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
VOID LoadMessageTable(PMESSAGE_STRING Table, UINT MessageCount)
{
LPSTR string;
DWORD count;
//
// for all messages in a MESSAGE_STRING table, load the string from this
// module, replacing the default string in the table (only there in case
// we get an error while loading the string, so we at least have English
// to fall back on)
//
while (MessageCount--) {
if (Table->Message != MSG_NO_MESSAGE) {
//
// we really want LoadString here, but LoadString doesn't indicate
// how big the string is, so it doesn't give us an opportunity to
// allocate exactly the right buffer size. FormatMessage does the
// right thing
//
count = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_HMODULE,
NULL, // use default hModule
Table->Message,
0, // use default language
(LPTSTR)&string,
0, // minimum size to allocate
NULL // no arguments for inclusion in strings
);
if (count) {
//
// Format message returned the string: replace the English
// language default
//
Table->String = string;
} else {
DEBUG_PRINT(("FormatMessage(%d) failed: %d\n", Table->Message, GetLastError()));
//
// this is ok if there is no string (e.g. just %0) in the .mc
// file
//
Table->String = "";
}
}
++Table;
}
}
/*******************************************************************************
*
* ConvertOemToUnicode
*
* Title says it all. Required because DhcpAcquireParameters etc. require the
* adapter name to be UNICODE
*
* ENTRY OemString
* Pointer to ANSI/OEM string to convert
*
* UnicodeString
* Pointer to place to store converted results
*
* EXIT UnicodeString contains converted string if successful
*
* RETURNS TRUE - it worked
* FALSE - it failed
*
* ASSUMES
*
******************************************************************************/
BOOL ConvertOemToUnicode(LPSTR OemString, LPWSTR UnicodeString)
{
OEM_STRING oString;
UNICODE_STRING uString;
RtlInitString(&oString, OemString);
uString.Buffer = UnicodeString;
uString.MaximumLength = (USHORT)RtlOemStringToUnicodeSize(&oString);
if (NT_SUCCESS(RtlOemStringToUnicodeString(&uString, &oString, FALSE))) {
return TRUE;
}
return FALSE;
}
/*******************************************************************************
*
* GetFixedInfo
*
* Retrieves the fixed information we wish to display by querying it from the
* various registry keys
*
* ENTRY nothing
*
* EXIT nothing
*
* RETURNS pointer to allocated FIXED_INFO structure
*
* ASSUMES
*
******************************************************************************/
PFIXED_INFO GetFixedInfo()
{
PFIXED_INFO fixedInfo = NEW(FIXED_INFO);
TRACE_PRINT(("Entered GetFixedInfo\n"));
if (fixedInfo) {
DWORD length;
BOOL ok;
length = sizeof(fixedInfo->HostName);
ok = ReadRegistryOemString(TcpipParametersKey,
L"Hostname",
fixedInfo->HostName,
&length
);
//
// domain: first try Domain then DhcpDomain
//
length = sizeof(fixedInfo->DomainName);
ok = ReadRegistryOemString(TcpipParametersKey,
L"Domain",
fixedInfo->DomainName,
&length
);
if (!ok) {
length = sizeof(fixedInfo->DomainName);
ok = ReadRegistryOemString(TcpipParametersKey,
L"DhcpDomain",
fixedInfo->DomainName,
&length
);
}
//
// DNS Server list: first try NameServer and then DhcpNameServer
//
#if 0
ok = ReadRegistryIpAddrString(TcpipParametersKey,
TEXT("NameServer"),
&fixedInfo->DnsServerList
);
if (ok) {
TRACE_PRINT(("GetFixedInfo: NameServer %s\n",
fixedInfo->DnsServerList ));
}
if (!ok) {
ok = ReadRegistryIpAddrString(TcpipParametersKey,
TEXT("DhcpNameServer"),
&fixedInfo->DnsServerList
);
if (ok) {
TRACE_PRINT(("GetFixedInfo: DhcpNameServer %s\n",
fixedInfo->DnsServerList));
}
}
#else
ok = GetDnsServerList(&fixedInfo->DnsServerList);
if (ok) {
TRACE_PRINT(("GetFixedInfo: DnsServerList %s\n",
fixedInfo->DnsServerList.IpAddress.String));
}
#endif
//
// NodeType: static then DHCP
//
ok = MyReadRegistryDword(NetbtParametersKey,
TEXT("NodeType"),
(LPDWORD)&fixedInfo->NodeType
);
if (!ok) {
ok = MyReadRegistryDword(NetbtParametersKey,
TEXT("DhcpNodeType"),
(LPDWORD)&fixedInfo->NodeType
);
}
//
// ScopeId: static then DHCP
//
length = sizeof(fixedInfo->ScopeId);
ok = ReadRegistryString(NetbtParametersKey,
TEXT("ScopeId"),
fixedInfo->ScopeId,
&length
);
if (!ok) {
length = sizeof(fixedInfo->ScopeId);
ok = ReadRegistryString(NetbtParametersKey,
TEXT("DhcpScopeId"),
fixedInfo->ScopeId,
&length
);
}
ok = MyReadRegistryDword(TcpipParametersKey,
TEXT("IPEnableRouter"),
(LPDWORD)&fixedInfo->EnableRouting
);
ok = MyReadRegistryDword(NetbtParametersKey,
TEXT("EnableProxy"),
(LPDWORD)&fixedInfo->EnableProxy
);
ok = MyReadRegistryDword(NetbtParametersKey,
TEXT("EnableDNS"),
(LPDWORD)&fixedInfo->EnableDns
);
}else{
DEBUG_PRINT(("No memory for fixedInfo\n"));
}
TRACE_PRINT(("Exit GetFixedInfo @ %p\n", fixedInfo ));
return fixedInfo;
}
/*******************************************************************************
*
* GetAdapterNameToIndexInfo
*
* Gets the mapping between IP if_index and AdapterName.
*
* RETURNS pointer to a PIP_INTERFACE_INFO structure that has been allocated.
*
******************************************************************************/
PIP_INTERFACE_INFO GetAdapterNameToIndexInfo( VOID )
{
PIP_INTERFACE_INFO pInfo;
ULONG dwSize, dwError;
dwSize = 0; pInfo = NULL;
for (;;) {
dwError = GetInterfaceInfo( pInfo, &dwSize );
if( (ERROR_INSUFFICIENT_BUFFER != dwError) && (ERROR_BUFFER_OVERFLOW != dwError) ) break;
if( NULL != pInfo ) ReleaseMemory(pInfo);
if( 0 == dwSize ) return NULL;
pInfo = GrabMemory(dwSize);
if( NULL == pInfo ) return NULL;
}
if( ERROR_SUCCESS != dwError || 0 == pInfo->NumAdapters ) {
if( NULL != pInfo ) ReleaseMemory(pInfo);
return NULL;
}
return pInfo;
}
/*******************************************************************************
*
* 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 IP_ADAPTER_INFO structures
*
* ASSUMES
*
******************************************************************************/
PIP_ADAPTER_INFO GetAdapterInfo(VOID)
{
PIP_ADAPTER_INFO adapterList;
PIP_ADAPTER_INFO adapter;
PIP_INTERFACE_INFO currentAdapterNames;
int i;
HKEY key;
TRACE_PRINT(("Entered GetAdapterInfo\n"));
if ((currentAdapterNames = GetAdapterNameToIndexInfo()) != NULL) {
if ((adapterList = GetAdapterList()) != NULL) {
//
// 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; i < currentAdapterNames->NumAdapters; ++i) {
SIZE_T dwLength;
DWORD dwIfIndex = currentAdapterNames->Adapter[i].Index;
TRACE_PRINT(("currentAdapterNames[%d]=%ws (if_index 0x%lx)\n",
i, currentAdapterNames->Adapter[i].Name, dwIfIndex ));
//
// now search through the list of adapters, looking for the one
// that has the IP address with the same index value as that
// just read. When found, apply the short name to that adapter
//
for (adapter = adapterList;
adapter ;
adapter = adapter->Next
)
{
if( adapter->Index == dwIfIndex ) {
dwLength = wcslen(currentAdapterNames->Adapter[i].Name) + 1 - strlen(TCPIP_DEVICE_PREFIX);
dwLength = wcstombs(adapter->AdapterName,
currentAdapterNames->Adapter[i].Name + strlen(TCPIP_DEVICE_PREFIX),
dwLength);
if( -1 == dwLength ) {
adapter->AdapterName[0] = '\0';
}
break;
}
}
}
}
else
{
DEBUG_PRINT(("GetAdapterInfo: GetAdapterInfo gave NULL\n"));
}
ReleaseMemory(currentAdapterNames);
//
// now get the other pieces of info from the registry for each adapter
//
for (adapter = adapterList; adapter; adapter = adapter->Next) {
TRACE_PRINT(("GetAdapterInfo: '%s'\n", adapter->AdapterName ));
if (adapter->AdapterName[0] &&
OpenAdapterKey(KEY_TCP, adapter->AdapterName, KEY_READ, &key)) {
char dhcpServerAddress[4 * 4];
DWORD addressLength;
MyReadRegistryDword(key,
TEXT("EnableDHCP"),
(LPDWORD)&adapter->DhcpEnabled
);
TRACE_PRINT(("..'EnableDHCP' %d\n", adapter->DhcpEnabled ));
#ifdef DBG
if ( uChangeMode )
{
DWORD dwAutoconfigEnabled =
( uChangeMode == SET_AUTO_MODE );
WriteRegistryDword(
key,
"IPAutoconfigurationEnabled",
&dwAutoconfigEnabled
);
}
#endif
if (adapter->DhcpEnabled) {
DWORD Temp;
MyReadRegistryDword(key,
TEXT("LeaseObtainedTime"),
&Temp
);
adapter->LeaseObtained = Temp;
MyReadRegistryDword(key,
TEXT("LeaseTerminatesTime"),
&Temp
);
adapter->LeaseExpires = Temp;
}
addressLength = sizeof( dhcpServerAddress );
if (ReadRegistryString(key,
TEXT("DhcpServer"),
dhcpServerAddress,
&addressLength
)) {
AddIpAddressString(&adapter->DhcpServer,
dhcpServerAddress,
""
);
}
RegCloseKey(key);
} else {
DEBUG_PRINT(("Cannot OpenAdapterKey KEY_TCP '%s', gle=%d\n",
adapter->AdapterName,
GetLastError()));
}
//
// get the info from the NetBT key - the WINS addresses
//
GetWinsServers(adapter);
}
} else {
DEBUG_PRINT(("GetAdapterInfo: GetBoundAdapterList gave NULL\n"));
adapterList = NULL;
}
TRACE_PRINT(("Exit GetAdapterInfo %p\n", adapterList));
return adapterList;
}
/*******************************************************************************
* AddIPv6UnicastAddressInfo
*
* This routine adds an IP_ADAPTER_UNICAST_ADDRESS entry for an IPv6 address
* to a list of entries.
*
* ENTRY IF - IPv6 interface information
* ADE - IPv6 address entry
* ppNext - Previous unicast entry's "next" pointer to update
*
* EXIT Entry added and args updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD AddIPv6UnicastAddressInfo(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE, PIP_ADAPTER_UNICAST_ADDRESS **ppNext)
{
DWORD dwErr = NO_ERROR;
PIP_ADAPTER_UNICAST_ADDRESS pCurr;
SOCKADDR_IN6 *pAddr;
UNREFERENCED_PARAMETER(IF);
ASSERT(ADE->Type == ADE_UNICAST);
pCurr = MALLOC(sizeof(IP_ADAPTER_UNICAST_ADDRESS));
if (!pCurr) {
return ERROR_NOT_ENOUGH_MEMORY;
}
pAddr = MALLOC(sizeof(SOCKADDR_IN6));
if (!pAddr) {
FREE(pCurr);
return ERROR_NOT_ENOUGH_MEMORY;
}
memset(pAddr, 0, sizeof(SOCKADDR_IN6));
pAddr->sin6_family = AF_INET6;
pAddr->sin6_scope_id = ADE->ScopeId;
memcpy(&pAddr->sin6_addr, &ADE->This.Address, sizeof(ADE->This.Address));
// Add address to linked list
**ppNext = pCurr;
*ppNext = &pCurr->Next;
pCurr->Next = NULL;
pCurr->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
pCurr->ValidLifetime = ADE->ValidLifetime;
pCurr->PreferredLifetime = ADE->PreferredLifetime;
pCurr->LeaseLifetime = 0xFFFFFFFF;
pCurr->Flags = 0;
pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN6);
pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
pCurr->PrefixOrigin = ADE->PrefixConf;
pCurr->SuffixOrigin = ADE->InterfaceIdConf;
pCurr->DadState = ADE->DADState;
// Only use DDNS on auto-configured addresses
// (either auto-configured by the system or from an RA)
// but NOT temporary addresses.
// Also do not use DDNS on link-local addresses
// or the loopback address.
if ((ADE->DADState == DAD_STATE_PREFERRED) &&
(pCurr->SuffixOrigin != IpSuffixOriginRandom) &&
!IN6_IS_ADDR_LOOPBACK(&ADE->This.Address) &&
!IN6_IS_ADDR_LINKLOCAL(&ADE->This.Address)) {
pCurr->Flags |= IP_ADAPTER_ADDRESS_DNS_ELIGIBLE;
}
return dwErr;
}
/*******************************************************************************
* AddIPv6AnycastAddressInfo
*
* This routine adds an IP_ADAPTER_ANYCAST_ADDRESS entry for an IPv6 address
* to a list of entries.
*
* ENTRY IF - IPv6 interface information
* ADE - IPv6 address entry
* ppNext - Previous anycast entry's "next" pointer to update
*
* EXIT Entry added and args updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD AddIPv6AnycastAddressInfo(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE, PIP_ADAPTER_ANYCAST_ADDRESS **ppNext)
{
DWORD dwErr = NO_ERROR;
PIP_ADAPTER_ANYCAST_ADDRESS pCurr;
SOCKADDR_IN6 *pAddr;
UNREFERENCED_PARAMETER(IF);
ASSERT(ADE->Type == ADE_ANYCAST);
pCurr = MALLOC(sizeof(IP_ADAPTER_ANYCAST_ADDRESS));
if (!pCurr) {
return ERROR_NOT_ENOUGH_MEMORY;
}
pAddr = MALLOC(sizeof(SOCKADDR_IN6));
if (!pAddr) {
FREE(pCurr);
return ERROR_NOT_ENOUGH_MEMORY;
}
memset(pAddr, 0, sizeof(SOCKADDR_IN6));
pAddr->sin6_family = AF_INET6;
pAddr->sin6_scope_id = ADE->ScopeId;
memcpy(&pAddr->sin6_addr, &ADE->This.Address, sizeof(ADE->This.Address));
// Add address to linked list
**ppNext = pCurr;
*ppNext = &pCurr->Next;
pCurr->Next = NULL;
pCurr->Length = sizeof(IP_ADAPTER_ANYCAST_ADDRESS);
pCurr->Flags = 0;
pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN6);
pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
return dwErr;
}
/*******************************************************************************
* AddIPv6MulticastAddressInfo
*
* This routine adds an IP_ADAPTER_MULTICAST_ADDRESS entry for an IPv6 address
* to a list of entries.
*
* ENTRY IF - IPv6 interface information
* ADE - IPv6 address entry
* ppNext - Previous multicast entry's "next" pointer to update
*
* EXIT Entry added and args updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD AddIPv6MulticastAddressInfo(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE, PIP_ADAPTER_MULTICAST_ADDRESS **ppNext)
{
DWORD dwErr = NO_ERROR;
PIP_ADAPTER_MULTICAST_ADDRESS pCurr;
SOCKADDR_IN6 *pAddr;
UNREFERENCED_PARAMETER(IF);
ASSERT(ADE->Type == ADE_MULTICAST);
pCurr = MALLOC(sizeof(IP_ADAPTER_MULTICAST_ADDRESS));
if (!pCurr) {
return ERROR_NOT_ENOUGH_MEMORY;
}
pAddr = MALLOC(sizeof(SOCKADDR_IN6));
if (!pAddr) {
FREE(pCurr);
return ERROR_NOT_ENOUGH_MEMORY;
}
memset(pAddr, 0, sizeof(SOCKADDR_IN6));
pAddr->sin6_family = AF_INET6;
pAddr->sin6_scope_id = ADE->ScopeId;
memcpy(&pAddr->sin6_addr, &ADE->This.Address, sizeof(ADE->This.Address));
// Add address to linked list
**ppNext = pCurr;
*ppNext = &pCurr->Next;
pCurr->Next = NULL;
pCurr->Length = sizeof(IP_ADAPTER_MULTICAST_ADDRESS);
pCurr->Flags = 0;
pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN6);
pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
return dwErr;
}
/*******************************************************************************
* AddIPv6AddressInfo
*
* This routine adds an IP_ADAPTER_UNICAST_ADDRESS entry for an IPv6 address
* to a list of entries.
*
* ENTRY IF - IPv6 interface information
* ADE - IPv6 address entry
* arg1 - Previous unicast entry's "next" pointer to update
* arg2 - Previous anycast entry's "next" pointer to update
* arg3 - Previous multicast entry's "next" pointer to update
* arg4 - Unused
* Flags - Flags specified by application
* Family - Address family constraint (for DNS server addresses)
*
* EXIT Entry added and args updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD AddIPv6AddressInfo(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, DWORD Flags, DWORD Family)
{
UNREFERENCED_PARAMETER(Family);
UNREFERENCED_PARAMETER(arg4);
switch (ADE->Type) {
case ADE_UNICAST:
if (Flags & GAA_FLAG_SKIP_UNICAST) {
return NO_ERROR;
}
return AddIPv6UnicastAddressInfo(IF, ADE,
(PIP_ADAPTER_UNICAST_ADDRESS**)arg1);
case ADE_ANYCAST:
if (Flags & GAA_FLAG_SKIP_ANYCAST) {
return NO_ERROR;
}
return AddIPv6AnycastAddressInfo(IF, ADE,
(PIP_ADAPTER_ANYCAST_ADDRESS**)arg2);
case ADE_MULTICAST:
if (Flags & GAA_FLAG_SKIP_MULTICAST) {
return NO_ERROR;
}
return AddIPv6MulticastAddressInfo(IF, ADE,
(PIP_ADAPTER_MULTICAST_ADDRESS**)arg3);
default:
ASSERT(0);
}
return NO_ERROR;
}
/*******************************************************************************
* ForEachIPv6Address
*
* This routine walks a set of IPv6 addresses and invokes a given function
* on each one.
*
* ENTRY IF - IPv6 interface information
* func - Function to invoke on each address
* arg1 - Argument to pass to func
* arg2 - Argument to pass to func
* arg3 - Argument to pass to func
* arg4 - Argument to pass to func
* Flags - Flags to pass to func
* Family - Address family constraint (for DNS server addresses)
*
* EXIT Nothing
*
* RETURNS Error status
*
******************************************************************************/
DWORD
ForEachIPv6Address(
IPV6_INFO_INTERFACE *IF,
DWORD (*func)(IPV6_INFO_INTERFACE *,IPV6_INFO_ADDRESS *, PVOID, PVOID, PVOID, PVOID, DWORD, DWORD),
PVOID arg1,
PVOID arg2,
PVOID arg3,
PVOID arg4,
DWORD Flags,
DWORD Family)
{
IPV6_QUERY_ADDRESS Query;
IPV6_INFO_ADDRESS ADE;
DWORD BytesReturned, BytesIn;
DWORD dwErr;
Query.IF = IF->This;
Query.Address = in6addr_any;
for (;;) {
BytesIn = sizeof Query;
BytesReturned = sizeof ADE;
dwErr = WsControl( IPPROTO_IPV6,
IOCTL_IPV6_QUERY_ADDRESS,
&Query, &BytesIn,
&ADE, &BytesReturned);
if (dwErr != NO_ERROR) {
return dwErr;
}
if (!IN6_ADDR_EQUAL(&Query.Address, &in6addr_any)) {
dwErr = (*func)(IF, &ADE, arg1, arg2, arg3, arg4, Flags, Family);
if (dwErr != NO_ERROR) {
return dwErr;
}
}
if (IN6_ADDR_EQUAL(&ADE.Next.Address, &in6addr_any))
break;
Query = ADE.Next;
}
return NO_ERROR;
}
/*******************************************************************************
* MapIpv4AddressToName
*
* This routine finds the name and description of the adapter which
* has a given IPv4 address on it.
*
* ENTRY pAdapterInfo - Buffer obtained from GetAdaptersInfo
* Ipv4Address - IPv4 address to search for
* pDescription - Where to place a pointer to the description text
*
* EXIT pDescription updated, if found
*
* RETURNS Adapter name, or NULL if not found
*
******************************************************************************/
LPSTR
MapIpv4AddressToName(IP_ADAPTER_INFO *pAdapterInfo, DWORD Ipv4Address, PCHAR *pDescription)
{
IP_ADAPTER_INFO *pAdapter;
IP_ADDR_STRING *pAddr;
for (pAdapter = pAdapterInfo;
pAdapter != NULL;
pAdapter = pAdapter->Next) {
for (pAddr = &pAdapter->IpAddressList; pAddr; pAddr=pAddr->Next) {
if (inet_addr(pAddr->IpAddress.String) == Ipv4Address) {
*pDescription = pAdapter->Description;
return pAdapter->AdapterName;
}
}
}
return NULL;
}
#define GUID_FORMAT_A "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"
/*******************************************************************************
* ConvertGuidToStringA
*
* This routine converts a GUID to a character string.
*
* ENTRY pGuid - Contains the GUID to translate.
* pszBuffer - Space for storing the string.
* Must be >= 39 * sizeof(CHAR).
*
* EXIT pszBuffer updated
*
* RETURNS Whatever sprintf returns
*
******************************************************************************/
DWORD
ConvertGuidToStringA(GUID *pGuid, PCHAR pszBuffer)
{
return sprintf(pszBuffer,
GUID_FORMAT_A,
pGuid->Data1,
pGuid->Data2,
pGuid->Data3,
pGuid->Data4[0],
pGuid->Data4[1],
pGuid->Data4[2],
pGuid->Data4[3],
pGuid->Data4[4],
pGuid->Data4[5],
pGuid->Data4[6],
pGuid->Data4[7]);
}
/*******************************************************************************
* ConvertStringToGuidA
*
* This routine converts a character string to a GUID.
*
* ENTRY pszGuid - Contains the string to translate
* pGuid - Space for storing the GUID
*
* EXIT pGuid updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD
ConvertStringToGuidA(PCHAR pszGuid, GUID *pGuid)
{
UNICODE_STRING Temp;
WCHAR wszGuid[40+1];
MultiByteToWideChar(CP_ACP, 0, pszGuid, -1, wszGuid, 40);
RtlInitUnicodeString(&Temp, wszGuid);
if(RtlGUIDFromString(&Temp, pGuid) != STATUS_SUCCESS)
{
return ERROR_INVALID_PARAMETER;
}
return NO_ERROR;
}
/*******************************************************************************
* MapGuidToAdapterName
*
* This routine gets an adapter name and description, given a GUID.
*
* ENTRY pAdapterInfo - Buffer obtained from GetAdaptersInfo
* Guid - GUID of the adapter
* pwszDescription - Buffer in which to place description text.
* Must be at least MAX_ADAPTER_DESCRIPTION_LENGTH
* WCHAR's long.
*
* EXIT pwszDescription buffer filled in, if found
*
* RETURNS Adapter name, or NULL if not found
*
******************************************************************************/
LPSTR
MapGuidToAdapterName(IP_ADAPTER_INFO *pAdapterInfo, GUID *Guid, PWCHAR pwszDescription)
{
IP_ADAPTER_INFO *pAdapter;
CHAR szGuid[40];
ConvertGuidToStringA(Guid, szGuid);
for (pAdapter = pAdapterInfo;
pAdapter != NULL;
pAdapter = pAdapter->Next) {
if (!strcmp(szGuid, pAdapter->AdapterName)) {
MultiByteToWideChar(CP_ACP, 0, pAdapter->Description, -1,
pwszDescription,
MAX_ADAPTER_DESCRIPTION_LENGTH);
return pAdapter->AdapterName;
}
}
pwszDescription[0] = L'\0';
return NULL;
}
/*******************************************************************************
* AddDnsServerAddressInfo
*
* This routine adds an IP_ADAPTER_DNS_SERVER_ADDRESS entry for an address
* to a list of entries.
*
* ENTRY IF - interface information
* Addr - Address in sockaddr format
* AddrLen- Size of sockaddr
* pFirst - First DNS server entry
* ppNext - Previous DNS server entry's "next" pointer to update
*
* EXIT Entry added and args updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD AddDnsServerAddressInfo(PIP_ADAPTER_DNS_SERVER_ADDRESS **ppNext, LPSOCKADDR Addr, SIZE_T AddrLen)
{
DWORD dwErr = NO_ERROR;
PIP_ADAPTER_DNS_SERVER_ADDRESS pCurr;
LPSOCKADDR pAddr;
pCurr = MALLOC(sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS));
if (!pCurr) {
return ERROR_NOT_ENOUGH_MEMORY;
}
pAddr = MALLOC(AddrLen);
if (!pAddr) {
FREE(pCurr);
return ERROR_NOT_ENOUGH_MEMORY;
}
memcpy(pAddr, Addr, AddrLen);
// Add address to linked list
**ppNext = pCurr;
*ppNext = &pCurr->Next;
pCurr->Next = NULL;
pCurr->Length = sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS);
pCurr->Address.iSockaddrLength = (INT)AddrLen;
pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
return dwErr;
}
/*******************************************************************************
* GetAdapterDnsServers
*
* This routine reads a list of DNS server addresses from a registry key.
*
* ENTRY TcpipKey - Registry key to look under
* pCurr - Interface entry to add servers to
*
* EXIT Entry updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD
GetAdapterDnsServers(HKEY TcpipKey, PIP_ADAPTER_ADDRESSES pCurr)
{
DWORD Size, Type, dwErr, i;
CHAR Servers[800], *Str;
PIP_ADAPTER_DNS_SERVER_ADDRESS *ppDNext;
ADDRINFO hints, *ai;
static LONG Initialized = FALSE;
if (InterlockedExchange(&Initialized, TRUE) == FALSE) {
WSADATA WsaData;
dwErr = WSAStartup(MAKEWORD(2, 0), &WsaData);
if (NO_ERROR != dwErr) {
return dwErr;
}
}
//
// Read DNS Server addresses.
//
Size = sizeof(Servers);
ZeroMemory(Servers, Size);
dwErr = RegQueryValueExA(TcpipKey, (LPSTR)"NameServer", NULL, &Type,
(LPBYTE)Servers, &Size);
if (NO_ERROR != dwErr) {
if (ERROR_FILE_NOT_FOUND != dwErr) {
return dwErr;
}
Size = 0;
Type = REG_SZ;
}
if (REG_SZ != Type) {
return ERROR_INVALID_DATA;
}
if ((0 == Size) || (0 == strlen(Servers))) {
Size = sizeof(Servers);
dwErr = RegQueryValueExA(TcpipKey, (LPSTR)"DhcpNameServer", NULL,
&Type, (LPBYTE)Servers, &Size);
if (NO_ERROR != dwErr) {
if (ERROR_FILE_NOT_FOUND != dwErr) {
return dwErr;
}
Size = 0;
Type = REG_SZ;
}
}
//
// If there are any DNS Servers, convert them to sockaddrs
//
ZeroMemory(&hints, sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
ppDNext = &pCurr->FirstDnsServerAddress;
while (*ppDNext) {
ppDNext = &(*ppDNext)->Next;
}
if ((0 != Size) && strlen(Servers)) {
for (i = 0; i < Size; i ++) {
if (Servers[i] == ' ' || Servers[i] == ','
|| Servers[i] == ';') {
Servers[i] = '\0';
}
}
Servers[Size] = '\0';
for (Str = (LPSTR)Servers;
*Str != '\0';
Str += strlen(Str) + 1)
{
if (getaddrinfo(Str, NULL, &hints, &ai) == NO_ERROR) {
AddDnsServerAddressInfo(&ppDNext, ai->ai_addr, ai->ai_addrlen);
freeaddrinfo(ai);
}
}
}
return NO_ERROR;
}
/*******************************************************************************
* GetAdapterDnsInfo
*
* This routine reads DNS configuration information for an interface.
*
* ENTRY dwFamily - Address family constraint
* name - Adapter name
* pCurr - Interface entry to update
* AppFlags - Flags controlling what fields to skip, if any
*
* EXIT Entry updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD
GetAdapterDnsInfo(DWORD dwFamily, char *name, PIP_ADAPTER_ADDRESSES pCurr, DWORD AppFlags)
{
WCHAR Buffer[MAX_DOMAIN_NAME_LEN+1];
DWORD dwErr = NO_ERROR, Size, Type, Value;
DWORD DnsSuffixSize = sizeof(Buffer);
HKEY TcpipKey = NULL;
PIP_ADAPTER_DNS_SERVER_ADDRESS DnsServerAddr;
LPSOCKADDR_IN6 Sockaddr;
Buffer[0] = L'\0';
pCurr->DnsSuffix = NULL;
pCurr->Flags = IP_ADAPTER_DDNS_ENABLED;
if (name == NULL) {
//
// If we couldn't find an adapter name, just use the default settings.
//
goto Done;
}
for (;;) {
if (!OpenAdapterKey(KEY_TCP, name, KEY_READ, &TcpipKey)) {
dwErr = ERROR_CAN_NOT_COMPLETE;
break;
}
//
// Get DnsSuffix for the interface
//
Size = DnsSuffixSize;
dwErr = RegQueryValueExW(TcpipKey, (LPWSTR)L"Domain", NULL, &Type,
(LPBYTE)Buffer, &Size );
if (NO_ERROR != dwErr) {
if (ERROR_FILE_NOT_FOUND != dwErr) {
break;
}
Size = 0;
Type = REG_SZ;
}
if (REG_SZ != Type) {
dwErr = ERROR_INVALID_DATA;
break;
}
if ((0 == Size) || (0 == wcslen(Buffer))) {
Size = DnsSuffixSize;
dwErr = RegQueryValueExW(TcpipKey, (LPWSTR)L"DhcpDomain", NULL,
&Type, (LPBYTE)Buffer, &Size );
if (NO_ERROR != dwErr) {
if (ERROR_FILE_NOT_FOUND != dwErr) {
break;
}
Size = 0;
Buffer[0] = L'\0';
}
}
if (MyReadRegistryDword(TcpipKey, "RegistrationEnabled",
&Value) && (Value == 0)) {
pCurr->Flags &= ~IP_ADAPTER_DDNS_ENABLED;
}
if (MyReadRegistryDword(TcpipKey,
"RegisterAdapterName", &Value)
&& Value) {
pCurr->Flags |= IP_ADAPTER_REGISTER_ADAPTER_SUFFIX;
}
//
// Now attempt to read the DnsServers list
//
if (!(AppFlags & GAA_FLAG_SKIP_DNS_SERVER)) {
if ((dwFamily != AF_INET) && bIp6DriverInstalled) {
//
// First look for IPv6 servers.
//
HKEY Tcpip6Key = NULL;
if (OpenAdapterKey(KEY_TCP6, name, KEY_READ, &Tcpip6Key)) {
GetAdapterDnsServers(Tcpip6Key, pCurr);
RegCloseKey(Tcpip6Key);
}
if (pCurr->FirstDnsServerAddress == NULL) {
//
// None are configured, so use the default list of
// well-known addresses.
//
SOCKADDR_IN6 Addr;
PIP_ADAPTER_DNS_SERVER_ADDRESS *ppDNext;
BYTE i;
ZeroMemory(&Addr, sizeof(Addr));
Addr.sin6_family = AF_INET6;
Addr.sin6_addr.s6_words[0] = 0xC0FE;
Addr.sin6_addr.s6_words[3] = 0xFFFF;
ppDNext = &pCurr->FirstDnsServerAddress;
while (*ppDNext) {
ppDNext = &(*ppDNext)->Next;
}
for (i=1; i<=3; i++) {
Addr.sin6_addr.s6_bytes[15] = i;
AddDnsServerAddressInfo(&ppDNext, (LPSOCKADDR)&Addr, sizeof(Addr));
}
}
// Now we need to go through any non-global IPv6 DNS server
// addresses and fill in the scope id.
for (DnsServerAddr = pCurr->FirstDnsServerAddress;
DnsServerAddr;
DnsServerAddr = DnsServerAddr->Next) {
if (DnsServerAddr->Address.lpSockaddr->sa_family != AF_INET6)
continue;
Sockaddr = (LPSOCKADDR_IN6)DnsServerAddr->Address.lpSockaddr;
if (IN6_IS_ADDR_LINKLOCAL(&Sockaddr->sin6_addr))
Sockaddr->sin6_scope_id = pCurr->ZoneIndices[ADE_LINK_LOCAL];
else if (IN6_IS_ADDR_SITELOCAL(&Sockaddr->sin6_addr))
Sockaddr->sin6_scope_id = pCurr->ZoneIndices[ADE_SITE_LOCAL];
}
}
if (dwFamily != AF_INET6) {
//
// Finally, add IPv4 servers.
//
GetAdapterDnsServers(TcpipKey, pCurr);
}
}
break;
}
if (TcpipKey) {
RegCloseKey(TcpipKey);
}
Done:
pCurr->DnsSuffix = MALLOC((wcslen(Buffer)+1) * sizeof(WCHAR));
if (pCurr->DnsSuffix) {
wcscpy(pCurr->DnsSuffix, Buffer);
}
return dwErr;
}
/*******************************************************************************
* NewIpAdapter
*
* This routine allocates an IP_ADAPTER_ADDRESSES entry and appends it to
* a list of such entries.
*
* ENTRY ppCurr - Location in which to return new entry
* ppNext - Previous entry's "next" pointer to update
* name - Adapter name
* Ipv4IfIndex - IPv4 Interface index
* Ipv6IfIndex - IPv6 Interface index
* AppFlags - Flags controlling what fields to skip, if any
* IfType - IANA ifType value
* Mtu - Maximum transmission unit
* PhysAddr - MAC address
* PhysAddrLen - Byte count of PhysAddr
* Description - Adapter description
* FriendlyName - User-friendly interface name
* Family - Address family constraint for DNS servers
*
* EXIT ppCurr and ppNext updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD NewIpAdapter(PIP_ADAPTER_ADDRESSES *ppCurr, PIP_ADAPTER_ADDRESSES **ppNext, char *AdapterName, char *NameForDnsInfo, UINT Ipv4IfIndex, UINT Ipv6IfIndex, DWORD AppFlags, DWORD IfType, SIZE_T Mtu, BYTE *PhysAddr, DWORD PhysAddrLen, PWCHAR Description, PWCHAR FriendlyName, DWORD *ZoneIndices, DWORD Family)
{
*ppCurr = MALLOC(sizeof(IP_ADAPTER_ADDRESSES));
if (!*ppCurr) {
return ERROR_NOT_ENOUGH_MEMORY;
}
ZeroMemory(*ppCurr, sizeof(IP_ADAPTER_ADDRESSES));
(*ppCurr)->AdapterName = MALLOC(strlen(AdapterName)+1);
if (!(*ppCurr)->AdapterName) {
goto Fail;
}
(*ppCurr)->Description = MALLOC((wcslen(Description)+1) * sizeof(WCHAR));
if (!(*ppCurr)->Description) {
goto Fail;
}
(*ppCurr)->FriendlyName = MALLOC((wcslen(FriendlyName)+1) * sizeof(WCHAR));
if (!(*ppCurr)->FriendlyName) {
goto Fail;
}
(*ppCurr)->Next = NULL;
(*ppCurr)->Length = sizeof(IP_ADAPTER_ADDRESSES);
strcpy((*ppCurr)->AdapterName, AdapterName);
(*ppCurr)->IfIndex = Ipv4IfIndex;
(*ppCurr)->Ipv6IfIndex = Ipv6IfIndex;
(*ppCurr)->FirstUnicastAddress = NULL;
(*ppCurr)->FirstAnycastAddress = NULL;
(*ppCurr)->FirstMulticastAddress = NULL;
(*ppCurr)->FirstDnsServerAddress = NULL;
(*ppCurr)->OperStatus = IfOperStatusUp;
CopyMemory((*ppCurr)->ZoneIndices, ZoneIndices, ADE_GLOBAL * sizeof(DWORD));
(*ppCurr)->ZoneIndices[ADE_GLOBAL] = 0;
(*ppCurr)->ZoneIndices[ADE_LARGEST_SCOPE] = 0;
//(*ppCurr)->Mtu = Mtu; "dword should be enough for MTU"
(*ppCurr)->Mtu = (DWORD)Mtu;
(*ppCurr)->IfType = IfType;
(*ppCurr)->PhysicalAddressLength = PhysAddrLen;
memcpy((*ppCurr)->PhysicalAddress, PhysAddr, PhysAddrLen);
wcscpy((*ppCurr)->Description, Description);
wcscpy((*ppCurr)->FriendlyName, FriendlyName);
GetAdapterDnsInfo(Family,
(NameForDnsInfo != NULL)? NameForDnsInfo : AdapterName,
*ppCurr, AppFlags);
if ((*ppCurr)->DnsSuffix == NULL) {
goto Fail;
}
**ppNext = *ppCurr;
*ppNext = &(*ppCurr)->Next;
return NO_ERROR;
Fail:
if ((*ppCurr)->AdapterName) {
FREE((*ppCurr)->AdapterName);
}
if ((*ppCurr)->FriendlyName) {
FREE((*ppCurr)->FriendlyName);
}
if ((*ppCurr)->Description) {
FREE((*ppCurr)->Description);
}
FREE(*ppCurr);
return ERROR_NOT_ENOUGH_MEMORY;
}
/*******************************************************************************
* FindOrCreateIpAdapter
*
* This routine finds an existing IP_ADAPTER_ADDRESSES entry (if any), or
* creates a new one and appends it to a list of such entries.
*
* ENTRY pFirst - Pointer to start of list to search
* ppCurr - Location in which to return new entry
* ppNext - Previous entry's "next" pointer to update
* name - Adapter name
* Ipv4IfIndex - IPv4 Interface index
* Ipv6IfIndex - IPv6 Interface index
* AppFlags - Flags controlling what fields to skip, if any
* IfType - IANA ifType value
* Mtu - Maximum transmission unit
* PhysAddr - MAC address
* PhysAddrLen - Byte count of PhysAddr
* Description - Adapter description
* FriendlyName - User-friendly interface name
* Family - Address family constraint (for DNS servers)
*
* EXIT ppCurr and ppNext updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD FindOrCreateIpAdapter(PIP_ADAPTER_ADDRESSES pFirst, PIP_ADAPTER_ADDRESSES *ppCurr, PIP_ADAPTER_ADDRESSES **ppNext, char *AdapterName, char *NameForDnsInfo, UINT Ipv4IfIndex, UINT Ipv6IfIndex, DWORD AppFlags, DWORD IfType, SIZE_T Mtu, BYTE *PhysAddr, DWORD PhysAddrLen, PWCHAR Description, PWCHAR FriendlyName, DWORD *ZoneIndices, DWORD Family)
{
PIP_ADAPTER_ADDRESSES pIf;
// Look for an existing entry for the GUID.
for (pIf = pFirst; pIf; pIf = pIf->Next) {
if (!strcmp(AdapterName, pIf->AdapterName)) {
if (Ipv4IfIndex != 0) {
ASSERT(pIf->IfIndex == 0);
pIf->IfIndex = Ipv4IfIndex;
}
if (Ipv6IfIndex != 0) {
PIP_ADAPTER_DNS_SERVER_ADDRESS pDNS;
PSOCKADDR_IN6 pAddr;
ASSERT(pIf->Ipv6IfIndex == 0);
pIf->Ipv6IfIndex = Ipv6IfIndex;
CopyMemory(pIf->ZoneIndices, ZoneIndices,
ADE_GLOBAL * sizeof(DWORD));
//
// Now that we have the zone ids, we need to update
// any IPv6 scoped DNS server addresses that were
// already added.
//
for (pDNS = pIf->FirstDnsServerAddress;
pDNS != NULL;
pDNS = pDNS->Next) {
if (pDNS->Address.lpSockaddr->sa_family != AF_INET6) {
continue;
}
pAddr = (PSOCKADDR_IN6) pDNS->Address.lpSockaddr;
if (IN6_IS_ADDR_LINKLOCAL(&pAddr->sin6_addr)) {
pAddr->sin6_scope_id = ZoneIndices[ScopeLevelLink];
} else if (IN6_IS_ADDR_SITELOCAL(&pAddr->sin6_addr)) {
pAddr->sin6_scope_id = ZoneIndices[ScopeLevelSite];
}
}
}
*ppCurr = pIf;
return NO_ERROR;
}
}
return NewIpAdapter(ppCurr, ppNext, AdapterName, NameForDnsInfo,
Ipv4IfIndex, Ipv6IfIndex, AppFlags, IfType, Mtu,
PhysAddr, PhysAddrLen, Description, FriendlyName,
ZoneIndices, Family);
}
__inline int IN6_IS_ADDR_6TO4(const struct in6_addr *a)
{
return ((a->s6_bytes[0] == 0x20) && (a->s6_bytes[1] == 0x02));
}
__inline int IN6_IS_ADDR_ISATAP(const struct in6_addr *a)
{
return (((a->s6_words[4] & 0xfffd) == 0) && (a->s6_words[5] == 0xfe5e));
}
//
// This array is used to convert from an internal IPv6 interface type value,
// as defined in ntddip6.h, to an IANA ifType value as defined in ipifcons.h.
//
DWORD
IPv6ToMibIfType[] = {
IF_TYPE_SOFTWARE_LOOPBACK,
IF_TYPE_ETHERNET_CSMACD,
IF_TYPE_FDDI,
IF_TYPE_TUNNEL,
IF_TYPE_TUNNEL,
IF_TYPE_TUNNEL,
IF_TYPE_TUNNEL,
IF_TYPE_TUNNEL
};
#define NUM_IPV6_IFTYPES (sizeof(IPv6ToMibIfType)/sizeof(DWORD))
/*******************************************************************************
* AddIPv6Prefix
*
* This routine adds an IP_ADAPTER_PREFIX entry for an IPv6 prefix
* to a list of entries.
*
* ENTRY Addr - IPv6 prefix (network byte order)
* MaskLen - IPv6 prefix length
* arg1 - Initial prefix entry, for duplicate avoidance
* arg2 - Previous prefix entry's "next" pointer to update
*
* EXIT Entry added and arg2 updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD AddIPv6Prefix(IN6_ADDR *Addr, DWORD MaskLen, PVOID arg1, PVOID arg2)
{
PIP_ADAPTER_PREFIX pFirst = *(PIP_ADAPTER_PREFIX*)arg1;
PIP_ADAPTER_PREFIX **ppNext = (PIP_ADAPTER_PREFIX**)arg2;
PIP_ADAPTER_PREFIX pCurr;
LPSOCKADDR_IN6 pAddr;
// Check if already in the list
for (pCurr = pFirst; pCurr; pCurr = pCurr->Next) {
if ((pCurr->PrefixLength == MaskLen) &&
(pCurr->Address.lpSockaddr->sa_family == AF_INET6) &&
IN6_ADDR_EQUAL(&((LPSOCKADDR_IN6)pCurr->Address.lpSockaddr)->sin6_addr, Addr)) {
return NO_ERROR;
}
}
pCurr = MALLOC(sizeof(IP_ADAPTER_PREFIX));
if (!pCurr) {
return ERROR_NOT_ENOUGH_MEMORY;
}
pAddr = MALLOC(sizeof(SOCKADDR_IN6));
if (!pAddr) {
FREE(pCurr);
return ERROR_NOT_ENOUGH_MEMORY;
}
memset(pAddr, 0, sizeof(SOCKADDR_IN6));
pAddr->sin6_family = AF_INET6;
pAddr->sin6_addr = *Addr;
// Add address to linked list
**ppNext = pCurr;
*ppNext = &pCurr->Next;
pCurr->Length = sizeof(IP_ADAPTER_PREFIX);
pCurr->Flags = 0;
pCurr->Next = NULL;
pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN6);
pCurr->PrefixLength = MaskLen;
return NO_ERROR;
}
/*******************************************************************************
* AddIPv6AutoAddressInfo
*
* This routine adds an IP_ADAPTER_UNICAST_ADDRESS entry for an IPv6 address
* on an "automatic tunnel" interface to a list of entries.
*
* ENTRY IF - IPv6 interface information
* ADE - IPv6 address entry
* arg1 - Previous entry's "next" pointer to update
* arg2 - Adapter info structure
* arg3 - "First" entry pointer to update
* arg4 - List of all adapters
* Flags - flags specified by application
* Family - Address family constraint (for DNS)
*
* EXIT Entry added and arg1 updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD AddIPv6AutoAddressInfo(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, DWORD Flags, DWORD Family)
{
PIP_ADAPTER_ADDRESSES **ppNext = (PIP_ADAPTER_ADDRESSES**)arg1;
IP_ADAPTER_INFO *pAdapterInfo = (IP_ADAPTER_INFO *)arg2;
PIP_ADAPTER_ADDRESSES pCurr, *ppFirst = (PIP_ADAPTER_ADDRESSES*)arg3;
PIP_ADAPTER_ADDRESSES pAdapterAddresses = (PIP_ADAPTER_ADDRESSES)arg4;
PIP_ADAPTER_UNICAST_ADDRESS *pNextUnicastAddr;
PIP_ADAPTER_ANYCAST_ADDRESS *pNextAnycastAddr;
PIP_ADAPTER_MULTICAST_ADDRESS *pNextMulticastAddr;
PIP_ADAPTER_PREFIX *pNextPrefix;
CHAR szGuid[80];
char *NameForDnsInfo, *pszDescription;
DWORD Ipv4Address, dwErr, dwIfType;
WCHAR wszFriendlyName[MAX_INTERFACE_NAME_LEN+1], *pwszDescription;
ULONG PrefixLength = 64;
IN6_ADDR Prefix;
if (ADE->Type != ADE_UNICAST) {
return NO_ERROR;
}
ConvertGuidToStringA(&IF->This.Guid, szGuid);
//
// We need the GUID ("NameForDnsInfo") of an interface which we
// can use to find additional relevant configuration information.
// For IPv6 pseudo-interfaces, we'll extract the IPv4 address, and
// find the GUID of the interface it's on, and use that, which assumes
// that configuration information (e.g. the DNS server to use) will
// still apply.
//
if (IF->Type == IPV6_IF_TYPE_TUNNEL_6TO4) {
if (IN6_IS_ADDR_6TO4(&ADE->This.Address)) {
// Extract IPv4 address from middle of IPv6 address
memcpy(&Ipv4Address, &ADE->This.Address.s6_bytes[2], sizeof(Ipv4Address));
} else {
return NO_ERROR;
}
pwszDescription = L"6to4 Tunneling Pseudo-Interface";
} else {
if (IN6_IS_ADDR_V4COMPAT(&ADE->This.Address) ||
IN6_IS_ADDR_ISATAP(&ADE->This.Address)) {
// Extract IPv4 address from last 4 bytes of IPv6 address
memcpy(&Ipv4Address, &ADE->This.Address.s6_bytes[12], sizeof(Ipv4Address));
} else {
return NO_ERROR;
}
pwszDescription = L"Automatic Tunneling Pseudo-Interface";
if (IN6_IS_ADDR_V4COMPAT(&ADE->This.Address)) {
PrefixLength = 96;
}
}
// Look for an existing interface with same physical address and index.
for (pCurr = *ppFirst; pCurr; pCurr = pCurr->Next) {
if ((pCurr->Ipv6IfIndex == ADE->This.IF.Index) &&
(*(DWORD*)pCurr->PhysicalAddress == Ipv4Address)) {
break;
}
}
if (pCurr == NULL) {
// Add an interface
NameForDnsInfo = MapIpv4AddressToName(pAdapterInfo, Ipv4Address,
&pszDescription);
if (NameForDnsInfo == NULL) {
return NO_ERROR;
}
wcscpy(wszFriendlyName, pwszDescription);
dwIfType = (IF->Type < NUM_IPV6_IFTYPES)? IPv6ToMibIfType[IF->Type]
: MIB_IF_TYPE_OTHER;
//
// Inherit some zone ids from the underlying interface.
//
for (pCurr = pAdapterAddresses; pCurr != NULL; pCurr = pCurr->Next) {
if (strcmp(pCurr->AdapterName, NameForDnsInfo) == 0) {
IF->ZoneIndices[ADE_SITE_LOCAL] =
pCurr->ZoneIndices[ADE_SITE_LOCAL];
if (pCurr->ZoneIndices[ADE_ADMIN_LOCAL] ==
pCurr->ZoneIndices[ADE_SITE_LOCAL]) {
IF->ZoneIndices[ADE_ADMIN_LOCAL] =
pCurr->ZoneIndices[ADE_ADMIN_LOCAL];
if (pCurr->ZoneIndices[ADE_SUBNET_LOCAL] ==
pCurr->ZoneIndices[ADE_SITE_LOCAL]) {
IF->ZoneIndices[ADE_SUBNET_LOCAL] =
pCurr->ZoneIndices[ADE_SUBNET_LOCAL];
}
}
break;
}
}
dwErr = NewIpAdapter(&pCurr, ppNext, szGuid, NameForDnsInfo,
0, ADE->This.IF.Index, Flags, dwIfType,
IF->LinkMTU, (BYTE*)&Ipv4Address,
sizeof(Ipv4Address), pwszDescription,
wszFriendlyName, (DWORD*)IF->ZoneIndices, Family);
if (dwErr != NO_ERROR) {
return dwErr;
}
// 6to4 and automatic tunneling interfaces don't support multicast
// today.
pCurr->Flags |= IP_ADAPTER_NO_MULTICAST;
if (*ppFirst == NULL) {
*ppFirst = pCurr;
}
}
// Add the address to the interface
pNextUnicastAddr = &pCurr->FirstUnicastAddress;
while (*pNextUnicastAddr) {
pNextUnicastAddr = &(*pNextUnicastAddr)->Next;
}
pNextAnycastAddr = &pCurr->FirstAnycastAddress;
while (*pNextAnycastAddr) {
pNextAnycastAddr = &(*pNextAnycastAddr)->Next;
}
pNextMulticastAddr = &pCurr->FirstMulticastAddress;
while (*pNextMulticastAddr) {
pNextMulticastAddr = &(*pNextMulticastAddr)->Next;
}
dwErr = AddIPv6AddressInfo(IF, ADE, &pNextUnicastAddr, &pNextAnycastAddr,
&pNextMulticastAddr, NULL, Flags, Family);
if (dwErr != NO_ERROR) {
return dwErr;
}
// Add the prefix to the interface
if (Flags & GAA_FLAG_INCLUDE_PREFIX) {
ZeroMemory(&Prefix, sizeof(Prefix));
CopyMemory(&Prefix, &ADE->This.Address, PrefixLength / 8);
pNextPrefix = &pCurr->FirstPrefix;
while (*pNextPrefix) {
pNextPrefix = &(*pNextPrefix)->Next;
}
dwErr = AddIPv6Prefix(&Prefix, PrefixLength, &pCurr->FirstPrefix,
&pNextPrefix);
}
return dwErr;
}
/*******************************************************************************
* GetString
*
* This routine reads a string value from the registry.
*
* ENTRY hKey - Handle to registry key
* lpName - Name of value to read
* pwszBuff - Buffer in which to place value read
* ulBytes - Size of buffer
*
* EXIT pwszBuff filled in
*
* RETURNS TRUE on success, FALSE on failure
*
******************************************************************************/
BOOL
GetString(HKEY hKey, LPCWSTR lpName, PWCHAR pwszBuff, SIZE_T ulBytes)
{
DWORD dwErr, dwType;
ULONG ulSize, ulValue;
ulSize = sizeof(ulValue);
dwErr = RegQueryValueExW(hKey, lpName, NULL, &dwType, (PBYTE)pwszBuff,
(LPDWORD)&ulBytes);
if (dwErr != ERROR_SUCCESS) {
return FALSE;
}
if (dwType != REG_SZ) {
return FALSE;
}
return TRUE;
}
BOOL MapAdapterNameToFriendlyName(GUID *Guid, char *name, PWCHAR pwszFriendlyName, ULONG ulNumChars)
{
DWORD dwErr, dwTemp;
dwTemp = ulNumChars;
//
// The following call can be time-consuming the first time it is called.
// If the caller doesn't need the friendly name, it should use the
// GAA_FLAG_SKIP_FRIENDLY_NAME flag, in which case we won't get called.
//
dwErr = HrLanConnectionNameFromGuidOrPath(Guid, NULL, pwszFriendlyName,
&dwTemp);
if (dwErr == NO_ERROR) {
return TRUE;
}
//
// NhGetInterfaceNameFromDeviceGuid uses a byte count rather than
// a character count.
//
dwTemp = ulNumChars * sizeof(WCHAR);
dwErr = NhGetInterfaceNameFromDeviceGuid(Guid, pwszFriendlyName, &dwTemp,
TRUE, FALSE );
if (dwErr == NO_ERROR) {
return TRUE;
}
MultiByteToWideChar(CP_ACP, 0, name, -1, pwszFriendlyName, ulNumChars);
return FALSE;
}
#define KEY_TCPIP6_IF L"System\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces"
VOID MapIpv6AdapterNameToFriendlyName(GUID *Guid, char *name, PWCHAR pwszFriendlyName, ULONG ulBytes)
{
DWORD dwErr;
HKEY hInterfaces = NULL, hIf = NULL;
CHAR szGuid[40];
if (MapAdapterNameToFriendlyName(Guid, name, pwszFriendlyName,
ulBytes/sizeof(WCHAR))) {
return;
}
dwErr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, KEY_TCPIP6_IF, 0, GENERIC_READ,
&hInterfaces);
if (dwErr != NO_ERROR) {
goto Fail;
}
dwErr = RegOpenKeyEx(hInterfaces, name, 0, GENERIC_READ, &hIf);
if (dwErr != NO_ERROR) {
goto Fail;
}
if (GetString(hIf, L"FriendlyName", pwszFriendlyName, ulBytes)) {
goto Cleanup;
}
Fail:
ConvertGuidToStringA(Guid, szGuid);
MultiByteToWideChar(CP_ACP, 0, szGuid, -1,
pwszFriendlyName, ulBytes / sizeof(WCHAR));
Cleanup:
if (hInterfaces) {
RegCloseKey(hInterfaces);
}
if (hIf) {
RegCloseKey(hIf);
}
}
IN6_ADDR Ipv6LinkLocalPrefix = { 0xfe, 0x80 };
/*******************************************************************************
* ForEachIPv6Prefix
*
* This routine walks the IPv6 routing table and invokes a given function
* on each prefix on a given interface.
*
* ENTRY Ipv6IfIndex - IPv6 interface index
* func - Function to invoke on each address
* arg1 - Argument to pass to func
* arg2 - Argument to pass to func
*
* EXIT Nothing
*
* RETURNS Error status
*
******************************************************************************/
DWORD ForEachIPv6Prefix(ULONG Ipv6IfIndex, DWORD (*func)(IN6_ADDR *, DWORD, PVOID, PVOID), PVOID arg1, PVOID arg2)
{
IPV6_QUERY_ROUTE_TABLE Query, NextQuery;
IPV6_INFO_ROUTE_TABLE RTE;
DWORD BytesIn, BytesReturned;
ULONG dwErr = NO_ERROR;
BOOL SawLinkLocal = FALSE;
ZeroMemory(&NextQuery, sizeof(NextQuery));
for (;;) {
Query = NextQuery;
BytesIn = sizeof Query;
BytesReturned = sizeof RTE;
dwErr = WsControl(IPPROTO_IPV6,
IOCTL_IPV6_QUERY_ROUTE_TABLE,
&Query, &BytesIn,
&RTE, &BytesReturned);
if (dwErr != NO_ERROR) {
return dwErr;
}
NextQuery = RTE.Next;
RTE.This = Query;
// Skip if it's not an onlink prefix for this interface.
if ((RTE.This.Neighbor.IF.Index == Ipv6IfIndex) &&
!IN6_IS_ADDR_MULTICAST(&RTE.This.Prefix)) {
if (IN6_IS_ADDR_LINKLOCAL(&RTE.This.Prefix)) {
// This interface has link-local addresses
// (the 6to4 interface, for example, does not).
SawLinkLocal = TRUE;
}
if ((RTE.Type != RTE_TYPE_SYSTEM) &&
IN6_IS_ADDR_UNSPECIFIED(&RTE.This.Neighbor.Address)) {
dwErr = func(&RTE.This.Prefix, RTE.This.PrefixLength,
arg1, arg2);
if (dwErr != NO_ERROR) {
return dwErr;
}
}
}
if (NextQuery.Neighbor.IF.Index == 0) {
break;
}
}
if (SawLinkLocal) {
dwErr = func(&Ipv6LinkLocalPrefix, 64, arg1, arg2);
}
return dwErr;
}
//
// This array is used to convert from an internal IPv6 media status value,
// as defined in ntddip6.h, to a MIB ifOperStatus value as defined in
// iptypes.h.
//
DWORD
IPv6ToMibOperStatus[] = {
IfOperStatusDown, // IPV6_IF_MEDIA_STATUS_DISCONNECTED
IfOperStatusUp, // IPV6_IF_MEDIA_STATUS_RECONNECTED
IfOperStatusUp, // IPV6_IF_MEDIA_STATUS_CONNECTED
};
#define NUM_IPV6_MEDIA_STATUSES (sizeof(IPv6ToMibOperStatus)/sizeof(DWORD))
#define IPV6_LOOPBACK_NAME L"Loopback Pseudo-Interface"
#define IPV6_TEREDO_NAME L"Teredo Tunneling Pseudo-Interface"
/*******************************************************************************
* AddIPv6InterfaceInfo
*
* This routine adds an IP_ADAPTER_ADDRESSES entry for an IPv6 interface
* to a list of such entries.
*
* ENTRY IF - IPv6 interface information
* arg1 - Previous entry's "next" pointer to update
* arg2 - Pointer to start of interface list
* pAdapterInfo - Additional adapter information
* Flags - Flags specified by application
* Family - Address family constraint (for DNS servers)
*
* EXIT Entry added and arg1 updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD AddIPv6InterfaceInfo(IPV6_INFO_INTERFACE *IF, PVOID arg1, PVOID arg2, IP_ADAPTER_INFO *pAdapterInfo, DWORD Flags, DWORD Family)
{
DWORD dwErr = NO_ERROR;
PIP_ADAPTER_ADDRESSES **ppNext = (PIP_ADAPTER_ADDRESSES**)arg1;
PIP_ADAPTER_ADDRESSES pFirst = *(PIP_ADAPTER_ADDRESSES*)arg2;
PIP_ADAPTER_ADDRESSES pCurr;
PIP_ADAPTER_UNICAST_ADDRESS *pNextUnicastAddr;
PIP_ADAPTER_ANYCAST_ADDRESS *pNextAnycastAddr;
PIP_ADAPTER_MULTICAST_ADDRESS *pNextMulticastAddr;
PIP_ADAPTER_PREFIX *pNextPrefix;
char *NameForDnsInfo = NULL, *pszDescription;
u_char *LinkLayerAddress;
DWORD Ipv4Address, dwIfType;
WCHAR wszDescription[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
WCHAR wszFriendlyName[MAX_INTERFACE_NAME_LEN + 1];
CHAR AdapterName[MAX_ADAPTER_NAME_LENGTH + 1];
LinkLayerAddress = (u_char *)(IF + 1);
ConvertGuidToStringA(&IF->This.Guid, AdapterName);
//
// Get a description and adapter name.
//
switch (IF->Type) {
case IPV6_IF_TYPE_TUNNEL_6TO4:
wcscpy(wszDescription, L"6to4 Pseudo-Interface");
NameForDnsInfo = AdapterName;
pCurr = NULL;
dwErr = ForEachIPv6Address(IF, AddIPv6AutoAddressInfo,
ppNext, pAdapterInfo, (PVOID)&pCurr,
pFirst, Flags, Family);
if (dwErr != NO_ERROR) {
return dwErr;
}
//
// Ensure that there exists an entry for the 6to4 interface.
//
if (pCurr == NULL) {
dwErr = NewIpAdapter(&pCurr, ppNext, AdapterName,
NameForDnsInfo, 0, IF->This.Index, Flags,
IF_TYPE_TUNNEL, IF->LinkMTU,
LinkLayerAddress, IF->LinkLayerAddressLength,
wszDescription, wszDescription,
(DWORD*)IF->ZoneIndices, Family);
}
return dwErr;
case IPV6_IF_TYPE_TUNNEL_AUTO:
wcscpy(wszDescription, L"Automatic Tunneling Pseudo-Interface");
NameForDnsInfo = AdapterName;
pCurr = NULL;
dwErr = ForEachIPv6Address(IF, AddIPv6AutoAddressInfo,
ppNext, pAdapterInfo, (PVOID)&pCurr,
pFirst, Flags, Family);
if (dwErr != NO_ERROR) {
return dwErr;
}
//
// Ensure that there exists an entry for the ISATAP interface.
//
if (pCurr == NULL) {
dwErr = NewIpAdapter(&pCurr, ppNext, AdapterName,
NameForDnsInfo, 0, IF->This.Index, Flags,
IF_TYPE_TUNNEL, IF->LinkMTU,
LinkLayerAddress, IF->LinkLayerAddressLength,
wszDescription, wszDescription,
(DWORD*)IF->ZoneIndices, Family);
}
return dwErr;
case IPV6_IF_TYPE_TUNNEL_6OVER4:
wcscpy(wszDescription, L"6over4 Pseudo-Interface");
memcpy(&Ipv4Address, LinkLayerAddress, sizeof(Ipv4Address));
NameForDnsInfo = MapIpv4AddressToName(pAdapterInfo, Ipv4Address, &pszDescription);
if (NameForDnsInfo == NULL) {
//
// IPv4 address does not exist, so just use the interface GUID.
//
NameForDnsInfo = AdapterName;
}
break;
case IPV6_IF_TYPE_TUNNEL_V6V4:
wcscpy(wszDescription, L"Configured Tunnel Interface");
memcpy(&Ipv4Address, LinkLayerAddress, sizeof(Ipv4Address));
NameForDnsInfo = MapIpv4AddressToName(pAdapterInfo, Ipv4Address, &pszDescription);
if (NameForDnsInfo == NULL) {
//
// IPv4 address does not exist, so just use the interface GUID.
//
NameForDnsInfo = AdapterName;
}
break;
case IPV6_IF_TYPE_TUNNEL_TEREDO:
wcscpy(wszDescription, IPV6_TEREDO_NAME);
NameForDnsInfo = AdapterName;
break;
case IPV6_IF_TYPE_LOOPBACK:
wcscpy(wszDescription, IPV6_LOOPBACK_NAME);
NameForDnsInfo = AdapterName;
break;
default:
NameForDnsInfo = MapGuidToAdapterName(pAdapterInfo,
&IF->This.Guid,
wszDescription);
if (NameForDnsInfo != NULL) {
strcpy(AdapterName, NameForDnsInfo);
}
}
if (Flags & GAA_FLAG_SKIP_FRIENDLY_NAME) {
wszFriendlyName[0] = L'\0';
} else if (IF->Type == IPV6_IF_TYPE_TUNNEL_TEREDO) {
//
// The Teredo interface does not have a friendly name.
//
wcscpy(wszFriendlyName, IPV6_TEREDO_NAME);
} else if (IF->Type == IPV6_IF_TYPE_LOOPBACK) {
//
// The IPv6 loopback interface will not have a friendly name,
// so use the same string as the description we set above.
//
wcscpy(wszFriendlyName, IPV6_LOOPBACK_NAME);
} else {
MapIpv6AdapterNameToFriendlyName(&IF->This.Guid, AdapterName,
wszFriendlyName,
sizeof(wszFriendlyName));
}
dwIfType = (IF->Type < NUM_IPV6_IFTYPES)? IPv6ToMibIfType[IF->Type]
: MIB_IF_TYPE_OTHER;
dwErr = FindOrCreateIpAdapter(pFirst, &pCurr, ppNext, AdapterName,
NameForDnsInfo, 0, IF->This.Index, Flags,
dwIfType, IF->LinkMTU, LinkLayerAddress,
IF->LinkLayerAddressLength, wszDescription,
wszFriendlyName, (DWORD*)IF->ZoneIndices,
Family);
if (dwErr != NO_ERROR) {
return dwErr;
}
if (IF->OtherStatefulConfig != 0) {
pCurr->Flags |= IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG;
}
pCurr->OperStatus = (IF->MediaStatus < NUM_IPV6_MEDIA_STATUSES)
? IPv6ToMibOperStatus[IF->MediaStatus]
: IfOperStatusUnknown;
// Add addresses
pNextUnicastAddr = &pCurr->FirstUnicastAddress;
while (*pNextUnicastAddr) {
pNextUnicastAddr = &(*pNextUnicastAddr)->Next;
}
pNextAnycastAddr = &pCurr->FirstAnycastAddress;
while (*pNextAnycastAddr) {
pNextAnycastAddr = &(*pNextAnycastAddr)->Next;
}
pNextMulticastAddr = &pCurr->FirstMulticastAddress;
while (*pNextMulticastAddr) {
pNextMulticastAddr = &(*pNextMulticastAddr)->Next;
}
dwErr = ForEachIPv6Address(IF, AddIPv6AddressInfo, &pNextUnicastAddr,
&pNextAnycastAddr, &pNextMulticastAddr,
NULL, Flags,
Family);
if (dwErr != NO_ERROR) {
return dwErr;
}
// Add prefixes
if (Flags & GAA_FLAG_INCLUDE_PREFIX) {
pNextPrefix = &pCurr->FirstPrefix;
while (*pNextPrefix) {
pNextPrefix = &(*pNextPrefix)->Next;
}
dwErr = ForEachIPv6Prefix(IF->This.Index, AddIPv6Prefix,
&pCurr->FirstPrefix, &pNextPrefix);
}
return dwErr;
}
#define MAX_LINK_LEVEL_ADDRESS_LENGTH 64
/*******************************************************************************
* ForEachIPv6Interface
*
* This routine walks a set of IPv6 interfaces and invokes a given function
* on each one.
*
* ENTRY func - Function to invoke on each interface
* arg1 - Argument to pass to func
* arg2 - Argument to pass to func
* pAdapterInfo - List of adapter information
* Flags - Flags to pass to func
* Family - Address family constraint (for DNS servers)
*
* EXIT Nothing
*
* RETURNS Error status
*
******************************************************************************/
DWORD ForEachIPv6Interface(DWORD (*func)(IPV6_INFO_INTERFACE *, PVOID, PVOID, IP_ADAPTER_INFO *, DWORD, DWORD), PVOID arg1, PVOID arg2, IP_ADAPTER_INFO *pAdapterInfo, DWORD Flags, DWORD Family)
{
IPV6_QUERY_INTERFACE Query;
IPV6_INFO_INTERFACE *IF;
DWORD InfoSize, BytesReturned, BytesIn;
DWORD dwErr;
InfoSize = sizeof *IF + 2 * MAX_LINK_LEVEL_ADDRESS_LENGTH;
IF = (IPV6_INFO_INTERFACE *) MALLOC(InfoSize);
if (IF == NULL) {
return ERROR_NOT_ENOUGH_MEMORY;
}
Query.Index = (u_int) -1;
for (;;) {
BytesIn = sizeof Query;
BytesReturned = InfoSize;
dwErr = WsControl( IPPROTO_IPV6,
IOCTL_IPV6_QUERY_INTERFACE,
&Query, &BytesIn,
IF, &BytesReturned);
if (dwErr != NO_ERROR) {
if (dwErr == ERROR_FILE_NOT_FOUND) {
// IPv6 is not installed
dwErr = NO_ERROR;
}
break;
}
if (Query.Index != (u_int) -1) {
if ((BytesReturned < sizeof *IF) ||
(IF->Length < sizeof *IF) ||
(BytesReturned != IF->Length +
((IF->LocalLinkLayerAddress != 0) ?
IF->LinkLayerAddressLength : 0) +
((IF->RemoteLinkLayerAddress != 0) ?
IF->LinkLayerAddressLength : 0))) {
dwErr = ERROR_INVALID_PARAMETER;
break;
}
dwErr = (*func)(IF, arg1, arg2, pAdapterInfo, Flags, Family);
if (dwErr != NO_ERROR) {
break;
}
}
if (IF->Next.Index == (u_int) -1)
break;
Query = IF->Next;
}
FREE(IF);
return dwErr;
}
//
// IPv4 equivalents of some standard IN6_* macros
//
#define IN_IS_ADDR_LOOPBACK(x) (*(x) == INADDR_LOOPBACK)
#define IN_IS_ADDR_LINKLOCAL(x) ((*(x) & 0x0000ffff) == 0x0000fea9)
/*******************************************************************************
* AddIPv4MulticastAddressInfo
*
* This routine adds an IP_ADAPTER_MULTICAST_ADDRESS entry for an IPv4 address
* to a list of entries.
*
* ENTRY IF - interface information
* Addr - IPv4 address
* pFirst - First multicast entry
* ppNext - Previous multicast entry's "next" pointer to update
*
* EXIT Entry added and args updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD AddIPv4MulticastAddressInfo(IP_ADAPTER_INFO *IF, DWORD Addr, PIP_ADAPTER_MULTICAST_ADDRESS *pFirst, PIP_ADAPTER_MULTICAST_ADDRESS **ppNext)
{
DWORD dwErr = NO_ERROR;
PIP_ADAPTER_MULTICAST_ADDRESS pCurr;
SOCKADDR_IN *pAddr;
UNREFERENCED_PARAMETER(IF);
for (pCurr=*pFirst; pCurr; pCurr=pCurr->Next) {
pAddr = (SOCKADDR_IN *)pCurr->Address.lpSockaddr;
if (pAddr->sin_family == AF_INET
&& pAddr->sin_addr.s_addr == Addr) {
return NO_ERROR;
}
}
pCurr = MALLOC(sizeof(IP_ADAPTER_MULTICAST_ADDRESS));
if (!pCurr) {
return ERROR_NOT_ENOUGH_MEMORY;
}
pAddr = MALLOC(sizeof(SOCKADDR_IN));
if (!pAddr) {
FREE(pCurr);
return ERROR_NOT_ENOUGH_MEMORY;
}
memset(pAddr, 0, sizeof(SOCKADDR_IN));
pAddr->sin_family = AF_INET;
pAddr->sin_addr.s_addr = Addr;
// Add address to linked list
**ppNext = pCurr;
*ppNext = &pCurr->Next;
pCurr->Next = NULL;
pCurr->Length = sizeof(IP_ADAPTER_MULTICAST_ADDRESS);
pCurr->Flags = 0;
pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN);
pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
return dwErr;
}
/*******************************************************************************
* AddIPv4UnicastAddressInfo
*
* This routine adds an IP_ADAPTER_UNICAST_ADDRESS entry for an IPv4 address
* to a list of entries.
*
* ENTRY IF - IPv4 interface information
* ADE - IPv4 address entry
* arg1 - Previous unicast entry's "next" pointer to update
* arg2 - Initial multicast entry, for duplicate avoidance
* arg3 - Previous multicast entry's "next" pointer to update
* AppFlags - Flags specified by application
*
* EXIT Entry added and arg1 updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD AddIPv4UnicastAddressInfo(IP_ADAPTER_INFO *IF, MIB_IPADDRROW *ADE, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, DWORD AppFlags)
{
PIP_ADAPTER_UNICAST_ADDRESS **ppNext = (PIP_ADAPTER_UNICAST_ADDRESS**)arg1;
PIP_ADAPTER_UNICAST_ADDRESS pCurr;
SOCKADDR_IN *pAddr;
DWORD Address, *pIfFlags = (DWORD *)arg4;
time_t Curtime;
DWORD dwStatus = NO_ERROR, i;
Address = ADE->dwAddr;
if (!Address) {
// Do nothing if address is 0.0.0.0
return NO_ERROR;
}
if ((Address & 0x000000FF) == 0) {
//
// An address in 0/8 isn't a real IP address, it's a fake one that
// the IPv4 stack sticks on a receive-only adapter.
//
(*pIfFlags) |= IP_ADAPTER_RECEIVE_ONLY;
return NO_ERROR;
}
if (!(AppFlags & GAA_FLAG_SKIP_UNICAST)) {
pCurr = MALLOC(sizeof(IP_ADAPTER_UNICAST_ADDRESS));
if (!pCurr) {
return ERROR_NOT_ENOUGH_MEMORY;
}
pAddr = MALLOC(sizeof(SOCKADDR_IN));
if (!pAddr) {
FREE(pCurr);
return ERROR_NOT_ENOUGH_MEMORY;
}
memset(pAddr, 0, sizeof(SOCKADDR_IN));
pAddr->sin_family = AF_INET;
memcpy(&pAddr->sin_addr, &Address, sizeof(Address));
// Add address to linked list
**ppNext = pCurr;
*ppNext = &pCurr->Next;
time(&Curtime);
pCurr->Next = NULL;
pCurr->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
pCurr->LeaseLifetime = (ULONG)(IF->LeaseExpires - Curtime);
pCurr->ValidLifetime = pCurr->PreferredLifetime = pCurr->LeaseLifetime;
pCurr->Flags = 0;
pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN);
pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
pCurr->PrefixOrigin = IpPrefixOriginManual;
pCurr->SuffixOrigin = IpSuffixOriginManual;
if (IF->DhcpEnabled) {
if (IN_IS_ADDR_LINKLOCAL(&Address)) {
pCurr->PrefixOrigin = IpPrefixOriginWellKnown;
pCurr->SuffixOrigin = IpSuffixOriginRandom;
} else {
pCurr->PrefixOrigin = IpPrefixOriginDhcp;
pCurr->SuffixOrigin = IpSuffixOriginDhcp;
}
}
pCurr->DadState = IpDadStatePreferred;
if ((pCurr->DadState == IpDadStatePreferred) &&
(pCurr->SuffixOrigin != IpSuffixOriginRandom) &&
!IN_IS_ADDR_LOOPBACK(&Address) &&
!IN_IS_ADDR_LINKLOCAL(&Address)) {
pCurr->Flags |= IP_ADAPTER_ADDRESS_DNS_ELIGIBLE;
}
if (ADE->wType & MIB_IPADDR_TRANSIENT) {
pCurr->Flags |= IP_ADAPTER_ADDRESS_TRANSIENT;
}
}
// Now add any new multicast addresses
if (!(AppFlags & GAA_FLAG_SKIP_MULTICAST)) {
DWORD *pIgmpList = NULL;
DWORD dwTotal, dwOutBufLen = 0;
dwStatus = GetIgmpList(Address, pIgmpList, &dwOutBufLen);
if (dwStatus == ERROR_INSUFFICIENT_BUFFER) {
pIgmpList = MALLOC(dwOutBufLen);
if (!pIgmpList) {
return ERROR_NOT_ENOUGH_MEMORY;
}
dwStatus = GetIgmpList(Address, pIgmpList, &dwOutBufLen);
}
if (dwStatus != NO_ERROR) {
if (pIgmpList) {
FREE(pIgmpList);
}
return dwStatus;
}
dwTotal = dwOutBufLen/sizeof(Address);
for (i=0; (i<dwTotal) && (dwStatus == NO_ERROR); i++) {
dwStatus = AddIPv4MulticastAddressInfo(IF, pIgmpList[i],
(PIP_ADAPTER_MULTICAST_ADDRESS *)arg2,
(PIP_ADAPTER_MULTICAST_ADDRESS **)arg3);
}
if (pIgmpList) {
FREE(pIgmpList);
}
}
return dwStatus;
}
/*******************************************************************************
* ForEachIPv4Address
*
* This routine walks a set of IPv4 addresses and invokes a given function
* on each one.
*
* ENTRY IF - IPv4 interface information
* func - Function to invoke on each address
* arg1 - Argument to pass to func
* arg2 - Argument to pass to func
* arg3 - Argument to pass to func
* Flags - Flags to pass to func
* pIpAddrTable - IPv4 address table with per-address flags
*
* EXIT Nothing
*
* RETURNS Error status
*
******************************************************************************/
DWORD ForEachIPv4Address(IP_ADAPTER_INFO *IF, DWORD (*func)(IP_ADAPTER_INFO *,PMIB_IPADDRROW, PVOID, PVOID, PVOID, PVOID, DWORD), PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, DWORD Flags, PMIB_IPADDRTABLE pIpAddrTable)
{
DWORD dwErr, i;
PMIB_IPADDRROW ADE;
for (i=0; i<pIpAddrTable->dwNumEntries; i++) {
ADE = &pIpAddrTable->table[i];
if (ADE->dwIndex != IF->Index) {
continue;
}
dwErr = (*func)(IF, ADE, arg1, arg2, arg3, arg4, Flags);
if (dwErr != NO_ERROR) {
return dwErr;
}
}
return NO_ERROR;
}
DWORD
MaskToMaskLen(
DWORD dwMask
)
{
register int i;
for (i=0; i<32 && !(dwMask & (1<<i)); i++);
return 32-i;
}
/*******************************************************************************
* AddIPv4Prefix
*
* This routine adds an IP_ADAPTER_PREFIX entry for an IPv4 prefix
* to a list of entries.
*
* ENTRY IF - IPv4 interface information
* Addr - IPv4 prefix (network byte order)
* MaskLen - IPv4 prefix length
* arg1 - Initial prefix entry, for duplicate avoidance
* arg2 - Previous prefix entry's "next" pointer to update
*
* EXIT Entry added and arg2 updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD AddIPv4Prefix(DWORD Addr, DWORD MaskLen, PVOID arg1, PVOID arg2)
{
PIP_ADAPTER_PREFIX pFirst = *(PIP_ADAPTER_PREFIX*)arg1;
PIP_ADAPTER_PREFIX **ppNext = (PIP_ADAPTER_PREFIX**)arg2;
PIP_ADAPTER_PREFIX pCurr;
LPSOCKADDR_IN pAddr;
// Check if already in the list
for (pCurr = pFirst; pCurr; pCurr = pCurr->Next) {
if ((pCurr->PrefixLength == MaskLen) &&
(pCurr->Address.lpSockaddr->sa_family == AF_INET) &&
(((LPSOCKADDR_IN)pCurr->Address.lpSockaddr)->sin_addr.s_addr == Addr)) {
return NO_ERROR;
}
}
pCurr = MALLOC(sizeof(IP_ADAPTER_PREFIX));
if (!pCurr) {
return ERROR_NOT_ENOUGH_MEMORY;
}
pAddr = MALLOC(sizeof(SOCKADDR_IN));
if (!pAddr) {
FREE(pCurr);
return ERROR_NOT_ENOUGH_MEMORY;
}
memset(pAddr, 0, sizeof(SOCKADDR_IN));
pAddr->sin_family = AF_INET;
pAddr->sin_addr.s_addr = Addr;
// Add address to linked list
**ppNext = pCurr;
*ppNext = &pCurr->Next;
pCurr->Length = sizeof(IP_ADAPTER_PREFIX);
pCurr->Flags = 0;
pCurr->Next = NULL;
pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN);
pCurr->PrefixLength = MaskLen;
return NO_ERROR;
}
/*******************************************************************************
* ForEachIPv4Prefix
*
* This routine walks a set of IPv4 prefixes and invokes a given function
* on each one.
*
* ENTRY IF - IPv4 interface information
* func - Function to invoke on each address
* arg1 - Argument to pass to func
* arg2 - Argument to pass to func
*
* EXIT Nothing
*
* RETURNS Error status
*
******************************************************************************/
DWORD ForEachIPv4Prefix(IP_ADAPTER_INFO *IF, DWORD (*func)(DWORD, DWORD, PVOID, PVOID), PVOID arg1, PVOID arg2)
{
PIP_ADDR_STRING Prefix;
DWORD Addr, Mask, MaskLen, dwErr;
for (Prefix = &IF->IpAddressList; Prefix; Prefix = Prefix->Next) {
if (Prefix->IpAddress.String[0] == '\0') {
continue;
}
Mask = inet_addr(Prefix->IpMask.String);
Addr = inet_addr(Prefix->IpAddress.String) & Mask;
MaskLen = MaskToMaskLen(ntohl(Mask));
dwErr = func(Addr, MaskLen, arg1, arg2);
if (dwErr != NO_ERROR) {
return dwErr;
}
}
return NO_ERROR;
}
//
// This array is used to convert from an internal IPv4 oper status value,
// as defined in ipifcons.h, to a MIB ifOperStatus value as defined in
// iptypes.h.
//
DWORD
IPv4ToMibOperStatus[] = {
IfOperStatusDown, // IF_OPER_STATUS_NON_OPERATIONAL
IfOperStatusDown, // IF_OPER_STATUS_UNREACHABLE
IfOperStatusDormant, // IF_OPER_STATUS_DISCONNECTED
IfOperStatusDormant, // IF_OPER_STATUS_CONNECTING
IfOperStatusUp, // IF_OPER_STATUS_CONNECTED
IfOperStatusUp, // IF_OPER_STATUS_OPERATIONAL
};
#define NUM_IPV4_OPER_STATUSES (sizeof(IPv4ToMibOperStatus)/sizeof(DWORD))
/*******************************************************************************
* AddIPv4InterfaceInfo
*
* This routine adds an IP_ADAPTER_ADDRESSES entry for an IPv4 interface
* to a list of such entries.
*
* ENTRY IF - IPv4 interface information
* arg1 - Previous entry's "next" pointer to update
* arg2 - Pointer to start of interface list
* Flags - Flags controlling what fields to skip, if any
* Family - Address family constraint (for DNS server addresses)
* pAddrTable - IPv4 address table
*
* EXIT Entry added and arg updated
*
* RETURNS Error status
*
******************************************************************************/
DWORD AddIPv4InterfaceInfo(IP_ADAPTER_INFO *IF, PVOID arg1, PVOID arg2, DWORD Flags, DWORD Family, PMIB_IPADDRTABLE pAddrTable)
{
DWORD dwErr = NO_ERROR, i;
PIP_ADAPTER_ADDRESSES **ppNext = (PIP_ADAPTER_ADDRESSES**)arg1;
PIP_ADAPTER_ADDRESSES pFirst = *(PIP_ADAPTER_ADDRESSES*)arg2;
PIP_ADAPTER_ADDRESSES pCurr;
PIP_ADAPTER_UNICAST_ADDRESS *pNextUAddr;
PIP_ADAPTER_MULTICAST_ADDRESS *pNextMAddr;
PIP_ADAPTER_PREFIX *pNextPrefix;
WCHAR wszDescription[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
WCHAR wszFriendlyName[MAX_INTERFACE_NAME_LEN + 1];
MIB_IFROW IfEntry;
GUID Guid;
DWORD ZoneIndices[ADE_NUM_SCOPES];
MultiByteToWideChar(CP_ACP, 0, IF->Description, -1,
wszDescription, MAX_ADAPTER_DESCRIPTION_LENGTH);
//
// Get information which isn't in IP_ADAPTER_INFO.
//
dwErr = GetIfEntryFromStack(&IfEntry, IF->Index, FALSE);
if (dwErr != NO_ERROR) {
return dwErr;
}
if (ConvertStringToGuidA(IF->AdapterName, &Guid) != NO_ERROR) {
ZeroMemory(&Guid, sizeof(Guid));
}
//
// Fill in some dummy zone indices.
//
ZoneIndices[0] = ZoneIndices[1] = ZoneIndices[2] = ZoneIndices[3] = IF->Index;
for (i=ADE_ADMIN_LOCAL; i<ADE_NUM_SCOPES; i++) {
ZoneIndices[i] = 1;
}
if (Flags & GAA_FLAG_SKIP_FRIENDLY_NAME) {
wszFriendlyName[0] = L'\0';
} else {
MapAdapterNameToFriendlyName(&Guid, IF->AdapterName, wszFriendlyName,
MAX_INTERFACE_NAME_LEN+1);
}
dwErr = FindOrCreateIpAdapter(pFirst, &pCurr, ppNext, IF->AdapterName,
IF->AdapterName, IF->Index, 0, Flags,
IF->Type, IfEntry.dwMtu, IF->Address,
IF->AddressLength, wszDescription, wszFriendlyName,
ZoneIndices, Family);
if (dwErr != NO_ERROR) {
return dwErr;
}
pCurr->OperStatus = (IfEntry.dwOperStatus < NUM_IPV4_OPER_STATUSES)
? IPv4ToMibOperStatus[IfEntry.dwOperStatus]
: IfOperStatusUnknown;
if (IF->DhcpEnabled) {
pCurr->Flags |= IP_ADAPTER_DHCP_ENABLED;
}
// Add addresses
pNextUAddr = &pCurr->FirstUnicastAddress;
pNextMAddr = &pCurr->FirstMulticastAddress;
dwErr = ForEachIPv4Address(IF, AddIPv4UnicastAddressInfo, &pNextUAddr,
pNextMAddr, &pNextMAddr, &pCurr->Flags,
Flags, pAddrTable);
if (dwErr != NO_ERROR) {
return dwErr;
}
// Add prefixes
if (Flags & GAA_FLAG_INCLUDE_PREFIX) {
pNextPrefix = &pCurr->FirstPrefix;
dwErr = ForEachIPv4Prefix(IF, AddIPv4Prefix, &pCurr->FirstPrefix,
&pNextPrefix);
}
return dwErr;
}
IP_ADAPTER_INFO IPv4LoopbackInterfaceInfo = {
NULL, // Next
1, // ComboIndex
"MS TCP Loopback interface", // AdapterName
"MS TCP Loopback interface", // Description
0, // Address Length
{0}, // Address
1, // Index
MIB_IF_TYPE_LOOPBACK, // Type
FALSE, // DhcpEnabled
NULL, // CurrentIpAddress,
{NULL}, // IpAddressList,
{NULL}, // GatewayList,
{NULL}, // DhcpServer,
FALSE, // HaveWins
{NULL}, // PrimaryWinsServer,
{NULL}, // SecondaryWinsServer,
0, // LeaseObtained
0 // LeaseExpires
};
/*******************************************************************************
* ForEachIPv4Interface
*
* This routine walks a set of IPv4 interfaces and invokes a given function
* on each one.
*
* ENTRY func - Function to invoke on each interface
* arg1 - Argument to pass to func
* arg2 - Argument to pass to func
* pAdapterInfo - List of IPv4 interfaces
* Flags - Flags to pass to func
* Family - Address family constraint (for DNS server addresses)
*
* EXIT Nothing
*
* RETURNS Error status
*
******************************************************************************/
DWORD ForEachIPv4Interface(DWORD (*func)(IP_ADAPTER_INFO *, PVOID, PVOID, DWORD, DWORD, PMIB_IPADDRTABLE), PVOID arg1, PVOID arg2, IP_ADAPTER_INFO *pAdapterInfo, DWORD Flags, DWORD Family, PMIB_IPADDRTABLE pIpAddrTable)
{
PIP_ADAPTER_INFO IF;
DWORD dwErr;
for (IF=pAdapterInfo; IF; IF=IF->Next) {
//
// An empty adapter name indicates the adapter should not be reported.
//
if (IF->AdapterName[0] == '\0') {
continue;
}
dwErr = (*func)(IF, arg1, arg2, Flags, Family, pIpAddrTable);
if (dwErr != NO_ERROR) {
return dwErr;
}
}
//
// The IPv4 loopback interface is missing from the pAdapterInfo list,
// so we special case it here.
//
dwErr = (*func)(&IPv4LoopbackInterfaceInfo, arg1, arg2, Flags, Family,
pIpAddrTable);
if (dwErr != NO_ERROR) {
return dwErr;
}
return NO_ERROR;
}
DWORD GetAdapterAddresses(ULONG Family, DWORD Flags, PIP_ADAPTER_ADDRESSES *pAddresses)
{
IP_ADAPTER_INFO *pAdapterInfo = NULL;
PIP_ADAPTER_ADDRESSES adapterList, *pCurr;
DWORD dwErr = NO_ERROR;
PMIB_IPADDRTABLE pIpAddrTable = NULL;
TRACE_PRINT(("Entered GetAdapterAddresses\n"));
pAdapterInfo = GetAdapterInfo();
*pAddresses = adapterList = NULL;
pCurr = &adapterList;
//
// If we want to return IPv6 DNS servers, find out now whether the
// IPv6 stack is installed.
//
if ((Family != AF_INET) && !(Flags & GAA_FLAG_SKIP_DNS_SERVER)) {
IPV6_GLOBAL_PARAMETERS Params;
DWORD BytesReturned = sizeof(Params);
DWORD InputBufferLength = 0;
dwErr = WsControl(IPPROTO_IPV6,
IOCTL_IPV6_QUERY_GLOBAL_PARAMETERS,
NULL, &InputBufferLength,
&Params, &BytesReturned);
bIp6DriverInstalled = (dwErr == NO_ERROR);
dwErr = NO_ERROR;
}
if ((Family == AF_UNSPEC) || (Family == AF_INET)) {
DWORD dwSize = 0;
//
// GetAdapterInfo alone isn't sufficient since it doesn't get
// per-address flags whereas GetIpAddrTable does.
// GetIpAddrTable doesn't get per-interface info however,
// so this is why we have to do both. We use pAdapterInfo
// for per-interface info and pIpAddrTable for
// per-address info.
//
dwErr = GetIpAddrTable(NULL, &dwSize, TRUE);
if (dwErr == ERROR_INSUFFICIENT_BUFFER) {
pIpAddrTable = MALLOC(dwSize);
if (!pIpAddrTable) {
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
dwErr = GetIpAddrTable(pIpAddrTable, &dwSize, TRUE);
}
if (dwErr != NO_ERROR) {
goto Cleanup;
}
dwErr = ForEachIPv4Interface(AddIPv4InterfaceInfo, &pCurr, &adapterList,
pAdapterInfo, Flags, Family, pIpAddrTable);
if (dwErr != NO_ERROR) {
goto Cleanup;
}
}
if ((Family == AF_UNSPEC) || (Family == AF_INET6)) {
dwErr = ForEachIPv6Interface(AddIPv6InterfaceInfo, &pCurr, &adapterList,
pAdapterInfo, Flags, Family);
if (dwErr != NO_ERROR) {
goto Cleanup;
}
}
*pAddresses = adapterList;
adapterList = NULL;
Cleanup:
if (pIpAddrTable) {
FREE(pIpAddrTable);
}
if (pAdapterInfo) {
KillAdapterInfo(pAdapterInfo);
}
if (adapterList) {
KillAdapterAddresses(adapterList);
}
TRACE_PRINT(("Exit GetAdapterAddresses %p\n", adapterList));
return dwErr;
}
/*******************************************************************************
*
* InternalGetPerAdapterInfo
*
* Gets per-adapter special information.
*
* ENTRY IfIndex
*
* EXIT nothing
*
* RETURNS pointer to the IP_PER_ADAPTER_INFO structure
*
* ASSUMES
*
******************************************************************************/
PIP_PER_ADAPTER_INFO InternalGetPerAdapterInfo(ULONG IfIndex)
{
PIP_ADAPTER_INFO adapterList;
PIP_ADAPTER_INFO adapter;
PIP_PER_ADAPTER_INFO perAdapterInfo = NULL;
HKEY key;
BOOL ok;
TRACE_PRINT(("Entered GetPerAdapterList\n"));
if ((adapterList = GetAdapterInfo()) != NULL) {
//
// scan the adapter list and find one that matches IfIndex
//
for (adapter = adapterList; adapter; adapter = adapter->Next) {
TRACE_PRINT(("GetPerAdapterInfo: '%s'\n", adapter->AdapterName));
if (adapter->Index == IfIndex &&
adapter->AdapterName[0] &&
OpenAdapterKey(KEY_TCP, adapter->AdapterName, KEY_READ, &key)) {
//
// found the right adapter so let's fill up the perAdapterInfo
//
perAdapterInfo = NEW(IP_PER_ADAPTER_INFO);
if (perAdapterInfo == NULL) {
DEBUG_PRINT(("GetPerAdapterInfo: no memory for perAdapterInfo\n"));
KillAdapterInfo(adapterList);
RegCloseKey(key);
return NULL;
}
ZeroMemory(perAdapterInfo, sizeof(IP_PER_ADAPTER_INFO));
if (!MyReadRegistryDword(key,
TEXT("IPAutoconfigurationEnabled"),
(LPDWORD)&perAdapterInfo->AutoconfigEnabled)) {
//
// autoconfig is enabled if no regval exists for this
// adapter
//
perAdapterInfo->AutoconfigEnabled = TRUE;
TRACE_PRINT(("IPAutoconfigurationEnabled not read\n"));
}
TRACE_PRINT(("IPAutoconfigurationEnableda = %d\n",
perAdapterInfo->AutoconfigEnabled));
if (perAdapterInfo->AutoconfigEnabled) {
MyReadRegistryDword(key,
TEXT("AddressType"),
(LPDWORD)&perAdapterInfo->AutoconfigActive);
TRACE_PRINT(("AddressType !%d\n",
perAdapterInfo->AutoconfigActive));
}
//
// DNS Server list: first NameServer and then DhcpNameServer
//
ok = ReadRegistryIpAddrString(key,
TEXT("NameServer"),
&perAdapterInfo->DnsServerList);
if (ok) {
TRACE_PRINT(("GetPerAdapterInfo: DhcpNameServer %s\n",
perAdapterInfo->DnsServerList));
}
if (!ok) {
ok = ReadRegistryIpAddrString(key,
TEXT("DhcpNameServer"),
&perAdapterInfo->DnsServerList);
if (ok) {
TRACE_PRINT(("GetPerAdapterInfo: DhcpNameServer %s\n",
perAdapterInfo->DnsServerList));
}
}
//
// we are done so let's exit the loop
//
RegCloseKey(key);
break;
} else {
DEBUG_PRINT(("Cannot OpenAdapterKey KEY_TCP '%s', gle=%d\n",
adapter->AdapterName,
GetLastError()));
}
}
KillAdapterInfo(adapterList);
} else {
DEBUG_PRINT(("GetPerAdapterInfo: GetAdapterInfo returns NULL\n"));
}
TRACE_PRINT(("Exit GetPerAdapterInfo %p\n", perAdapterInfo));
return perAdapterInfo;
}
/*******************************************************************************
*
* OpenAdapterKey
*
* Opens one of the 3 per-adapter registry keys:
* Tcpip\\Parameters"\<adapter>
* or NetBT\Adapters\<Adapter>
* or Tcpip6\Paramters\<adapter>
*
* ENTRY KeyType - KEY_TCP or KEY_NBT or KEY_TCP6
* Name - pointer to adapter name to use
* Key - pointer to returned key
*
* EXIT Key updated
*
* RETURNS TRUE if success
*
* ASSUMES
* HISTORY: MohsinA, 16-May-97. Fixing for PNP.
*
******************************************************************************/
static
BOOL OpenAdapterKey(DWORD KeyType, const LPSTR Name, REGSAM Access, PHKEY Key)
{
LONG err;
CHAR keyName[MAX_ADAPTER_NAME_LENGTH + sizeof(TCPIP_PARAMS_INTER_KEY)];
switch (KeyType) {
case KEY_TCP:
//
// open the handle to this adapter's TCPIP parameter key
//
strcpy(keyName, TCPIP_PARAMS_INTER_KEY );
strcat(keyName, Name);
break;
case KEY_TCP6:
//
// open the handle to this adapter's TCPIP6 parameter key
//
strcpy(keyName, TCPIP6_PARAMS_INTER_KEY );
strcat(keyName, Name);
break;
case KEY_NBT:
//
// open the handle to the NetBT\Adapters\<Adapter> handle
//
strcpy(keyName, NETBT_ADAPTER_KEY );
strcat(keyName, Name);
break;
default:
return FALSE;
}
TRACE_PRINT(("OpenAdapterKey: %s\n", keyName ));
err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, Access, Key );
if( err != ERROR_SUCCESS ){
DEBUG_PRINT(("OpenAdapterKey: RegOpenKey %s, err=%d\n",
keyName, GetLastError() ));
}else{
TRACE_PRINT(("Exit OpenAdapterKey: %s ok\n", keyName ));
}
return (err == ERROR_SUCCESS);
}
BOOL WriteRegistryDword(HKEY hKey, LPSTR szParameter, DWORD *pdwValue )
{
DWORD dwResult;
TRACE_PRINT(("WriteRegistryDword: %s %d\n", szParameter, *pdwValue ));
dwResult = RegSetValueEx(
hKey,
szParameter,
0,
REG_DWORD,
(CONST BYTE *) pdwValue,
sizeof( *pdwValue )
);
return ( ERROR_SUCCESS == dwResult );
}
BOOL WriteRegistryMultiString(HKEY hKey,
LPSTR szParameter,
LPSTR szValue
)
{
DWORD dwResult;
LPSTR psz;
for (psz = szValue; *psz; psz += lstrlen(szValue) + 1) { }
dwResult = RegSetValueEx(
hKey,
szParameter,
0,
REG_MULTI_SZ,
(CONST BYTE *) szValue,
(DWORD)(psz - szValue) + 1
);
return ( ERROR_SUCCESS == dwResult );
}
/*******************************************************************************
*
* MyReadRegistryDword
*
* Reads a registry value that is stored as a DWORD
*
* ENTRY Key - open registry key where value resides
* ParameterName - name of value to read from registry
* Value - pointer to returned value
*
* EXIT *Value = value read
*
* RETURNS TRUE if success
*
* ASSUMES
*
******************************************************************************/
BOOL MyReadRegistryDword(HKEY Key, LPSTR ParameterName, LPDWORD Value)
{
LONG err;
DWORD valueLength;
DWORD valueType;
valueLength = sizeof(*Value);
err = RegQueryValueEx(Key,
ParameterName,
NULL, // reserved
&valueType,
(LPBYTE)Value,
&valueLength
);
if ((err == ERROR_SUCCESS) && (valueType == REG_DWORD) && (valueLength == sizeof(DWORD))) {
DEBUG_PRINT(("MyReadRegistryDword(%s): val = %d, type = %d, len = %d\n",
ParameterName,
*Value,
valueType,
valueLength
));
} else {
DEBUG_PRINT(("MyReadRegistryDword(%p,%s): err = %d\n",
Key, ParameterName, err));
err = !ERROR_SUCCESS;
}
return (err == ERROR_SUCCESS);
}
// ========================================================================
// Was DWORD IPInterfaceContext, now CHAR NTEContextList[][].
// Reads in a REG_MULTI_SZ and converts it into a list of numbers.
// MohsinA, 21-May-97.
// ========================================================================
// max length of REG_MULTI_SZ.
#define MAX_VALUE 5002
BOOL
ReadRegistryList(HKEY Key, LPSTR ParameterName,
DWORD NumList[], int *MaxList
)
{
LONG err;
DWORD valueType;
BYTE Value[MAX_VALUE];
DWORD valueLength = MAX_VALUE;
SIZE_T i = 0;
int k = 0;
err = RegQueryValueEx(Key,
ParameterName,
NULL,
&valueType,
&Value[0],
&valueLength
);
if( ( err == ERROR_SUCCESS) &&
( valueType == REG_MULTI_SZ ) &&
((valueLength+2) < MAX_VALUE)
){
TRACE_PRINT(("ReadRegistryList %s ok\n", ParameterName ));
Value[MAX_VALUE-1] = '\0';
Value[MAX_VALUE-2] = '\0';
while( (i < MAX_VALUE) && Value[i] && (k < (*MaxList)) ){
NumList[k] = strtoul( (const char*)&Value[i], NULL, 0 );
TRACE_PRINT((" NumList[%d] = '%s' => %d\n",
k, &Value[i], NumList[k] ));
k++;
i += strlen( (const char*)&Value[i] ) + 1;
}
assert( (i < MAX_VALUE) && !Value[i] && (k < MaxList) );
*MaxList = k;
}
else
{
*MaxList = 0;
DEBUG_PRINT(("ReadRegistryList %s failed\n", ParameterName ));
err = !ERROR_SUCCESS;
}
return (err == ERROR_SUCCESS);
}
BOOL
IsIncluded( DWORD Context, DWORD contextlist[], int len_contextlist )
{
int i;
for( i = 0; i < len_contextlist; i++ )
{
if( Context == contextlist[i] ){
return TRUE;
}
}
return FALSE;
}
/*******************************************************************************
*
* ReadRegistryString
*
* Reads a registry value that is stored as a string
*
* ENTRY Key - open registry key
* ParameterName - name of value to read from registry
* String - pointer to returned string
* Length - IN: length of String buffer. OUT: length of returned string
*
* EXIT String contains string read
*
* RETURNS TRUE if success
*
* ASSUMES
*
******************************************************************************/
BOOL ReadRegistryString(HKEY Key, LPSTR ParameterName, LPSTR String, LPDWORD Length)
{
LONG err;
DWORD valueType;
*String = '\0';
err = RegQueryValueEx(Key,
ParameterName,
NULL, // reserved
&valueType,
(LPBYTE)String,
Length
);
if (err == ERROR_SUCCESS) {
ASSERT(valueType == REG_SZ || valueType == REG_MULTI_SZ);
DEBUG_PRINT(("ReadRegistryString(%s): val = \"%s\", type = %d, len = %d\n",
ParameterName,
String,
valueType,
*Length
));
} else {
DEBUG_PRINT(("ReadRegistryString(%s): err = %d\n", ParameterName, err));
}
return ((err == ERROR_SUCCESS) && (*Length > sizeof('\0')));
}
/*******************************************************************************
*
* ReadRegistryOemString
*
* Reads a registry value as a wide character string
*
* ENTRY Key - open registry key
* ParameterName - name of value to read from registry
* String - pointer to returned string
* Length - IN: length of String buffer. OUT: length of returned string
*
* EXIT String contains string read
*
* RETURNS TRUE if success
*
* ASSUMES
*
******************************************************************************/
BOOL ReadRegistryOemString(HKEY Key, LPWSTR ParameterName, LPSTR String, LPDWORD Length)
{
LONG err;
DWORD valueType;
DWORD valueLength;
//
// first, get the length of the string
//
*String = '\0';
err = RegQueryValueExW(Key,
ParameterName,
NULL, // reserved
&valueType,
NULL,
&valueLength
);
if ((err == ERROR_SUCCESS) && (valueType == REG_SZ)) {
if ((valueLength <= *Length) && (valueLength > sizeof(L'\0'))) {
UNICODE_STRING unicodeString;
OEM_STRING oemString;
LPWSTR str = (LPWSTR)GrabMemory(valueLength);
if (!str) {
return FALSE;
}
//
// read the UNICODE string into allocated memory
//
err = RegQueryValueExW(Key,
ParameterName,
NULL,
&valueType,
(LPBYTE)str,
&valueLength
);
if (err == ERROR_SUCCESS) {
NTSTATUS Status;
//
// convert the UNICODE string to OEM character set
//
RtlInitUnicodeString(&unicodeString, str);
Status = RtlUnicodeStringToOemString(&oemString, &unicodeString, TRUE);
if (NT_SUCCESS(Status)) {
strcpy(String, oemString.Buffer);
RtlFreeOemString(&oemString);
} else {
err = !ERROR_SUCCESS;
}
DEBUG_PRINT(("ReadRegistryOemString(%ws): val = \"%s\", len = %d\n",
ParameterName,
String,
valueLength
));
} else {
DEBUG_PRINT(("ReadRegistryOemString(%ws): err = %d, type = %d, len = %d\n",
ParameterName,
err,
valueType,
valueLength
));
}
ReleaseMemory(str);
} else {
DEBUG_PRINT(("ReadRegistryOemString(%ws): err = %d, type = %d, len = %d\n",
ParameterName,
err,
valueType,
valueLength
));
err = !ERROR_SUCCESS;
}
} else {
DEBUG_PRINT(("ReadRegistryOemString(%ws): err = %d, type = %d, len = %d\n",
ParameterName,
err,
valueType,
valueLength
));
err = !ERROR_SUCCESS;
}
return (err == ERROR_SUCCESS);
}
/*******************************************************************************
*
* ReadRegistryIpAddrString
*
* Reads zero or more IP addresses from a space-delimited string in a registry
* parameter and converts them to a list of IP_ADDR_STRINGs
*
* ENTRY Key - registry key
* ParameterName - name of value entry under Key to read from
* IpAddr - pointer to IP_ADDR_STRING to update
*
* EXIT IpAddr updated if success
*
* RETURNS TRUE if success
*
* ASSUMES
*
******************************************************************************/
BOOL ReadRegistryIpAddrString(HKEY Key, LPSTR ParameterName, PIP_ADDR_STRING IpAddr)
{
LONG err;
DWORD valueLength;
DWORD valueType;
LPBYTE valueBuffer;
err = RegQueryValueEx(Key,
ParameterName,
NULL, // reserved
&valueType,
NULL,
&valueLength
);
if ((err == ERROR_SUCCESS)) {
if((valueLength > 1) && (valueType == REG_SZ)
|| (valueLength > 2) && (valueType == REG_MULTI_SZ) ) {
valueBuffer = GrabMemory(valueLength);
if (!valueBuffer) {
return FALSE;
}
err = RegQueryValueEx(Key,
ParameterName,
NULL, // reserved
&valueType,
valueBuffer,
&valueLength
);
if ((err == ERROR_SUCCESS) && (valueLength > 1)) {
UINT stringCount;
LPSTR stringPointer = (LPSTR)valueBuffer;
LPSTR *stringAddress;
UINT i;
DEBUG_PRINT(("ReadRegistryIpAddrString(%s): \"%s\", len = %d\n",
ParameterName,
valueBuffer,
valueLength
));
stringAddress = GrabMemory(valueLength / 2 * sizeof(LPSTR));
if (stringAddress) {
if( REG_SZ == valueType ) {
stringPointer += strspn(stringPointer, STRING_ARRAY_DELIMITERS);
stringAddress[0] = stringPointer;
stringCount = 1;
while ((stringPointer = strpbrk(stringPointer, STRING_ARRAY_DELIMITERS)) != NULL) {
*stringPointer++ = '\0';
stringPointer += strspn(stringPointer, STRING_ARRAY_DELIMITERS);
stringAddress[stringCount] = stringPointer;
if (*stringPointer) {
++stringCount;
}
}
for (i = 0; i < stringCount; ++i) {
AddIpAddressString(IpAddr, stringAddress[i], "");
}
} else if( REG_MULTI_SZ == valueType ) {
stringCount = 0;
while(strlen(stringPointer)) {
AddIpAddressString(IpAddr, stringPointer, "");
stringPointer += 1+strlen(stringPointer);
stringCount ++;
}
if( 0 == stringCount ) err = ERROR_PATH_NOT_FOUND;
} else {
err = ERROR_PATH_NOT_FOUND;
}
ReleaseMemory(stringAddress);
} else {
err = ERROR_NOT_ENOUGH_MEMORY;
}
} else {
DEBUG_PRINT(("ReadRegistryIpAddrString(%s): err = %d, len = %d\n",
ParameterName,
err,
valueLength
));
err = ERROR_PATH_NOT_FOUND;
}
ReleaseMemory(valueBuffer);
} else {
DEBUG_PRINT(("ReadRegistryIpAddrString(%s): err = %d, type = %d, len = %d\n",
ParameterName,
err,
valueType,
valueLength
));
err = ERROR_PATH_NOT_FOUND;
}
}
return (err == ERROR_SUCCESS);
}
/*******************************************************************************
*
* GetBoundAdapterList
*
* Gets a list of names of all adapters bound to a protocol (TCP/IP). Returns
* a pointer to an array of pointers to strings - basically an argv list. The
* memory for the strings is concatenated to the array and the array is NULL
* terminated. If Elnkii1 and IbmTok2 are bound to TCP/IP then this function
* will return:
*
* ---> addr of string1 \
* addr of string2 \
* NULL > allocated as one block
* &string1: "Elnkii1" /
* &string2: "IbmTok2" /
*
* ENTRY BindingsSectionKey
* - Open registry handle to a linkage key (e.g. Tcpip\Linkage)
*
* EXIT
*
* RETURNS pointer to argv[] style array, or NULL
*
* ASSUMES
*
******************************************************************************/
LPSTR* GetBoundAdapterList(HKEY BindingsSectionKey)
{
LONG err;
DWORD valueType;
PBYTE valueBuffer;
DWORD valueLength;
LPSTR* resultBuffer;
LPSTR* nextResult;
int len;
DWORD resultLength;
LPSTR nextValue;
LPSTR variableData;
DWORD numberOfBindings;
//
// get required size of value buffer
//
valueLength = 0;
err = RegQueryValueEx(BindingsSectionKey,
TEXT("Bind"),
NULL, // reserved
&valueType,
NULL,
&valueLength
);
if (err != ERROR_SUCCESS) {
return NULL;
}
if (valueType != REG_MULTI_SZ) {
return NULL;
}
if (!valueLength) {
return NULL;
}
valueBuffer = (PBYTE)GrabMemory(valueLength);
if (!valueBuffer) {
return NULL;
}
err = RegQueryValueEx(BindingsSectionKey,
TEXT("Bind"),
NULL, // reserved
&valueType,
valueBuffer,
&valueLength
);
if (err != ERROR_SUCCESS) {
DEBUG_PRINT(("GetBoundAdapterList: RegQueryValueEx 'Bind' failed\n"));
ReleaseMemory(valueBuffer);
return NULL;
}
resultLength = sizeof(LPSTR); // the NULL at the end of the list
numberOfBindings = 0;
nextValue = (LPSTR)valueBuffer;
while ((len = (int)strlen(nextValue)) != 0) {
resultLength += sizeof(LPSTR) + len + 1;
if (!_strnicmp(nextValue, DEVICE_PREFIX, sizeof(DEVICE_PREFIX) - 1)) {
resultLength -= sizeof(DEVICE_PREFIX) - 1;
}
nextValue += len + 1;
++numberOfBindings;
}
resultBuffer = (LPSTR*)GrabMemory(resultLength);
if (!resultBuffer) {
return NULL;
}
nextValue = (LPSTR)valueBuffer;
nextResult = resultBuffer;
variableData = (LPSTR)(((LPSTR*)resultBuffer) + numberOfBindings + 1);
while (numberOfBindings--) {
LPSTR adapterName;
adapterName = nextValue;
if (!_strnicmp(adapterName, DEVICE_PREFIX, sizeof(DEVICE_PREFIX) - 1)) {
adapterName += sizeof(DEVICE_PREFIX) - 1;
}
*nextResult++ = variableData;
strcpy(variableData, adapterName);
TRACE_PRINT(("GetBoundAdapterList: adapterName=%s\n", adapterName ));
while (*variableData) {
++variableData;
}
++variableData;
while (*nextValue) {
++nextValue;
}
++nextValue;
}
*nextResult = NULL;
ReleaseMemory(valueBuffer);
return resultBuffer;
}
/*******************************************************************************
*
* MapNodeType
*
* Converts node type to descriptive string
*
* ENTRY
*
* EXIT
*
* RETURNS pointer to string
*
* ASSUMES
*
******************************************************************************/
LPSTR MapNodeType(UINT Parm)
{
DWORD dwParm = LAST_NODE_TYPE + 1;
//
// 1, 2, 4, 8 => log2(n) + 1 [1, 2, 3, 4]
//
switch (Parm) {
case 0:
//
// according to JStew value of 0 will be treated as BNode (default)
//
case BNODE:
dwParm = 1;
break;
case PNODE:
dwParm = 2;
break;
case MNODE:
dwParm = 3;
break;
case HNODE:
dwParm = 4;
break;
}
if ((dwParm >= FIRST_NODE_TYPE) && (dwParm <= LAST_NODE_TYPE)) {
return NodeTypes[dwParm].String;
}
//
// if no node type is defined then we default to Hybrid
//
return NodeTypes[LAST_NODE_TYPE].String;
}
/*******************************************************************************
*
* MapNodeTypeEx
*
* Converts node type to descriptive string
*
* ENTRY
*
* EXIT
*
* RETURNS pointer to string
*
* ASSUMES
*
******************************************************************************/
LPSTR MapNodeTypeEx(UINT Parm)
{
DWORD dwParm = LAST_NODE_TYPE + 1;
LPSTR Buf;
Buf = GrabMemory(10);
if (!Buf) {
return NULL;
}
//
// 1, 2, 4, 8 => log2(n) + 1 [1, 2, 3, 4]
//
switch (Parm) {
case 0:
//
// according to JStew value of 0 will be treated as BNode (default)
//
case BNODE:
dwParm = 1;
break;
case PNODE:
dwParm = 2;
break;
case MNODE:
dwParm = 3;
break;
case HNODE:
dwParm = 4;
break;
}
if ((dwParm >= FIRST_NODE_TYPE) && (dwParm <= LAST_NODE_TYPE)) {
strcpy(Buf, NodeTypesEx[dwParm]);
return Buf;
}
//
// if no node type is defined then we default to Hybrid
//
strcpy(Buf, NodeTypesEx[LAST_NODE_TYPE]);
return Buf;
}
/*******************************************************************************
*
* MapAdapterType
*
* Returns a string describing the type of adapter, based on the type retrieved
* from TCP/IP
*
* ENTRY type - type of adapter
*
* EXIT nothing
*
* RETURNS pointer to mapped type or pointer to NUL string
*
* ASSUMES
*
******************************************************************************/
LPSTR MapAdapterType(UINT type)
{
switch (type) {
case IF_TYPE_OTHER:
return ADAPTER_TYPE(MI_IF_OTHER); // ?
case IF_TYPE_ETHERNET_CSMACD:
return ADAPTER_TYPE(MI_IF_ETHERNET);
case IF_TYPE_ISO88025_TOKENRING:
return ADAPTER_TYPE(MI_IF_TOKEN_RING);
case IF_TYPE_FDDI:
return ADAPTER_TYPE(MI_IF_FDDI);
case IF_TYPE_PPP:
return ADAPTER_TYPE(MI_IF_PPP);
case IF_TYPE_SOFTWARE_LOOPBACK:
return ADAPTER_TYPE(MI_IF_LOOPBACK);
case IF_TYPE_SLIP:
return ADAPTER_TYPE(MI_IF_SLIP);
}
return "";
}
/*******************************************************************************
*
* MapAdapterTypeEx
*
* Returns a string describing the type of adapter, based on the type retrieved
* from TCP/IP
*
* ENTRY type - type of adapter
*
* EXIT nothing
*
* RETURNS pointer to mapped type or pointer to NUL string
*
* ASSUMES
*
******************************************************************************/
LPSTR MapAdapterTypeEx(UINT type)
{
LPSTR Buf;
Buf = GrabMemory(12);
if (!Buf) {
return NULL;
}
switch (type) {
case IF_TYPE_OTHER:
strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_OTHER)); // ?
return Buf;
case IF_TYPE_ETHERNET_CSMACD:
strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_ETHERNET));
return Buf;
case IF_TYPE_ISO88025_TOKENRING:
strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_TOKEN_RING));
return Buf;
case IF_TYPE_FDDI:
strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_FDDI));
return Buf;
case IF_TYPE_PPP:
strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_PPP));
return Buf;
case IF_TYPE_SOFTWARE_LOOPBACK:
strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_LOOPBACK));
return Buf;
case IF_TYPE_SLIP:
strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_SLIP));
return Buf;
}
strcpy(Buf, "");
return Buf;
}
/*******************************************************************************
*
* MapAdapterAddress
*
* Converts the binary adapter address retrieved from TCP/IP into an ASCII
* string. Allows for various conversions based on adapter type. The only
* mapping we do currently is basic 6-byte MAC address (e.g. 02-60-8C-4C-97-0E)
*
* ENTRY pAdapterInfo - pointer to IP_ADAPTER_INFO containing address info
* Buffer - pointer to buffer where address will be put
*
* EXIT Buffer - contains converted address
*
* RETURNS pointer to Buffer
*
* ASSUMES
*
******************************************************************************/
LPSTR MapAdapterAddress(PIP_ADAPTER_INFO pAdapterInfo, LPSTR Buffer)
{
LPSTR format;
int separator;
int len;
int i;
LPSTR pbuf = Buffer;
UINT mask;
len = min((int)pAdapterInfo->AddressLength, sizeof(pAdapterInfo->Address));
switch (pAdapterInfo->Type) {
case IF_TYPE_ETHERNET_CSMACD:
case IF_TYPE_ISO88025_TOKENRING:
case IF_TYPE_FDDI:
format = "%02X";
mask = 0xff;
separator = TRUE;
break;
default:
format = "%02x";
mask = 0xff;
separator = TRUE;
break;
}
for (i = 0; i < len; ++i) {
pbuf += sprintf(pbuf, format, pAdapterInfo->Address[i] & mask);
if (separator && (i != len - 1)) {
pbuf += sprintf(pbuf, "-");
}
}
return Buffer;
}
/*******************************************************************************
*
* MapTime
*
* Converts IP lease time to more human-sensible string
*
* ENTRY AdapterInfo - pointer to IP_ADAPTER_INFO owning time variable
* TimeVal - DWORD (time_t) time value (number of milliseconds since
* virtual year dot)
*
* EXIT static buffer updated
*
* RETURNS pointer to string
*
* ASSUMES 1. The caller realizes this function returns a pointer to a static
* buffer, hence calling this function a second time, but before
* the results from the previous call have been used, will destroy
* the previous results
*
******************************************************************************/
LPSTR MapTime(PIP_ADAPTER_INFO AdapterInfo, DWORD_PTR TimeVal)
{
struct tm* pTime;
static char timeBuf[128];
static char oemTimeBuf[256];
UNREFERENCED_PARAMETER(AdapterInfo);
if ((pTime = localtime((const time_t*)&TimeVal)) != NULL) {
SYSTEMTIME systemTime;
int n;
systemTime.wYear = (WORD)(pTime->tm_year + 1900);
systemTime.wMonth = (WORD)(pTime->tm_mon + 1);
systemTime.wDayOfWeek = (WORD)pTime->tm_wday;
systemTime.wDay = (WORD)pTime->tm_mday;
systemTime.wHour = (WORD)pTime->tm_hour;
systemTime.wMinute = (WORD)pTime->tm_min;
systemTime.wSecond = (WORD)pTime->tm_sec;
systemTime.wMilliseconds = 0;
n = GetDateFormat(0, DATE_LONGDATE, &systemTime, NULL, timeBuf, sizeof(timeBuf));
timeBuf[n - 1] = ' ';
GetTimeFormat(0, 0, &systemTime, NULL, &timeBuf[n], sizeof(timeBuf) - n);
//
// we have to convert the returned ANSI string to the OEM charset
//
//
if (CharToOem(timeBuf, oemTimeBuf)) {
return oemTimeBuf;
}
return timeBuf;
}
return "";
}
/*******************************************************************************
*
* MapTimeEx
*
* Converts IP lease time to more human-sensible string
*
* ENTRY AdapterInfo - pointer to IP_ADAPTER_INFO owning time variable
* TimeVal - DWORD (time_t) time value (number of milliseconds since
* virtual year dot)
*
* EXIT buffer allocated
*
* RETURNS pointer to string
*
* ASSUMES 1. The caller realizes this function returns a pointer to a static
* buffer, hence calling this function a second time, but before
* the results from the previous call have been used, will destroy
* the previous results
*
******************************************************************************/
LPSTR MapTimeEx(PIP_ADAPTER_INFO AdapterInfo, DWORD_PTR TimeVal)
{
LPSTR rettime, rettimeBuf;
rettimeBuf = GrabMemory(128);
if (!rettimeBuf) {
return NULL;
}
rettime = MapTime(AdapterInfo, TimeVal);
if (strcmp(rettime, "") == 0) {
rettimeBuf[0] = '\0';
}
else {
strcpy(rettimeBuf, rettime);
}
return rettimeBuf;
}
/*******************************************************************************
*
* MapScopeId
*
* Converts scope id value. Input is a string. If it is "*" then this denotes
* that the scope id is really a null string, so we return an empty string.
* Otherwise, the input string is returned
*
* ENTRY
*
* EXIT
*
* RETURNS pointer to string
*
* ASSUMES
*
******************************************************************************/
LPSTR MapScopeId(PVOID Param)
{
return !strcmp((LPSTR)Param, "*") ? "" : (LPSTR)Param;
}
/*******************************************************************************
*
* Terminate
*
* Cleans up - closes the registry handles, ready for process exit
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
VOID Terminate()
{
//
// this function probably isn't even necessary - I'm sure the system will
// clean up these handles if we just fall out
//
if (NetbtParametersKey != INVALID_HANDLE_VALUE) {
RegCloseKey(NetbtParametersKey);
}
if (NetbtInterfacesKey != INVALID_HANDLE_VALUE) {
RegCloseKey(NetbtInterfacesKey);
}
if (TcpipParametersKey != INVALID_HANDLE_VALUE) {
RegCloseKey(TcpipParametersKey);
}
if (TcpipLinkageKey != INVALID_HANDLE_VALUE) {
RegCloseKey(TcpipLinkageKey);
}
}
/*******************************************************************************
*
* GrabMemory
*
* Allocates memory. Exits with a fatal error if LocalAlloc fails, since on NT
* I don't expect this ever to occur
*
* ENTRY size
* Number of bytes to allocate
*
* EXIT
*
* RETURNS pointer to allocated memory
*
* ASSUMES
*
******************************************************************************/
LPVOID GrabMemory(DWORD size)
{
LPVOID p;
p = (LPVOID)LocalAlloc(LMEM_FIXED, size);
if (!p) {
return NULL;
}
return p;
}
/*******************************************************************************
*
* DisplayMessage
*
* Outputs a message retrieved from the string resource attached to the exe.
* Mainly for internationalizable reasons
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
VOID DisplayMessage(BOOL Tabbed, DWORD MessageId, ...)
{
va_list argptr;
char messageBuffer[2048];
int count;
va_start(argptr, MessageId);
count = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE,
NULL, // use default hModule
MessageId,
0, // use default Language
messageBuffer,
sizeof(messageBuffer),
&argptr
);
if (count == 0) {
DEBUG_PRINT(("DisplayMessage: GetLastError() returns %d\n", GetLastError()));
}
va_end(argptr);
if (Tabbed) {
putchar('\t');
}
printf(messageBuffer);
}
/*******************************************************************************
*
* KillFixedInfo
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
VOID KillFixedInfo(PFIXED_INFO Info)
{
PIP_ADDR_STRING p;
PIP_ADDR_STRING next;
for (p = Info->DnsServerList.Next; p != NULL; p = next) {
next = p->Next;
ReleaseMemory(p);
}
ReleaseMemory(Info);
}
/*******************************************************************************
*
* KillAdapterInfo
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
VOID KillAdapterInfo(PIP_ADAPTER_INFO Info)
{
PIP_ADDR_STRING p;
PIP_ADDR_STRING next;
PIP_ADAPTER_INFO CurrAdapter;
PIP_ADAPTER_INFO NextAdapter;
for (CurrAdapter=Info; CurrAdapter != NULL; CurrAdapter = NextAdapter) {
for (p = CurrAdapter->IpAddressList.Next; p != NULL; p = next) {
next = p->Next;
ReleaseMemory(p);
}
for (p = CurrAdapter->GatewayList.Next; p != NULL; p = next) {
next = p->Next;
ReleaseMemory(p);
}
for (p = CurrAdapter->SecondaryWinsServer.Next; p != NULL; p = next) {
next = p->Next;
ReleaseMemory(p);
}
NextAdapter = CurrAdapter->Next;
ReleaseMemory(CurrAdapter);
}
}
VOID KillAdapterAddresses(PIP_ADAPTER_ADDRESSES Info)
{
PIP_ADAPTER_UNICAST_ADDRESS pU;
PIP_ADAPTER_UNICAST_ADDRESS nextU;
PIP_ADAPTER_ANYCAST_ADDRESS pA;
PIP_ADAPTER_ANYCAST_ADDRESS nextA;
PIP_ADAPTER_MULTICAST_ADDRESS pM;
PIP_ADAPTER_MULTICAST_ADDRESS nextM;
PIP_ADAPTER_DNS_SERVER_ADDRESS pD;
PIP_ADAPTER_DNS_SERVER_ADDRESS nextD;
PIP_ADAPTER_PREFIX pP;
PIP_ADAPTER_PREFIX nextP;
PIP_ADAPTER_ADDRESSES CurrAdapter;
PIP_ADAPTER_ADDRESSES NextAdapter;
for (CurrAdapter=Info; CurrAdapter != NULL; CurrAdapter = NextAdapter) {
FREE(CurrAdapter->Description);
FREE(CurrAdapter->FriendlyName);
FREE(CurrAdapter->DnsSuffix);
FREE(CurrAdapter->AdapterName);
for (pU = CurrAdapter->FirstUnicastAddress; pU != NULL; pU = nextU) {
FREE(pU->Address.lpSockaddr);
nextU = pU->Next;
FREE(pU);
}
for (pA = CurrAdapter->FirstAnycastAddress; pA != NULL; pA = nextA) {
FREE(pA->Address.lpSockaddr);
nextA = pA->Next;
FREE(pA);
}
for (pM = CurrAdapter->FirstMulticastAddress; pM != NULL; pM = nextM) {
FREE(pM->Address.lpSockaddr);
nextM = pM->Next;
FREE(pM);
}
for (pD = CurrAdapter->FirstDnsServerAddress; pD != NULL; pD = nextD) {
FREE(pD->Address.lpSockaddr);
nextD = pD->Next;
FREE(pD);
}
for (pP = CurrAdapter->FirstPrefix; pP != NULL; pP = nextP) {
FREE(pP->Address.lpSockaddr);
nextP = pP->Next;
FREE(pP);
}
NextAdapter = CurrAdapter->Next;
FREE(CurrAdapter);
}
}
/*******************************************************************************
*
* KillPerAdapterInfo
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
VOID KillPerAdapterInfo(PIP_PER_ADAPTER_INFO Info)
{
PIP_ADDR_STRING p;
PIP_ADDR_STRING next;
for (p = Info->DnsServerList.Next; p != NULL; p = next) {
next = p->Next;
ReleaseMemory(p);
}
ReleaseMemory(Info);
}
/*******************************************************************************
*
* GetIPAddrStringLen
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
DWORD
GetIPAddrStringLen(PIP_ADDR_STRING pIPAddrString)
{
PIP_ADDR_STRING Curr=pIPAddrString->Next;
int len = 0;
while (Curr != NULL) {
Curr=Curr->Next;
len++;
}
return len;
}
/*******************************************************************************
*
* GetSizeofFixedInfo
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
DWORD
GetSizeofFixedInfo(PFIXED_INFO pFixedInfo)
{
return (sizeof(FIXED_INFO) + (GetIPAddrStringLen(&pFixedInfo->DnsServerList) * sizeof(IP_ADDR_STRING)));
}
/*******************************************************************************
*
* GetFixedInfoEx
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
DWORD
GetFixedInfoEx(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
{
PFIXED_INFO getinfo;
PIP_ADDR_STRING DnsServerList, CurrDnsServerList;
uint len;
if (pOutBufLen == NULL) {
return ERROR_INVALID_PARAMETER;
}
getinfo = GetFixedInfo();
try {
if (!pFixedInfo || (*pOutBufLen < GetSizeofFixedInfo(getinfo)) ) {
*pOutBufLen = GetSizeofFixedInfo(getinfo);
KillFixedInfo(getinfo);
return ERROR_BUFFER_OVERFLOW;
}
ZeroMemory(pFixedInfo, *pOutBufLen);
CopyMemory(pFixedInfo, getinfo, sizeof(FIXED_INFO));
DnsServerList = getinfo->DnsServerList.Next;
CurrDnsServerList = &pFixedInfo->DnsServerList;
CurrDnsServerList->Next = NULL;
len = sizeof(FIXED_INFO);
while (DnsServerList != NULL) {
CurrDnsServerList->Next = (PIP_ADDR_STRING)((ULONG_PTR)pFixedInfo + len);
CopyMemory(CurrDnsServerList->Next, DnsServerList, sizeof(IP_ADDR_STRING));
CurrDnsServerList = CurrDnsServerList->Next;
DnsServerList = DnsServerList->Next;
len = len + sizeof(IP_ADDR_STRING);
}
KillFixedInfo(getinfo);
return ERROR_SUCCESS;
}
except (EXCEPTION_EXECUTE_HANDLER) {
// printf("Exception %d \n", GetExceptionCode());
return ERROR_INVALID_PARAMETER;
}
}
/*******************************************************************************
*
* GetSizeofAdapterInfo
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
DWORD
GetSizeofAdapterInfo(PIP_ADAPTER_INFO pAdapterInfo)
{
DWORD size = 0;
while (pAdapterInfo != NULL) {
size += sizeof(IP_ADAPTER_INFO) +
(GetIPAddrStringLen(&pAdapterInfo->IpAddressList) *
sizeof(IP_ADDR_STRING)) +
(GetIPAddrStringLen(&pAdapterInfo->GatewayList) *
sizeof(IP_ADDR_STRING)) +
(GetIPAddrStringLen(&pAdapterInfo->SecondaryWinsServer) *
sizeof(IP_ADDR_STRING));
pAdapterInfo = pAdapterInfo->Next;
}
return size;
}
/*******************************************************************************
* GetSizeofAdapterAddresses
*
* This routine determines how much memory is used by data organized in a set
* of IP_ADAPTER_ADDRESSES information.
*
* ENTRY pAdapterInfo - information to get total size for
*
* EXIT
*
* RETURNS amount of memory used
*
******************************************************************************/
DWORD GetSizeofAdapterAddresses(PIP_ADAPTER_ADDRESSES pAdapterInfo)
{
DWORD size = 0;
PIP_ADAPTER_UNICAST_ADDRESS pUAddress;
PIP_ADAPTER_ANYCAST_ADDRESS pAAddress;
PIP_ADAPTER_MULTICAST_ADDRESS pMAddress;
PIP_ADAPTER_DNS_SERVER_ADDRESS pDAddress;
PIP_ADAPTER_PREFIX pPrefix;
while (pAdapterInfo != NULL) {
size += sizeof(IP_ADAPTER_ADDRESSES);
size += (DWORD)(wcslen(pAdapterInfo->FriendlyName)+1) * sizeof(WCHAR);
size += (DWORD)(wcslen(pAdapterInfo->Description)+1) * sizeof(WCHAR);
size += (DWORD)(wcslen(pAdapterInfo->DnsSuffix)+1) * sizeof(WCHAR);
size += (DWORD)(strlen(pAdapterInfo->AdapterName)+1);
size = ALIGN_UP(size, PVOID);
for ( pUAddress = pAdapterInfo->FirstUnicastAddress;
pUAddress;
pUAddress = pUAddress->Next) {
size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) + ALIGN_UP(pUAddress->Address.iSockaddrLength, PVOID);
}
for ( pAAddress = pAdapterInfo->FirstAnycastAddress;
pAAddress;
pAAddress = pAAddress->Next) {
size += sizeof(IP_ADAPTER_ANYCAST_ADDRESS) + ALIGN_UP(pAAddress->Address.iSockaddrLength, PVOID);
}
for ( pMAddress = pAdapterInfo->FirstMulticastAddress;
pMAddress;
pMAddress = pMAddress->Next) {
size += sizeof(IP_ADAPTER_MULTICAST_ADDRESS) + ALIGN_UP(pMAddress->Address.iSockaddrLength, PVOID);
}
for ( pDAddress = pAdapterInfo->FirstDnsServerAddress;
pDAddress;
pDAddress = pDAddress->Next) {
size += sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) + ALIGN_UP(pDAddress->Address.iSockaddrLength, PVOID);
}
for ( pPrefix = pAdapterInfo->FirstPrefix;
pPrefix;
pPrefix = pPrefix->Next) {
size += sizeof(IP_ADAPTER_PREFIX) + ALIGN_UP(pPrefix->Address.iSockaddrLength, PVOID);
}
pAdapterInfo = pAdapterInfo->Next;
}
return size;
}
/*******************************************************************************
*
* GetSizeofPerAdapterInfo
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
DWORD
GetSizeofPerAdapterInfo(PIP_PER_ADAPTER_INFO pPerAdapterInfo)
{
return (sizeof(IP_PER_ADAPTER_INFO) + (GetIPAddrStringLen(&pPerAdapterInfo->DnsServerList) * sizeof(IP_ADDR_STRING)));
}
/*******************************************************************************
*
* GetAdapterInfoEx
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
DWORD
GetAdapterInfoEx(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
{
PIP_ADAPTER_INFO getinfo, orginfoptr, CurrAdapterInfo;
PIP_ADDR_STRING IpAddressList, CurrIpAddressList;
PIP_ADDR_STRING GatewayList, CurrGatewayList;
PIP_ADDR_STRING SecondaryWinsServer, CurrSecondaryWinsServer;
uint len;
if (pOutBufLen == NULL) {
return ERROR_INVALID_PARAMETER;
}
getinfo = GetAdapterInfo();
if (getinfo == NULL) {
return ERROR_NO_DATA;
}
orginfoptr = getinfo;
try {
if (!pAdapterInfo || (*pOutBufLen < GetSizeofAdapterInfo(getinfo)) ) {
*pOutBufLen = GetSizeofAdapterInfo(getinfo);
KillAdapterInfo(getinfo);
return ERROR_BUFFER_OVERFLOW;
}
ZeroMemory(pAdapterInfo, *pOutBufLen);
CurrAdapterInfo = pAdapterInfo;
while (getinfo != NULL) {
// pAdapterInfo->Next = (PIP_ADAPTER_INFO)((uint)pAdapterInfo + len);
// copy the adapter info structure
CopyMemory(CurrAdapterInfo, getinfo, sizeof(IP_ADAPTER_INFO));
// copy the IPAddressList & GatewayList
IpAddressList = getinfo->IpAddressList.Next;
CurrIpAddressList = &CurrAdapterInfo->IpAddressList;
CurrIpAddressList->Next = NULL;
len = sizeof(IP_ADAPTER_INFO);
while (IpAddressList != NULL) {
CurrIpAddressList->Next = (PIP_ADDR_STRING)((ULONG_PTR)CurrAdapterInfo + len);
CopyMemory(CurrIpAddressList->Next, IpAddressList, sizeof(IP_ADDR_STRING));
CurrIpAddressList = CurrIpAddressList->Next;
IpAddressList = IpAddressList->Next;
len = len + sizeof(IP_ADDR_STRING);
}
GatewayList = getinfo->GatewayList.Next;
CurrGatewayList = &CurrAdapterInfo->GatewayList;
CurrGatewayList->Next = NULL;
while (GatewayList != NULL) {
CurrGatewayList->Next = (PIP_ADDR_STRING) ((ULONG_PTR)CurrAdapterInfo + len);
CopyMemory(CurrGatewayList->Next, GatewayList, sizeof(IP_ADDR_STRING));
CurrGatewayList = CurrGatewayList->Next;
GatewayList = GatewayList->Next;
len = len + sizeof(IP_ADDR_STRING);
}
SecondaryWinsServer = getinfo->SecondaryWinsServer.Next;
CurrSecondaryWinsServer = &CurrAdapterInfo->SecondaryWinsServer;
CurrSecondaryWinsServer->Next = NULL;
while (SecondaryWinsServer != NULL) {
CurrSecondaryWinsServer->Next =
(PIP_ADDR_STRING) ((ULONG_PTR)CurrAdapterInfo + len);
CopyMemory(CurrSecondaryWinsServer->Next,
SecondaryWinsServer, sizeof(IP_ADDR_STRING));
CurrSecondaryWinsServer = CurrSecondaryWinsServer->Next;
SecondaryWinsServer = SecondaryWinsServer->Next;
len = len + sizeof(IP_ADDR_STRING);
}
pAdapterInfo = CurrAdapterInfo;
CurrAdapterInfo->Next = (PIP_ADAPTER_INFO)((ULONG_PTR)CurrAdapterInfo + len);
CurrAdapterInfo = CurrAdapterInfo->Next;
getinfo = getinfo->Next;
}
pAdapterInfo->Next = NULL;
KillAdapterInfo(orginfoptr);
return ERROR_SUCCESS;
} except ((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// printf("Exception %d \n", GetExceptionCode());
KillAdapterInfo(orginfoptr);
return ERROR_INVALID_PARAMETER;
}
}
DWORD
GetAdapterAddressesEx(ULONG Family, DWORD Flags, PIP_ADAPTER_ADDRESSES pAdapterInfo, PULONG pOutBufLen)
{
PIP_ADAPTER_ADDRESSES getinfo, orginfoptr, CurrAdapterInfo;
PIP_ADAPTER_UNICAST_ADDRESS SrcUAddress, *pDestUAddress;
PIP_ADAPTER_ANYCAST_ADDRESS SrcAAddress, *pDestAAddress;
PIP_ADAPTER_MULTICAST_ADDRESS SrcMAddress, *pDestMAddress;
PIP_ADAPTER_DNS_SERVER_ADDRESS SrcDAddress, *pDestDAddress;
ULONG_PTR pDestBuffer;
DWORD dwErr;
if (pOutBufLen == NULL) {
return ERROR_INVALID_PARAMETER;
}
dwErr = GetAdapterAddresses(Family, Flags, &getinfo);
if (dwErr != NO_ERROR) {
if (getinfo) {
KillAdapterAddresses(getinfo);
}
return dwErr;
}
if (getinfo == NULL) {
return ERROR_NO_DATA;
}
orginfoptr = getinfo;
try {
if (!pAdapterInfo || (*pOutBufLen < GetSizeofAdapterAddresses(getinfo)) ) {
*pOutBufLen = GetSizeofAdapterAddresses(getinfo);
KillAdapterAddresses(getinfo);
return ERROR_BUFFER_OVERFLOW;
}
ZeroMemory(pAdapterInfo, *pOutBufLen);
CurrAdapterInfo = pAdapterInfo;
while (getinfo != NULL) {
// pAdapterInfo->Next = (PIP_ADAPTER_ADDRESSES)((uint)pAdapterInfo + len);
// copy the adapter info structure
CopyMemory(CurrAdapterInfo, getinfo, sizeof(IP_ADAPTER_ADDRESSES));
pDestBuffer = (ULONG_PTR)CurrAdapterInfo + sizeof(IP_ADAPTER_ADDRESSES);
CurrAdapterInfo->FriendlyName = (PWCHAR)pDestBuffer;
wcscpy(CurrAdapterInfo->FriendlyName, getinfo->FriendlyName);
pDestBuffer += (wcslen(CurrAdapterInfo->FriendlyName)+1) * sizeof(WCHAR);
CurrAdapterInfo->Description = (PWCHAR)pDestBuffer;
wcscpy(CurrAdapterInfo->Description, getinfo->Description);
pDestBuffer += (wcslen(CurrAdapterInfo->Description)+1) * sizeof(WCHAR);
CurrAdapterInfo->DnsSuffix = (PWCHAR)pDestBuffer;
wcscpy(CurrAdapterInfo->DnsSuffix, getinfo->DnsSuffix);
pDestBuffer += (wcslen(CurrAdapterInfo->DnsSuffix)+1) * sizeof(WCHAR);
CurrAdapterInfo->AdapterName = (PCHAR)pDestBuffer;
strcpy(CurrAdapterInfo->AdapterName, getinfo->AdapterName);
pDestBuffer += (strlen(CurrAdapterInfo->AdapterName)+1);
pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
// copy the address lists
if (!(Flags & GAA_FLAG_SKIP_UNICAST)) {
SrcUAddress = getinfo->FirstUnicastAddress;
pDestUAddress = &CurrAdapterInfo->FirstUnicastAddress;
while (SrcUAddress != NULL) {
*pDestUAddress = (PIP_ADAPTER_UNICAST_ADDRESS)pDestBuffer;
// copy address structure
CopyMemory((PVOID)pDestBuffer, SrcUAddress,
sizeof(IP_ADAPTER_UNICAST_ADDRESS));
pDestBuffer += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
(*pDestUAddress)->Address.lpSockaddr = (LPSOCKADDR)pDestBuffer;
// copy sockaddr
CopyMemory((PVOID)pDestBuffer, SrcUAddress->Address.lpSockaddr,
SrcUAddress->Address.iSockaddrLength);
pDestBuffer += SrcUAddress->Address.iSockaddrLength;
pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
pDestUAddress = &(*pDestUAddress)->Next;
SrcUAddress = SrcUAddress->Next;
}
}
if (!(Flags & GAA_FLAG_SKIP_ANYCAST)) {
SrcAAddress = getinfo->FirstAnycastAddress;
pDestAAddress = &CurrAdapterInfo->FirstAnycastAddress;
while (SrcAAddress != NULL) {
*pDestAAddress = (PIP_ADAPTER_ANYCAST_ADDRESS)pDestBuffer;
// copy address structure
CopyMemory((PVOID)pDestBuffer, SrcAAddress,
sizeof(IP_ADAPTER_ANYCAST_ADDRESS));
pDestBuffer += sizeof(IP_ADAPTER_ANYCAST_ADDRESS);
(*pDestAAddress)->Address.lpSockaddr = (LPSOCKADDR)pDestBuffer;
// copy sockaddr
CopyMemory((PVOID)pDestBuffer, SrcAAddress->Address.lpSockaddr,
SrcAAddress->Address.iSockaddrLength);
pDestBuffer += SrcAAddress->Address.iSockaddrLength;
pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
pDestAAddress = &(*pDestAAddress)->Next;
SrcAAddress = SrcAAddress->Next;
}
}
if (!(Flags & GAA_FLAG_SKIP_MULTICAST)) {
SrcMAddress = getinfo->FirstMulticastAddress;
pDestMAddress = &CurrAdapterInfo->FirstMulticastAddress;
while (SrcMAddress != NULL) {
*pDestMAddress = (PIP_ADAPTER_MULTICAST_ADDRESS)pDestBuffer;
// copy address structure
CopyMemory((PVOID)pDestBuffer, SrcMAddress,
sizeof(IP_ADAPTER_MULTICAST_ADDRESS));
pDestBuffer += sizeof(IP_ADAPTER_MULTICAST_ADDRESS);
(*pDestMAddress)->Address.lpSockaddr = (LPSOCKADDR)pDestBuffer;
// copy sockaddr
CopyMemory((PVOID)pDestBuffer, SrcMAddress->Address.lpSockaddr,
SrcMAddress->Address.iSockaddrLength);
pDestBuffer += SrcMAddress->Address.iSockaddrLength;
pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
pDestMAddress = &(*pDestMAddress)->Next;
SrcMAddress = SrcMAddress->Next;
}
}
if (!(Flags & GAA_FLAG_SKIP_DNS_SERVER)) {
SrcDAddress = getinfo->FirstDnsServerAddress;
pDestDAddress = &CurrAdapterInfo->FirstDnsServerAddress;
while (SrcDAddress != NULL) {
*pDestDAddress = (PIP_ADAPTER_DNS_SERVER_ADDRESS)pDestBuffer;
// copy address structure
CopyMemory((PVOID)pDestBuffer, SrcDAddress,
sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS));
pDestBuffer += sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS);
(*pDestDAddress)->Address.lpSockaddr = (LPSOCKADDR)pDestBuffer;
// copy sockaddr
CopyMemory((PVOID)pDestBuffer, SrcDAddress->Address.lpSockaddr,
SrcDAddress->Address.iSockaddrLength);
pDestBuffer += SrcDAddress->Address.iSockaddrLength;
pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
pDestDAddress = &(*pDestDAddress)->Next;
SrcDAddress = SrcDAddress->Next;
}
}
if (Flags & GAA_FLAG_INCLUDE_PREFIX) {
PIP_ADAPTER_PREFIX SrcPrefix, *pDestPrefix;
SrcPrefix = getinfo->FirstPrefix;
pDestPrefix = &CurrAdapterInfo->FirstPrefix;
while (SrcPrefix != NULL) {
*pDestPrefix = (PIP_ADAPTER_PREFIX)pDestBuffer;
// copy structure
CopyMemory((PVOID)pDestBuffer, SrcPrefix,
sizeof(IP_ADAPTER_PREFIX));
pDestBuffer += sizeof(IP_ADAPTER_PREFIX);
(*pDestPrefix)->Address.lpSockaddr = (LPSOCKADDR)pDestBuffer;
// copy sockaddr
CopyMemory((PVOID)pDestBuffer, SrcPrefix->Address.lpSockaddr,
SrcPrefix->Address.iSockaddrLength);
pDestBuffer += SrcPrefix->Address.iSockaddrLength;
pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
pDestPrefix = &(*pDestPrefix)->Next;
SrcPrefix = SrcPrefix->Next;
}
}
pAdapterInfo = CurrAdapterInfo;
CurrAdapterInfo->Next = (PIP_ADAPTER_ADDRESSES)pDestBuffer;
CurrAdapterInfo = CurrAdapterInfo->Next;
getinfo = getinfo->Next;
}
pAdapterInfo->Next = NULL;
KillAdapterAddresses(orginfoptr);
return ERROR_SUCCESS;
} except ((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// printf("Exception %d \n", GetExceptionCode());
KillAdapterAddresses(orginfoptr);
return ERROR_INVALID_PARAMETER;
}
}
/*******************************************************************************
*
* GetPerAdapterInfoEx
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
DWORD
GetPerAdapterInfoEx(ULONG IfIndex,
PIP_PER_ADAPTER_INFO pPerAdapterInfo,
PULONG pOutBufLen
)
{
PIP_PER_ADAPTER_INFO getinfo;
PIP_ADDR_STRING DnsServerList, CurrDnsServerList;
UINT len;
if (pOutBufLen == NULL) {
return ERROR_INVALID_PARAMETER;
}
getinfo = InternalGetPerAdapterInfo(IfIndex);
if (getinfo == NULL) {
return ERROR_NO_DATA;
}
try {
if (!pPerAdapterInfo ||
*pOutBufLen < GetSizeofPerAdapterInfo(getinfo)) {
*pOutBufLen = GetSizeofPerAdapterInfo(getinfo);
KillPerAdapterInfo(getinfo);
return ERROR_BUFFER_OVERFLOW;
}
ZeroMemory(pPerAdapterInfo, *pOutBufLen);
CopyMemory(pPerAdapterInfo, getinfo, sizeof(IP_PER_ADAPTER_INFO));
DnsServerList = getinfo->DnsServerList.Next;
CurrDnsServerList = &pPerAdapterInfo->DnsServerList;
CurrDnsServerList->Next = NULL;
len = sizeof(IP_PER_ADAPTER_INFO);
while (DnsServerList != NULL) {
CurrDnsServerList->Next = (PIP_ADDR_STRING)((ULONG_PTR)pPerAdapterInfo + len);
CopyMemory(CurrDnsServerList->Next, DnsServerList, sizeof(IP_ADDR_STRING));
CurrDnsServerList = CurrDnsServerList->Next;
DnsServerList = DnsServerList->Next;
len = len + sizeof(IP_ADDR_STRING);
}
KillPerAdapterInfo(getinfo);
return ERROR_SUCCESS;
}
except (EXCEPTION_EXECUTE_HANDLER) {
// printf("Exception %d \n", GetExceptionCode());
return ERROR_INVALID_PARAMETER;
}
}
/*******************************************************************************
*
* ReleaseAdapterIpAddress
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
BOOL
ReleaseAdapterIpAddress(PIP_ADAPTER_INFO adapterInfo)
{
WCHAR wAdapter[MAX_ALLOWED_ADAPTER_NAME_LENGTH + 1];
DWORD status;
//
// check adapter pointer and name
//
if (adapterInfo == NULL || strcmp(adapterInfo->AdapterName, "") == 0) {
return FALSE;
}
//
// don't bother releasing if the address is already released (0.0.0.0).
//
if (ZERO_IP_ADDRESS(adapterInfo->IpAddressList.IpAddress.String)) {
return FALSE;
}
//
// convert adapter name to unicode and call DhcpReleaseParameters
//
ConvertOemToUnicode(adapterInfo->AdapterName, wAdapter);
status = DhcpReleaseParameters(wAdapter);
TRACE_PRINT(("DhcpReleaseParameters(%ws) returns %d\n",
wAdapter, status));
return status == ERROR_SUCCESS;
}
/*******************************************************************************
*
* RenewAdapterIpAddress
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
BOOL
RenewAdapterIpAddress(PIP_ADAPTER_INFO adapterInfo)
{
WCHAR wAdapter[MAX_ALLOWED_ADAPTER_NAME_LENGTH + 1];
DWORD status;
//
// check adapter pointer and name
//
if (adapterInfo == NULL || strcmp(adapterInfo->AdapterName, "") == 0) {
return FALSE;
}
//
// convert adapter name to unicode and call DhcpAcquireParameters
//
ConvertOemToUnicode(adapterInfo->AdapterName, wAdapter);
status = DhcpAcquireParameters(wAdapter);
TRACE_PRINT(("DhcpAcquireParameters(%ws) returns %d\n",
wAdapter, status));
return status == ERROR_SUCCESS;
}
/*******************************************************************************
*
* SetAdapterIpAddress
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
DWORD APIENTRY
SetAdapterIpAddress(LPSTR AdapterName,
BOOL EnableDHCP,
ULONG IPAddress,
ULONG SubnetMask,
ULONG DefaultGateway
)
{
DWORD dwEnableDHCP;
DWORD dwWasDHCPEnabled = FALSE;
IP_ADDR_STRING IpAddrString;
HKEY key;
WCHAR Name[MAX_ADAPTER_NAME_LENGTH + 1];
CHAR String[20];
DWORD status;
if (!OpenAdapterKey(KEY_TCP, AdapterName, KEY_ALL_ACCESS, &key)) {
return ERROR_CAN_NOT_COMPLETE;
}
//
// We cannot handle netcards with multiple addresses,
// so check for that case up front
//
ZeroMemory(&IpAddrString, sizeof(IpAddrString));
if (!ReadRegistryIpAddrString(key, "IPAddress", &IpAddrString)) {
return ERROR_CAN_NOT_COMPLETE;
}
if (IpAddrString.Next) {
PIP_ADDR_STRING p;
for (p = IpAddrString.Next; p != NULL; p = IpAddrString.Next) {
IpAddrString.Next = p->Next;
ReleaseMemory(p);
}
return ERROR_TOO_MANY_NAMES;
}
//
// If we're setting a static address, check to see if the adapter
// currently has a static or DHCP address.
//
if (!EnableDHCP) {
MyReadRegistryDword(key, "EnableDHCP", &dwWasDHCPEnabled);
}
//
// Update the address, mask, and gateway in the registry
//
dwEnableDHCP = !!EnableDHCP;
WriteRegistryDword(key, "EnableDHCP", &dwEnableDHCP);
if (EnableDHCP) { IPAddress = SubnetMask = DefaultGateway = 0; }
ZeroMemory(String, sizeof(String));
lstrcpy(String, inet_ntoa(*(struct in_addr*)&IPAddress));
WriteRegistryMultiString(key, "IPAddress", String);
ZeroMemory(String, sizeof(String));
lstrcpy(String, inet_ntoa(*(struct in_addr*)&SubnetMask));
WriteRegistryMultiString(key, "SubnetMask", String);
ZeroMemory(String, sizeof(String));
if (DefaultGateway) {
lstrcpy(String, inet_ntoa(*(struct in_addr*)&DefaultGateway));
}
WriteRegistryMultiString(key, "DefaultGateway", String);
RegCloseKey(key);
//
// Notify DHCP of the change
//
mbstowcs(Name, AdapterName, MAX_ADAPTER_NAME_LENGTH);
if (EnableDHCP) {
status = DhcpNotifyConfigChange(NULL, Name, FALSE, 0, 0, 0,
DhcpEnable
);
}
else {
//
// If the netcard previously had a static address we need
// to remove it before setting the new address.
//
if (!dwWasDHCPEnabled) {
DhcpNotifyConfigChange(NULL, Name, TRUE, 0, 0, 0,
IgnoreFlag
);
}
status = DhcpNotifyConfigChange(NULL, Name, TRUE, 0,
IPAddress, SubnetMask,
DhcpDisable
);
}
return status;
}
/*******************************************************************************
*
* GetDnsServerList
*
* Gets DNS server List
*
* ENTRY
*
* EXIT
*
* RETURNS
*
* ASSUMES
*
******************************************************************************/
BOOL
GetDnsServerList(PIP_ADDR_STRING IpAddr)
{
PIP_ADAPTER_INFO adapterList;
PIP_ADAPTER_INFO adapter;
LONG err = ERROR_PATH_NOT_FOUND;
HKEY key;
BOOL ok;
TRACE_PRINT(("Entered GetDnsServerList\n"));
if ((adapterList = GetAdapterInfo()) != NULL) {
//
// scan the adapter list and try to insert DNS names to IpAddr
//
for (adapter = adapterList; adapter; adapter = adapter->Next) {
if (adapter->AdapterName[0] &&
OpenAdapterKey(KEY_TCP, adapter->AdapterName, KEY_READ, &key)) {
//
// DNS Server list: first NameServer and then DhcpNameServer
//
ok = ReadRegistryIpAddrString(key,
TEXT("NameServer"),
IpAddr);
if (!ok) {
ok = ReadRegistryIpAddrString(key,
TEXT("DhcpNameServer"),
IpAddr);
}
if (ok) {
err = ERROR_SUCCESS;
}
RegCloseKey(key);
} else {
DEBUG_PRINT(("Cannot OpenAdapterKey KEY_TCP '%s', gle=%d\n",
adapter->AdapterName,
GetLastError()));
}
}
KillAdapterInfo(adapterList);
} else {
DEBUG_PRINT(("GetDnsServerList: GetAdapterInfo returns NULL\n"));
}
TRACE_PRINT(("Exit GetDnsServerList\n"));
return (err == ERROR_SUCCESS);
}
/*******************************************************************************
* GetAdapterOrderMap
*
* This routine builds an array which maps interface indices to their
* respective adapter orderings.
*
* ENTRY nothing
*
* EXIT nothing
*
* RETURNS IP_ADAPTER_ORDER_MAP
*
******************************************************************************/
PIP_ADAPTER_ORDER_MAP APIENTRY GetAdapterOrderMap()
{
LPWSTR AdapterOrder = NULL;
LPWSTR Adapter;
PIP_ADAPTER_ORDER_MAP AdapterOrderMap = NULL;
DWORD dwErr;
DWORD dwType;
DWORD dwSize;
DWORD i;
DWORD j;
PIP_INTERFACE_INFO InterfaceInfo = NULL;
for(;;) {
//
// Retrieve the 'Bind' REG_MULTI_SZ from the Tcpip\Linkage key.
// This string-list tells us the current adapter order,
// with each entry being of the form \Device\{GUID}.
//
dwSize = 0;
dwErr = RegQueryValueExW(TcpipLinkageKey, L"Bind", NULL, &dwType,
NULL, &dwSize);
if (dwErr != NO_ERROR || dwType != REG_MULTI_SZ) { break; }
AdapterOrder = (LPWSTR)GrabMemory(dwSize);
if (!AdapterOrder) { break; }
dwErr = RegQueryValueExW(TcpipLinkageKey, L"Bind", NULL, &dwType,
(LPBYTE)AdapterOrder, &dwSize);
if (dwErr != NO_ERROR || dwType != REG_MULTI_SZ) { break; }
//
// Retrieve the IP interface information from TCP/IP.
// This information tells us the interface index
// for each adapter GUID,
//
dwSize = 0;
dwErr = GetInterfaceInfo(NULL, &dwSize);
if (dwErr != ERROR_INSUFFICIENT_BUFFER &&
dwErr != ERROR_BUFFER_OVERFLOW) {
break;
}
InterfaceInfo = GrabMemory(dwSize);
if (!InterfaceInfo) { break; }
dwErr = GetInterfaceInfo(InterfaceInfo, &dwSize);
if (dwErr != NO_ERROR) { break; }
//
// Construct a mapping from the interfaces in 'InterfaceInfo'
// to their positions in 'AdapterOrder'. In other words,
// construct an array of interface indices in which location i
// contains the index of the interface which is in location i
// in 'AdapterOrder'.
//
AdapterOrderMap =
GrabMemory(FIELD_OFFSET(IP_ADAPTER_ORDER_MAP,
AdapterOrder[InterfaceInfo->NumAdapters]));
if (!AdapterOrderMap) { break; }
for (i = 0, Adapter = AdapterOrder;
*Adapter && i < (DWORD)InterfaceInfo->NumAdapters;
Adapter += lstrlenW(Adapter) + 1) {
//
// See if this is the NdiswanIp device, which corresponds to
// all Ndiswan interfaces. To implement adapter ordering
// for Ndiswan interfaces, we store their indices
// into successive locations in the adapter-order map
// based on the location of the string '\Device\NdiswanIp'
// in the adapter-order list.
//
if (lstrcmpiW(c_szDeviceNdiswanIp, Adapter) == 0) {
//
// This is the \Device\NdiswanIp entry, so list all Ndiswan
// interfaces in the adapter-order map now.
// Unfortunately, 'InterfaceInfo' does not tell us the type
// of each interface. In order to figure out which interfaces
// are Ndiswan interfaces, we enumerate all interfaces (again)
// and look for entries whose type is 'IF_TYPE_PPP'.
//
PMIB_IFTABLE IfTable;
dwErr = AllocateAndGetIfTableFromStack(&IfTable, FALSE,
GetProcessHeap(), 0,
FALSE);
if (dwErr == NO_ERROR) {
for (j = 0;
j < IfTable->dwNumEntries &&
i < (DWORD)InterfaceInfo->NumAdapters; j++) {
if (IfTable->table[j].dwType == IF_TYPE_PPP) {
AdapterOrderMap->AdapterOrder[i++] =
IfTable->table[j].dwIndex;
}
}
HeapFree(GetProcessHeap(), 0, IfTable);
}
continue;
}
//
// Now handle all other interfaces by matching the GUID
// in 'Adapter' to the GUID of an interface in 'InterfaceInfo'.
// We then store the index of the interface found, if any,
// in the next location in 'AdapterOrderMap'.
//
for (j = 0; j < (DWORD)InterfaceInfo->NumAdapters; j++) {
if (lstrcmpiW(InterfaceInfo->Adapter[j].Name +
sizeof(c_szDeviceTcpip) - 1,
Adapter + sizeof(c_szDevice) - 1) == 0) {
AdapterOrderMap->AdapterOrder[i++] =
InterfaceInfo->Adapter[j].Index;
break;
}
}
}
AdapterOrderMap->NumAdapters = i;
ReleaseMemory(InterfaceInfo);
ReleaseMemory(AdapterOrder);
return AdapterOrderMap;
}
if (InterfaceInfo) { ReleaseMemory(InterfaceInfo); }
if (AdapterOrder) { ReleaseMemory(AdapterOrder); }
return NULL;
}