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.
691 lines
16 KiB
691 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 2001-2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
common.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the shipworm interface to the IPv6 Helper Service.
|
|
|
|
Author:
|
|
|
|
Mohit Talwar (mohitt) Wed Nov 07 11:27:01 2001
|
|
|
|
Environment:
|
|
|
|
User mode only.
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
ULONG ShipwormClientRefreshInterval = SHIPWORM_REFRESH_INTERVAL;
|
|
BOOL ShipwormClientEnabled = (SHIPWORM_DEFAULT_TYPE == SHIPWORM_CLIENT);
|
|
BOOL ShipwormServerEnabled = (SHIPWORM_DEFAULT_TYPE == SHIPWORM_SERVER);
|
|
WCHAR ShipwormServerName[NI_MAXHOST] = SHIPWORM_SERVER_NAME;
|
|
WCHAR ShipwormServiceName[NI_MAXSERV] = SHIPWORM_SERVICE_NAME;
|
|
|
|
CONST IN6_ADDR ShipwormIpv6ServicePrefix = SHIPWORM_SERVICE_PREFIX;
|
|
|
|
#define DEVICE_PREFIX L"\\Device\\"
|
|
|
|
LPGUID ShipwormWmiEvent[] = {
|
|
(LPGUID) &GUID_NDIS_NOTIFY_ADAPTER_ARRIVAL,
|
|
(LPGUID) &GUID_NDIS_NOTIFY_ADAPTER_REMOVAL,
|
|
};
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
ShipwormWmiEventNotification(
|
|
IN PWNODE_HEADER Event,
|
|
IN UINT_PTR Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process a WMI event (Adapter arrival or removal).
|
|
|
|
Arguments:
|
|
|
|
Event - Supplies the event specific information.
|
|
|
|
Context - Supplies the context
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Caller LOCK: API.
|
|
|
|
--*/
|
|
{
|
|
PWNODE_SINGLE_INSTANCE Instance = (PWNODE_SINGLE_INSTANCE) Event;
|
|
USHORT AdapterNameLength;
|
|
WCHAR AdapterName[MAX_ADAPTER_NAME_LENGTH], *AdapterGuid;
|
|
PSHIPWORM_IO Io = NULL;
|
|
|
|
if (Instance == NULL) {
|
|
return;
|
|
}
|
|
|
|
ENTER_API();
|
|
|
|
TraceEnter("ShipwormWmiEventNotification");
|
|
|
|
//
|
|
// WNODE_SINGLE_INSTANCE is organized thus...
|
|
// +-----------------------------------------------------------+
|
|
// |<--- DataBlockOffset --->| AdapterNameLength | AdapterName |
|
|
// +-----------------------------------------------------------+
|
|
//
|
|
// AdapterName is defined as "\DEVICE\"AdapterGuid
|
|
//
|
|
AdapterNameLength =
|
|
*((PUSHORT) (((PUCHAR) Instance) + Instance->DataBlockOffset));
|
|
RtlCopyMemory(
|
|
AdapterName,
|
|
((PUCHAR) Instance) + Instance->DataBlockOffset + sizeof(USHORT),
|
|
AdapterNameLength);
|
|
AdapterName[AdapterNameLength] = L'\0';
|
|
AdapterGuid = AdapterName + wcslen(DEVICE_PREFIX);
|
|
Trace1(ANY, L"ShipwormAdapter: %s", AdapterGuid);
|
|
|
|
|
|
if (memcmp(
|
|
&(Event->Guid), &GUID_NDIS_NOTIFY_ADAPTER_ARRIVAL, sizeof(GUID)) == 0) {
|
|
Trace0(ANY, L"GUID_NDIS_NOTIFY_ADAPTER_ARRIVAL");
|
|
//
|
|
// Adapter arrival (perhaps TUN).
|
|
// Attempt to start the service (if it is not already running).
|
|
//
|
|
ShipwormStart();
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
if (memcmp(
|
|
&(Event->Guid), &GUID_NDIS_NOTIFY_ADAPTER_REMOVAL, sizeof(GUID)) == 0)
|
|
{
|
|
|
|
Trace0(ANY, L"GUID_NDIS_NOTIFY_ADAPTER_REMOVAL");
|
|
if (ShipwormClient.State != SHIPWORM_STATE_OFFLINE) {
|
|
Io = &(ShipwormClient.Io);
|
|
}
|
|
|
|
if (ShipwormServer.State != SHIPWORM_STATE_OFFLINE) {
|
|
Io = &(ShipwormServer.Io);
|
|
}
|
|
|
|
if ((Io != NULL) &&
|
|
(_wcsicmp(Io->TunnelInterface, AdapterGuid) == 0)) {
|
|
//
|
|
// TUN adapter removal.
|
|
// Stop the service if it is running.
|
|
//
|
|
ShipwormStop();
|
|
|
|
|
|
}
|
|
}
|
|
|
|
LEAVE_API();
|
|
}
|
|
|
|
|
|
DWORD
|
|
__inline
|
|
ShipwormEnableWmiEvent(
|
|
IN LPGUID EventGuid,
|
|
IN BOOLEAN Enable
|
|
)
|
|
{
|
|
return WmiNotificationRegistrationW(
|
|
EventGuid, // Event Type.
|
|
Enable, // Enable or Disable.
|
|
ShipwormWmiEventNotification, // Callback.
|
|
0, // Context.
|
|
NOTIFICATION_CALLBACK_DIRECT); // Notification Flags.
|
|
}
|
|
|
|
|
|
VOID
|
|
__inline
|
|
ShipwormDeregisterWmiEventNotification(
|
|
VOID
|
|
)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < (sizeof(ShipwormWmiEvent) / sizeof(LPGUID)); i++) {
|
|
(VOID) ShipwormEnableWmiEvent(ShipwormWmiEvent[i], FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
__inline
|
|
ShipwormRegisterWmiEventNotification(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD Error;
|
|
int i;
|
|
|
|
for (i = 0; i < (sizeof(ShipwormWmiEvent) / sizeof(LPGUID)); i++) {
|
|
Error = ShipwormEnableWmiEvent(ShipwormWmiEvent[i], TRUE);
|
|
if (Error != NO_ERROR) {
|
|
goto Bail;
|
|
}
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
Bail:
|
|
ShipwormDeregisterWmiEventNotification();
|
|
return Error;
|
|
}
|
|
|
|
|
|
ICMPv6Header *
|
|
ShipwormParseIpv6Headers (
|
|
IN PUCHAR Buffer,
|
|
IN ULONG Bytes
|
|
)
|
|
{
|
|
UCHAR NextHeader = IP_PROTOCOL_V6;
|
|
ULONG Length;
|
|
|
|
//
|
|
// Parse up until the ICMPv6 header.
|
|
//
|
|
while (TRUE) {
|
|
switch (NextHeader) {
|
|
case IP_PROTOCOL_V6:
|
|
if (Bytes < sizeof(IP6_HDR)) {
|
|
return NULL;
|
|
}
|
|
NextHeader = ((PIP6_HDR) Buffer)->ip6_nxt;
|
|
Length = sizeof(IP6_HDR);
|
|
break;
|
|
|
|
case IP_PROTOCOL_HOP_BY_HOP:
|
|
case IP_PROTOCOL_DEST_OPTS:
|
|
case IP_PROTOCOL_ROUTING:
|
|
if (Bytes < sizeof(ExtensionHeader)) {
|
|
return NULL;
|
|
}
|
|
NextHeader = ((ExtensionHeader *) Buffer)->NextHeader;
|
|
Length = ((ExtensionHeader *) Buffer)->HeaderExtLength * 8 + 8;
|
|
break;
|
|
|
|
case IP_PROTOCOL_FRAGMENT:
|
|
if (Bytes < sizeof(FragmentHeader)) {
|
|
return NULL;
|
|
}
|
|
NextHeader = ((FragmentHeader *) Buffer)->NextHeader;
|
|
Length = sizeof(FragmentHeader);
|
|
break;
|
|
|
|
case IP_PROTOCOL_AH:
|
|
if (Bytes < sizeof(AHHeader)) {
|
|
return NULL;
|
|
}
|
|
NextHeader = ((AHHeader *) Buffer)->NextHeader;
|
|
Length = sizeof(AHHeader) +
|
|
((AHHeader *) Buffer)->PayloadLen * 4 + 8;
|
|
break;
|
|
|
|
case IP_PROTOCOL_ICMPv6:
|
|
if (Bytes < sizeof(ICMPv6Header)) {
|
|
return NULL;
|
|
}
|
|
return (ICMPv6Header *) Buffer;
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
|
|
if (Bytes < Length) {
|
|
return NULL;
|
|
}
|
|
Buffer += Length;
|
|
Bytes -= Length;
|
|
}
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
|
|
__inline
|
|
VOID
|
|
ShipwormStart(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Both client and server should not be enabled on the same node.
|
|
//
|
|
ASSERT(!ShipwormClientEnabled || !ShipwormServerEnabled);
|
|
|
|
if (ShipwormClientEnabled) {
|
|
//
|
|
// The service might already be running, but that's alright.
|
|
//
|
|
ShipwormStartClient();
|
|
}
|
|
|
|
if (ShipwormServerEnabled) {
|
|
//
|
|
// The service might already be running, but that's alright.
|
|
//
|
|
ShipwormStartServer();
|
|
}
|
|
}
|
|
|
|
|
|
__inline
|
|
VOID
|
|
ShipwormStop(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Both client and server should not be enabled on the same node.
|
|
//
|
|
ASSERT(!ShipwormClientEnabled || !ShipwormServerEnabled);
|
|
|
|
if (ShipwormClientEnabled) {
|
|
//
|
|
// The service might not be running, but that's alright.
|
|
//
|
|
ShipwormStopClient();
|
|
}
|
|
|
|
if (ShipwormServerEnabled) {
|
|
//
|
|
// The service might not be running, but that's alright.
|
|
//
|
|
ShipwormStopServer();
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
ShipwormInitialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the shipworm client and server and attempts to start them.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or failure code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
BOOL ClientInitialized = FALSE, ServerInitialized = FALSE;
|
|
|
|
Error = ShipwormRegisterWmiEventNotification();
|
|
if (Error != NO_ERROR) {
|
|
return Error;
|
|
}
|
|
|
|
Error = ShipwormInitializeClient();
|
|
if (Error != NO_ERROR) {
|
|
goto Bail;
|
|
}
|
|
ClientInitialized = TRUE;
|
|
|
|
|
|
Error = ShipwormInitializeServer();
|
|
if (Error != NO_ERROR) {
|
|
goto Bail;
|
|
}
|
|
ServerInitialized = TRUE;
|
|
|
|
ShipwormStart();
|
|
|
|
return NO_ERROR;
|
|
|
|
Bail:
|
|
ShipwormDeregisterWmiEventNotification();
|
|
|
|
if (ClientInitialized) {
|
|
ShipwormUninitializeClient();
|
|
}
|
|
|
|
if (ServerInitialized) {
|
|
ShipwormUninitializeServer();
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
|
|
VOID
|
|
ShipwormUninitialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Uninitializes the shipworm client and server.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ShipwormUninitializeClient();
|
|
ShipwormUninitializeServer();
|
|
ShipwormDeregisterWmiEventNotification();
|
|
}
|
|
|
|
|
|
VOID
|
|
ShipwormAddressChangeNotification(
|
|
IN BOOL Delete,
|
|
IN IN_ADDR Address
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process an address deletion or addition request.
|
|
|
|
Arguments:
|
|
|
|
Delete - Supplies a boolean. TRUE if the address was deleted, FALSE o/w.
|
|
|
|
Address - Supplies the IPv4 address that was deleted or added.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Caller LOCK: API.
|
|
|
|
--*/
|
|
{
|
|
if (Delete) {
|
|
//
|
|
// Both client and server should not be running on the same node.
|
|
//
|
|
ASSERT((ShipwormClient.State == SHIPWORM_STATE_OFFLINE) ||
|
|
(ShipwormServer.State == SHIPWORM_STATE_OFFLINE));
|
|
|
|
if (ShipwormClient.State != SHIPWORM_STATE_OFFLINE) {
|
|
ShipwormClientAddressDeletionNotification(Address);
|
|
}
|
|
|
|
if (ShipwormServer.State != SHIPWORM_STATE_OFFLINE) {
|
|
ShipwormServerAddressDeletionNotification(Address);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Address addition.
|
|
// Attempt to start the service (if it is not already running).
|
|
//
|
|
ShipwormStart();
|
|
}
|
|
|
|
|
|
VOID
|
|
ShipwormConfigurationChangeNotification(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process an configuration change request.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Caller LOCK: API.
|
|
|
|
--*/
|
|
{
|
|
HKEY Key = INVALID_HANDLE_VALUE;
|
|
SHIPWORM_TYPE Type;
|
|
BOOL EnableClient, EnableServer;
|
|
ULONG RefreshInterval;
|
|
WCHAR OldServerName[NI_MAXHOST];
|
|
WCHAR OldServiceName[NI_MAXSERV];
|
|
BOOL IoStateChange = FALSE;
|
|
|
|
(VOID) RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE, KEY_SHIPWORM, 0, KEY_QUERY_VALUE, &Key);
|
|
//
|
|
// Continue despite errors, reverting to default values.
|
|
//
|
|
|
|
//
|
|
// Get the new configuration parameters.
|
|
//
|
|
RefreshInterval = GetInteger(
|
|
Key, KEY_SHIPWORM_REFRESH_INTERVAL, SHIPWORM_REFRESH_INTERVAL);
|
|
if (RefreshInterval == 0) {
|
|
//
|
|
// Invalid value. Revert to default.
|
|
//
|
|
RefreshInterval = SHIPWORM_REFRESH_INTERVAL;
|
|
}
|
|
ShipwormClientRefreshInterval = RefreshInterval;
|
|
|
|
Type = GetInteger(Key, KEY_SHIPWORM_TYPE, SHIPWORM_DEFAULT_TYPE);
|
|
if ((Type == SHIPWORM_DEFAULT) || (Type >= SHIPWORM_MAXIMUM)) {
|
|
//
|
|
// Invalid value. Revert to default.
|
|
//
|
|
Type = SHIPWORM_DEFAULT_TYPE;
|
|
}
|
|
EnableClient = (Type == SHIPWORM_CLIENT);
|
|
EnableServer = (Type == SHIPWORM_SERVER);
|
|
|
|
wcscpy(OldServerName, ShipwormServerName);
|
|
GetString(
|
|
Key,
|
|
KEY_SHIPWORM_SERVER_NAME,
|
|
ShipwormServerName,
|
|
NI_MAXHOST,
|
|
SHIPWORM_SERVER_NAME);
|
|
if (_wcsicmp(ShipwormServerName, OldServerName) != 0) {
|
|
IoStateChange = TRUE;
|
|
}
|
|
|
|
wcscpy(OldServiceName, ShipwormServiceName);
|
|
GetString(
|
|
Key,
|
|
KEY_SHIPWORM_SERVICE_NAME,
|
|
ShipwormServiceName,
|
|
NI_MAXSERV,
|
|
SHIPWORM_SERVICE_NAME);
|
|
if (_wcsicmp(ShipwormServiceName, OldServiceName) != 0) {
|
|
IoStateChange = TRUE;
|
|
}
|
|
|
|
RegCloseKey(Key);
|
|
|
|
//
|
|
// Both client and server should not be enabled on the same node.
|
|
//
|
|
ASSERT(!ShipwormClientEnabled || !ShipwormServerEnabled);
|
|
|
|
//
|
|
// Stop / Start / Reconfigure.
|
|
//
|
|
if (!EnableClient && ShipwormClientEnabled) {
|
|
ShipwormClientEnabled = FALSE;
|
|
ShipwormStopClient();
|
|
}
|
|
|
|
if (!EnableServer && ShipwormServerEnabled) {
|
|
ShipwormServerEnabled = FALSE;
|
|
ShipwormStopServer();
|
|
}
|
|
|
|
if (EnableClient) {
|
|
if (ShipwormClient.State != SHIPWORM_STATE_OFFLINE) {
|
|
if (IoStateChange) {
|
|
//
|
|
// Refresh I/O state.
|
|
//
|
|
ShipwormClientAddressDeletionNotification(
|
|
ShipwormClient.Io.SourceAddress.sin_addr);
|
|
}
|
|
} else {
|
|
ShipwormClientEnabled = TRUE;
|
|
ShipwormStartClient();
|
|
}
|
|
}
|
|
|
|
if (EnableServer) {
|
|
if (ShipwormServer.State != SHIPWORM_STATE_OFFLINE) {
|
|
if (IoStateChange) {
|
|
//
|
|
// Refresh I/O state.
|
|
//
|
|
ShipwormServerAddressDeletionNotification(
|
|
ShipwormServer.Io.SourceAddress.sin_addr);
|
|
}
|
|
} else {
|
|
ShipwormServerEnabled = TRUE;
|
|
ShipwormStartServer();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ShipwormDeviceChangeNotification(
|
|
IN DWORD Type,
|
|
IN PVOID Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process an adapter arrival or removal request.
|
|
|
|
Arguments:
|
|
|
|
Type - Supplies the event type.
|
|
|
|
Data - Supplies the data associated with the event.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Caller LOCK: API.
|
|
|
|
--*/
|
|
{
|
|
DEV_BROADCAST_DEVICEINTERFACE *Adapter =
|
|
(DEV_BROADCAST_DEVICEINTERFACE *) Data;
|
|
PSHIPWORM_IO Io = NULL;
|
|
PWCHAR AdapterGuid;
|
|
|
|
TraceEnter("ShipwormDeviceChangeNotification");
|
|
|
|
switch(Type) {
|
|
case DBT_DEVICEARRIVAL:
|
|
Trace0(ANY, L"DeviceArrival");
|
|
break;
|
|
|
|
case DBT_DEVICEREMOVECOMPLETE:
|
|
Trace0(ANY, L"DeviceRemoveComplete");
|
|
break;
|
|
|
|
case DBT_DEVICEQUERYREMOVE:
|
|
Trace0(ANY, L"DeviceQueryRemove");
|
|
break;
|
|
|
|
case DBT_DEVICEQUERYREMOVEFAILED:
|
|
Trace0(ANY, L"DeviceQueryRemoveFailed");
|
|
break;
|
|
|
|
case DBT_DEVICEREMOVEPENDING:
|
|
Trace0(ANY, L"DeviceQueryRemovePending");
|
|
break;
|
|
|
|
case DBT_CUSTOMEVENT:
|
|
Trace0(ANY, L"DeviceCustomEvent");
|
|
break;
|
|
|
|
default:
|
|
Trace2(ANY, L"Device Type %u, %u", Type, Adapter->dbcc_devicetype);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Scan for the last occurance of the '{' character.
|
|
// The string beginning at that position is the adapter GUID.
|
|
//
|
|
if ((Adapter == NULL) ||
|
|
(Adapter->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE) ||
|
|
((AdapterGuid = wcsrchr(Adapter->dbcc_name, L'{')) == NULL)) {
|
|
return;
|
|
}
|
|
|
|
switch(Type) {
|
|
case DBT_DEVICEARRIVAL:
|
|
//
|
|
// Adapter arrival (perhaps TUN).
|
|
// Attempt to start the service (if it is not already running).
|
|
//
|
|
ShipwormStart();
|
|
return;
|
|
|
|
case DBT_DEVICEREMOVECOMPLETE:
|
|
if (ShipwormClient.State != SHIPWORM_STATE_OFFLINE) {
|
|
Io = &(ShipwormClient.Io);
|
|
}
|
|
|
|
if (ShipwormServer.State != SHIPWORM_STATE_OFFLINE) {
|
|
Io = &(ShipwormServer.Io);
|
|
}
|
|
|
|
if ((Io != NULL) &&
|
|
(_wcsicmp(Io->TunnelInterface, AdapterGuid) == 0)) {
|
|
//
|
|
// TUN adapter removal.
|
|
// Stop the service if it is running.
|
|
//
|
|
ShipwormStop();
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|