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

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;
}
}