946 lines
27 KiB
C
946 lines
27 KiB
C
/*++
|
|
|
|
Copyright(c) 1999-2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
brdgtdi.c
|
|
|
|
Abstract:
|
|
|
|
Ethernet MAC level bridge.
|
|
Tdi registration for address notifications.
|
|
|
|
Author:
|
|
|
|
Salahuddin J. Khan (sjkhan)
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
March 2002 - Original version
|
|
|
|
--*/
|
|
|
|
#define NDIS_MINIPORT_DRIVER
|
|
#define NDIS50_MINIPORT 1
|
|
#define NDIS_WDM 1
|
|
|
|
#pragma warning( push, 3 )
|
|
#include <ndis.h>
|
|
#include <tdikrnl.h>
|
|
#include <ntstatus.h>
|
|
#include <wchar.h>
|
|
#pragma warning( pop )
|
|
|
|
#include "bridge.h"
|
|
#include "brdgtdi.h"
|
|
|
|
#include "brdgsta.h"
|
|
#include "brdgmini.h"
|
|
#include "brdgprot.h"
|
|
#include "brdgbuf.h"
|
|
#include "brdgfwd.h"
|
|
#include "brdgtbl.h"
|
|
#include "brdgctl.h"
|
|
#include "brdggpo.h"
|
|
|
|
// ===========================================================================
|
|
//
|
|
// GLOBALS
|
|
//
|
|
// ===========================================================================
|
|
|
|
BRDG_TDI_GLOBALS g_BrdgTdiGlobals;
|
|
|
|
// ===========================================================================
|
|
//
|
|
// CONSTANTS
|
|
//
|
|
// ===========================================================================
|
|
|
|
#define MAX_GUID_LEN 39
|
|
#define MAX_IP4_STRING_LEN 17
|
|
|
|
const WCHAR TcpipAdaptersKey[] = {L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters"};
|
|
|
|
// ===========================================================================
|
|
//
|
|
// PRIVATE PROTOTYPES
|
|
//
|
|
// ===========================================================================
|
|
|
|
NTSTATUS
|
|
BrdgTdiPnpPowerHandler(
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PNET_PNP_EVENT PowerEvent,
|
|
IN PTDI_PNP_CONTEXT Context1,
|
|
IN PTDI_PNP_CONTEXT Context2
|
|
);
|
|
|
|
VOID
|
|
BrdgTdiBindingHandler(
|
|
IN TDI_PNP_OPCODE PnPOpcode,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PWSTR MultiSZBindList
|
|
);
|
|
|
|
VOID
|
|
BrdgTdiAddAddressHandler(
|
|
IN PTA_ADDRESS Address,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PTDI_PNP_CONTEXT Context
|
|
);
|
|
|
|
VOID
|
|
BrdgTdiDelAddressHandler(
|
|
IN PTA_ADDRESS Address,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PTDI_PNP_CONTEXT Context
|
|
);
|
|
|
|
VOID
|
|
TSPrintTaAddress(PTA_ADDRESS pTaAddress);
|
|
|
|
// ===========================================================================
|
|
//
|
|
// INLINE FUNCTIONS
|
|
//
|
|
// ===========================================================================
|
|
|
|
__forceinline
|
|
BOOLEAN
|
|
IsLower(WCHAR c)
|
|
{
|
|
return (BOOLEAN)((c >= L'a') && (c <= 'z'));
|
|
}
|
|
|
|
__forceinline
|
|
BOOLEAN
|
|
IsDigit(WCHAR c)
|
|
{
|
|
return (BOOLEAN)((c >= L'0') && (c <= '9'));
|
|
}
|
|
|
|
__forceinline
|
|
BOOLEAN
|
|
IsXDigit(WCHAR c)
|
|
{
|
|
return (BOOLEAN)( ((c >= L'0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F')) );
|
|
}
|
|
|
|
// ===========================================================================
|
|
//
|
|
// BRIDGE TDI IMPLEMENTATION
|
|
//
|
|
// ===========================================================================
|
|
|
|
VOID
|
|
BrdgTdiInitializeClientInterface(
|
|
IN PTDI_CLIENT_INTERFACE_INFO ClientInterfaceInfo,
|
|
IN PUNICODE_STRING ClientName
|
|
)
|
|
{
|
|
DBGPRINT(TDI, ("BrdgTdiInitializeClientInterface\r\n"));
|
|
ClientInterfaceInfo->MajorTdiVersion = TDI_CURRENT_MAJOR_VERSION;
|
|
ClientInterfaceInfo->MinorTdiVersion = TDI_CURRENT_MINOR_VERSION;
|
|
ClientInterfaceInfo->ClientName = ClientName;
|
|
ClientInterfaceInfo->PnPPowerHandler = BrdgTdiPnpPowerHandler;
|
|
ClientInterfaceInfo->BindingHandler = BrdgTdiBindingHandler;
|
|
ClientInterfaceInfo->AddAddressHandlerV2 = BrdgTdiAddAddressHandler;
|
|
ClientInterfaceInfo->DelAddressHandlerV2 = BrdgTdiDelAddressHandler;
|
|
}
|
|
|
|
NTSTATUS
|
|
BrdgTdiDriverInit()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Driver load-time initialization
|
|
|
|
Return Value:
|
|
|
|
Status of initialization
|
|
|
|
Locking Constraints:
|
|
|
|
Top-level function. Assumes no locks are held by caller.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
DBGPRINT(TDI, ("BrdgTdiDriverInit\r\n"));
|
|
|
|
RtlInitUnicodeString(&g_BrdgTdiGlobals.ClientName, L"Bridge");
|
|
|
|
RtlZeroMemory(&g_BrdgTdiGlobals.ciiBridge, sizeof(TDI_CLIENT_INTERFACE_INFO));
|
|
|
|
BrdgTdiInitializeClientInterface(&g_BrdgTdiGlobals.ciiBridge, &g_BrdgTdiGlobals.ClientName);
|
|
|
|
status = BrdgGpoDriverInit();
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
BrdgTdiCleanup();
|
|
}
|
|
else
|
|
{
|
|
status = TdiRegisterPnPHandlers(&g_BrdgTdiGlobals.ciiBridge,
|
|
sizeof(TDI_CLIENT_INTERFACE_INFO),
|
|
&g_BrdgTdiGlobals.hBindingHandle);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
BrdgTdiCleanup()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Driver shutdown cleanup
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Locking Constraints:
|
|
|
|
Top-level function. Assumes no locks are held by caller.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = TdiDeregisterPnPHandlers(g_BrdgTdiGlobals.hBindingHandle);
|
|
|
|
SAFEASSERT(NT_SUCCESS(status));
|
|
|
|
BrdgGpoCleanup();
|
|
}
|
|
|
|
NTSTATUS
|
|
BrdgTdiPnpPowerHandler(
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PNET_PNP_EVENT PowerEvent,
|
|
IN PTDI_PNP_CONTEXT Context1,
|
|
IN PTDI_PNP_CONTEXT Context2
|
|
)
|
|
{
|
|
DBGPRINT(TDI, ("BrdgTdiPnpPowerHandler\r\n"));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
BrdgTdiBindingHandler(
|
|
IN TDI_PNP_OPCODE PnPOpcode,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PWSTR MultiSZBindList
|
|
)
|
|
{
|
|
DBGPRINT(TDI, ("BrdgTdiBindingHandler\r\n"));
|
|
}
|
|
|
|
VOID
|
|
BrdgTdiAddAddressHandler(
|
|
IN PTA_ADDRESS Address,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PTDI_PNP_CONTEXT Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called if a new address is added.
|
|
|
|
Arguments:
|
|
|
|
Address - New address that has been added.
|
|
|
|
DeviceName - The device that this is changing for.
|
|
|
|
Context - Not something we're interested in for now.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGPRINT(TDI, ("BrdgTdiAddAddressHandler\r\n"));
|
|
|
|
if ((Address->AddressType == TDI_ADDRESS_TYPE_IP))
|
|
{
|
|
if (NULL != DeviceName->Buffer)
|
|
{
|
|
//
|
|
// Find the start of the GUID
|
|
//
|
|
PWCHAR DeviceId = wcsrchr(DeviceName->Buffer, L'{');
|
|
if (NULL != DeviceId)
|
|
{
|
|
NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
|
|
LPWSTR AdapterPath;
|
|
|
|
AdapterPath = ExAllocatePoolWithTag(PagedPool,
|
|
(wcslen(TcpipAdaptersKey) + 1 + wcslen(DeviceId) + 1) * sizeof(WCHAR),
|
|
'gdrB');
|
|
if (AdapterPath)
|
|
{
|
|
OBJECT_ATTRIBUTES ObAttr;
|
|
UNICODE_STRING Adapter;
|
|
HANDLE hKey;
|
|
|
|
wcscpy(AdapterPath, TcpipAdaptersKey);
|
|
wcscat(AdapterPath, L"\\");
|
|
wcscat(AdapterPath, DeviceId);
|
|
|
|
RtlInitUnicodeString(&Adapter, AdapterPath);
|
|
|
|
InitializeObjectAttributes( &ObAttr,
|
|
&Adapter,
|
|
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
status = ZwOpenKey(&hKey,
|
|
KEY_READ,
|
|
&ObAttr);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
ZwClose(hKey);
|
|
//
|
|
// This is a valid adapter on this machine. Otherwise it could be an NdisAdapter etc and
|
|
// we don't pay attention to these for group policies.
|
|
//
|
|
BrdgGpoNewAddressNotification(DeviceId);
|
|
}
|
|
|
|
ExFreePool(AdapterPath);
|
|
}
|
|
}
|
|
}
|
|
#if DBG
|
|
TSPrintTaAddress(Address);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
VOID
|
|
BrdgTdiDelAddressHandler(
|
|
IN PTA_ADDRESS Address,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PTDI_PNP_CONTEXT Context
|
|
)
|
|
{
|
|
DBGPRINT(TDI, ("BrdgTdiDelAddressHandler\r\n"));
|
|
//
|
|
// We don't delete the current list of networks that we have since we need them to make
|
|
// an accurate assessment on whether to follow the GPO. Instead, the AddAddressHandler
|
|
// will simply update the existing network address for the ID's and if this results in
|
|
// a different network then we'll change the bridge mode.
|
|
//
|
|
}
|
|
|
|
VOID
|
|
TSPrintTaAddress(PTA_ADDRESS pTaAddress)
|
|
{
|
|
BOOLEAN fShowAddress = TRUE;
|
|
|
|
DbgPrint("AddressType = TDI_ADDRESS_TYPE_");
|
|
switch (pTaAddress->AddressType)
|
|
{
|
|
case TDI_ADDRESS_TYPE_UNSPEC:
|
|
DbgPrint("UNSPEC\n");
|
|
break;
|
|
case TDI_ADDRESS_TYPE_UNIX:
|
|
DbgPrint("UNIX\n");
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_IP:
|
|
DbgPrint("IP\n");
|
|
fShowAddress = FALSE;
|
|
{
|
|
PTDI_ADDRESS_IP pTdiAddressIp = (PTDI_ADDRESS_IP)pTaAddress->Address;
|
|
PUCHAR pucTemp = (PUCHAR)&pTdiAddressIp->in_addr;
|
|
DbgPrint("sin_port = 0x%04x\n"
|
|
"in_addr = %u.%u.%u.%u\n",
|
|
pTdiAddressIp->sin_port,
|
|
pucTemp[0], pucTemp[1],
|
|
pucTemp[2], pucTemp[3]);
|
|
}
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_IMPLINK:
|
|
DbgPrint("IMPLINK\n");
|
|
break;
|
|
case TDI_ADDRESS_TYPE_PUP:
|
|
DbgPrint("PUP\n");
|
|
break;
|
|
case TDI_ADDRESS_TYPE_CHAOS:
|
|
DbgPrint("CHAOS\n");
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_IPX:
|
|
DbgPrint("IPX\n");
|
|
fShowAddress = FALSE;
|
|
{
|
|
PTDI_ADDRESS_IPX pTdiAddressIpx = (PTDI_ADDRESS_IPX)pTaAddress->Address;
|
|
DbgPrint("NetworkAddress = 0x%08x\n"
|
|
"NodeAddress = %u.%u.%u.%u.%u.%u\n"
|
|
"Socket = 0x%04x\n",
|
|
pTdiAddressIpx->NetworkAddress,
|
|
pTdiAddressIpx->NodeAddress[0],
|
|
pTdiAddressIpx->NodeAddress[1],
|
|
pTdiAddressIpx->NodeAddress[2],
|
|
pTdiAddressIpx->NodeAddress[3],
|
|
pTdiAddressIpx->NodeAddress[4],
|
|
pTdiAddressIpx->NodeAddress[5],
|
|
pTdiAddressIpx->Socket);
|
|
|
|
}
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_NBS:
|
|
DbgPrint("NBS\n");
|
|
break;
|
|
case TDI_ADDRESS_TYPE_ECMA:
|
|
DbgPrint("ECMA\n");
|
|
break;
|
|
case TDI_ADDRESS_TYPE_DATAKIT:
|
|
DbgPrint("DATAKIT\n");
|
|
break;
|
|
case TDI_ADDRESS_TYPE_CCITT:
|
|
DbgPrint("CCITT\n");
|
|
break;
|
|
case TDI_ADDRESS_TYPE_SNA:
|
|
DbgPrint("SNA\n");
|
|
break;
|
|
case TDI_ADDRESS_TYPE_DECnet:
|
|
DbgPrint("DECnet\n");
|
|
break;
|
|
case TDI_ADDRESS_TYPE_DLI:
|
|
DbgPrint("DLI\n");
|
|
break;
|
|
case TDI_ADDRESS_TYPE_LAT:
|
|
DbgPrint("LAT\n");
|
|
break;
|
|
case TDI_ADDRESS_TYPE_HYLINK:
|
|
DbgPrint("HYLINK\n");
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_APPLETALK:
|
|
DbgPrint("APPLETALK\n");
|
|
fShowAddress = FALSE;
|
|
{
|
|
PTDI_ADDRESS_APPLETALK pTdiAddressAppleTalk = (PTDI_ADDRESS_APPLETALK)pTaAddress->Address;
|
|
|
|
DbgPrint("Network = 0x%04x\n"
|
|
"Node = 0x%02x\n"
|
|
"Socket = 0x%02x\n",
|
|
pTdiAddressAppleTalk->Network,
|
|
pTdiAddressAppleTalk->Node,
|
|
pTdiAddressAppleTalk->Socket);
|
|
}
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_NETBIOS:
|
|
DbgPrint("NETBIOS\n");
|
|
fShowAddress = FALSE;
|
|
{
|
|
PTDI_ADDRESS_NETBIOS pTdiAddressNetbios = (PTDI_ADDRESS_NETBIOS)pTaAddress->Address;
|
|
UCHAR pucName[17];
|
|
|
|
//
|
|
// make sure we have a zero-terminated name to print...
|
|
//
|
|
RtlCopyMemory(pucName, pTdiAddressNetbios->NetbiosName, 16);
|
|
pucName[16] = 0;
|
|
DbgPrint("NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_");
|
|
switch (pTdiAddressNetbios->NetbiosNameType)
|
|
{
|
|
case TDI_ADDRESS_NETBIOS_TYPE_UNIQUE:
|
|
DbgPrint("UNIQUE\n");
|
|
break;
|
|
case TDI_ADDRESS_NETBIOS_TYPE_GROUP:
|
|
DbgPrint("GROUP\n");
|
|
break;
|
|
case TDI_ADDRESS_NETBIOS_TYPE_QUICK_UNIQUE:
|
|
DbgPrint("QUICK_UNIQUE\n");
|
|
break;
|
|
case TDI_ADDRESS_NETBIOS_TYPE_QUICK_GROUP:
|
|
DbgPrint("QUICK_GROUP\n");
|
|
break;
|
|
default:
|
|
DbgPrint("INVALID [0x%04x]\n",
|
|
pTdiAddressNetbios->NetbiosNameType);
|
|
break;
|
|
}
|
|
DbgPrint("NetbiosName = %s\n", pucName);
|
|
}
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_8022:
|
|
DbgPrint("8022\n");
|
|
fShowAddress = FALSE;
|
|
{
|
|
PTDI_ADDRESS_8022 pTdiAddress8022 = (PTDI_ADDRESS_8022)pTaAddress->Address;
|
|
|
|
DbgPrint("Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
|
|
pTdiAddress8022->MACAddress[0],
|
|
pTdiAddress8022->MACAddress[1],
|
|
pTdiAddress8022->MACAddress[2],
|
|
pTdiAddress8022->MACAddress[3],
|
|
pTdiAddress8022->MACAddress[4],
|
|
pTdiAddress8022->MACAddress[5]);
|
|
|
|
}
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_OSI_TSAP:
|
|
DbgPrint("OSI_TSAP\n");
|
|
fShowAddress = FALSE;
|
|
{
|
|
PTDI_ADDRESS_OSI_TSAP pTdiAddressOsiTsap = (PTDI_ADDRESS_OSI_TSAP)pTaAddress->Address;
|
|
ULONG ulSelectorLength;
|
|
ULONG ulAddressLength;
|
|
PUCHAR pucTemp = pTdiAddressOsiTsap->tp_addr;
|
|
|
|
DbgPrint("TpAddrType = ISO_");
|
|
switch (pTdiAddressOsiTsap->tp_addr_type)
|
|
{
|
|
case ISO_HIERARCHICAL:
|
|
DbgPrint("HIERARCHICAL\n");
|
|
ulSelectorLength = pTdiAddressOsiTsap->tp_tsel_len;
|
|
ulAddressLength = pTdiAddressOsiTsap->tp_taddr_len;
|
|
break;
|
|
case ISO_NON_HIERARCHICAL:
|
|
DbgPrint("NON_HIERARCHICAL\n");
|
|
ulSelectorLength = 0;
|
|
ulAddressLength = pTdiAddressOsiTsap->tp_taddr_len;
|
|
break;
|
|
default:
|
|
DbgPrint("INVALID [0x%04x]\n",
|
|
pTdiAddressOsiTsap->tp_addr_type);
|
|
ulSelectorLength = 0;
|
|
ulAddressLength = 0;
|
|
break;
|
|
}
|
|
if (ulSelectorLength)
|
|
{
|
|
ULONG ulCount;
|
|
|
|
DbgPrint("TransportSelector: ");
|
|
for (ulCount = 0; ulCount < ulSelectorLength; ulCount++)
|
|
{
|
|
DbgPrint("%02x ", *pucTemp);
|
|
++pucTemp;
|
|
}
|
|
DbgPrint("\n");
|
|
}
|
|
if (ulAddressLength)
|
|
{
|
|
ULONG ulCount;
|
|
|
|
DbgPrint("TransportAddress: ");
|
|
for (ulCount = 0; ulCount < ulAddressLength; ulCount++)
|
|
{
|
|
DbgPrint("%02x ", *pucTemp);
|
|
++pucTemp;
|
|
}
|
|
DbgPrint("\n");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_NETONE:
|
|
DbgPrint("NETONE\n");
|
|
fShowAddress = FALSE;
|
|
{
|
|
PTDI_ADDRESS_NETONE pTdiAddressNetone = (PTDI_ADDRESS_NETONE)pTaAddress->Address;
|
|
UCHAR pucName[21];
|
|
|
|
//
|
|
// make sure have 0-terminated name
|
|
//
|
|
RtlCopyMemory(pucName,
|
|
pTdiAddressNetone->NetoneName,
|
|
20);
|
|
pucName[20] = 0;
|
|
DbgPrint("NetoneNameType = TDI_ADDRESS_NETONE_TYPE_");
|
|
switch (pTdiAddressNetone->NetoneNameType)
|
|
{
|
|
case TDI_ADDRESS_NETONE_TYPE_UNIQUE:
|
|
DbgPrint("UNIQUE\n");
|
|
break;
|
|
case TDI_ADDRESS_NETONE_TYPE_ROTORED:
|
|
DbgPrint("ROTORED\n");
|
|
break;
|
|
default:
|
|
DbgPrint("INVALID [0x%04x]\n",
|
|
pTdiAddressNetone->NetoneNameType);
|
|
break;
|
|
}
|
|
DbgPrint("NetoneName = %s\n",
|
|
pucName);
|
|
}
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_VNS:
|
|
DbgPrint("VNS\n");
|
|
fShowAddress = FALSE;
|
|
{
|
|
PTDI_ADDRESS_VNS pTdiAddressVns = (PTDI_ADDRESS_VNS)pTaAddress->Address;
|
|
|
|
DbgPrint("NetAddress: %02x-%02x-%02x-%02x\n",
|
|
pTdiAddressVns->net_address[0],
|
|
pTdiAddressVns->net_address[1],
|
|
pTdiAddressVns->net_address[2],
|
|
pTdiAddressVns->net_address[3]);
|
|
DbgPrint("SubnetAddr: %02x-%02x\n"
|
|
"Port: %02x-%02x\n"
|
|
"Hops: %u\n",
|
|
pTdiAddressVns->subnet_addr[0],
|
|
pTdiAddressVns->subnet_addr[1],
|
|
pTdiAddressVns->port[0],
|
|
pTdiAddressVns->port[1],
|
|
pTdiAddressVns->hops);
|
|
|
|
|
|
}
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_NETBIOS_EX:
|
|
DbgPrint("NETBIOS_EX\n");
|
|
fShowAddress = FALSE;
|
|
{
|
|
PTDI_ADDRESS_NETBIOS_EX pTdiAddressNetbiosEx = (PTDI_ADDRESS_NETBIOS_EX)pTaAddress->Address;
|
|
UCHAR pucEndpointName[17];
|
|
UCHAR pucNetbiosName[17];
|
|
|
|
//
|
|
// make sure we have zero-terminated names to print...
|
|
//
|
|
RtlCopyMemory(pucEndpointName,
|
|
pTdiAddressNetbiosEx->EndpointName,
|
|
16);
|
|
pucEndpointName[16] = 0;
|
|
RtlCopyMemory(pucNetbiosName,
|
|
pTdiAddressNetbiosEx->NetbiosAddress.NetbiosName,
|
|
16);
|
|
pucNetbiosName[16] = 0;
|
|
|
|
DbgPrint("EndpointName = %s\n"
|
|
"NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_",
|
|
pucEndpointName);
|
|
|
|
switch (pTdiAddressNetbiosEx->NetbiosAddress.NetbiosNameType)
|
|
{
|
|
case TDI_ADDRESS_NETBIOS_TYPE_UNIQUE:
|
|
DbgPrint("UNIQUE\n");
|
|
break;
|
|
case TDI_ADDRESS_NETBIOS_TYPE_GROUP:
|
|
DbgPrint("GROUP\n");
|
|
break;
|
|
case TDI_ADDRESS_NETBIOS_TYPE_QUICK_UNIQUE:
|
|
DbgPrint("QUICK_UNIQUE\n");
|
|
break;
|
|
case TDI_ADDRESS_NETBIOS_TYPE_QUICK_GROUP:
|
|
DbgPrint("QUICK_GROUP\n");
|
|
break;
|
|
default:
|
|
DbgPrint("INVALID [0x%04x]\n",
|
|
pTdiAddressNetbiosEx->NetbiosAddress.NetbiosNameType);
|
|
break;
|
|
}
|
|
DbgPrint("NetbiosName = %s\n", pucNetbiosName);
|
|
}
|
|
break;
|
|
|
|
case TDI_ADDRESS_TYPE_IP6:
|
|
DbgPrint("IPv6\n");
|
|
fShowAddress = FALSE;
|
|
{
|
|
PTDI_ADDRESS_IP6 pTdiAddressIp6 = (PTDI_ADDRESS_IP6)pTaAddress->Address;
|
|
PUCHAR pucTemp = (PUCHAR)&pTdiAddressIp6->sin6_addr;
|
|
|
|
DbgPrint("SinPort6 = 0x%04x\n"
|
|
"FlowInfo = 0x%08x\n"
|
|
"ScopeId = 0x%08x\n",
|
|
pTdiAddressIp6->sin6_port,
|
|
pTdiAddressIp6->sin6_flowinfo,
|
|
pTdiAddressIp6->sin6_scope_id);
|
|
|
|
DbgPrint("In6_addr = %x%02x:%x%02x:%x%02x:%x%02x:",
|
|
pucTemp[0], pucTemp[1],
|
|
pucTemp[2], pucTemp[3],
|
|
pucTemp[4], pucTemp[5],
|
|
pucTemp[6], pucTemp[7]);
|
|
DbgPrint("%x%02x:%x%02x:%x%02x:%x%02x\n",
|
|
pucTemp[8], pucTemp[9],
|
|
pucTemp[10], pucTemp[11],
|
|
pucTemp[12], pucTemp[13],
|
|
pucTemp[14], pucTemp[15]);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DbgPrint("UNKNOWN [0x%08x]\n", pTaAddress->AddressType);
|
|
break;
|
|
}
|
|
|
|
if (fShowAddress)
|
|
{
|
|
PUCHAR pucTemp = pTaAddress->Address;
|
|
ULONG ulCount;
|
|
|
|
DbgPrint("AddressLength = %d\n"
|
|
"Address = ",
|
|
pTaAddress->AddressLength);
|
|
|
|
for (ulCount = 0; ulCount < pTaAddress->AddressLength; ulCount++)
|
|
{
|
|
DbgPrint("%02x ", *pucTemp);
|
|
pucTemp++;
|
|
}
|
|
|
|
DbgPrint("\n");
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
BrdgTdiIpv4StringToAddress(
|
|
IN LPWSTR String,
|
|
IN BOOLEAN Strict,
|
|
OUT LPWSTR *Terminator,
|
|
OUT in_addr *Addr)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function interprets the character string specified by the cp
|
|
parameter. This string represents a numeric Internet address
|
|
expressed in the Internet standard ".'' notation. The value
|
|
returned is a number suitable for use as an Internet address. All
|
|
Internet addresses are returned in network order (bytes ordered from
|
|
left to right).
|
|
|
|
Internet Addresses
|
|
|
|
Values specified using the "." notation take one of the following
|
|
forms:
|
|
|
|
a.b.c.d a.b.c a.b a
|
|
|
|
When four parts are specified, each is interpreted as a byte of data
|
|
and assigned, from left to right, to the four bytes of an Internet
|
|
address. Note that when an Internet address is viewed as a 32-bit
|
|
integer quantity on the Intel architecture, the bytes referred to
|
|
above appear as "d.c.b.a''. That is, the bytes on an Intel
|
|
processor are ordered from right to left.
|
|
|
|
Note: The following notations are only used by Berkeley, and nowhere
|
|
else on the Internet. In the interests of compatibility with their
|
|
software, they are supported as specified.
|
|
|
|
When a three part address is specified, the last part is interpreted
|
|
as a 16-bit quantity and placed in the right most two bytes of the
|
|
network address. This makes the three part address format
|
|
convenient for specifying Class B network addresses as
|
|
"128.net.host''.
|
|
|
|
When a two part address is specified, the last part is interpreted
|
|
as a 24-bit quantity and placed in the right most three bytes of the
|
|
network address. This makes the two part address format convenient
|
|
for specifying Class A network addresses as "net.host''.
|
|
|
|
When only one part is given, the value is stored directly in the
|
|
network address without any byte rearrangement.
|
|
|
|
Arguments:
|
|
|
|
String - A character string representing a number expressed in the
|
|
Internet standard "." notation.
|
|
|
|
Terminator - Receives a pointer to the character that terminated
|
|
the conversion.
|
|
|
|
Addr - Receives a pointer to the structure to fill in with
|
|
a suitable binary representation of the Internet address given.
|
|
|
|
Return Value:
|
|
|
|
TRUE if parsing was successful. FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG val, n;
|
|
LONG base;
|
|
WCHAR c;
|
|
ULONG parts[4], *pp = parts;
|
|
BOOLEAN sawDigit;
|
|
|
|
again:
|
|
//
|
|
// We must see at least one digit for address to be valid.
|
|
//
|
|
sawDigit = FALSE;
|
|
|
|
//
|
|
// Collect number up to ``.''.
|
|
// Values are specified as for C:
|
|
// 0x=hex, 0=octal, other=decimal.
|
|
//
|
|
val = 0; base = 10;
|
|
if (*String == L'0')
|
|
{
|
|
String++;
|
|
if (IsDigit(*String))
|
|
{
|
|
base = 8;
|
|
} else if (*String == L'x' || *String == L'X')
|
|
{
|
|
base = 16;
|
|
String++;
|
|
} else
|
|
{
|
|
//
|
|
// It is still decimal but we saw the digit
|
|
// and it was 0.
|
|
//
|
|
sawDigit = TRUE;
|
|
}
|
|
}
|
|
if (Strict && (base != 10))
|
|
{
|
|
*Terminator = String;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
do
|
|
{
|
|
ULONG newVal;
|
|
|
|
c = *String;
|
|
|
|
if (IsDigit(c) && ((c - L'0') < base)) {
|
|
newVal = (val * base) + (c - L'0');
|
|
} else if ((base == 16) && IsXDigit(c)) {
|
|
newVal = (val << 4) + (c + 10 - (IsLower(c) ? L'a' : L'A'));
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Protect from overflow
|
|
//
|
|
if (newVal < val) {
|
|
*Terminator = String;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
String++;
|
|
sawDigit = TRUE;
|
|
val = newVal;
|
|
} while (c != L'\0');
|
|
|
|
if (*String == L'.')
|
|
{
|
|
//
|
|
// Internet format:
|
|
// a.b.c.d
|
|
// a.b.c (with c treated as 16-bits)
|
|
// a.b (with b treated as 24 bits)
|
|
//
|
|
if (pp >= parts + 3)
|
|
{
|
|
*Terminator = String;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
*pp++ = val, String++;
|
|
|
|
//
|
|
// Check if we saw at least one digit.
|
|
//
|
|
if (!sawDigit) {
|
|
*Terminator = String;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
goto again;
|
|
} while (c != L'\0');
|
|
|
|
//
|
|
// Check if we saw at least one digit.
|
|
//
|
|
if (!sawDigit) {
|
|
*Terminator = String;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
*pp++ = val;
|
|
|
|
//
|
|
// Concoct the address according to
|
|
// the number of parts specified.
|
|
//
|
|
n = (ULONG)(pp - parts);
|
|
if (Strict && (n != 4)) {
|
|
*Terminator = String;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
switch ((int) n) {
|
|
|
|
case 1: /* a -- 32 bits */
|
|
val = parts[0];
|
|
break;
|
|
|
|
case 2: /* a.b -- 8.24 bits */
|
|
if ((parts[0] > 0xff) || (parts[1] > 0xffffff)) {
|
|
*Terminator = String;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
val = (parts[0] << 24) | (parts[1] & 0xffffff);
|
|
break;
|
|
|
|
case 3: /* a.b.c -- 8.8.16 bits */
|
|
if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
|
|
(parts[2] > 0xffff)) {
|
|
*Terminator = String;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
|
|
(parts[2] & 0xffff);
|
|
break;
|
|
|
|
case 4: /* a.b.c.d -- 8.8.8.8 bits */
|
|
if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
|
|
(parts[2] > 0xff) || (parts[3] > 0xff)) {
|
|
*Terminator = String;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
|
|
((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
|
|
break;
|
|
|
|
default:
|
|
*Terminator = String;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
val = RtlUlongByteSwap(val);
|
|
*Terminator = String;
|
|
Addr->s_addr = val;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|