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.
3709 lines
108 KiB
3709 lines
108 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ioctl.c
|
|
|
|
Abstract:
|
|
|
|
This file contains functions to indicate to the other system
|
|
services that the IP address and other TCP/IP parameters have
|
|
changed.
|
|
|
|
Author:
|
|
|
|
Madan Appiah (madana) 30-Nov-1993
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
#include "dhcpglobal.h"
|
|
#include <dhcploc.h>
|
|
#include <dhcppro.h>
|
|
#include <dhcpcapi.h>
|
|
#include <apiappl.h> // for DhcpReRegisterDynDns ?
|
|
|
|
#define NT // to include data structures for NT build.
|
|
|
|
#include <nbtioctl.h>
|
|
#include <ntddip.h>
|
|
#include <ntddtcp.h>
|
|
|
|
#include <tdiinfo.h>
|
|
#include <tdistat.h>
|
|
#include <ipexport.h>
|
|
#include <tcpinfo.h>
|
|
#include <ipinfo.h>
|
|
#include <llinfo.h>
|
|
|
|
#include <lmcons.h>
|
|
#include <lmsname.h>
|
|
#include <winsvc.h>
|
|
#include <ntddbrow.h>
|
|
#include <limits.h>
|
|
#include <ndispnp.h>
|
|
#include <secobj.h>
|
|
|
|
#define DEFAULT_DEST 0
|
|
#define DEFAULT_DEST_MASK 0
|
|
#define DEFAULT_METRIC 1
|
|
|
|
//
|
|
// Following two functions (APIs) should be remove when MIKEMAS provides
|
|
// entry point DLL for these API.
|
|
//
|
|
// Also all TDI related include files that are checked-in in this dir.
|
|
// should be delfile'd when MIKEMAS checkin those files in private\inc.
|
|
//
|
|
|
|
|
|
|
|
NTSTATUS
|
|
TCPQueryInformationEx(
|
|
IN HANDLE TCPHandle,
|
|
IN TDIObjectID FAR *ID,
|
|
OUT void FAR *Buffer,
|
|
IN OUT DWORD FAR *BufferSize,
|
|
IN OUT BYTE FAR *Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine provides the interface to the TDI QueryInformationEx
|
|
facility of the TCP/IP stack on NT. Someday, this facility will be
|
|
part of TDI.
|
|
|
|
Arguments:
|
|
|
|
TCPHandle - Open handle to the TCP driver
|
|
ID - The TDI Object ID to query
|
|
Buffer - Data buffer to contain the query results
|
|
BufferSize - Pointer to the size of the results buffer. Filled in
|
|
with the amount of results data on return.
|
|
Context - Context value for the query. Should be zeroed for a
|
|
new query. It will be filled with context
|
|
information for linked enumeration queries.
|
|
|
|
Return Value:
|
|
|
|
An NTSTATUS value.
|
|
|
|
--*/
|
|
|
|
{
|
|
TCP_REQUEST_QUERY_INFORMATION_EX queryBuffer;
|
|
DWORD queryBufferSize;
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
|
|
|
|
if (TCPHandle == NULL) {
|
|
return(TDI_INVALID_PARAMETER);
|
|
}
|
|
|
|
queryBufferSize = sizeof(TCP_REQUEST_QUERY_INFORMATION_EX);
|
|
RtlCopyMemory(
|
|
&(queryBuffer.ID),
|
|
ID,
|
|
sizeof(TDIObjectID)
|
|
);
|
|
RtlCopyMemory(
|
|
&(queryBuffer.Context),
|
|
Context,
|
|
CONTEXT_SIZE
|
|
);
|
|
|
|
status = NtDeviceIoControlFile(
|
|
TCPHandle, // Driver handle
|
|
NULL, // Event
|
|
NULL, // APC Routine
|
|
NULL, // APC context
|
|
&ioStatusBlock, // Status block
|
|
IOCTL_TCP_QUERY_INFORMATION_EX, // Control code
|
|
&queryBuffer, // Input buffer
|
|
queryBufferSize, // Input buffer size
|
|
Buffer, // Output buffer
|
|
*BufferSize // Output buffer size
|
|
);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
status = NtWaitForSingleObject(
|
|
TCPHandle,
|
|
TRUE,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
//
|
|
// Copy the return context to the caller's context buffer
|
|
//
|
|
RtlCopyMemory(
|
|
Context,
|
|
&(queryBuffer.Context),
|
|
CONTEXT_SIZE
|
|
);
|
|
|
|
*BufferSize = (ULONG)ioStatusBlock.Information;
|
|
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
else {
|
|
if ( status != TDI_BUFFER_OVERFLOW) {
|
|
DhcpPrint((DEBUG_ERRORS, "TCPQueryInformationEx returned failure %lx\n", status ));
|
|
}
|
|
*BufferSize = 0;
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
TCPSetInformationEx(
|
|
IN HANDLE TCPHandle,
|
|
IN TDIObjectID FAR *ID,
|
|
IN void FAR *Buffer,
|
|
IN DWORD FAR BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine provides the interface to the TDI SetInformationEx
|
|
facility of the TCP/IP stack on NT. Someday, this facility will be
|
|
part of TDI.
|
|
|
|
Arguments:
|
|
|
|
TCPHandle - Open handle to the TCP driver
|
|
ID - The TDI Object ID to set
|
|
Buffer - Data buffer containing the information to be set
|
|
BufferSize - The size of the set data buffer.
|
|
|
|
Return Value:
|
|
|
|
An NTSTATUS value.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTCP_REQUEST_SET_INFORMATION_EX setBuffer;
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
DWORD setBufferSize;
|
|
|
|
|
|
if (TCPHandle == NULL) {
|
|
return(TDI_INVALID_PARAMETER);
|
|
}
|
|
|
|
setBufferSize = FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer) +
|
|
BufferSize;
|
|
|
|
setBuffer = LocalAlloc(LMEM_FIXED, setBufferSize);
|
|
|
|
if (setBuffer == NULL) {
|
|
return(TDI_NO_RESOURCES);
|
|
}
|
|
|
|
setBuffer->BufferSize = BufferSize;
|
|
|
|
RtlCopyMemory(
|
|
&(setBuffer->ID),
|
|
ID,
|
|
sizeof(TDIObjectID)
|
|
);
|
|
|
|
RtlCopyMemory(
|
|
&(setBuffer->Buffer[0]),
|
|
Buffer,
|
|
BufferSize
|
|
);
|
|
|
|
status = NtDeviceIoControlFile(
|
|
TCPHandle, // Driver handle
|
|
NULL, // Event
|
|
NULL, // APC Routine
|
|
NULL, // APC context
|
|
&ioStatusBlock, // Status block
|
|
IOCTL_TCP_SET_INFORMATION_EX, // Control code
|
|
setBuffer, // Input buffer
|
|
setBufferSize, // Input buffer size
|
|
NULL, // Output buffer
|
|
0 // Output buffer size
|
|
);
|
|
|
|
if (status == STATUS_PENDING)
|
|
{
|
|
status = NtWaitForSingleObject(
|
|
TCPHandle,
|
|
TRUE,
|
|
NULL
|
|
);
|
|
|
|
if ( STATUS_SUCCESS == status )
|
|
status = ioStatusBlock.Status;
|
|
|
|
} else if ( status == STATUS_SUCCESS ) {
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
|
|
LocalFree(setBuffer);
|
|
return(status);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
OpenDriver(
|
|
HANDLE *Handle,
|
|
LPWSTR DriverName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function opens a specified IO drivers.
|
|
|
|
Arguments:
|
|
|
|
Handle - pointer to location where the opened drivers handle is
|
|
returned.
|
|
|
|
DriverName - name of the driver to be opened.
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
UNICODE_STRING nameString;
|
|
NTSTATUS status;
|
|
|
|
*Handle = NULL;
|
|
|
|
//
|
|
// Open a Handle to the IP driver.
|
|
//
|
|
|
|
RtlInitUnicodeString(&nameString, DriverName);
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes,
|
|
&nameString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
(HANDLE) NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL
|
|
);
|
|
|
|
status = NtCreateFile(
|
|
Handle,
|
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
|
|
&objectAttributes,
|
|
&ioStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN_IF,
|
|
0,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
return( RtlNtStatusToDosError( status ) );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
IPSetIPAddress(
|
|
DWORD IpInterfaceContext,
|
|
DHCP_IP_ADDRESS Address,
|
|
DHCP_IP_ADDRESS SubnetMask
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This rountine sets the IP Address and subnet mask of the IP stack.
|
|
|
|
Arguments:
|
|
|
|
IpInterfaceContext - Context value of the Ip Table Entry.
|
|
|
|
Address - New IP Address.
|
|
|
|
SubnetMask - New subnet mask.
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
HANDLE IPHandle;
|
|
IP_SET_ADDRESS_REQUEST requestBuffer;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
NTSTATUS status;
|
|
DWORD Error;
|
|
|
|
|
|
DhcpPrint((DEBUG_TRACE, "IPSetIPAddress: settting %s address on interface context %lx\n",
|
|
inet_ntoa(*(struct in_addr *)&Address), IpInterfaceContext ));
|
|
|
|
Error = OpenDriver(&IPHandle, DD_IP_DEVICE_NAME);
|
|
|
|
if (Error != ERROR_SUCCESS) {
|
|
return( Error );
|
|
}
|
|
|
|
//
|
|
// Initialize the input buffer.
|
|
//
|
|
|
|
requestBuffer.Context = (USHORT)IpInterfaceContext;
|
|
requestBuffer.Address = Address;
|
|
requestBuffer.SubnetMask = SubnetMask;
|
|
|
|
status = NtDeviceIoControlFile(
|
|
IPHandle, // Driver handle
|
|
NULL, // Event
|
|
NULL, // APC Routine
|
|
NULL, // APC context
|
|
&ioStatusBlock, // Status block
|
|
IOCTL_IP_SET_ADDRESS, // Control code
|
|
&requestBuffer, // Input buffer
|
|
sizeof(IP_SET_ADDRESS_REQUEST), // Input buffer size
|
|
NULL, // Output buffer
|
|
0 // Output buffer size
|
|
);
|
|
|
|
|
|
if ( status == STATUS_UNSUCCESSFUL ) { // whoa? syscall failed? should not really happen
|
|
DhcpPrint( (DEBUG_ERRORS,
|
|
"IOCTL_IP_SET_ADDRESS returned immediate STATUS_UNSUCCESSFUL for %s\n",
|
|
inet_ntoa(*(struct in_addr *)&Address)));
|
|
|
|
} else if ( STATUS_PENDING == status ) { // ip is trying to do things..
|
|
status = NtWaitForSingleObject( IPHandle, TRUE, NULL );
|
|
status = ioStatusBlock.Status;
|
|
} else if ( STATUS_SUCCESS == status ) { // DeviceIoControl worked, but how does ip feel?
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
|
|
if ( STATUS_SUCCESS != status ) {
|
|
DhcpPrint((DEBUG_ERRORS,
|
|
"IOCTL_IP_SET_ADDRESS returned STATUS_UNSUCCESSFUL<0x%lx> for %s\n",
|
|
status, inet_ntoa(*(struct in_addr *)&Address)));
|
|
}
|
|
|
|
NtClose( IPHandle );
|
|
|
|
if( 0 == Address && STATUS_DUPLICATE_NAME == status ) {
|
|
// I think this is what happens when you try to set zero if it is already zero!!!
|
|
DhcpPrint((DEBUG_ERRORS, "Trying to set zero address: ADDRESS_CONFLICT??? Ignored\n"));
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if( IP_MEDIA_DISCONNECT == status ) {
|
|
//
|
|
// You get this if the media is disconnected... We just ignore this for now.
|
|
//
|
|
DhcpPrint((DEBUG_ERRORS, "Trying to set address while media disconnected..\n"));
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return( RtlNtStatusToDosError( status ) );
|
|
}
|
|
|
|
DWORD
|
|
IPDelIPAddress(
|
|
DWORD IpInterfaceContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This rountine deletes a static IP address for the supplied IpInterfaceContext
|
|
|
|
Arguments:
|
|
|
|
IpInterfaceContext - Context value of the Ip Table Entry.
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
HANDLE IPHandle;
|
|
IP_DELETE_NTE_REQUEST requestBuffer;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
NTSTATUS status;
|
|
DWORD Error;
|
|
|
|
DhcpPrint((DEBUG_MISC, "IPDelIPAddress: deleting address with ipcontext %x \n", IpInterfaceContext));
|
|
Error = OpenDriver(&IPHandle, DD_IP_DEVICE_NAME);
|
|
|
|
if (Error != ERROR_SUCCESS) {
|
|
return( Error );
|
|
}
|
|
|
|
|
|
requestBuffer.Context = (USHORT)IpInterfaceContext;
|
|
|
|
status = NtDeviceIoControlFile(
|
|
IPHandle, // Driver handle
|
|
NULL, // Event
|
|
NULL, // APC Routine
|
|
NULL, // APC context
|
|
&ioStatusBlock, // Status block
|
|
IOCTL_IP_DELETE_NTE, // Control code
|
|
&requestBuffer, // Input buffer
|
|
sizeof(requestBuffer), // Input buffer size
|
|
NULL, // Output buffer
|
|
0 // Output buffer size
|
|
);
|
|
|
|
|
|
if ( status == STATUS_UNSUCCESSFUL )
|
|
{
|
|
DhcpPrint( (DEBUG_ERRORS,
|
|
"IOCTL_IP_DELETE_NTE returned immediate STATUS_UNSUCCESSFUL for context %lx\n",
|
|
IpInterfaceContext));
|
|
}
|
|
else if ( STATUS_PENDING == status )
|
|
{
|
|
status = NtWaitForSingleObject( IPHandle, TRUE, NULL );
|
|
status = ioStatusBlock.Status;
|
|
|
|
if ( STATUS_UNSUCCESSFUL == status ){
|
|
DhcpPrint( (DEBUG_ERRORS,
|
|
"IOCTL_IP_DELETE_NTE returned STATUS_UNSUCCESSFUL for context %lx\n",
|
|
IpInterfaceContext));
|
|
}
|
|
|
|
} else if ( STATUS_SUCCESS == status ) {
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
|
|
|
|
NtClose( IPHandle );
|
|
return( RtlNtStatusToDosError( status ) );
|
|
}
|
|
|
|
DWORD
|
|
IPDelNonPrimaryAddresses(
|
|
LPWSTR AdapterName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This rountine deletes all the static ip addresses but
|
|
the primary one.
|
|
|
|
Arguments:
|
|
|
|
AdapterName - The adaptername that identifies the ip interface
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
LPWSTR RegKey = NULL;
|
|
HKEY KeyHandle = NULL;
|
|
LPWSTR nteContextList = NULL;
|
|
PCHAR oemNextContext = NULL;
|
|
LPWSTR nextContext;
|
|
DWORD i;
|
|
|
|
//
|
|
// Open device parameter.
|
|
//
|
|
|
|
RegKey = DhcpAllocateMemory(
|
|
(wcslen(DHCP_SERVICES_KEY) +
|
|
wcslen(REGISTRY_CONNECT_STRING) +
|
|
wcslen(AdapterName) +
|
|
wcslen(DHCP_ADAPTER_PARAMETERS_KEY) + 1) *
|
|
sizeof(WCHAR) ); // termination char.
|
|
|
|
if( RegKey == NULL ) {
|
|
Error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
wcscpy( RegKey, DHCP_SERVICES_KEY );
|
|
wcscat( RegKey, DHCP_ADAPTER_PARAMETERS_KEY );
|
|
wcscat( RegKey, REGISTRY_CONNECT_STRING );
|
|
wcscat( RegKey, AdapterName );
|
|
|
|
|
|
//
|
|
// open this key.
|
|
//
|
|
|
|
Error = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
RegKey,
|
|
0, // Reserved field
|
|
DHCP_CLIENT_KEY_ACCESS,
|
|
&KeyHandle
|
|
);
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
Error = GetRegistryString(
|
|
KeyHandle,
|
|
DHCP_NTE_CONTEXT_LIST,
|
|
&nteContextList,
|
|
NULL
|
|
);
|
|
|
|
if ( ERROR_SUCCESS != Error )
|
|
{
|
|
DhcpPrint( (DEBUG_ERRORS,
|
|
"GetIpInterfaceContext: Could not read nteContextList %lx\n",
|
|
Error));
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
// if the adapter is disabled, nteContextList contains nothing
|
|
// more than a L'\0'. No address to be deleted in this case.
|
|
if (*nteContextList != L'\0')
|
|
{
|
|
nextContext = nteContextList;
|
|
// delete all the addresses but the first one.
|
|
for( nextContext += (wcslen(nextContext) + 1), i = 1;
|
|
*nextContext != L'\0';
|
|
i++, nextContext += (wcslen(nextContext) + 1) ) {
|
|
ULONG ival;
|
|
oemNextContext = DhcpUnicodeToOem(nextContext, NULL);
|
|
if ( NULL == oemNextContext ) {
|
|
Error = ERROR_BAD_FORMAT;
|
|
} else {
|
|
ival = strtoul(oemNextContext, NULL, 0);
|
|
if ( ival == ULONG_MAX || ival == 0) {
|
|
Error = ERROR_BAD_FORMAT;
|
|
} else {
|
|
// delete this address
|
|
Error = IPDelIPAddress( ival );
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if( RegKey != NULL ) {
|
|
DhcpFreeMemory( RegKey );
|
|
}
|
|
|
|
if( KeyHandle != NULL ) {
|
|
RegCloseKey( KeyHandle );
|
|
}
|
|
|
|
if ( nteContextList != NULL ) {
|
|
DhcpFreeMemory( nteContextList );
|
|
}
|
|
|
|
if ( oemNextContext != NULL ) {
|
|
DhcpFreeMemory( oemNextContext );
|
|
}
|
|
|
|
|
|
return( Error );
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
IPGetWOLCapability(
|
|
IN ULONG IfIndex,
|
|
OUT PULONG pRetVal
|
|
)
|
|
{
|
|
HANDLE IPHandle;
|
|
ULONG RetVal;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
NTSTATUS status;
|
|
DWORD Error;
|
|
|
|
|
|
DhcpPrint((
|
|
DEBUG_MISC, "IPGetWOLCapability(0x%lx) called\n", IfIndex
|
|
));
|
|
Error = OpenDriver(&IPHandle, DD_IP_DEVICE_NAME);
|
|
|
|
if (Error != ERROR_SUCCESS) {
|
|
return( Error );
|
|
}
|
|
|
|
status = NtDeviceIoControlFile(
|
|
IPHandle, // Driver handle
|
|
NULL, // Event
|
|
NULL, // APC Routine
|
|
NULL, // APC context
|
|
&ioStatusBlock, // Status block
|
|
IOCTL_IP_GET_WOL_CAPABILITY, // Control code
|
|
&IfIndex, // Input buffer
|
|
sizeof(IfIndex), // Input buffer size
|
|
pRetVal, // Output buffer
|
|
sizeof(*pRetVal) // Output buffer size
|
|
);
|
|
|
|
|
|
if ( status == STATUS_UNSUCCESSFUL )
|
|
{
|
|
DhcpPrint((
|
|
DEBUG_ERRORS,
|
|
"IOCTL_IP_GET_WOL_CAPABILITY(0x%lx): STATUS_UNSUCCESSFUL\n", IfIndex
|
|
));
|
|
}
|
|
else if ( STATUS_PENDING == status )
|
|
{
|
|
status = NtWaitForSingleObject( IPHandle, TRUE, NULL );
|
|
status = ioStatusBlock.Status;
|
|
|
|
if ( STATUS_UNSUCCESSFUL == status )
|
|
DhcpPrint((
|
|
DEBUG_ERRORS,
|
|
"IOCTL_IP_GET_WOL_CAPABILITY(0x%lx): failed\n", IfIndex
|
|
));
|
|
} else if( STATUS_SUCCESS == status ) {
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
|
|
NtClose( IPHandle );
|
|
return( RtlNtStatusToDosError( status ) );
|
|
}
|
|
|
|
DWORD
|
|
IPAddIPAddress(
|
|
LPWSTR AdapterName,
|
|
DHCP_IP_ADDRESS Address,
|
|
DHCP_IP_ADDRESS SubnetMask
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This rountine adds an static ipaddress to the IP interface for
|
|
the given adaptername.
|
|
|
|
Arguments:
|
|
|
|
AdapterName - The adaptername that identifies the ip interface
|
|
|
|
Address - IPaddress to be added
|
|
|
|
SubnetMask - SubnetMask
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
HANDLE IPHandle;
|
|
PIP_ADD_NTE_REQUEST requestBuffer;
|
|
IP_ADD_NTE_RESPONSE responseBuffer;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
NTSTATUS status;
|
|
DWORD Error;
|
|
DWORD requestBufferSize;
|
|
|
|
|
|
DhcpPrint((DEBUG_MISC, "IPAddIPAddress: adding an address on adapter %ws\n", AdapterName));
|
|
Error = OpenDriver(&IPHandle, DD_IP_DEVICE_NAME);
|
|
|
|
if (Error != ERROR_SUCCESS) {
|
|
return( Error );
|
|
}
|
|
|
|
//
|
|
// The adapter name that we pass to TCPIP should be of form
|
|
// \device\TCPIP_<adaptername>
|
|
//
|
|
|
|
|
|
//
|
|
// Initialize the input buffer.
|
|
//
|
|
requestBufferSize = FIELD_OFFSET(IP_ADD_NTE_REQUEST, InterfaceNameBuffer) +
|
|
(wcslen(DHCP_TCPIP_DEVICE_STRING) // \Device
|
|
+ wcslen(AdapterName)) * sizeof(WCHAR);
|
|
|
|
requestBuffer = DhcpAllocateMemory( requestBufferSize + sizeof(WCHAR));
|
|
if (requestBuffer == NULL) {
|
|
NtClose(IPHandle);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
wcscpy((PWCHAR)requestBuffer->InterfaceNameBuffer, DHCP_TCPIP_DEVICE_STRING);
|
|
wcscat((PWCHAR)requestBuffer->InterfaceNameBuffer, AdapterName);
|
|
RtlInitUnicodeString(&requestBuffer->InterfaceName, (PWCHAR)requestBuffer->InterfaceNameBuffer);
|
|
RtlUpcaseUnicodeString( &requestBuffer->InterfaceName, &requestBuffer->InterfaceName, FALSE );
|
|
|
|
requestBuffer->InterfaceContext = INVALID_INTERFACE_CONTEXT;
|
|
requestBuffer->Address = Address;
|
|
requestBuffer->SubnetMask = SubnetMask;
|
|
|
|
status = NtDeviceIoControlFile(
|
|
IPHandle, // Driver handle
|
|
NULL, // Event
|
|
NULL, // APC Routine
|
|
NULL, // APC context
|
|
&ioStatusBlock, // Status block
|
|
IOCTL_IP_ADD_NTE, // Control code
|
|
requestBuffer, // Input buffer
|
|
requestBufferSize, // Input buffer size
|
|
&responseBuffer, // Output buffer
|
|
sizeof(responseBuffer) // Output buffer size
|
|
);
|
|
|
|
|
|
if ( status == STATUS_UNSUCCESSFUL )
|
|
{
|
|
DhcpPrint( (DEBUG_ERRORS,
|
|
"IOCTL_IP_ADD_NTE returned immediate STATUS_UNSUCCESSFUL for %s\n",
|
|
inet_ntoa(*(struct in_addr *)&Address)));
|
|
}
|
|
else if ( STATUS_PENDING == status )
|
|
{
|
|
status = NtWaitForSingleObject( IPHandle, TRUE, NULL );
|
|
status = ioStatusBlock.Status;
|
|
} else if (STATUS_SUCCESS == status ) {
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
|
|
DhcpPrint( (DEBUG_ERRORS,
|
|
"IOCTL_IP_ADD_NTE returned 0x%lx for %s\n",
|
|
status, inet_ntoa(*(struct in_addr *)&Address)));
|
|
NtClose( IPHandle );
|
|
DhcpFreeMemory(requestBuffer);
|
|
return( RtlNtStatusToDosError( status ) );
|
|
}
|
|
|
|
|
|
DWORD
|
|
IPSetInterface(
|
|
DWORD IpInterfaceContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This rountine sets the IP interface for sending DHCP broadcasts.
|
|
|
|
Arguments:
|
|
|
|
IpInterfaceContext - Context value of the Ip Table Entry.
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
HANDLE IPHandle;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
NTSTATUS status;
|
|
DWORD Error;
|
|
|
|
Error = OpenDriver(&IPHandle, DD_IP_DEVICE_NAME);
|
|
|
|
if (Error != ERROR_SUCCESS) {
|
|
return( Error );
|
|
}
|
|
|
|
status = NtDeviceIoControlFile(
|
|
IPHandle, // Driver handle
|
|
NULL, // Event
|
|
NULL, // APC Routine
|
|
NULL, // APC context
|
|
&ioStatusBlock, // Status block
|
|
IOCTL_IP_SET_DHCP_INTERFACE, // Control code
|
|
&IpInterfaceContext, // Input buffer
|
|
sizeof(IpInterfaceContext), // Input buffer size
|
|
NULL, // Output buffer
|
|
0 // Output buffer size
|
|
);
|
|
|
|
if (status == STATUS_PENDING)
|
|
{
|
|
status = NtWaitForSingleObject(
|
|
IPHandle,
|
|
TRUE,
|
|
NULL
|
|
);
|
|
|
|
if ( STATUS_SUCCESS == status )
|
|
status = ioStatusBlock.Status;
|
|
|
|
} else if ( STATUS_SUCCESS == status ) {
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
|
|
NtClose(IPHandle);
|
|
return( RtlNtStatusToDosError( status ) );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
IPResetInterface(
|
|
DWORD dwIpInterfaceContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This rountine resets the IP interface to restore normal IP
|
|
interface behaviour.
|
|
|
|
Arguments:
|
|
|
|
VOID
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
|
|
LOCK_INTERFACE();
|
|
Error = IPSetInterface(dwIpInterfaceContext);
|
|
if( ERROR_SUCCESS == Error ) {
|
|
Error = IPSetInterface( 0xFFFFFFFF );
|
|
}
|
|
UNLOCK_INTERFACE();
|
|
|
|
return Error;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
IPResetIPAddress(
|
|
DWORD dwInterfaceContext,
|
|
DHCP_IP_ADDRESS SubnetMask
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This rountine resets the IP Address of the IP to ZERO.
|
|
|
|
Arguments:
|
|
|
|
IpInterfaceContext - Context value of the Ip Table Entry.
|
|
|
|
SubnetMask - default subnet mask.
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwResult = IPSetIPAddress( dwInterfaceContext, 0, SubnetMask);
|
|
|
|
if ( ERROR_SUCCESS != dwResult )
|
|
DhcpPrint( ( DEBUG_ERRORS,
|
|
"IPResetIPAddress failed: %x\n", dwResult ));
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
//
|
|
// Doing our own NdisHandlePnPRequest per Alid's suggestion
|
|
//
|
|
|
|
#include <ntddndis.h>
|
|
#include <ndisprv.h>
|
|
|
|
#define UNICODE_STRING_SIZE(x) \
|
|
((((x) == NULL) ? 0 : (x)->Length) + sizeof(WCHAR))
|
|
|
|
VOID
|
|
DhcpNdispUnicodeStringToVar(
|
|
IN PVOID Base,
|
|
IN PUNICODE_STRING String,
|
|
IN OUT PNDIS_VAR_DATA_DESC NdisVar
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function copies the contents of a UNICODE_STRING to an
|
|
NDIS_VAR_DATA structure. NdisVar->Offset is treated as an input parameter
|
|
and represents the offset into Base that the string characters should be
|
|
copied to.
|
|
|
|
Arguments:
|
|
|
|
Base - Specifies the base address of the IOCTL buffer.
|
|
|
|
String - Supplies a pointer to the UNICODE_STRING that should be copied.
|
|
|
|
NdisVar - Supplies a pointer to the target NDIS_VAR_DATA_DESC. Its Offset
|
|
field is taken as input, and its Length and MaximumLength fields
|
|
are treated as output.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWCHAR destination;
|
|
|
|
//
|
|
// NdisVar->Offset is assumed to be filled in and is treated
|
|
// as an input parameter.
|
|
//
|
|
|
|
destination = (PWCHAR)(((PCHAR)Base) + NdisVar->Offset);
|
|
|
|
//
|
|
// Copy over the UNICODE_STRING, if any, and set NdisVar->Length
|
|
//
|
|
|
|
if ((String != NULL) && (String->Length > 0)) {
|
|
NdisVar->Length = String->Length;
|
|
memcpy(destination, String->Buffer, NdisVar->Length );
|
|
} else {
|
|
NdisVar->Length = 0;
|
|
}
|
|
|
|
//
|
|
// Null-terminate, fill in MaxiumLength and we're done.
|
|
//
|
|
|
|
*(destination + NdisVar->Length / sizeof(WCHAR)) = L'\0';
|
|
NdisVar->MaximumLength = NdisVar->Length + sizeof(WCHAR);
|
|
}
|
|
|
|
|
|
UINT
|
|
DhcpNdisHandlePnPEvent(
|
|
IN UINT Layer,
|
|
IN UINT Operation,
|
|
IN PUNICODE_STRING LowerComponent OPTIONAL,
|
|
IN PUNICODE_STRING UpperComponent OPTIONAL,
|
|
IN PUNICODE_STRING BindList OPTIONAL,
|
|
IN PVOID ReConfigBuffer OPTIONAL,
|
|
IN UINT ReConfigBufferSize OPTIONAL
|
|
)
|
|
{
|
|
PNDIS_PNP_OPERATION Op;
|
|
NDIS_PNP_OPERATION tempOp;
|
|
HANDLE hDevice;
|
|
BOOL fResult = FALSE;
|
|
UINT cb, Size;
|
|
DWORD Error;
|
|
ULONG padding;
|
|
|
|
do
|
|
{
|
|
//
|
|
// Validate Layer & Operation
|
|
//
|
|
if (((Layer != NDIS) && (Layer != TDI)) ||
|
|
((Operation != BIND) && (Operation != UNBIND) && (Operation != RECONFIGURE) &&
|
|
(Operation != UNLOAD) && (Operation != REMOVE_DEVICE) &&
|
|
(Operation != ADD_IGNORE_BINDING) &&
|
|
(Operation != DEL_IGNORE_BINDING) &&
|
|
(Operation != BIND_LIST)))
|
|
{
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate and initialize memory for the block to be passed down. The buffer
|
|
// will look like this:
|
|
//
|
|
//
|
|
// +=================================+
|
|
// | NDIS_PNP_OPERATION |
|
|
// | ReConfigBufferOff | ----+
|
|
// +--- | LowerComponent.Offset | |
|
|
// | | UpperComponent.Offset | --+ |
|
|
// +-|--- | BindList.Offset | | |
|
|
// | +--> +---------------------------------+ | |
|
|
// | | LowerComponentStringBuffer | | |
|
|
// | +---------------------------------+ <-+ |
|
|
// | | UpperComponentStringBuffer | |
|
|
// +----> +---------------------------------+ |
|
|
// | BindListStringBuffer | |
|
|
// +---------------------------------+ |
|
|
// | Padding to ensure ULONG_PTR | |
|
|
// | alignment of ReConfigBuffer | |
|
|
// +---------------------------------+ <---+
|
|
// | ReConfigBuffer |
|
|
// +=================================+
|
|
//
|
|
// tempOp is a temporary structure into which we will store offsets as
|
|
// they are calculated. This temporary structure will be moved to
|
|
// the head of the real buffer once its size is known and it is
|
|
// allocated.
|
|
//
|
|
|
|
Size = sizeof(NDIS_PNP_OPERATION);
|
|
tempOp.LowerComponent.Offset = Size;
|
|
|
|
Size += UNICODE_STRING_SIZE(LowerComponent);
|
|
tempOp.UpperComponent.Offset = Size;
|
|
|
|
Size += UNICODE_STRING_SIZE(UpperComponent);
|
|
tempOp.BindList.Offset = Size;
|
|
|
|
Size += UNICODE_STRING_SIZE(BindList);
|
|
|
|
padding = (sizeof(ULONG_PTR) - (Size & (sizeof(ULONG_PTR) - 1))) &
|
|
(sizeof(ULONG_PTR) - 1);
|
|
|
|
Size += padding;
|
|
tempOp.ReConfigBufferOff = Size;
|
|
|
|
Size += ReConfigBufferSize + 1;
|
|
|
|
Op = (PNDIS_PNP_OPERATION)LocalAlloc(LPTR, Size);
|
|
if (Op == NULL)
|
|
{
|
|
Error = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We have a buffer of the necessary size. Copy in the partially-
|
|
// filled in tempOp, then fill in the remaining fields and copy the
|
|
// data into the buffer.
|
|
//
|
|
|
|
*Op = tempOp;
|
|
|
|
Op->Layer = Layer;
|
|
Op->Operation = Operation;
|
|
|
|
//
|
|
// Copy over the three unicode strings
|
|
//
|
|
|
|
DhcpNdispUnicodeStringToVar( Op, LowerComponent, &Op->LowerComponent );
|
|
DhcpNdispUnicodeStringToVar( Op, UpperComponent, &Op->UpperComponent );
|
|
DhcpNdispUnicodeStringToVar( Op, BindList, &Op->BindList );
|
|
|
|
//
|
|
// Finally, copy over the ReConfigBuffer
|
|
//
|
|
|
|
Op->ReConfigBufferSize = ReConfigBufferSize;
|
|
if (ReConfigBufferSize > 0)
|
|
{
|
|
memcpy((PUCHAR)Op + Op->ReConfigBufferOff,
|
|
ReConfigBuffer,
|
|
ReConfigBufferSize);
|
|
}
|
|
*((PUCHAR)Op + Op->ReConfigBufferOff + ReConfigBufferSize) = 0;
|
|
|
|
hDevice = CreateFile(L"\\\\.\\NDIS",
|
|
0,
|
|
0, // sharing mode - not significant
|
|
NULL, // security attributes
|
|
OPEN_EXISTING,
|
|
0, // file attributes and flags
|
|
NULL); // handle to template file
|
|
|
|
if (hDevice != INVALID_HANDLE_VALUE)
|
|
{
|
|
fResult = DeviceIoControl(hDevice,
|
|
IOCTL_NDIS_DO_PNP_OPERATION,
|
|
Op, // input buffer
|
|
Size, // input buffer size
|
|
NULL, // output buffer
|
|
0, // output buffer size
|
|
&cb, // bytes returned
|
|
NULL); // OVERLAPPED structure
|
|
Error = GetLastError();
|
|
CloseHandle(hDevice);
|
|
}
|
|
else
|
|
{
|
|
Error = GetLastError();
|
|
}
|
|
|
|
LocalFree(Op);
|
|
|
|
} while (FALSE);
|
|
|
|
SetLastError(Error);
|
|
|
|
return(fResult);
|
|
}
|
|
|
|
ULONG
|
|
TcpIpNotifyRouterDiscoveryOption(
|
|
IN LPCWSTR AdapterName,
|
|
IN BOOL fOptionPresent,
|
|
IN DWORD OptionValue
|
|
)
|
|
{
|
|
ULONG Error;
|
|
ULONG RetVal;
|
|
WCHAR TcpipAdapter[300+sizeof(DHCP_ADAPTERS_DEVICE_STRING)];
|
|
UNICODE_STRING UpperLayer, LowerLayer, BindString;
|
|
IP_PNP_RECONFIG_REQUEST Request;
|
|
|
|
Error = NO_ERROR;
|
|
|
|
if (wcslen(AdapterName) > 150) {
|
|
ASSERT(0);
|
|
Error = ERROR_INVALID_DATA;
|
|
return Error;
|
|
}
|
|
|
|
RtlZeroMemory(&Request, sizeof(Request));
|
|
Request.version = IP_PNP_RECONFIG_VERSION;
|
|
Request.Flags |= IP_PNP_FLAG_DHCP_PERFORM_ROUTER_DISCOVERY;
|
|
if( fOptionPresent ) {
|
|
Request.DhcpPerformRouterDiscovery = (BOOLEAN)OptionValue;
|
|
}
|
|
|
|
wcscpy(TcpipAdapter, DHCP_ADAPTERS_DEVICE_STRING);
|
|
wcscat(TcpipAdapter, AdapterName);
|
|
|
|
RtlInitUnicodeString(&BindString, NULL); // no bind string
|
|
RtlInitUnicodeString(&UpperLayer, TEXT("Tcpip"));
|
|
RtlInitUnicodeString(&LowerLayer, TcpipAdapter);
|
|
RetVal = DhcpNdisHandlePnPEvent(
|
|
NDIS, // uiLayer
|
|
RECONFIGURE, // Operation
|
|
&LowerLayer,
|
|
&UpperLayer,
|
|
&BindString,
|
|
&Request,
|
|
sizeof(Request)
|
|
);
|
|
if( 0 == RetVal) Error = GetLastError();
|
|
|
|
if( ERROR_SUCCESS != Error) {
|
|
DhcpPrint((DEBUG_ERRORS, "TcpipNotifyRegChanges:0x%ld\n", Error));
|
|
}
|
|
return Error;
|
|
}
|
|
|
|
|
|
DWORD // win32 status
|
|
NetBTNotifyRegChanges( // Notify NetBT of some parameter changes
|
|
IN LPWSTR AdapterName // the adapter that needs this change notification
|
|
)
|
|
{
|
|
DWORD Error;
|
|
DWORD RetVal;
|
|
WCHAR NetBTBindAdapter[300+sizeof( DHCP_TCPIP_DEVICE_STRING )];
|
|
UNICODE_STRING UpperLayer;
|
|
UNICODE_STRING LowerLayer;
|
|
UNICODE_STRING BindString;
|
|
|
|
if (wcslen(AdapterName) > 150) {
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
Error = ERROR_SUCCESS;
|
|
wcscpy(NetBTBindAdapter, DHCP_TCPIP_DEVICE_STRING);
|
|
wcscat(NetBTBindAdapter, AdapterName); // \\Device\\Tcpip_{AdapterGuid} is what NetBT expects.
|
|
|
|
RtlInitUnicodeString(&BindString, NULL); // no bind string
|
|
RtlInitUnicodeString(&UpperLayer, TEXT("NetBT"));
|
|
RtlInitUnicodeString(&LowerLayer, NetBTBindAdapter);
|
|
RetVal = DhcpNdisHandlePnPEvent(
|
|
TDI, // uiLayer
|
|
RECONFIGURE, // Operation
|
|
&LowerLayer,
|
|
&UpperLayer,
|
|
&BindString,
|
|
NULL,
|
|
0
|
|
);
|
|
if( 0 != RetVal) Error = GetLastError();
|
|
|
|
if( ERROR_SUCCESS != Error) {
|
|
DhcpPrint((DEBUG_ERRORS, "NetBTNotifyRegChanges:0x%ld\n", Error));
|
|
}
|
|
return Error;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
FindHardwareAddr(
|
|
HANDLE TCPHandle,
|
|
TDIEntityID *EList,
|
|
DWORD cEntities,
|
|
IPAddrEntry *pIAE,
|
|
LPBYTE HardwareAddressType,
|
|
LPBYTE *HardwareAddress,
|
|
LPDWORD HardwareAddressLength,
|
|
DWORD *pIpInterfaceInstance,
|
|
#ifdef BOOTPERF
|
|
BOOL *pfInterfaceDown,
|
|
#endif BOOTPERF
|
|
BOOL *pfFound
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function browses the TDI entries list and finds out the
|
|
hardware address for the specified address entry.
|
|
|
|
Arguments:
|
|
|
|
TCPHandle - handle TCP driver.
|
|
|
|
EList - list of TDI entries.
|
|
|
|
cEntities - number of entries in the above list.
|
|
|
|
pIAE - IP entry for which we need HW address.
|
|
|
|
HardwareAddressType - hardware address type.
|
|
|
|
HardwareAddress - pointer to location where the HW address buffer
|
|
pointer is returned.
|
|
|
|
HardwareAddressLength - length of the HW address returned.
|
|
|
|
pIpInterfaceInstance - pointer to interface instance for the matching entry
|
|
|
|
pfFound - pointer to BOOL location which is set to TRUE if we found
|
|
the HW address otherwise set to FALSE.
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
BYTE Context[CONTEXT_SIZE];
|
|
TDIObjectID ID;
|
|
NTSTATUS Status;
|
|
DWORD Size;
|
|
|
|
*pfFound = FALSE;
|
|
|
|
ID.toi_entity.tei_entity = IF_MIB;
|
|
ID.toi_type = INFO_TYPE_PROVIDER;
|
|
|
|
for ( i = 0; i < cEntities; i++ ) {
|
|
DhcpPrint((DEBUG_TCP_INFO, "FindHardwareAddress: entity %lx, type %lx, instance %lx\n",
|
|
i, EList[i].tei_entity, EList[i].tei_instance));
|
|
|
|
if (EList[i].tei_entity == IF_ENTITY) {
|
|
|
|
IFEntry IFE;
|
|
DWORD IFType;
|
|
|
|
//
|
|
// Check and make sure the interface supports MIB-2
|
|
//
|
|
|
|
ID.toi_entity.tei_entity = EList[i].tei_entity;
|
|
ID.toi_entity.tei_instance = EList[i].tei_instance;
|
|
ID.toi_class = INFO_CLASS_GENERIC;
|
|
ID.toi_id = ENTITY_TYPE_ID;
|
|
|
|
Size = sizeof( IFType );
|
|
IFType = 0;
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "FindHardwareAddress: querying IF_ENTITY %lx\n",i));
|
|
|
|
Status = TCPQueryInformationEx(
|
|
TCPHandle,
|
|
&ID,
|
|
&IFType,
|
|
&Size,
|
|
Context);
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
|
|
if ( IFType != IF_MIB ) {
|
|
DhcpPrint((DEBUG_TCP_INFO, "FindHardwareAddress: entity %lx does not support MIB\n",i));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// We've found an interface, get its index and see if it
|
|
// matches the IP Address entry
|
|
//
|
|
|
|
ID.toi_class = INFO_CLASS_PROTOCOL;
|
|
ID.toi_id = IF_MIB_STATS_ID;
|
|
|
|
Size = sizeof(IFEntry);
|
|
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
RtlZeroMemory(&IFE, Size);
|
|
Status = TCPQueryInformationEx(
|
|
TCPHandle,
|
|
&ID,
|
|
&IFE,
|
|
&Size,
|
|
Context);
|
|
|
|
if ( Status != TDI_SUCCESS &&
|
|
Status != TDI_BUFFER_OVERFLOW ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
DhcpPrint(( DEBUG_TCP_INFO, "FindHardwareAddress: IFEntry %lx has if_index %lx.\n", &IFE, IFE.if_index ));
|
|
|
|
if ( IFE.if_index == pIAE->iae_index ) {
|
|
|
|
LPBYTE Address;
|
|
DhcpPrint(( DEBUG_TCP_INFO, "FindHardwareAddress: IFEntry %lx has our if_index %lx\n",
|
|
&IFE, pIAE->iae_index ));
|
|
|
|
//
|
|
// Allocate Memory.
|
|
//
|
|
|
|
Address = DhcpAllocateMemory( IFE.if_physaddrlen );
|
|
|
|
if( Address == NULL ) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
Address,
|
|
IFE.if_physaddr,
|
|
IFE.if_physaddrlen );
|
|
|
|
switch( IFE.if_type ) {
|
|
case IF_TYPE_ETHERNET_CSMACD:
|
|
*HardwareAddressType = HARDWARE_TYPE_10MB_EITHERNET;
|
|
break;
|
|
|
|
case IF_TYPE_ISO88025_TOKENRING:
|
|
case IF_TYPE_FDDI:
|
|
*HardwareAddressType = HARDWARE_TYPE_IEEE_802;
|
|
break;
|
|
|
|
case IF_TYPE_OTHER:
|
|
*HardwareAddressType = HARDWARE_ARCNET;
|
|
break;
|
|
|
|
case IF_TYPE_PPP:
|
|
*HardwareAddressType = HARDWARE_PPP;
|
|
break;
|
|
|
|
case IF_TYPE_IEEE1394:
|
|
*HardwareAddressType = HARDWARE_1394;
|
|
break;
|
|
|
|
default:
|
|
DhcpPrint(( DEBUG_ERRORS, "Invalid HW Type, %ld.\n", IFE.if_type ));
|
|
*HardwareAddressType = HARDWARE_ARCNET;
|
|
break;
|
|
}
|
|
|
|
*HardwareAddress = Address;
|
|
*HardwareAddressLength = IFE.if_physaddrlen;
|
|
*pIpInterfaceInstance = ID.toi_entity.tei_instance;
|
|
|
|
DhcpPrint( (DEBUG_MISC,
|
|
"tei_instance = %d\n", *pIpInterfaceInstance ));
|
|
|
|
*pfFound = TRUE;
|
|
#ifdef BOOTPERF
|
|
if( pfInterfaceDown ) {
|
|
*pfInterfaceDown = (IFE.if_adminstatus != IF_STATUS_UP);
|
|
}
|
|
#endif BOOTPERF
|
|
Status = TDI_SUCCESS;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// we couldn't find a corresponding entry. But it may be available
|
|
// in another tanel.
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
DhcpPrint(( DEBUG_ERRORS, "FindHardwareAddr failed, %lx.\n", Status ));
|
|
}
|
|
|
|
return TDI_SUCCESS;
|
|
}
|
|
|
|
#ifdef BOOTPERF
|
|
DWORD
|
|
DhcpQueryHWInfoEx(
|
|
DWORD IpInterfaceContext,
|
|
DWORD *pIpInterfaceInstance,
|
|
DWORD *pOldIpAddress OPTIONAL,
|
|
DWORD *pOldMask OPTIONAL,
|
|
BOOL *pfInterfaceDown OPTIONAL,
|
|
LPBYTE HardwareAddressType,
|
|
LPBYTE *HardwareAddress,
|
|
LPDWORD HardwareAddressLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function queries and browses through the TDI list to find out
|
|
the specified IpTable entry and then determines the HW address that
|
|
corresponds to this entry.
|
|
|
|
Arguments:
|
|
|
|
IpInterfaceContext - Context value of the Ip Table Entry.
|
|
|
|
pIpInterfaceInstance - pointer to the interface instance ID that corresponds
|
|
to matching IpTable entry
|
|
|
|
pOldIpAddress - the old IP address that used to exist.
|
|
|
|
pOldMask - the old IP mask for this entry.
|
|
|
|
pfInterfaceDown -- location of BOOL that tells if the interface is DOWN or UP
|
|
|
|
HardwareAddressType - hardware address type.
|
|
|
|
HardwareAddress - pointer to location where the HW address buffer
|
|
pointer is returned.
|
|
|
|
HardwareAddressLength - length of the HW address returned.
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
NTSTATUS Status;
|
|
DWORD i, j;
|
|
|
|
BYTE Context[CONTEXT_SIZE];
|
|
TDIEntityID *EList = NULL;
|
|
TDIObjectID ID;
|
|
DWORD Size;
|
|
DWORD NumReturned;
|
|
BOOL fFound;
|
|
|
|
IPAddrEntry * pIAE = NULL;
|
|
IPAddrEntry *pIAEMatch = NULL;
|
|
HANDLE TCPHandle = NULL;
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying for interface context %lx\n", IpInterfaceContext));
|
|
|
|
Error = OpenDriver(&TCPHandle, DD_TCP_DEVICE_NAME);
|
|
if (Error != ERROR_SUCCESS) {
|
|
return( Error );
|
|
}
|
|
|
|
//
|
|
// The first thing to do is get the list of available entities, and make
|
|
// sure that there are some interface entities present.
|
|
//
|
|
|
|
ID.toi_entity.tei_entity = GENERIC_ENTITY;
|
|
ID.toi_entity.tei_instance = 0;
|
|
ID.toi_class = INFO_CLASS_GENERIC;
|
|
ID.toi_type = INFO_TYPE_PROVIDER;
|
|
ID.toi_id = ENTITY_LIST_ID;
|
|
|
|
Size = sizeof(TDIEntityID) * MAX_TDI_ENTITIES;
|
|
EList = (TDIEntityID*)DhcpAllocateMemory(Size);
|
|
if (EList == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Cleanup;
|
|
}
|
|
RtlZeroMemory(EList, Size);
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
Status = TCPQueryInformationEx(TCPHandle, &ID, EList, &Size, Context);
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
NumReturned = Size/sizeof(TDIEntityID);
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: No of total entities %lx\n", NumReturned));
|
|
|
|
for (i = 0; i < NumReturned; i++) {
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, type %lx, instance %lx\n",
|
|
i, EList[i].tei_entity, EList[i].tei_instance));
|
|
|
|
if ( EList[i].tei_entity == CL_NL_ENTITY ) {
|
|
|
|
IPSNMPInfo IPStats;
|
|
DWORD NLType;
|
|
|
|
//
|
|
// Does this entity support IP?
|
|
//
|
|
|
|
ID.toi_entity.tei_entity = EList[i].tei_entity;
|
|
ID.toi_entity.tei_instance = EList[i].tei_instance;
|
|
ID.toi_class = INFO_CLASS_GENERIC;
|
|
ID.toi_type = INFO_TYPE_PROVIDER;
|
|
ID.toi_id = ENTITY_TYPE_ID;
|
|
|
|
Size = sizeof( NLType );
|
|
NLType = 0;
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying CL_NL_ENTITY %lx\n",i));
|
|
Status = TCPQueryInformationEx(TCPHandle, &ID, &NLType, &Size, Context);
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( NLType != CL_NL_IP ) {
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx does not support IP\n",i));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// We've got an IP driver so get it's address table
|
|
//
|
|
|
|
ID.toi_class = INFO_CLASS_PROTOCOL;
|
|
ID.toi_id = IP_MIB_STATS_ID;
|
|
Size = sizeof(IPStats);
|
|
RtlZeroMemory( &IPStats, Size);
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
Status = TCPQueryInformationEx(
|
|
TCPHandle,
|
|
&ID,
|
|
&IPStats,
|
|
&Size,
|
|
Context);
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, numaddr %lx\n",i, IPStats.ipsi_numaddr));
|
|
|
|
if ( IPStats.ipsi_numaddr == 0 ) {
|
|
continue;
|
|
}
|
|
|
|
Size = sizeof(IPAddrEntry) * IPStats.ipsi_numaddr;
|
|
|
|
while (1) {
|
|
DWORD OldSize;
|
|
pIAE = DhcpAllocateMemory(Size);
|
|
|
|
if ( pIAE == NULL ) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
OldSize = Size;
|
|
Status = TCPQueryInformationEx(TCPHandle, &ID, pIAE, &Size, Context);
|
|
|
|
if (Status == TDI_BUFFER_OVERFLOW) {
|
|
Size = OldSize * 2;
|
|
DhcpFreeMemory(pIAE);
|
|
pIAE = NULL;
|
|
continue;
|
|
}
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (Status == TDI_SUCCESS) {
|
|
IPStats.ipsi_numaddr = Size/sizeof(IPAddrEntry);
|
|
DhcpAssert((Size % sizeof(IPAddrEntry)) == 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We have the IP address table for this IP driver.
|
|
// Find the hardware address corresponds to the given
|
|
// IpInterfaceContext.
|
|
//
|
|
// Loop through the IP table entries and findout the
|
|
// matching entry.
|
|
//
|
|
|
|
pIAEMatch = NULL;
|
|
for( j = 0; j < IPStats.ipsi_numaddr ; j++) {
|
|
DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has iae_index %lx iae_context %lx\n",
|
|
&pIAE[j], pIAE[j].iae_index, pIAE[j].iae_context ));
|
|
|
|
if( pIAE[j].iae_context == IpInterfaceContext ) {
|
|
|
|
DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has our interface context %lx\n",
|
|
&pIAE[j], IpInterfaceContext ));
|
|
pIAEMatch = &pIAE[j];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( pIAEMatch == NULL ) {
|
|
|
|
//
|
|
// freeup the loop memory.
|
|
//
|
|
|
|
DhcpFreeMemory( pIAE );
|
|
pIAE = NULL;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// NOTE : There may be more than one IpTable in the TDI
|
|
// list. We need additional information to select the
|
|
// IpTable we want. For now, we assume only one table
|
|
// is supported, so pick the first and only table from the
|
|
// list.
|
|
|
|
//
|
|
// If the old ip address is requested, return it.
|
|
//
|
|
if( pOldIpAddress ) *pOldIpAddress = pIAE->iae_addr;
|
|
if( pOldMask ) *pOldMask = pIAE->iae_mask;
|
|
|
|
Status = FindHardwareAddr(
|
|
TCPHandle,
|
|
EList,
|
|
NumReturned,
|
|
pIAEMatch,
|
|
HardwareAddressType,
|
|
HardwareAddress,
|
|
HardwareAddressLength,
|
|
pIpInterfaceInstance,
|
|
pfInterfaceDown,
|
|
&fFound
|
|
);
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( fFound ) {
|
|
Status = TDI_SUCCESS;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// freeup the loop memory.
|
|
//
|
|
|
|
DhcpFreeMemory( pIAE );
|
|
pIAE = NULL;
|
|
|
|
} // if IP
|
|
|
|
} // entity traversal
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
|
|
Cleanup:
|
|
|
|
if( pIAE != NULL ) {
|
|
DhcpFreeMemory( pIAE );
|
|
}
|
|
|
|
if( TCPHandle != NULL ) {
|
|
NtClose( TCPHandle );
|
|
}
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
DhcpPrint(( DEBUG_ERRORS, "QueryHWInfo failed, %lx.\n", Status ));
|
|
}
|
|
|
|
if (NULL != EList) {
|
|
DhcpFreeMemory(EList);
|
|
}
|
|
|
|
return( RtlNtStatusToDosError( Status ) );
|
|
}
|
|
|
|
DWORD
|
|
DhcpQueryHWInfo(
|
|
DWORD IpInterfaceContext,
|
|
DWORD *pIpInterfaceInstance,
|
|
LPBYTE HardwareAddressType,
|
|
LPBYTE *HardwareAddress,
|
|
LPDWORD HardwareAddressLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
See DhcpQueryHWInfo
|
|
|
|
--*/
|
|
{
|
|
return DhcpQueryHWInfoEx(
|
|
IpInterfaceContext,
|
|
pIpInterfaceInstance,
|
|
NULL, NULL, NULL,
|
|
HardwareAddressType,
|
|
HardwareAddress,
|
|
HardwareAddressLength
|
|
);
|
|
}
|
|
|
|
#else BOOTPERF
|
|
|
|
DWORD
|
|
DhcpQueryHWInfo(
|
|
DWORD IpInterfaceContext,
|
|
DWORD *pIpInterfaceInstance,
|
|
LPBYTE HardwareAddressType,
|
|
LPBYTE *HardwareAddress,
|
|
LPDWORD HardwareAddressLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function queries and browses through the TDI list to find out
|
|
the specified IpTable entry and then determines the HW address that
|
|
corresponds to this entry.
|
|
|
|
Arguments:
|
|
|
|
IpInterfaceContext - Context value of the Ip Table Entry.
|
|
|
|
pIpInterfaceInstance - pointer to the interface instance ID that corresponds
|
|
to matching IpTable entry
|
|
|
|
HardwareAddressType - hardware address type.
|
|
|
|
HardwareAddress - pointer to location where the HW address buffer
|
|
pointer is returned.
|
|
|
|
HardwareAddressLength - length of the HW address returned.
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
NTSTATUS Status;
|
|
DWORD i, j;
|
|
|
|
BYTE Context[CONTEXT_SIZE];
|
|
TDIEntityID *EList = NULL;
|
|
TDIObjectID ID;
|
|
DWORD Size;
|
|
DWORD NumReturned;
|
|
BOOL fFound;
|
|
|
|
IPAddrEntry * pIAE = NULL;
|
|
IPAddrEntry *pIAEMatch = NULL;
|
|
HANDLE TCPHandle = NULL;
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying for interface context %lx\n", IpInterfaceContext));
|
|
|
|
Error = OpenDriver(&TCPHandle, DD_TCP_DEVICE_NAME);
|
|
if (Error != ERROR_SUCCESS) {
|
|
return( Error );
|
|
}
|
|
|
|
//
|
|
// The first thing to do is get the list of available entities, and make
|
|
// sure that there are some interface entities present.
|
|
//
|
|
|
|
ID.toi_entity.tei_entity = GENERIC_ENTITY;
|
|
ID.toi_entity.tei_instance = 0;
|
|
ID.toi_class = INFO_CLASS_GENERIC;
|
|
ID.toi_type = INFO_TYPE_PROVIDER;
|
|
ID.toi_id = ENTITY_LIST_ID;
|
|
|
|
Size = sizeof(TDIEntityID) * MAX_TDI_ENTITIES;
|
|
EList = (TDIEntityID*)DhcpAllocateMemory(Size);
|
|
if (EList == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Cleanup;
|
|
}
|
|
RtlZeroMemory(EList, Size);
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
Status = TCPQueryInformationEx(TCPHandle, &ID, EList, &Size, Context);
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
NumReturned = Size/sizeof(TDIEntityID);
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: No of total entities %lx\n", NumReturned));
|
|
|
|
for (i = 0; i < NumReturned; i++) {
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, type %lx, instance %lx\n",
|
|
i, EList[i].tei_entity, EList[i].tei_instance));
|
|
|
|
if ( EList[i].tei_entity == CL_NL_ENTITY ) {
|
|
|
|
IPSNMPInfo IPStats;
|
|
DWORD NLType;
|
|
|
|
//
|
|
// Does this entity support IP?
|
|
//
|
|
|
|
ID.toi_entity.tei_entity = EList[i].tei_entity;
|
|
ID.toi_entity.tei_instance = EList[i].tei_instance;
|
|
ID.toi_class = INFO_CLASS_GENERIC;
|
|
ID.toi_type = INFO_TYPE_PROVIDER;
|
|
ID.toi_id = ENTITY_TYPE_ID;
|
|
|
|
Size = sizeof( NLType );
|
|
NLType = 0;
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying CL_NL_ENTITY %lx\n",i));
|
|
Status = TCPQueryInformationEx(TCPHandle, &ID, &NLType, &Size, Context);
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( NLType != CL_NL_IP ) {
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx does not support IP\n",i));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// We've got an IP driver so get it's address table
|
|
//
|
|
|
|
ID.toi_class = INFO_CLASS_PROTOCOL;
|
|
ID.toi_id = IP_MIB_STATS_ID;
|
|
Size = sizeof(IPStats);
|
|
RtlZeroMemory( &IPStats, Size);
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
Status = TCPQueryInformationEx(
|
|
TCPHandle,
|
|
&ID,
|
|
&IPStats,
|
|
&Size,
|
|
Context);
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, numaddr %lx\n",i, IPStats.ipsi_numaddr));
|
|
|
|
if ( IPStats.ipsi_numaddr == 0 ) {
|
|
continue;
|
|
}
|
|
|
|
Size = sizeof(IPAddrEntry) * IPStats.ipsi_numaddr;
|
|
|
|
while (1) {
|
|
DWORD OldSize;
|
|
pIAE = DhcpAllocateMemory(Size);
|
|
|
|
if ( pIAE == NULL ) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
OldSize = Size;
|
|
Status = TCPQueryInformationEx(TCPHandle, &ID, pIAE, &Size, Context);
|
|
|
|
if (Status == TDI_BUFFER_OVERFLOW) {
|
|
Size = OldSize * 2;
|
|
DhcpFreeMemory(pIAE);
|
|
pIAE = NULL;
|
|
continue;
|
|
}
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (Status == TDI_SUCCESS) {
|
|
IPStats.ipsi_numaddr = Size/sizeof(IPAddrEntry);
|
|
DhcpAssert((Size % sizeof(IPAddrEntry)) == 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We have the IP address table for this IP driver.
|
|
// Find the hardware address corresponds to the given
|
|
// IpInterfaceContext.
|
|
//
|
|
// Loop through the IP table entries and findout the
|
|
// matching entry.
|
|
//
|
|
|
|
pIAEMatch = NULL;
|
|
for( j = 0; j < IPStats.ipsi_numaddr ; j++) {
|
|
DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has iae_index %lx iae_context %lx\n",
|
|
&pIAE[j], pIAE[j].iae_index, pIAE[j].iae_context ));
|
|
|
|
if( pIAE[j].iae_context == IpInterfaceContext ) {
|
|
|
|
DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has our interface context %lx\n",
|
|
&pIAE[j], IpInterfaceContext ));
|
|
|
|
pIAEMatch = &pIAE[j];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( pIAEMatch == NULL ) {
|
|
|
|
//
|
|
// freeup the loop memory.
|
|
//
|
|
|
|
DhcpFreeMemory( pIAE );
|
|
pIAE = NULL;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// NOTE : There may be more than one IpTable in the TDI
|
|
// list. We need additional information to select the
|
|
// IpTable we want. For now, we assume only one table
|
|
// is supported, so pick the first and only table from the
|
|
// list.
|
|
|
|
Status = FindHardwareAddr(
|
|
TCPHandle,
|
|
EList,
|
|
NumReturned,
|
|
pIAEMatch,
|
|
HardwareAddressType,
|
|
HardwareAddress,
|
|
HardwareAddressLength,
|
|
pIpInterfaceInstance,
|
|
&fFound );
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( fFound ) {
|
|
Status = TDI_SUCCESS;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// freeup the loop memory.
|
|
//
|
|
|
|
DhcpFreeMemory( pIAE );
|
|
pIAE = NULL;
|
|
|
|
} // if IP
|
|
|
|
} // entity traversal
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
|
|
Cleanup:
|
|
|
|
if( pIAE != NULL ) {
|
|
DhcpFreeMemory( pIAE );
|
|
}
|
|
|
|
if( TCPHandle != NULL ) {
|
|
NtClose( TCPHandle );
|
|
}
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
DhcpPrint(( DEBUG_ERRORS, "QueryHWInfo failed, %lx.\n", Status ));
|
|
}
|
|
|
|
if (NULL != EList) {
|
|
DhcpFreeMemory(EList);
|
|
}
|
|
|
|
return( RtlNtStatusToDosError( Status ) );
|
|
}
|
|
|
|
#endif BOOTPERF
|
|
|
|
#if DBG
|
|
#define print(X) DhcpPrint((DEBUG_TRACE, "%20s\t", inet_ntoa(*(struct in_addr *)&X)))
|
|
#define printx(X) DhcpPrint((DEBUG_TRACE, "%05x\t", X))
|
|
|
|
|
|
DWORD
|
|
PrintDefaultGateways( VOID ) {
|
|
DWORD Error;
|
|
NTSTATUS Status;
|
|
|
|
HANDLE TCPHandle = NULL;
|
|
BYTE Context[CONTEXT_SIZE];
|
|
TDIObjectID ID;
|
|
DWORD Size;
|
|
IPSNMPInfo IPStats;
|
|
IPAddrEntry *AddrTable = NULL;
|
|
DWORD NumReturned;
|
|
DWORD Type;
|
|
DWORD i;
|
|
DWORD MatchIndex;
|
|
IPRouteEntry RouteEntry;
|
|
IPRouteEntry *RtTable;
|
|
DHCP_IP_ADDRESS NetworkOrderGatewayAddress;
|
|
|
|
Error = OpenDriver(&TCPHandle, DD_TCP_DEVICE_NAME);
|
|
if (Error != ERROR_SUCCESS) {
|
|
return( Error );
|
|
}
|
|
|
|
//
|
|
// Get the NetAddr info, to find an interface index for the gateway.
|
|
//
|
|
|
|
ID.toi_entity.tei_entity = CL_NL_ENTITY;
|
|
ID.toi_entity.tei_instance = 0;
|
|
ID.toi_class = INFO_CLASS_PROTOCOL;
|
|
ID.toi_type = INFO_TYPE_PROVIDER;
|
|
ID.toi_id = IP_MIB_STATS_ID;
|
|
|
|
Size = sizeof(IPStats);
|
|
RtlZeroMemory(&IPStats, Size);
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
Status = TCPQueryInformationEx(
|
|
TCPHandle,
|
|
&ID,
|
|
&IPStats,
|
|
&Size,
|
|
Context);
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
// hack: RouteTable in IP is about 32 in size... and IP seems tob
|
|
// be writing the whole bunch always!
|
|
if(IPStats.ipsi_numroutes <= 32)
|
|
IPStats.ipsi_numroutes = 32;
|
|
Size = IPStats.ipsi_numroutes * sizeof(IPRouteEntry);
|
|
RtTable = DhcpAllocateMemory(Size);
|
|
|
|
if (RtTable == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
Status = TCPQueryInformationEx(
|
|
TCPHandle,
|
|
&ID,
|
|
RtTable,
|
|
&Size,
|
|
Context);
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
NumReturned = Size/sizeof(IPAddrEntry);
|
|
DhcpPrint((DEBUG_TRACE, "IP returned %ld routes\n", NumReturned));
|
|
// The following is almost always true... IP returns the whole array.. valid or not!
|
|
// DhcpAssert( NumReturned == IPStats.ipsi_numroutes );
|
|
if( NumReturned > IPStats.ipsi_numroutes)
|
|
NumReturned = IPStats.ipsi_numroutes;
|
|
|
|
//
|
|
// We've got the address table. Loop through it. If we find an exact
|
|
// match for the gateway, then we're adding or deleting a direct route
|
|
// and we're done. Otherwise try to find a match on the subnet mask,
|
|
// and remember the first one we find.
|
|
//
|
|
|
|
DhcpPrint((DEBUG_TRACE,"Dest mask nexthop index metric1 type proto\n"));
|
|
for (i = 0, MatchIndex = 0xffff; i < NumReturned; i++) {
|
|
print(RtTable[i].ire_dest);
|
|
print(RtTable[i].ire_mask);
|
|
print(RtTable[i].ire_nexthop);
|
|
|
|
printx(RtTable[i].ire_index);
|
|
printx(RtTable[i].ire_metric1);
|
|
printx(RtTable[i].ire_type);
|
|
printx(RtTable[i].ire_proto);
|
|
DhcpPrint((DEBUG_TRACE, "\n"));
|
|
}
|
|
DhcpPrint((DEBUG_TRACE, "--------------------------------------------------------\n"));
|
|
Status = TDI_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
if( AddrTable != NULL ) {
|
|
DhcpFreeMemory( AddrTable );
|
|
}
|
|
|
|
if( TCPHandle != NULL ) {
|
|
NtClose( TCPHandle );
|
|
}
|
|
|
|
if( (Status != TDI_SUCCESS) &&
|
|
(Status != STATUS_UNSUCCESSFUL) ) { // HACK.
|
|
|
|
DhcpPrint(( DEBUG_ERRORS, "SetDefaultGateway failed, %lx.\n", Status ));
|
|
}
|
|
|
|
return( RtlNtStatusToDosError( Status ) );
|
|
}
|
|
#endif
|
|
|
|
DWORD
|
|
SetDefaultGateway(
|
|
DWORD Command,
|
|
DHCP_IP_ADDRESS GatewayAddress,
|
|
DWORD Metric
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function adds/deletes a default gateway entry from the router table.
|
|
|
|
Arguments:
|
|
|
|
Command : Either DEFAULT_GATEWAY_ADD/DEFAULT_GATEWAY_DELETE.
|
|
|
|
GatewayAddress : Address of the default gateway.
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
NTSTATUS Status;
|
|
|
|
HANDLE TCPHandle = NULL;
|
|
BYTE Context[CONTEXT_SIZE];
|
|
TDIObjectID ID;
|
|
DWORD Size;
|
|
IPSNMPInfo IPStats;
|
|
IPAddrEntry *AddrTable = NULL;
|
|
DWORD NumReturned;
|
|
DWORD Type;
|
|
DWORD i;
|
|
DWORD MatchIndex;
|
|
IPRouteEntry RouteEntry;
|
|
DHCP_IP_ADDRESS NetworkOrderGatewayAddress;
|
|
|
|
NetworkOrderGatewayAddress = htonl( GatewayAddress );
|
|
|
|
Error = OpenDriver(&TCPHandle, DD_TCP_DEVICE_NAME);
|
|
if (Error != ERROR_SUCCESS) {
|
|
return( Error );
|
|
}
|
|
|
|
//
|
|
// Get the NetAddr info, to find an interface index for the gateway.
|
|
//
|
|
|
|
ID.toi_entity.tei_entity = CL_NL_ENTITY;
|
|
ID.toi_entity.tei_instance = 0;
|
|
ID.toi_class = INFO_CLASS_PROTOCOL;
|
|
ID.toi_type = INFO_TYPE_PROVIDER;
|
|
ID.toi_id = IP_MIB_STATS_ID;
|
|
|
|
Size = sizeof(IPStats);
|
|
RtlZeroMemory(&IPStats, Size);
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
Status = TCPQueryInformationEx(
|
|
TCPHandle,
|
|
&ID,
|
|
&IPStats,
|
|
&Size,
|
|
Context
|
|
);
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
Size = IPStats.ipsi_numaddr * sizeof(IPAddrEntry);
|
|
AddrTable = DhcpAllocateMemory(Size);
|
|
|
|
if (AddrTable == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
Status = TCPQueryInformationEx(
|
|
TCPHandle,
|
|
&ID,
|
|
AddrTable,
|
|
&Size,
|
|
Context
|
|
);
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
NumReturned = Size/sizeof(IPAddrEntry);
|
|
DhcpAssert( NumReturned == IPStats.ipsi_numaddr );
|
|
|
|
//
|
|
// We've got the address table. Loop through it. If we find an exact
|
|
// match for the gateway, then we're adding or deleting a direct route
|
|
// and we're done. Otherwise try to find a match on the subnet mask,
|
|
// and remember the first one we find.
|
|
//
|
|
|
|
Type = IRE_TYPE_INDIRECT;
|
|
for (i = 0, MatchIndex = 0xffff; i < NumReturned; i++) {
|
|
|
|
if( AddrTable[i].iae_addr == NetworkOrderGatewayAddress ) {
|
|
|
|
//
|
|
// Found an exact match.
|
|
//
|
|
|
|
MatchIndex = i;
|
|
Type = IRE_TYPE_DIRECT;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// The next hop is on the same subnet as this address. If
|
|
// we haven't already found a match, remember this one.
|
|
//
|
|
|
|
if ( (MatchIndex == 0xffff) &&
|
|
(AddrTable[i].iae_addr != 0) &&
|
|
(AddrTable[i].iae_mask != 0) &&
|
|
((AddrTable[i].iae_addr & AddrTable[i].iae_mask) ==
|
|
(NetworkOrderGatewayAddress & AddrTable[i].iae_mask)) ) {
|
|
|
|
MatchIndex = i;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We've looked at all of the entries. See if we found a match.
|
|
//
|
|
|
|
if (MatchIndex == 0xffff) {
|
|
//
|
|
// Didn't find a match.
|
|
//
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// We've found a match. Fill in the route entry, and call the
|
|
// Set API.
|
|
//
|
|
|
|
RouteEntry.ire_dest = DEFAULT_DEST;
|
|
RouteEntry.ire_index = AddrTable[MatchIndex].iae_index;
|
|
RouteEntry.ire_metric1 = Metric;
|
|
RouteEntry.ire_metric2 = (DWORD)(-1);
|
|
RouteEntry.ire_metric3 = (DWORD)(-1);
|
|
RouteEntry.ire_metric4 = (DWORD)(-1);
|
|
RouteEntry.ire_nexthop = NetworkOrderGatewayAddress;
|
|
RouteEntry.ire_type =
|
|
(Command == DEFAULT_GATEWAY_DELETE ? IRE_TYPE_INVALID : Type);
|
|
RouteEntry.ire_proto = IRE_PROTO_NETMGMT;
|
|
RouteEntry.ire_age = 0;
|
|
RouteEntry.ire_mask = DEFAULT_DEST_MASK;
|
|
RouteEntry.ire_metric5 = (DWORD)(-1);
|
|
RouteEntry.ire_context = 0;
|
|
|
|
Size = sizeof(RouteEntry);
|
|
|
|
ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
|
|
|
|
Status = TCPSetInformationEx(
|
|
TCPHandle,
|
|
&ID,
|
|
&RouteEntry,
|
|
Size );
|
|
|
|
if ( Status != TDI_SUCCESS &&
|
|
Status != TDI_BUFFER_OVERFLOW ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
Status = TDI_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
if( AddrTable != NULL ) {
|
|
DhcpFreeMemory( AddrTable );
|
|
}
|
|
|
|
if( TCPHandle != NULL ) {
|
|
NtClose( TCPHandle );
|
|
}
|
|
|
|
if( (Status != TDI_SUCCESS) &&
|
|
(Status != STATUS_UNSUCCESSFUL) ) { // HACK.
|
|
|
|
DhcpPrint(( DEBUG_ERRORS, "SetDefaultGateway failed, %lx.\n", Status ));
|
|
}
|
|
|
|
return( RtlNtStatusToDosError( Status ) );
|
|
}
|
|
|
|
DWORD
|
|
GetIpInterfaceContext(
|
|
LPWSTR AdapterName,
|
|
DWORD IpIndex,
|
|
LPDWORD IpInterfaceContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the IpInterfaceContext for the specified
|
|
IpAddress and devicename.
|
|
|
|
Arguments:
|
|
|
|
AdapterName - name of the device.
|
|
|
|
IpIndex - index of the IpAddress for this device.
|
|
|
|
IpInterfaceContext - pointer to a location where the
|
|
interface context is returned.
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
LPWSTR RegKey = NULL;
|
|
HKEY KeyHandle = NULL;
|
|
LPWSTR nteContextList = NULL;
|
|
PCHAR oemNextContext = NULL;
|
|
LPWSTR nextContext;
|
|
DWORD i;
|
|
|
|
|
|
*IpInterfaceContext = INVALID_INTERFACE_CONTEXT;
|
|
|
|
//
|
|
// Open device parameter.
|
|
//
|
|
|
|
RegKey = DhcpAllocateMemory(
|
|
(wcslen(DHCP_SERVICES_KEY) +
|
|
wcslen(REGISTRY_CONNECT_STRING) +
|
|
wcslen(AdapterName) +
|
|
wcslen(DHCP_ADAPTER_PARAMETERS_KEY) + 1) *
|
|
sizeof(WCHAR) ); // termination char.
|
|
|
|
if( RegKey == NULL ) {
|
|
Error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
wcscpy( RegKey, DHCP_SERVICES_KEY );
|
|
wcscat( RegKey, DHCP_ADAPTER_PARAMETERS_KEY );
|
|
wcscat( RegKey, REGISTRY_CONNECT_STRING );
|
|
wcscat( RegKey, AdapterName );
|
|
|
|
|
|
//
|
|
// open this key.
|
|
//
|
|
|
|
Error = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
RegKey,
|
|
0, // Reserved field
|
|
DHCP_CLIENT_KEY_ACCESS,
|
|
&KeyHandle
|
|
);
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
Error = GetRegistryString(
|
|
KeyHandle,
|
|
DHCP_NTE_CONTEXT_LIST,
|
|
&nteContextList,
|
|
NULL
|
|
);
|
|
|
|
if( nteContextList == NULL ) {
|
|
Error = ERROR_BAD_FORMAT;
|
|
|
|
DhcpPrint((DEBUG_ERRORS, "NteContextList empty\n"));
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( ERROR_SUCCESS != Error )
|
|
{
|
|
DhcpPrint( (DEBUG_ERRORS,
|
|
"GetIpInterfaceContext: Could not read nteContextList %lx\n",
|
|
Error));
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
for( nextContext = nteContextList, i = 0;
|
|
*nextContext != L'\0' && i < IpIndex;
|
|
i++, nextContext += (wcslen(nextContext) + 1) );
|
|
|
|
if ( *nextContext != L'\0' && i == IpIndex ) {
|
|
ULONG ival;
|
|
oemNextContext = DhcpUnicodeToOem(nextContext, NULL);
|
|
if ( NULL == oemNextContext ) {
|
|
Error = ERROR_BAD_FORMAT;
|
|
} else {
|
|
ival = strtoul(oemNextContext, NULL, 0);
|
|
if ( ival == ULONG_MAX || ival == 0) {
|
|
Error = ERROR_BAD_FORMAT;
|
|
} else {
|
|
*IpInterfaceContext = ival;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
if( RegKey != NULL ) {
|
|
DhcpFreeMemory( RegKey );
|
|
}
|
|
|
|
if( KeyHandle != NULL ) {
|
|
RegCloseKey( KeyHandle );
|
|
}
|
|
|
|
if ( nteContextList != NULL ) {
|
|
DhcpFreeMemory( nteContextList );
|
|
}
|
|
|
|
if ( oemNextContext != NULL ) {
|
|
DhcpFreeMemory( oemNextContext );
|
|
}
|
|
|
|
|
|
return( Error );
|
|
}
|
|
|
|
HANDLE
|
|
APIENTRY
|
|
DhcpOpenGlobalEvent(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This functions creates global event that signals the the ipaddress
|
|
changes to other waiting processes. The security dacl is set to NULL
|
|
that makes anyone to open and read/set this event.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Handle value of the global event. If the handle is NULL,
|
|
GetLastError() function will return Windows error code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error = NO_ERROR, Status, Length;
|
|
BOOL BoolError;
|
|
HANDLE EventHandle = NULL;
|
|
SECURITY_ATTRIBUTES SecurityAttributes;
|
|
SID_IDENTIFIER_AUTHORITY Authority = SECURITY_WORLD_SID_AUTHORITY;
|
|
PACL Acl = NULL;
|
|
PSID WorldSID = NULL;
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
|
|
|
|
//
|
|
// If event can be opened, chose that, don't attempt create
|
|
//
|
|
|
|
EventHandle = OpenEvent(
|
|
EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE,
|
|
DHCP_NEW_IPADDRESS_EVENT_NAME
|
|
);
|
|
if( NULL != EventHandle ) return EventHandle;
|
|
|
|
//
|
|
// Set DACL also.. first create basic SIDs
|
|
//
|
|
|
|
BoolError = AllocateAndInitializeSid(
|
|
&Authority, 1, SECURITY_WORLD_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&WorldSID
|
|
);
|
|
if( BoolError == FALSE ) {
|
|
return NULL;
|
|
}
|
|
|
|
Length = ( (ULONG)sizeof(ACL) + (ULONG)sizeof(ACCESS_ALLOWED_ACE)
|
|
+ GetLengthSid( WorldSID ) + 16 );
|
|
|
|
Acl = DhcpAllocateMemory( Length );
|
|
if( NULL == Acl ) {
|
|
Error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
BoolError = InitializeAcl( Acl, Length, ACL_REVISION2 );
|
|
if( FALSE == BoolError ) {
|
|
Error = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
BoolError = AddAccessAllowedAce(
|
|
Acl, ACL_REVISION2,
|
|
EVENT_MODIFY_STATE | SYNCHRONIZE,
|
|
WorldSID
|
|
);
|
|
|
|
if( FALSE == BoolError ) {
|
|
Error = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
SecurityDescriptor = DhcpAllocateMemory(
|
|
SECURITY_DESCRIPTOR_MIN_LENGTH
|
|
);
|
|
if( NULL == SecurityDescriptor ) {
|
|
Error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
BoolError = InitializeSecurityDescriptor(
|
|
SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION
|
|
);
|
|
|
|
if( BoolError == FALSE ) {
|
|
Error = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
BoolError = SetSecurityDescriptorDacl(
|
|
SecurityDescriptor, TRUE, Acl, FALSE
|
|
);
|
|
|
|
if( BoolError == FALSE ) {
|
|
Error = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
SecurityAttributes.nLength = sizeof( SecurityAttributes );
|
|
SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
|
|
SecurityAttributes.bInheritHandle = FALSE;
|
|
|
|
EventHandle = CreateEvent(
|
|
&SecurityAttributes,
|
|
// everyone all access security.
|
|
TRUE, // MANUAL reset.
|
|
FALSE, // initial state is signaled.
|
|
DHCP_NEW_IPADDRESS_EVENT_NAME
|
|
);
|
|
|
|
if( NULL == EventHandle ) {
|
|
Error = GetLastError();
|
|
} else {
|
|
Error = NO_ERROR;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if( SecurityDescriptor ) {
|
|
DhcpFreeMemory( SecurityDescriptor );
|
|
}
|
|
|
|
if( Acl ) {
|
|
DhcpFreeMemory( Acl );
|
|
}
|
|
|
|
if( WorldSID ) {
|
|
FreeSid( WorldSID );
|
|
}
|
|
|
|
if( NO_ERROR != Error ) {
|
|
SetLastError( Error );
|
|
}
|
|
|
|
return( EventHandle );
|
|
}
|
|
|
|
BOOL
|
|
NdisWanAdapter( // Is this an NdisWan adapter?
|
|
IN PDHCP_CONTEXT DhcpContext
|
|
)
|
|
{
|
|
return DhcpContext->HardwareAddressType == HARDWARE_PPP;
|
|
}
|
|
|
|
DWORD INLINE // win32 status
|
|
DhcpEnableDynamicConfigEx( // convert from static to dhcp and start DHCP client if reqd
|
|
IN LPWSTR AdapterName
|
|
)
|
|
{
|
|
DWORD Error;
|
|
|
|
// ask the dhcp client to takeup this adapter also
|
|
Error = DhcpEnableDynamicConfig(AdapterName);
|
|
|
|
// now there are a couple possibilities:
|
|
// - the above call succeeded
|
|
// - DHCP service is not started or just got terminated
|
|
// - DHCP service failed to process the request with some error
|
|
// in the first case just go on straight to exit and return success
|
|
// in the second case we attempt to start the DHCP service if it is not already started
|
|
// in the last case we just bail out with the specific error
|
|
if( Error == ERROR_FILE_NOT_FOUND || Error == ERROR_BROKEN_PIPE )
|
|
{
|
|
SC_HANDLE SCHandle;
|
|
SC_HANDLE ServiceHandle;
|
|
SERVICE_STATUS svcStatus;
|
|
|
|
// attempt now to start the DHCP service.
|
|
// first thing to do is to open SCM
|
|
SCHandle = OpenSCManager(
|
|
NULL,
|
|
NULL,
|
|
SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS
|
|
);
|
|
if( SCHandle == NULL )
|
|
return GetLastError(); // shouldn't happen normally
|
|
|
|
// attempt to open the DHCP service
|
|
ServiceHandle = OpenService(
|
|
SCHandle,
|
|
SERVICE_DHCP,
|
|
SERVICE_QUERY_STATUS | SERVICE_START
|
|
);
|
|
if (ServiceHandle != NULL)
|
|
{
|
|
|
|
// check the status of the service
|
|
if (!QueryServiceStatus(ServiceHandle, &svcStatus) ||
|
|
svcStatus.dwCurrentState != SERVICE_RUNNING)
|
|
{
|
|
// is it worthy to attempt to start the service if QueryServiceStatus failed?
|
|
Error = StartService(ServiceHandle, 0, NULL) ? ERROR_SUCCESS : GetLastError();
|
|
}
|
|
|
|
CloseServiceHandle(ServiceHandle);
|
|
}
|
|
else
|
|
Error = GetLastError();
|
|
|
|
CloseServiceHandle(SCHandle);
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
DWORD // win32 status
|
|
DhcpNotifyConfigChangeNotifications( // notify whoever needed of param changes
|
|
VOID
|
|
)
|
|
{
|
|
HANDLE NotifyEvent;
|
|
DWORD Error;
|
|
BOOL BoolError;
|
|
|
|
NotifyEvent = DhcpOpenGlobalEvent();
|
|
if( NULL == NotifyEvent ) {
|
|
Error = GetLastError();
|
|
DhcpPrint((DEBUG_ERRORS, "DhcpOpenGlobalEvent:0x%lx\n", Error));
|
|
return Error;
|
|
}
|
|
BoolError = PulseEvent(NotifyEvent);
|
|
if( BoolError ) Error = ERROR_SUCCESS;
|
|
else Error = GetLastError();
|
|
CloseHandle(NotifyEvent);
|
|
|
|
if( ERROR_SUCCESS != Error ) {
|
|
DhcpPrint((DEBUG_ERRORS, "PulseEvent(NotifyEvent): 0x%lx\n", Error));
|
|
}
|
|
return Error;
|
|
}
|
|
|
|
DWORD // win32 status
|
|
APIENTRY
|
|
DhcpNotifyConfigChangeEx( // handle address changes, param changes etc.
|
|
IN LPWSTR ServerName, // name of server where this will be executed
|
|
IN LPWSTR AdapterName, // which adapter is going to be reconfigured?
|
|
IN BOOL IsNewIpAddress,// is address new/ or address is same?
|
|
IN DWORD IpIndex, // index of addr for this adapter -- 0 ==> first interface...
|
|
IN DWORD IpAddress, // the ip address that is being set
|
|
IN DWORD SubnetMask, // corresponding subnet mask
|
|
IN SERVICE_ENABLE DhcpServiceEnabled,
|
|
IN ULONG Flags
|
|
)
|
|
{
|
|
DWORD Error;
|
|
DWORD IpInterfaceContext;
|
|
DWORD DefaultSubnetMask;
|
|
|
|
DhcpPrint(( DEBUG_MISC, "DhcpNotifyConfigChange: Adapter %ws, IsNewIp %s, IpAddr %lx, IpIndex %x, ServiceFlag %d\n",
|
|
AdapterName, IsNewIpAddress ? "TRUE" : "FALSE", IpAddress, IpIndex, DhcpServiceEnabled ));
|
|
|
|
// param checks
|
|
if( NULL == AdapterName ) return ERROR_INVALID_PARAMETER;
|
|
|
|
if( DhcpEnable == DhcpServiceEnabled ) { // converting from static to dhcp enabled address
|
|
if( FALSE != IsNewIpAddress ) return ERROR_INVALID_PARAMETER;
|
|
if( 0 != IpIndex ) return ERROR_INVALID_PARAMETER;
|
|
if( IpAddress || SubnetMask ) return ERROR_INVALID_PARAMETER;
|
|
} else if( DhcpDisable == DhcpServiceEnabled){// converting from dhcp to static address
|
|
if( TRUE != IsNewIpAddress ) return ERROR_INVALID_PARAMETER;
|
|
if( 0 != IpIndex ) return ERROR_INVALID_PARAMETER;
|
|
if( 0 == IpAddress || 0 == SubnetMask ) return ERROR_INVALID_PARAMETER;
|
|
} else {
|
|
if( IgnoreFlag != DhcpServiceEnabled ) return ERROR_INVALID_PARAMETER;
|
|
// if( TRUE != IsNewIpAddress ) return ERROR_INVALID_PARAMETER;
|
|
if( 0xFFFF == IpIndex ) {
|
|
if( 0 == SubnetMask || 0 == IpAddress ) return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
if( IgnoreFlag == DhcpServiceEnabled && FALSE == IsNewIpAddress ) {
|
|
ULONG LocalError;
|
|
|
|
// just some parameters changed -- currently, this could only be DNS domain name or server list change
|
|
// or may be static gateway list change or static route change
|
|
Error = DhcpStaticRefreshParams(AdapterName);
|
|
if( ERROR_SUCCESS != Error ) {
|
|
DhcpPrint((DEBUG_ERRORS, "DhcpNotifyConfigChange:DhcpStaticRefreshParams:0x%lx\n", Error));
|
|
}
|
|
|
|
LocalError = NetBTNotifyRegChanges(AdapterName);
|
|
if( ERROR_SUCCESS != LocalError ) {
|
|
DhcpPrint((
|
|
DEBUG_ERRORS, "NetbtNotify(%ws): 0x%lx\n",
|
|
AdapterName, LocalError
|
|
));
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
if( DhcpEnable == DhcpServiceEnabled ) { // convert from static to dhcp
|
|
|
|
Error = IPDelNonPrimaryAddresses( // remove all but the first static address
|
|
AdapterName
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return Error;
|
|
|
|
Error = DhcpEnableDynamicConfigEx( // convert this to dhcp, maybe starting dhcp in the process
|
|
AdapterName
|
|
);
|
|
|
|
return Error; // notifications already done by service when we dhcp enable it..
|
|
} else if( DhcpDisable == DhcpServiceEnabled ) {
|
|
|
|
Error = DhcpDisableDynamicConfig( AdapterName );
|
|
if( Error != ERROR_SUCCESS ) return Error;
|
|
}
|
|
|
|
// NetBt device name stuff removed, see any version pre- Oct 10, 1997
|
|
DhcpAssert(TRUE == IsNewIpAddress); // ip address changed in some way
|
|
DhcpAssert(DhcpEnable != DhcpServiceEnabled); // static->dhcp already handled before
|
|
|
|
DefaultSubnetMask = DhcpDefaultSubnetMask(0);
|
|
|
|
if( INVALID_INTERFACE_CONTEXT == IpIndex ) { // adding a new ip address
|
|
DhcpAssert( IpAddress && SubnetMask); // cannot be zero, these
|
|
|
|
Error = IPAddIPAddress( // add the reqd ip address
|
|
AdapterName,
|
|
IpAddress,
|
|
SubnetMask
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return Error;
|
|
|
|
} else { // either delete or modify -- first find ipinterfacecontext
|
|
Error = GetIpInterfaceContext( // get the interface context value for this
|
|
AdapterName,
|
|
IpIndex,
|
|
&IpInterfaceContext
|
|
);
|
|
|
|
if( ERROR_SUCCESS != Error ) {
|
|
DhcpPrint((DEBUG_ERRORS, "GetIpInterfaceContext: 0x%lx\n", Error));
|
|
return Error;
|
|
}
|
|
|
|
if( IpInterfaceContext == INVALID_INTERFACE_CONTEXT) {
|
|
DhcpPrint((DEBUG_ERRORS, "GetIpInterfaceContext: returned ifctxt=INVALID_INTERFACE_CONTEXT\n"));
|
|
return ERROR_INVALID_DRIVE;
|
|
}
|
|
|
|
if ( IpAddress != 0 ) { // if address is non-zero, we are changing address
|
|
|
|
if (Flags & NOTIFY_FLG_RESET_IPADDR)
|
|
{
|
|
Error = IPResetIPAddress( // first reset the interface to zero address
|
|
IpInterfaceContext,
|
|
DefaultSubnetMask
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return Error;
|
|
}
|
|
|
|
Error = IPSetIPAddress( // then set the required address
|
|
IpInterfaceContext,
|
|
IpAddress,
|
|
SubnetMask
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return Error;
|
|
Error = SetOverRideDefaultGateway( AdapterName );
|
|
} else { // we are deleting addresses
|
|
// we need to treat the 0th index separately from others.
|
|
// IPDelIPAddress actually destroys the NTE from IP. But
|
|
// we never blow away 0th index NTE. Just reset the ipaddr on it.
|
|
if ( IpIndex == 0 ) {
|
|
Error = IPResetIPAddress( // just set this address to zero, dont blow interface away
|
|
IpInterfaceContext,DefaultSubnetMask
|
|
);
|
|
} else { // in this case, blow this interface altogether
|
|
Error = IPDelIPAddress( IpInterfaceContext );
|
|
}
|
|
if( ERROR_SUCCESS != Error ) return Error;
|
|
}
|
|
|
|
}
|
|
|
|
Error = DhcpNotifyConfigChangeNotifications();// notify clients, pulse the global event
|
|
if( ERROR_SUCCESS != Error ) return Error;
|
|
|
|
// refresh the parameters for static addresses
|
|
Error = DhcpStaticRefreshParamsInternal(
|
|
AdapterName, (Flags & NOTIFY_FLG_DO_DNS) ? TRUE : FALSE
|
|
);
|
|
if( ERROR_SUCCESS != Error ) { // ignore this error anyways
|
|
DhcpPrint((DEBUG_ERRORS, "DhcpStaticRefreshParams(%ws):0x%lx\n", AdapterName,Error));
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//================================================================================
|
|
// This function (API) notifies the TCP/IP configuration changes to
|
|
// appropriate services. These changes will be in effect as soon as
|
|
// possible.
|
|
//
|
|
// If the IP Address is modified, the services are reset to ZERO IP
|
|
// address (to cleanup the current IP address) and then set to new
|
|
// address.
|
|
//
|
|
// IpIndex - if the specified device is configured with multiple IP
|
|
// addresses, specify index of address that is modified (0 - first
|
|
// IpAddress, 1 - second IpAddres, so on) Pass 0xFFFF if adding an
|
|
// additional address. The order of IP address is determined by the
|
|
// order in the registry MULTI_SZ value "IPAddress" for the static
|
|
// addresses. For dhcp enabled ip address, only ipindex 0 is valid.
|
|
//
|
|
// Everytime when an address is added, removed or modified, the
|
|
// order in the registry may change. It is caller's responsibility
|
|
// to check the current order, and hence the index, before calling
|
|
// this api.
|
|
//
|
|
// DhcpServiceEnabled -
|
|
// IgnoreFlag - indicates Ignore this flag. IgnoreFlag
|
|
// DhcpEnable - indicates DHCP is enabled for this adapter.
|
|
// DhcpDisable - indicates DHCP is diabled for this adapter.
|
|
//
|
|
//Invarient:
|
|
//
|
|
// (1) DHCP enabled IPAddr and Static addr can exists only mutually exclusively.
|
|
// (2) An interface cannot have more than 1 dhcp enabled ip address. However it
|
|
// can have many static addresses.
|
|
//
|
|
//Usage:
|
|
//
|
|
// Case 1: Changing from dhcp enabled ipaddress to static address(es)
|
|
// - Firstly, change the first dhcp enabled ipaddress to static address.
|
|
// arguments {SN, AN, TRUE, 0, I1, S1, DhcpDisable}
|
|
// - Seconfly, add the remaining static address(es)
|
|
// arguments (SN, AN, TRUE, 0xFFFF, I2, S2, DhcpIgnore)
|
|
// arguments (SN, AN, TRUE, 0xFFFF, I3, S3, IgnoreFlag) and so on.
|
|
//
|
|
// Case 2: Changing from static address(es) to dhcp enabled ipaddress
|
|
// - Change the first static address to dhcp enabled. The api will delete
|
|
// the remaining static address(es).
|
|
// arguments (SN, AN, FALSE, 0, 0, 0, DhcpEnable)
|
|
//
|
|
// Case 3: Adding, removing or changing static addresses.
|
|
// - Adding:
|
|
// arguments (SN, AN, TRUE, 0xFFFF, I, S, DhcpIgnore)
|
|
// - Removing, say address # 2 i.e ipindex = 1
|
|
// arguments (SN, AN, TRUE, 1, 0, 0, DhcpIgnore)
|
|
// - Changing, say address # 2 i.e ipindex = 1
|
|
// arguments (SN, AN, TRUE, 1, I, S, DhcpIgnore)
|
|
//
|
|
//================================================================================
|
|
DWORD // win32 status
|
|
APIENTRY
|
|
DhcpNotifyConfigChange( // handle address changes, param changes etc.
|
|
IN LPWSTR ServerName, // name of server where this will be executed
|
|
IN LPWSTR AdapterName, // which adapter is going to be reconfigured?
|
|
IN BOOL IsNewIpAddress,// is address new/ or address is same?
|
|
IN DWORD IpIndex, // index of addr for this adapter -- 0 ==> first interface...
|
|
IN DWORD IpAddress, // the ip address that is being set
|
|
IN DWORD SubnetMask, // corresponding subnet mask
|
|
IN SERVICE_ENABLE DhcpServiceEnabled
|
|
)
|
|
{
|
|
return DhcpNotifyConfigChangeEx(
|
|
ServerName, AdapterName, IsNewIpAddress,
|
|
IpIndex, IpAddress, SubnetMask, DhcpServiceEnabled,
|
|
NOTIFY_FLG_DO_DNS | NOTIFY_FLG_RESET_IPADDR
|
|
);
|
|
}
|
|
|
|
|
|
|
|
DWORD BringUpInterface( PVOID pvLocalInformation )
|
|
{
|
|
LOCAL_CONTEXT_INFO *pContext;
|
|
TCP_REQUEST_SET_INFORMATION_EX *pTcpRequest;
|
|
TDIObjectID *pObjectID;
|
|
IFEntry *pIFEntry;
|
|
int cbTcpRequest;
|
|
HANDLE hDriver = NULL;
|
|
DWORD dwResult;
|
|
NTSTATUS NtStatus;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
DhcpPrint( ( DEBUG_MISC, "Entering BringUpInterface\n" ));
|
|
|
|
dwResult = OpenDriver( &hDriver, DD_TCP_DEVICE_NAME );
|
|
if ( ERROR_SUCCESS != dwResult )
|
|
{
|
|
DhcpPrint( ( DEBUG_ERRORS,
|
|
"BringUpInterface: Unable to open TCP driver.\n" ) );
|
|
return dwResult;
|
|
}
|
|
|
|
pContext = (LOCAL_CONTEXT_INFO *) pvLocalInformation;
|
|
|
|
//
|
|
// compute the input buffer size and allocate
|
|
//
|
|
|
|
|
|
cbTcpRequest = sizeof( TCP_REQUEST_SET_INFORMATION_EX )
|
|
+ sizeof( IFEntry ) -1;
|
|
|
|
//
|
|
// initialize the request
|
|
//
|
|
|
|
pTcpRequest = DhcpAllocateMemory( cbTcpRequest );
|
|
if ( !pTcpRequest )
|
|
{
|
|
NtClose( hDriver );
|
|
DhcpPrint( ( DEBUG_ERRORS,
|
|
"BringUpInterface: Insufficient memory\n" ));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
pTcpRequest->BufferSize = cbTcpRequest - sizeof(TCP_REQUEST_SET_INFORMATION_EX);
|
|
|
|
pObjectID = &pTcpRequest->ID;
|
|
pIFEntry = (IFEntry *) &pTcpRequest->Buffer[0];
|
|
|
|
pObjectID->toi_entity.tei_entity = IF_ENTITY;
|
|
pObjectID->toi_entity.tei_instance = pContext->IpInterfaceInstance;
|
|
|
|
pObjectID->toi_class = INFO_CLASS_PROTOCOL;
|
|
pObjectID->toi_type = INFO_TYPE_PROVIDER;
|
|
pObjectID->toi_id = IF_MIB_STATS_ID;
|
|
|
|
pIFEntry->if_adminstatus = IF_STATUS_UP;
|
|
|
|
NtStatus = NtDeviceIoControlFile(
|
|
hDriver, NULL, NULL, NULL, &IoStatusBlock,
|
|
IOCTL_TCP_SET_INFORMATION_EX,
|
|
pTcpRequest, cbTcpRequest,
|
|
NULL, 0
|
|
);
|
|
|
|
if ( STATUS_PENDING == NtStatus )
|
|
{
|
|
if ( STATUS_SUCCESS == NtWaitForSingleObject( hDriver, TRUE, NULL ) )
|
|
NtStatus = IoStatusBlock.Status;
|
|
|
|
#ifdef DBG
|
|
if ( STATUS_SUCCESS != NtStatus )
|
|
DhcpPrint( ( DEBUG_ERRORS,
|
|
"BringUpInterface: failed to bring up adapter\n" ));
|
|
#endif
|
|
|
|
|
|
} else if ( STATUS_SUCCESS == NtStatus ) {
|
|
NtStatus = IoStatusBlock.Status;
|
|
}
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
|
|
if ( hDriver )
|
|
NtClose( hDriver );
|
|
|
|
if ( pTcpRequest )
|
|
DhcpFreeMemory( pTcpRequest );
|
|
|
|
DhcpPrint( ( DEBUG_MISC,
|
|
"Leaving BringUpInterface\n" ) );
|
|
|
|
return RtlNtStatusToDosError( NtStatus );
|
|
}
|
|
|
|
#if defined(_PNP_POWER_)
|
|
|
|
|
|
DWORD
|
|
IPGetIPEventRequest(
|
|
HANDLE handle,
|
|
HANDLE event,
|
|
UINT seqNo,
|
|
PIP_GET_IP_EVENT_RESPONSE responseBuffer,
|
|
DWORD responseBufferSize,
|
|
PIO_STATUS_BLOCK ioStatusBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This rountine sends the ioctl to get media sense notification from
|
|
IP.
|
|
|
|
Arguments:
|
|
|
|
handle - handle to tcpip driver.
|
|
|
|
event - the event we need to do wait on.
|
|
|
|
seqNo - seqNo of the last event received.
|
|
|
|
responseBuffer - pointer to the buffer where event info will be stored.
|
|
|
|
ioStatusBlock - status of the operation, if not pending.
|
|
|
|
Return Value:
|
|
|
|
NT Error Code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
DWORD Error;
|
|
IP_GET_IP_EVENT_REQUEST requestBuffer;
|
|
|
|
requestBuffer.SequenceNo = seqNo;
|
|
|
|
|
|
RtlZeroMemory( responseBuffer, sizeof(IP_GET_IP_EVENT_RESPONSE));
|
|
responseBuffer->ContextStart = 0xFFFF;
|
|
|
|
status = NtDeviceIoControlFile(
|
|
handle, // Driver handle
|
|
event, // Event
|
|
NULL, // APC Routine
|
|
NULL, // APC context
|
|
ioStatusBlock, // Status block
|
|
IOCTL_IP_GET_IP_EVENT, // Control code
|
|
&requestBuffer, // Input buffer
|
|
sizeof(IP_GET_IP_EVENT_REQUEST), // Input buffer size
|
|
responseBuffer, // Output buffer
|
|
responseBufferSize // Output buffer size
|
|
);
|
|
|
|
|
|
if ( status == STATUS_SUCCESS ) {
|
|
status = ioStatusBlock->Status;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
DWORD
|
|
IPCancelIPEventRequest(
|
|
HANDLE handle,
|
|
PIO_STATUS_BLOCK ioStatusBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This rountine cancels the ioctl that was sent to get media sense
|
|
notification from IP.
|
|
|
|
Arguments:
|
|
|
|
handle - handle to the ip driver.
|
|
|
|
Return Value:
|
|
|
|
NT Error Code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
DWORD Error;
|
|
|
|
status = NtCancelIoFile(
|
|
handle, // Driver handle
|
|
ioStatusBlock); // Status block
|
|
|
|
|
|
DhcpPrint( (DEBUG_TRACE,"IPCancelIPEventRequest: status %lx\n",status));
|
|
DhcpAssert( status == STATUS_SUCCESS );
|
|
|
|
return RtlNtStatusToDosError( status );
|
|
}
|
|
#endif _PNP_POWER_
|
|
|
|
#define IPSTRING(x) (inet_ntoa(*(struct in_addr*)&(x)))
|
|
|
|
|
|
DWORD // return interface index or -1
|
|
DhcpIpGetIfIndex( // get the IF index for this adapter
|
|
IN PDHCP_CONTEXT DhcpContext // context of adapter to get IfIndex for
|
|
) {
|
|
|
|
return ((PLOCAL_CONTEXT_INFO)DhcpContext->LocalInformation)->IfIndex;
|
|
}
|
|
|
|
DWORD
|
|
QueryIfIndex(
|
|
IN ULONG IpInterfaceContext,
|
|
IN ULONG IpInterfaceInstance
|
|
)
|
|
{
|
|
|
|
DWORD Error;
|
|
DWORD Index;
|
|
DWORD Size;
|
|
DWORD NumReturned;
|
|
DWORD i;
|
|
BYTE Context[CONTEXT_SIZE];
|
|
HANDLE TcpHandle;
|
|
NTSTATUS Status;
|
|
TDIObjectID ID;
|
|
IFEntry IFE;
|
|
|
|
Error = OpenDriver(&TcpHandle, DD_TCP_DEVICE_NAME);
|
|
if( ERROR_SUCCESS != Error ) {
|
|
DhcpPrint((DEBUG_ERRORS, "DhcpIpGetIfIndex:OpenDriver(DD_TCP):0x%lx\n", Error));
|
|
return (DWORD)-1;
|
|
}
|
|
|
|
ID.toi_entity.tei_entity = IF_ENTITY;
|
|
ID.toi_entity.tei_instance = IpInterfaceInstance;
|
|
ID.toi_class = INFO_CLASS_PROTOCOL;
|
|
ID.toi_type = INFO_TYPE_PROVIDER;
|
|
ID.toi_id = IF_MIB_STATS_ID;
|
|
|
|
Size = sizeof(IFE);
|
|
RtlZeroMemory(&IFE, sizeof(IFE));
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
Index = -1;
|
|
|
|
Status = TCPQueryInformationEx(
|
|
TcpHandle,
|
|
&ID,
|
|
&IFE,
|
|
&Size,
|
|
Context
|
|
);
|
|
if( TDI_SUCCESS != Status && TDI_BUFFER_OVERFLOW != Status ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
Index = IFE.if_index;
|
|
DhcpPrint((DEBUG_STACK, "IfIndex(0x%lx,0x%lx):0x%lx\n",
|
|
IpInterfaceContext, IpInterfaceInstance, Index
|
|
));
|
|
Cleanup:
|
|
|
|
if( TcpHandle ) NtClose(TcpHandle);
|
|
|
|
if( TDI_SUCCESS != Status ) {
|
|
DhcpPrint((DEBUG_ERRORS, "DhcpIpGetIfIndex:TCPQueryInformationEx:%ld\n", Status));
|
|
}
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpIpGetIfIndex:0x%lx\n", Index));
|
|
return Index;
|
|
}
|
|
|
|
DWORD // win32 status
|
|
DhcpSetRoute( // set a route with the stack
|
|
IN DWORD Dest, // network order destination
|
|
IN DWORD DestMask, // network order destination mask
|
|
IN DWORD IfIndex, // interface index to route
|
|
IN DWORD NextHop, // next hop n/w order address
|
|
IN DWORD Metric, // metric
|
|
IN BOOL IsLocal, // is this a local address? (IRE_DIRECT)
|
|
IN BOOL IsDelete // is this route being deleted?
|
|
)
|
|
{
|
|
DWORD Error;
|
|
NTSTATUS Status;
|
|
HANDLE TcpHandle;
|
|
IPRouteEntry RTE;
|
|
TDIObjectID ID;
|
|
|
|
if( 0xFFFFFFFF == IfIndex ) { // invalid If Index
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
Error = OpenDriver(&TcpHandle, DD_TCP_DEVICE_NAME);
|
|
if( ERROR_SUCCESS != Error ) { // should not really fail
|
|
DhcpPrint((DEBUG_ERRORS, "OpenDriver(TCP_DEVICE):%ld\n", Error));
|
|
return Error;
|
|
}
|
|
|
|
memset(&RTE, 0, sizeof(RTE));
|
|
memset(&ID, 0, sizeof(ID));
|
|
|
|
RTE.ire_dest = Dest;
|
|
RTE.ire_index = IfIndex;
|
|
RTE.ire_metric1 = Metric;
|
|
RTE.ire_metric2 = (DWORD)(-1);
|
|
RTE.ire_metric3 = (DWORD)(-1);
|
|
RTE.ire_metric4 = (DWORD)(-1);
|
|
RTE.ire_metric5 = (DWORD)(-1);
|
|
RTE.ire_nexthop = NextHop;
|
|
RTE.ire_type = (IsDelete?IRE_TYPE_INVALID:(IsLocal?IRE_TYPE_DIRECT:IRE_TYPE_INDIRECT));
|
|
RTE.ire_proto = IRE_PROTO_NETMGMT;
|
|
RTE.ire_age = 0;
|
|
RTE.ire_mask = DestMask;
|
|
RTE.ire_context = 0;
|
|
|
|
ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
|
|
ID.toi_entity.tei_entity = CL_NL_ENTITY;
|
|
ID.toi_entity.tei_instance = 0;
|
|
ID.toi_class = INFO_CLASS_PROTOCOL;
|
|
ID.toi_type = INFO_TYPE_PROVIDER;
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpSetRoute:n/w Dest: %s\n", IPSTRING(Dest)));
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpSetRoute:n/w IfIndex:0x%lx\n", IfIndex));
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpSetRoute:n/w NextHop:%s\n", IPSTRING(NextHop)));
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpSetRoute:n/w Type:0x%lx\n", RTE.ire_type));
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpSetRoute:n/w DestMask:%s\n", IPSTRING(DestMask)));
|
|
|
|
Status = TCPSetInformationEx(
|
|
TcpHandle,
|
|
&ID,
|
|
&RTE,
|
|
sizeof(RTE)
|
|
);
|
|
|
|
if( TDI_BUFFER_OVERFLOW == Status ) Status = TDI_SUCCESS;
|
|
NtClose(TcpHandle);
|
|
|
|
if( TDI_SUCCESS != Status ) {
|
|
DhcpPrint((DEBUG_ERRORS, "DhcpSetRoute: 0x%lx\n", Status));
|
|
}
|
|
|
|
return RtlNtStatusToDosError(Status);
|
|
}
|
|
|
|
DWORD
|
|
GetAdapterFlag(
|
|
HANDLE TCPHandle,
|
|
DHCP_IP_ADDRESS ipaddr
|
|
)
|
|
{
|
|
BYTE Buffer[256];
|
|
DWORD AdapterFlag;
|
|
NTSTATUS Status;
|
|
DWORD Size;
|
|
TDIObjectID ID;
|
|
BYTE Context[CONTEXT_SIZE];
|
|
|
|
/*
|
|
* Read in adapter flag, which could be
|
|
* 1. Point to Point
|
|
* 2. Point to MultiPoint
|
|
* 3. Unidirectional
|
|
* 4. Non of the above
|
|
*/
|
|
DhcpAssert(CONTEXT_SIZE >= sizeof(ipaddr));
|
|
|
|
RtlCopyMemory(Context, &ipaddr, CONTEXT_SIZE);
|
|
ID.toi_entity.tei_entity = CL_NL_ENTITY;
|
|
ID.toi_entity.tei_instance = 0;
|
|
ID.toi_class = INFO_CLASS_PROTOCOL;
|
|
ID.toi_type = INFO_TYPE_PROVIDER;
|
|
ID.toi_id = IP_INTFC_INFO_ID;
|
|
Size = sizeof(Buffer);
|
|
Status = TCPQueryInformationEx(TCPHandle, &ID, Buffer, &Size, Context);
|
|
if (Status != TDI_SUCCESS) {
|
|
AdapterFlag = 0;
|
|
DhcpPrint(( DEBUG_TCP_INFO, "QueryInterfaceType: IpAddress=%s Status=%lx\n",
|
|
inet_ntoa(*(struct in_addr*)&ipaddr), Status));
|
|
} else {
|
|
AdapterFlag = ((IPInterfaceInfo*)Buffer)->iii_flags;
|
|
DhcpPrint(( DEBUG_TCP_INFO, "QueryInterfaceType: IpAddress=%s AdapterFlag=%lx\n",
|
|
inet_ntoa(*(struct in_addr*)&ipaddr), AdapterFlag));
|
|
}
|
|
|
|
return AdapterFlag;
|
|
}
|
|
|
|
BOOL
|
|
IsUnidirectionalAdapter(
|
|
DWORD IpInterfaceContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function queries and browses through the TDI list to find out
|
|
the specified IpTable entry and then determines if it is a unidirectional
|
|
adapter.
|
|
It almost identical to DhcpQueryHWInfo
|
|
|
|
Arguments:
|
|
|
|
IpInterfaceContext - Context value of the Ip Table Entry.
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
NTSTATUS Status;
|
|
DWORD i, j;
|
|
|
|
BYTE Context[CONTEXT_SIZE];
|
|
TDIEntityID *EList = NULL;
|
|
TDIObjectID ID;
|
|
DWORD Size;
|
|
DWORD NumReturned;
|
|
BOOL fFound;
|
|
|
|
IPAddrEntry * pIAE = NULL;
|
|
IPAddrEntry *pIAEMatch = NULL;
|
|
HANDLE TCPHandle = NULL;
|
|
DWORD AdapterFlag = 0;
|
|
BYTE HardwareAddressType = 0;
|
|
LPBYTE HardwareAddress = NULL;
|
|
DWORD HardwareAddressLength = 0;
|
|
DWORD pIpInterfaceInstance = 0;
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying for interface context %lx\n", IpInterfaceContext));
|
|
|
|
Error = OpenDriver(&TCPHandle, DD_TCP_DEVICE_NAME);
|
|
if (Error != ERROR_SUCCESS) {
|
|
return( Error );
|
|
}
|
|
|
|
//
|
|
// The first thing to do is get the list of available entities, and make
|
|
// sure that there are some interface entities present.
|
|
//
|
|
|
|
ID.toi_entity.tei_entity = GENERIC_ENTITY;
|
|
ID.toi_entity.tei_instance = 0;
|
|
ID.toi_class = INFO_CLASS_GENERIC;
|
|
ID.toi_type = INFO_TYPE_PROVIDER;
|
|
ID.toi_id = ENTITY_LIST_ID;
|
|
|
|
Size = sizeof(TDIEntityID) * MAX_TDI_ENTITIES;
|
|
EList = (TDIEntityID*)DhcpAllocateMemory(Size);
|
|
if (EList == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Cleanup;
|
|
}
|
|
RtlZeroMemory(EList, Size);
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
Status = TCPQueryInformationEx(TCPHandle, &ID, EList, &Size, Context);
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
NumReturned = Size/sizeof(TDIEntityID);
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: No of total entities %lx\n", NumReturned));
|
|
|
|
for (i = 0; i < NumReturned; i++) {
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, type %lx, instance %lx\n",
|
|
i, EList[i].tei_entity, EList[i].tei_instance));
|
|
|
|
if ( EList[i].tei_entity == CL_NL_ENTITY ) {
|
|
|
|
IPSNMPInfo IPStats;
|
|
DWORD NLType;
|
|
|
|
//
|
|
// Does this entity support IP?
|
|
//
|
|
|
|
ID.toi_entity.tei_entity = EList[i].tei_entity;
|
|
ID.toi_entity.tei_instance = EList[i].tei_instance;
|
|
ID.toi_class = INFO_CLASS_GENERIC;
|
|
ID.toi_type = INFO_TYPE_PROVIDER;
|
|
ID.toi_id = ENTITY_TYPE_ID;
|
|
|
|
Size = sizeof( NLType );
|
|
NLType = 0;
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying CL_NL_ENTITY %lx\n",i));
|
|
Status = TCPQueryInformationEx(TCPHandle, &ID, &NLType, &Size, Context);
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( NLType != CL_NL_IP ) {
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx does not support IP\n",i));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// We've got an IP driver so get it's address table
|
|
//
|
|
|
|
ID.toi_class = INFO_CLASS_PROTOCOL;
|
|
ID.toi_id = IP_MIB_STATS_ID;
|
|
Size = sizeof(IPStats);
|
|
RtlZeroMemory( &IPStats, Size);
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
Status = TCPQueryInformationEx(
|
|
TCPHandle,
|
|
&ID,
|
|
&IPStats,
|
|
&Size,
|
|
Context);
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, numaddr %lx\n",i, IPStats.ipsi_numaddr));
|
|
|
|
if ( IPStats.ipsi_numaddr == 0 ) {
|
|
continue;
|
|
}
|
|
|
|
Size = sizeof(IPAddrEntry) * IPStats.ipsi_numaddr;
|
|
|
|
while (1) {
|
|
DWORD OldSize;
|
|
pIAE = DhcpAllocateMemory(Size);
|
|
|
|
if ( pIAE == NULL ) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
|
|
RtlZeroMemory(Context, CONTEXT_SIZE);
|
|
|
|
OldSize = Size;
|
|
Status = TCPQueryInformationEx(TCPHandle, &ID, pIAE, &Size, Context);
|
|
|
|
if (Status == TDI_BUFFER_OVERFLOW) {
|
|
Size = OldSize * 2;
|
|
DhcpFreeMemory(pIAE);
|
|
pIAE = NULL;
|
|
continue;
|
|
}
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (Status == TDI_SUCCESS) {
|
|
IPStats.ipsi_numaddr = Size/sizeof(IPAddrEntry);
|
|
DhcpAssert((Size % sizeof(IPAddrEntry)) == 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We have the IP address table for this IP driver.
|
|
// Find the hardware address corresponds to the given
|
|
// IpInterfaceContext.
|
|
//
|
|
// Loop through the IP table entries and findout the
|
|
// matching entry.
|
|
//
|
|
|
|
pIAEMatch = NULL;
|
|
for( j = 0; j < IPStats.ipsi_numaddr ; j++) {
|
|
DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has iae_index %lx iae_context %lx\n",
|
|
&pIAE[j], pIAE[j].iae_index, pIAE[j].iae_context ));
|
|
|
|
if( pIAE[j].iae_context == IpInterfaceContext ) {
|
|
|
|
DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has our interface context %lx\n",
|
|
&pIAE[j], IpInterfaceContext ));
|
|
|
|
pIAEMatch = &pIAE[j];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( pIAEMatch == NULL ) {
|
|
|
|
//
|
|
// freeup the loop memory.
|
|
//
|
|
|
|
DhcpFreeMemory( pIAE );
|
|
pIAE = NULL;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// NOTE : There may be more than one IpTable in the TDI
|
|
// list. We need additional information to select the
|
|
// IpTable we want. For now, we assume only one table
|
|
// is supported, so pick the first and only table from the
|
|
// list.
|
|
|
|
Status = FindHardwareAddr(
|
|
TCPHandle,
|
|
EList,
|
|
NumReturned,
|
|
pIAEMatch,
|
|
&HardwareAddressType,
|
|
&HardwareAddress,
|
|
&HardwareAddressLength,
|
|
&pIpInterfaceInstance,
|
|
&fFound );
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( fFound ) {
|
|
Status = TDI_SUCCESS;
|
|
AdapterFlag = GetAdapterFlag(TCPHandle, pIAEMatch->iae_addr);
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// freeup the loop memory.
|
|
//
|
|
|
|
DhcpFreeMemory( pIAE );
|
|
pIAE = NULL;
|
|
|
|
} // if IP
|
|
|
|
} // entity traversal
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
|
|
Cleanup:
|
|
|
|
if( pIAE != NULL ) {
|
|
DhcpFreeMemory( pIAE );
|
|
}
|
|
|
|
if( TCPHandle != NULL ) {
|
|
NtClose( TCPHandle );
|
|
}
|
|
|
|
if (Status != TDI_SUCCESS) {
|
|
DhcpPrint(( DEBUG_ERRORS, "QueryHWInfo failed, %lx.\n", Status ));
|
|
}
|
|
if( HardwareAddress ) DhcpFreeMemory(HardwareAddress);
|
|
|
|
if (NULL != EList) {
|
|
DhcpFreeMemory(EList);
|
|
}
|
|
|
|
return (AdapterFlag & IP_INTFC_FLAG_UNIDIRECTIONAL);
|
|
}
|
|
|