|
|
/*++
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; } }
|