1476 lines
43 KiB
C
1476 lines
43 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 2000-2000 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
PnP.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the various PnP handlers
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Mohammad Shabbir Alam (MAlam) 3-30-2000
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
|
|||
|
#include <ipinfo.h> // for IPInterfaceInfo
|
|||
|
#include "ntddip.h" // Needed for IP_INTERFACE_INFO
|
|||
|
#include <tcpinfo.h> // for AO_OPTION_xxx, TCPSocketOption
|
|||
|
|
|||
|
//******************* Pageable Routine Declarations ****************
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE, SetTdiHandlers)
|
|||
|
#endif
|
|||
|
//******************* Pageable Routine Declarations ****************
|
|||
|
|
|||
|
|
|||
|
HANDLE TdiClientHandle = NULL;
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
BOOLEAN
|
|||
|
SrcIsUs(
|
|||
|
tIPADDRESS IpAddress
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine determines if the IP address passed in is a
|
|||
|
local address
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN IpAddress -- IpAddress to verify
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if IpAddress is local, FALSE otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LIST_ENTRY *pEntry;
|
|||
|
LIST_ENTRY *pEntry2;
|
|||
|
PGMLockHandle OldIrq;
|
|||
|
tLOCAL_INTERFACE *pLocalInterface;
|
|||
|
tADDRESS_ON_INTERFACE *pLocalAddress;
|
|||
|
|
|||
|
PgmLock (&PgmDynamicConfig, OldIrq);
|
|||
|
|
|||
|
pEntry = &PgmDynamicConfig.LocalInterfacesList;
|
|||
|
while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.LocalInterfacesList)
|
|||
|
{
|
|||
|
pLocalInterface = CONTAINING_RECORD (pEntry, tLOCAL_INTERFACE, Linkage);
|
|||
|
pEntry2 = &pLocalInterface->Addresses;
|
|||
|
while ((pEntry2 = pEntry2->Flink) != &pLocalInterface->Addresses)
|
|||
|
{
|
|||
|
pLocalAddress = CONTAINING_RECORD (pEntry2, tADDRESS_ON_INTERFACE, Linkage);
|
|||
|
if (pLocalAddress->IpAddress == IpAddress)
|
|||
|
{
|
|||
|
PgmUnlock (&PgmDynamicConfig, OldIrq);
|
|||
|
return (TRUE);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
PgmUnlock (&PgmDynamicConfig, OldIrq);
|
|||
|
|
|||
|
return (FALSE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
GetIpInterfaceContextFromAddress(
|
|||
|
IN tIPADDRESS IpAddr,
|
|||
|
OUT ULONG *pIPInterfaceContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Given an IP address, this routine determines will return the
|
|||
|
Ip interface context that address is registered on
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN IpAddress -- IpAddress
|
|||
|
OUT IpInterfaceContext -- IpInterfaceContext for the IP address passed
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if IpAddress was matched to interface,
|
|||
|
STATUS_UNSUCCESSFUL otherwise
|
|||
|
|
|||
|
The DynamicConfig lock is held on entry and exit from this routine
|
|||
|
--*/
|
|||
|
{
|
|||
|
LIST_ENTRY *pEntry;
|
|||
|
LIST_ENTRY *pEntry2;
|
|||
|
tLOCAL_INTERFACE *pLocalInterface;
|
|||
|
tADDRESS_ON_INTERFACE *pLocalAddress;
|
|||
|
|
|||
|
ASSERT (IpAddr);
|
|||
|
|
|||
|
pEntry = &PgmDynamicConfig.LocalInterfacesList;
|
|||
|
while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.LocalInterfacesList)
|
|||
|
{
|
|||
|
pLocalInterface = CONTAINING_RECORD (pEntry, tLOCAL_INTERFACE, Linkage);
|
|||
|
pEntry2 = &pLocalInterface->Addresses;
|
|||
|
while ((pEntry2 = pEntry2->Flink) != &pLocalInterface->Addresses)
|
|||
|
{
|
|||
|
pLocalAddress = CONTAINING_RECORD (pEntry2, tADDRESS_ON_INTERFACE, Linkage);
|
|||
|
if (pLocalAddress->IpAddress == IpAddr)
|
|||
|
{
|
|||
|
*pIPInterfaceContext = pLocalInterface->IpInterfaceContext;
|
|||
|
return (STATUS_SUCCESS);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return (STATUS_UNSUCCESSFUL);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
GetIpInterfaceContextFromDeviceName(
|
|||
|
IN tIPADDRESS NetIpAddr,
|
|||
|
IN PUNICODE_STRING pucBindString,
|
|||
|
OUT ULONG *pIPInterfaceContext,
|
|||
|
IN ULONG BufferLength,
|
|||
|
OUT UCHAR *pBuffer,
|
|||
|
IN BOOLEAN fGetInterfaceInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Given a Unicode device name string, this routine will query Ip
|
|||
|
and return the IpInterfaceContext for that device
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN NetIpAddr -- IpAddress on Device
|
|||
|
IN pucBindString -- Pointer to unicode device name string
|
|||
|
OUT IpInterfaceContext -- IpInterfaceContext for the device name
|
|||
|
IN BufferLength -- Length of Output buffer passed
|
|||
|
OUT pBuffer -- Output buffer passed for Interface properties
|
|||
|
IN fGetInterfaceInfo -- Whether to return Interface properties or not
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if IpInterfaceContext was found, and properties
|
|||
|
successfully queried, STATUS_UNSUCCESSFUL otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LONG i;
|
|||
|
NTSTATUS status;
|
|||
|
PVOID *pIPInfo;
|
|||
|
PIP_INTERFACE_INFO pIPIfInfo;
|
|||
|
UNICODE_STRING ucDeviceName;
|
|||
|
ULONG BufferLen = 2 * sizeof(IP_ADAPTER_INDEX_MAP); // assume
|
|||
|
|
|||
|
status = PgmProcessIPRequest (IOCTL_IP_INTERFACE_INFO,
|
|||
|
NULL, // No Input buffer
|
|||
|
0,
|
|||
|
&pIPIfInfo,
|
|||
|
&BufferLen);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_PNP, "GetInterfaceContext",
|
|||
|
"PgmProcessIPRequest returned status=<%x> for IOCTL_IP_INTERFACE_INFO, pDevice=<%wZ>!\n",
|
|||
|
status, pucBindString);
|
|||
|
|
|||
|
return (status);
|
|||
|
}
|
|||
|
|
|||
|
status = STATUS_UNSUCCESSFUL;
|
|||
|
for (i=0; i < pIPIfInfo->NumAdapters; i++)
|
|||
|
{
|
|||
|
ucDeviceName.Buffer = pIPIfInfo->Adapter[i].Name;
|
|||
|
ucDeviceName.Length = sizeof (WCHAR) * wcslen (pIPIfInfo->Adapter[i].Name);
|
|||
|
ucDeviceName.MaximumLength = ucDeviceName.Length + sizeof (WCHAR);
|
|||
|
|
|||
|
PgmLog (PGM_LOG_INFORM_PATH, DBG_PNP, "GetInterfaceContext",
|
|||
|
"[%d/%d]\t<%wZ>\n",
|
|||
|
i+1, pIPIfInfo->NumAdapters, &ucDeviceName);
|
|||
|
|
|||
|
if (RtlCompareUnicodeString (&ucDeviceName, pucBindString, TRUE) == 0)
|
|||
|
{
|
|||
|
*pIPInterfaceContext = pIPIfInfo->Adapter[i].Index;
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
PgmFreeMem (pIPIfInfo);
|
|||
|
|
|||
|
if (!NT_SUCCESS (status))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_PNP, "GetInterfaceContext",
|
|||
|
"Could not find IPInterfaceContext for Device=<%wZ>\n", pucBindString);
|
|||
|
|
|||
|
return (status);
|
|||
|
}
|
|||
|
|
|||
|
status = PgmQueryTcpInfo (pgPgmDevice->hControl,
|
|||
|
IP_INTFC_INFO_ID,
|
|||
|
&NetIpAddr,
|
|||
|
sizeof (tIPADDRESS),
|
|||
|
pBuffer,
|
|||
|
BufferLength);
|
|||
|
|
|||
|
if (!NT_SUCCESS (status))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_PNP, "GetInterfaceContext",
|
|||
|
"PgmQueryTcpInfo returned <%x>\n", status);
|
|||
|
|
|||
|
return (status);
|
|||
|
}
|
|||
|
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "GetInterfaceContext",
|
|||
|
"IPInterfaceContext=<%x> for Device=<%wZ>\n",
|
|||
|
*pIPInterfaceContext, pucBindString);
|
|||
|
|
|||
|
return (status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
|
|||
|
ULONG
|
|||
|
StopListeningOnInterface(
|
|||
|
#ifdef IP_FIX
|
|||
|
IN ULONG IpInterfaceContext,
|
|||
|
#else
|
|||
|
IN tIPADDRESS IpAddress, // Host format
|
|||
|
#endif // IP_FIX
|
|||
|
IN PGMLockHandle *pOldIrqDynamicConfig
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Given an IPInterfaceContext, this routine traverses the list of
|
|||
|
all Receivers, and if any are determined to be listening on that
|
|||
|
interface, stops them from listening on all the addresses on this
|
|||
|
interface. In the case that the listener is part of an active
|
|||
|
session, the routine will also change the state of the Receiver
|
|||
|
to start listening on all interfaces
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN IpInterfaceContext -- IpInterfaceContext to stop listening on
|
|||
|
IN pOldIrqDynamicConfig-- OldIrq for DynamicConfig lock held
|
|||
|
|
|||
|
The DynamicConfig lock is held on entry and exit from this routine
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Number of receivers found listening on this interface
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
tRECEIVE_SESSION *pReceive;
|
|||
|
tADDRESS_CONTEXT *pAddress;
|
|||
|
LIST_ENTRY *pEntry;
|
|||
|
LIST_ENTRY *pEntry2;
|
|||
|
PGMLockHandle OldIrq1, OldIrq2;
|
|||
|
USHORT i;
|
|||
|
tMCAST_INFO MCastInfo;
|
|||
|
ULONG NumDisconnected = 0;
|
|||
|
tADDRESS_CONTEXT *pAddressToDeref = NULL;
|
|||
|
|
|||
|
#ifdef IP_FIX
|
|||
|
MCastInfo.MCastInIf = IpInterfaceContext;
|
|||
|
#else
|
|||
|
MCastInfo.MCastInIf = htonl (IpAddress);
|
|||
|
#endif // IP_FIX
|
|||
|
|
|||
|
pEntry = &PgmDynamicConfig.ReceiverAddressHead;
|
|||
|
while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.ReceiverAddressHead)
|
|||
|
{
|
|||
|
pAddress = CONTAINING_RECORD (pEntry, tADDRESS_CONTEXT, Linkage);
|
|||
|
PgmLock (pAddress, OldIrq1);
|
|||
|
|
|||
|
if (!(pAddress->Flags & PGM_ADDRESS_LISTEN_ON_ALL_INTERFACES))
|
|||
|
{
|
|||
|
//
|
|||
|
// If the app had specified interfaces to listen on,
|
|||
|
// then don't manage interfaces!
|
|||
|
//
|
|||
|
PgmUnlock (pAddress, OldIrq1);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// See if this address was listening on this interface
|
|||
|
//
|
|||
|
for (i=0; i<pAddress->NumReceiveInterfaces; i++)
|
|||
|
{
|
|||
|
#ifdef IP_FIX
|
|||
|
if (pAddress->ReceiverInterfaceList[i] == IpInterfaceContext)
|
|||
|
#else
|
|||
|
if (pAddress->ReceiverInterfaceList[i] == IpAddress)
|
|||
|
#endif // IP_FIX
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (i >= pAddress->NumReceiveInterfaces)
|
|||
|
{
|
|||
|
PgmUnlock (pAddress, OldIrq1);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remove this Interface from the list of listening interfaces
|
|||
|
//
|
|||
|
pAddress->NumReceiveInterfaces--;
|
|||
|
while (i < pAddress->NumReceiveInterfaces)
|
|||
|
{
|
|||
|
pAddress->ReceiverInterfaceList[i] = pAddress->ReceiverInterfaceList[i+1];
|
|||
|
i++;
|
|||
|
}
|
|||
|
|
|||
|
PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_STOP_LISTENING, TRUE);
|
|||
|
|
|||
|
//
|
|||
|
// If this were the only interface we were listening on
|
|||
|
// for an active session (or waiting for a session), ensure
|
|||
|
// that we go back into listening mode!
|
|||
|
//
|
|||
|
if ((pAddress->Flags & PGM_ADDRESS_LISTEN_ON_ALL_INTERFACES) &&
|
|||
|
(!pAddress->NumReceiveInterfaces))
|
|||
|
{
|
|||
|
pAddress->Flags |= PGM_ADDRESS_WAITING_FOR_NEW_INTERFACE;
|
|||
|
|
|||
|
if (!IsListEmpty (&PgmDynamicConfig.LocalInterfacesList))
|
|||
|
{
|
|||
|
status = ListenOnAllInterfaces (pAddress, pOldIrqDynamicConfig, &OldIrq1);
|
|||
|
|
|||
|
if (NT_SUCCESS (status))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_ADDRESS, "StopListeningOnInterface",
|
|||
|
"ListenOnAllInterfaces for pAddress=<%x> succeeded\n", pAddress);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "StopListeningOnInterface",
|
|||
|
"ListenOnAllInterfaces for pAddress=<%x> returned <%x>\n",
|
|||
|
pAddress, status);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
PgmUnlock (pAddress, OldIrq1);
|
|||
|
PgmUnlock (&PgmDynamicConfig, *pOldIrqDynamicConfig);
|
|||
|
|
|||
|
if (pAddressToDeref)
|
|||
|
{
|
|||
|
PGM_DEREFERENCE_ADDRESS (pAddressToDeref, REF_ADDRESS_STOP_LISTENING);
|
|||
|
}
|
|||
|
pAddressToDeref = pAddress;
|
|||
|
|
|||
|
//
|
|||
|
// So, stop listening on this interface
|
|||
|
//
|
|||
|
MCastInfo.MCastIpAddr = htonl (pAddress->ReceiverMCastAddr);
|
|||
|
#ifdef IP_FIX
|
|||
|
status = PgmSetTcpInfo (pAddress->FileHandle,
|
|||
|
AO_OPTION_INDEX_DEL_MCAST,
|
|||
|
&MCastInfo,
|
|||
|
sizeof (tMCAST_INFO));
|
|||
|
#else
|
|||
|
status = PgmSetTcpInfo (pAddress->FileHandle,
|
|||
|
AO_OPTION_DEL_MCAST,
|
|||
|
&MCastInfo,
|
|||
|
sizeof (tMCAST_INFO));
|
|||
|
#endif // IP_FIX
|
|||
|
|
|||
|
if (NT_SUCCESS (status))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "\tStopListeningOnInterface",
|
|||
|
"Stopped pAddress=<%x> from listening on Interface=<%x>\n",
|
|||
|
pAddress, MCastInfo.MCastInIf);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// We failed to stop listening on this interface -- don't so anything!
|
|||
|
//
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_PNP, "\tStopListeningOnInterface",
|
|||
|
"AO_OPTION_INDEX_DEL_MCAST for If=<%x> on Address=<%x> returned <%x>\n",
|
|||
|
MCastInfo.MCastInIf, pAddress, status);
|
|||
|
}
|
|||
|
|
|||
|
PgmLock (&PgmDynamicConfig, *pOldIrqDynamicConfig);
|
|||
|
}
|
|||
|
|
|||
|
if (pAddressToDeref)
|
|||
|
{
|
|||
|
PGM_DEREFERENCE_ADDRESS (pAddressToDeref, REF_ADDRESS_STOP_LISTENING);
|
|||
|
}
|
|||
|
|
|||
|
return (NumDisconnected);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
|
|||
|
VOID
|
|||
|
StopListeningOnAllInterfacesExcept(
|
|||
|
IN tADDRESS_CONTEXT *pAddress,
|
|||
|
IN PVOID Data1,
|
|||
|
IN PVOID Unused
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Given an Address Context and IPInterfaceContext (Data1), this routine
|
|||
|
stops the Address from listening on all the addresses except on this
|
|||
|
interface.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN pAddress -- Address Context
|
|||
|
IN Data1 -- IpInterfaceContext to stop listening on
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PGMLockHandle OldIrq;
|
|||
|
tMCAST_INFO MCastInfo;
|
|||
|
ULONG InterfacesToStop[MAX_RECEIVE_INTERFACES+1];
|
|||
|
USHORT NumInterfaces, i;
|
|||
|
ULONG InterfaceToKeep = PtrToUlong (Data1);
|
|||
|
#ifndef IP_FIX
|
|||
|
PGMLockHandle OldIrq0;
|
|||
|
LIST_ENTRY *pEntry;
|
|||
|
tLOCAL_INTERFACE *pLocalInterface;
|
|||
|
tADDRESS_ON_INTERFACE *pLocalAddress;
|
|||
|
USHORT j;
|
|||
|
#endif // !IP_FIX
|
|||
|
|
|||
|
PgmLock (&PgmDynamicConfig, OldIrq0);
|
|||
|
PgmLock (pAddress, OldIrq);
|
|||
|
|
|||
|
//
|
|||
|
// pAddress must be referenced before entering this routine
|
|||
|
//
|
|||
|
if (!(PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS)) ||
|
|||
|
(pAddress->Flags & PGM_ADDRESS_WAITING_FOR_NEW_INTERFACE))
|
|||
|
{
|
|||
|
//
|
|||
|
// Out state has changed -- deref and return immediately
|
|||
|
//
|
|||
|
PgmUnlock (pAddress, OldIrq);
|
|||
|
PgmUnlock (&PgmDynamicConfig, OldIrq0);
|
|||
|
|
|||
|
PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_STOP_LISTENING);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef IP_FIX
|
|||
|
//
|
|||
|
// If this is the only interface we are listening on,
|
|||
|
// return success
|
|||
|
//
|
|||
|
if ((pAddress->NumReceiveInterfaces == 1) &&
|
|||
|
(pAddress->ReceiverInterfaceList[0] == InterfaceToKeep))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "StopListeningOnAllInterfacesExcept",
|
|||
|
"pAddress=<%x> is only listening on 1 Interface=<%x>\n",
|
|||
|
pAddress, InterfaceToKeep);
|
|||
|
|
|||
|
PgmUnlock (pAddress, OldIrq);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT (pAddress->NumReceiveInterfaces > 1);
|
|||
|
|
|||
|
//
|
|||
|
// First, enumerate all interfaces to stop listening on
|
|||
|
//
|
|||
|
NumInterfaces = 0;
|
|||
|
for (i=0; i<pAddress->NumReceiveInterfaces; i++)
|
|||
|
{
|
|||
|
if (pAddress->ReceiverInterfaceList[i] != InterfaceToKeep)
|
|||
|
{
|
|||
|
InterfacesToStop[NumInterfaces++] = pAddress->ReceiverInterfaceList[i];
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
pAddress->ReceiverInterfaceList[0] = InterfaceToKeep;
|
|||
|
pAddress->NumReceiveInterfaces = 1;
|
|||
|
|
|||
|
//
|
|||
|
// Now, remove the remaining interfaces
|
|||
|
//
|
|||
|
#else
|
|||
|
//
|
|||
|
// First, make a copy of all addresses being listened on
|
|||
|
//
|
|||
|
NumInterfaces = 0;
|
|||
|
for (i=0; i<pAddress->NumReceiveInterfaces; i++)
|
|||
|
{
|
|||
|
InterfacesToStop[NumInterfaces++] = pAddress->ReceiverInterfaceList[i];
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Zero out the current listening list on the address
|
|||
|
//
|
|||
|
pAddress->NumReceiveInterfaces = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Now, remove the addresses on this interface from this list
|
|||
|
//
|
|||
|
pEntry = &PgmDynamicConfig.LocalInterfacesList;
|
|||
|
while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.LocalInterfacesList)
|
|||
|
{
|
|||
|
pLocalInterface = CONTAINING_RECORD (pEntry, tLOCAL_INTERFACE, Linkage);
|
|||
|
if (InterfaceToKeep == pLocalInterface->IpInterfaceContext)
|
|||
|
{
|
|||
|
//
|
|||
|
// Found the interface -- now save these addresses in the Address
|
|||
|
// list and remove from the stop list
|
|||
|
//
|
|||
|
pEntry = &pLocalInterface->Addresses;
|
|||
|
while ((pEntry = pEntry->Flink) != &pLocalInterface->Addresses)
|
|||
|
{
|
|||
|
pLocalAddress = CONTAINING_RECORD (pEntry, tADDRESS_ON_INTERFACE, Linkage);
|
|||
|
|
|||
|
pAddress->ReceiverInterfaceList[pAddress->NumReceiveInterfaces++] = pLocalAddress->IpAddress;
|
|||
|
|
|||
|
i = 0;
|
|||
|
while (i < NumInterfaces)
|
|||
|
{
|
|||
|
if (InterfacesToStop[i] == pLocalAddress->IpAddress)
|
|||
|
{
|
|||
|
j = i;
|
|||
|
NumInterfaces--;
|
|||
|
while (j < NumInterfaces)
|
|||
|
{
|
|||
|
InterfacesToStop[j] = InterfacesToStop[j+1];
|
|||
|
j++;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
i++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
#endif // IP_FIX
|
|||
|
|
|||
|
PgmUnlock (pAddress, OldIrq);
|
|||
|
PgmUnlock (&PgmDynamicConfig, OldIrq0);
|
|||
|
|
|||
|
MCastInfo.MCastIpAddr = htonl (pAddress->ReceiverMCastAddr);
|
|||
|
for (i=0; i<NumInterfaces; i++)
|
|||
|
{
|
|||
|
#ifdef IP_FIX
|
|||
|
MCastInfo.MCastInIf = InterfacesToStop[i];
|
|||
|
status = PgmSetTcpInfo (pAddress->FileHandle,
|
|||
|
AO_OPTION_INDEX_DEL_MCAST,
|
|||
|
&MCastInfo,
|
|||
|
sizeof (tMCAST_INFO));
|
|||
|
#else
|
|||
|
MCastInfo.MCastInIf = htonl (InterfacesToStop[i]);
|
|||
|
status = PgmSetTcpInfo (pAddress->FileHandle,
|
|||
|
AO_OPTION_DEL_MCAST,
|
|||
|
&MCastInfo,
|
|||
|
sizeof (tMCAST_INFO));
|
|||
|
#endif // IP_FIX
|
|||
|
|
|||
|
if (NT_SUCCESS (status))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "\tStopListeningOnAllInterfacesExcept",
|
|||
|
"Stopped pAddress=<%x> from listening on Interface=<%x>\n",
|
|||
|
pAddress, MCastInfo.MCastInIf);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// We failed to stop this interface -- don't so anything!
|
|||
|
//
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_PNP, "\tStopListeningOnAllInterfacesExcept",
|
|||
|
"AO_OPTION_INDEX_DEL_MCAST for If=<%x> on Address=<%x> returned <%x>\n",
|
|||
|
MCastInfo.MCastInIf, pAddress, status);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_STOP_LISTENING);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ListenOnAllInterfaces(
|
|||
|
IN tADDRESS_CONTEXT *pAddress,
|
|||
|
IN PGMLockHandle *pOldIrqDynamicConfig,
|
|||
|
IN PGMLockHandle *pOldIrqAddress
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Given an Address Context, this routine enables the Address to
|
|||
|
start listening on all interfaces
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN pAddress -- Address Context
|
|||
|
IN pOldIrqDynamicConfig-- OldIrq for DynamicConfig lock held
|
|||
|
IN pOldIrqAddress -- OldIrq for Address lock held
|
|||
|
|
|||
|
The DynamicConfig and Address locks are held on entry and exit
|
|||
|
from this routine
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
LIST_ENTRY *pEntry;
|
|||
|
tLOCAL_INTERFACE *pLocalInterface;
|
|||
|
tMCAST_INFO MCastInfo;
|
|||
|
ULONG InterfacesToAdd[MAX_RECEIVE_INTERFACES+1];
|
|||
|
USHORT NumInterfaces, i, j;
|
|||
|
#ifndef IP_FIX
|
|||
|
LIST_ENTRY *pEntry2;
|
|||
|
tADDRESS_ON_INTERFACE *pLocalAddress;
|
|||
|
#endif // !IP_FIX
|
|||
|
|
|||
|
//
|
|||
|
// First, get the list of all active interfaces
|
|||
|
//
|
|||
|
NumInterfaces = 0;
|
|||
|
pEntry = &PgmDynamicConfig.LocalInterfacesList;
|
|||
|
while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.LocalInterfacesList)
|
|||
|
{
|
|||
|
pLocalInterface = CONTAINING_RECORD (pEntry, tLOCAL_INTERFACE, Linkage);
|
|||
|
#ifdef IP_FIX
|
|||
|
InterfacesToAdd[NumInterfaces++] = pLocalInterface->IpInterfaceContext;
|
|||
|
#else
|
|||
|
pEntry2 = &pLocalInterface->Addresses;
|
|||
|
while ((pEntry2 = pEntry2->Flink) != &pLocalInterface->Addresses)
|
|||
|
{
|
|||
|
pLocalAddress = CONTAINING_RECORD (pEntry2, tADDRESS_ON_INTERFACE, Linkage);
|
|||
|
|
|||
|
InterfacesToAdd[NumInterfaces++] = pLocalAddress->IpAddress;
|
|||
|
|
|||
|
if (NumInterfaces >= MAX_RECEIVE_INTERFACES)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
#endif // IP_FIX
|
|||
|
|
|||
|
if (NumInterfaces >= MAX_RECEIVE_INTERFACES)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remove all the interfaces we are already listening
|
|||
|
// on from the list of interfaces to be added
|
|||
|
//
|
|||
|
for (i=0; i<pAddress->NumReceiveInterfaces; i++)
|
|||
|
{
|
|||
|
for (j = 0; j < NumInterfaces; j++)
|
|||
|
{
|
|||
|
if (pAddress->ReceiverInterfaceList[i] == InterfacesToAdd[j])
|
|||
|
{
|
|||
|
NumInterfaces--;
|
|||
|
while (j < NumInterfaces)
|
|||
|
{
|
|||
|
InterfacesToAdd[j] = InterfacesToAdd[j+1];
|
|||
|
j++;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!NumInterfaces)
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "ListenOnAllInterfaces",
|
|||
|
"No new interfaces to listen on for pAddress=<%x>, currently listening on <%x> Ifs\n",
|
|||
|
pAddress, pAddress->NumReceiveInterfaces);
|
|||
|
|
|||
|
return (STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Ensure that the complete list will not
|
|||
|
// exceed the maximum limit
|
|||
|
//
|
|||
|
if ((pAddress->NumReceiveInterfaces + NumInterfaces) > MAX_RECEIVE_INTERFACES)
|
|||
|
{
|
|||
|
NumInterfaces = MAX_RECEIVE_INTERFACES - pAddress->NumReceiveInterfaces;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now, add the remaining interfaces
|
|||
|
//
|
|||
|
PgmUnlock (pAddress, *pOldIrqAddress);
|
|||
|
PgmUnlock (&PgmDynamicConfig, *pOldIrqDynamicConfig);
|
|||
|
|
|||
|
MCastInfo.MCastIpAddr = htonl (pAddress->ReceiverMCastAddr);
|
|||
|
i = 0;
|
|||
|
while (i < NumInterfaces)
|
|||
|
{
|
|||
|
#ifdef IP_FIX
|
|||
|
MCastInfo.MCastInIf = InterfacesToAdd[i];
|
|||
|
status = PgmSetTcpInfo (pAddress->FileHandle,
|
|||
|
AO_OPTION_INDEX_ADD_MCAST,
|
|||
|
&MCastInfo,
|
|||
|
sizeof (tMCAST_INFO));
|
|||
|
#else
|
|||
|
MCastInfo.MCastInIf = htonl (InterfacesToAdd[i]);
|
|||
|
status = PgmSetTcpInfo (pAddress->FileHandle,
|
|||
|
AO_OPTION_ADD_MCAST,
|
|||
|
&MCastInfo,
|
|||
|
sizeof (tMCAST_INFO));
|
|||
|
#endif // IP_FIX
|
|||
|
|
|||
|
if (NT_SUCCESS (status))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "\tListenOnAllInterfaces",
|
|||
|
"pAddress=<%x> now also listening on If=<%x>\n",
|
|||
|
pAddress, MCastInfo.MCastInIf);
|
|||
|
|
|||
|
i++;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We failed to add this interface, so remove it from
|
|||
|
// the list
|
|||
|
//
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_PNP, "\tListenOnAllInterfaces",
|
|||
|
"pAddress=<%x> could not listen on If=<%x>\n",
|
|||
|
pAddress, MCastInfo.MCastInIf);
|
|||
|
|
|||
|
j = i;
|
|||
|
NumInterfaces--;
|
|||
|
while (j < NumInterfaces)
|
|||
|
{
|
|||
|
InterfacesToAdd[j] = InterfacesToAdd[j+1];
|
|||
|
j++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
PgmLock (&PgmDynamicConfig, *pOldIrqDynamicConfig);
|
|||
|
PgmLock (pAddress, *pOldIrqAddress);
|
|||
|
|
|||
|
//
|
|||
|
// Now, append the new list to the Address context
|
|||
|
//
|
|||
|
for (i=0; i<NumInterfaces; i++)
|
|||
|
{
|
|||
|
if (pAddress->NumReceiveInterfaces > MAX_RECEIVE_INTERFACES)
|
|||
|
{
|
|||
|
ASSERT (0);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
pAddress->ReceiverInterfaceList[pAddress->NumReceiveInterfaces] = InterfacesToAdd[i];
|
|||
|
pAddress->NumReceiveInterfaces++;
|
|||
|
}
|
|||
|
|
|||
|
return (STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
|
|||
|
VOID
|
|||
|
TdiAddressArrival(
|
|||
|
PTA_ADDRESS Addr,
|
|||
|
PUNICODE_STRING pDeviceName,
|
|||
|
PTDI_PNP_CONTEXT Context
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
PnP TDI_ADD_ADDRESS_HANDLER
|
|||
|
This routine handles an IP address arriving.
|
|||
|
It is called by TDI when an address arrives.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN Addr -- IP address that's coming.
|
|||
|
IN pDeviceName -- Unicode string Ptr for Device whose address is changing
|
|||
|
IN Context -- Tdi PnP context
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Nothing!
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
tIPADDRESS IpAddr, NetIpAddr;
|
|||
|
LIST_ENTRY *pEntry;
|
|||
|
PGMLockHandle OldIrq, OldIrq1;
|
|||
|
tLOCAL_INTERFACE *pLocalInterface = NULL;
|
|||
|
tADDRESS_ON_INTERFACE *pLocalAddress = NULL;
|
|||
|
ULONG BufferLength = 50;
|
|||
|
UCHAR pBuffer[50];
|
|||
|
IPInterfaceInfo *pIpIfInfo = (IPInterfaceInfo *) pBuffer;
|
|||
|
NTSTATUS status;
|
|||
|
tADDRESS_CONTEXT *pAddress;
|
|||
|
tADDRESS_CONTEXT *pAddressToDeref = NULL;
|
|||
|
ULONG IpInterfaceContext;
|
|||
|
BOOLEAN fFound;
|
|||
|
|
|||
|
//
|
|||
|
// Proceed only if this is an IP address
|
|||
|
//
|
|||
|
if (Addr->AddressType != TDI_ADDRESS_TYPE_IP)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// First, verify that we are not getting unloaded
|
|||
|
//
|
|||
|
PgmLock (&PgmDynamicConfig, OldIrq);
|
|||
|
if (!PGM_VERIFY_HANDLE (pgPgmDevice, PGM_VERIFY_DEVICE))
|
|||
|
{
|
|||
|
//
|
|||
|
// The driver is most probably being unloaded now
|
|||
|
//
|
|||
|
PgmUnlock (&PgmDynamicConfig, OldIrq);
|
|||
|
return;
|
|||
|
}
|
|||
|
PGM_REFERENCE_DEVICE (pgPgmDevice, REF_DEV_ADDRESS_NOTIFICATION, FALSE);
|
|||
|
PgmUnlock (&PgmDynamicConfig, OldIrq);
|
|||
|
|
|||
|
NetIpAddr = ((PTDI_ADDRESS_IP)&Addr->Address[0])->in_addr;
|
|||
|
IpAddr = ntohl (NetIpAddr);
|
|||
|
|
|||
|
//
|
|||
|
// Now, get the interface context and other info from TcpIp
|
|||
|
//
|
|||
|
status = GetIpInterfaceContextFromDeviceName (NetIpAddr,
|
|||
|
pDeviceName,
|
|||
|
&IpInterfaceContext,
|
|||
|
BufferLength,
|
|||
|
pBuffer,
|
|||
|
TRUE);
|
|||
|
if (!NT_SUCCESS (status))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_PNP, "TdiAddressArrival",
|
|||
|
"GetIpInterfaceContext returned <%x>\n", status);
|
|||
|
|
|||
|
PGM_DEREFERENCE_DEVICE (&pgPgmDevice, REF_DEV_ADDRESS_NOTIFICATION);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
PgmLock (&PgmDynamicConfig, OldIrq);
|
|||
|
|
|||
|
fFound = FALSE;
|
|||
|
pEntry = &PgmDynamicConfig.LocalInterfacesList;
|
|||
|
while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.LocalInterfacesList)
|
|||
|
{
|
|||
|
pLocalInterface = CONTAINING_RECORD (pEntry, tLOCAL_INTERFACE, Linkage);
|
|||
|
if (pLocalInterface->IpInterfaceContext == IpInterfaceContext)
|
|||
|
{
|
|||
|
fFound = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (fFound)
|
|||
|
{
|
|||
|
fFound = FALSE;
|
|||
|
pEntry = &pLocalInterface->Addresses;
|
|||
|
while ((pEntry = pEntry->Flink) != &pLocalInterface->Addresses)
|
|||
|
{
|
|||
|
pLocalAddress = CONTAINING_RECORD (pEntry, tADDRESS_ON_INTERFACE, Linkage);
|
|||
|
if (pLocalAddress->IpAddress == IpAddr)
|
|||
|
{
|
|||
|
PgmUnlock (&PgmDynamicConfig, OldIrq);
|
|||
|
PGM_DEREFERENCE_DEVICE (&pgPgmDevice, REF_DEV_ADDRESS_NOTIFICATION);
|
|||
|
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_PNP, "TdiAddressArrival",
|
|||
|
"\tDUPLICATE address notification for [%d.%d.%d.%d] on <%wZ>\n",
|
|||
|
(IpAddr>>24)&0xFF,(IpAddr>>16)&0xFF,(IpAddr>>8)&0xFF,IpAddr&0xFF,
|
|||
|
pDeviceName);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else if (pLocalInterface = PgmAllocMem (sizeof(tLOCAL_INTERFACE), PGM_TAG('0')))
|
|||
|
{
|
|||
|
PgmZeroMemory (pLocalInterface, sizeof (tLOCAL_INTERFACE));
|
|||
|
InitializeListHead (&pLocalInterface->Addresses);
|
|||
|
|
|||
|
pLocalInterface->IpInterfaceContext = IpInterfaceContext;
|
|||
|
pLocalInterface->MTU = pIpIfInfo->iii_mtu - (sizeof(IPV4Header) + ROUTER_ALERT_SIZE);
|
|||
|
pLocalInterface->Flags = pIpIfInfo->iii_flags;
|
|||
|
|
|||
|
BufferLength = pIpIfInfo->iii_addrlength < sizeof(tMAC_ADDRESS) ?
|
|||
|
pIpIfInfo->iii_addrlength : sizeof(tMAC_ADDRESS);
|
|||
|
PgmCopyMemory (&pLocalInterface->MacAddress, pIpIfInfo->iii_addr, BufferLength);
|
|||
|
|
|||
|
if (pLocalInterface->MTU > PgmDynamicConfig.MaxMTU)
|
|||
|
{
|
|||
|
PgmDynamicConfig.MaxMTU = pLocalInterface->MTU;
|
|||
|
}
|
|||
|
InsertTailList (&PgmDynamicConfig.LocalInterfacesList, &pLocalInterface->Linkage);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
PgmUnlock (&PgmDynamicConfig, OldIrq);
|
|||
|
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_PNP, "TdiAddressArrival",
|
|||
|
"STATUS_INSUFFICIENT_RESOURCES[Interface] for IP=<%x>, IfContext=<%x>\n",
|
|||
|
IpAddr, IpInterfaceContext);
|
|||
|
|
|||
|
PGM_DEREFERENCE_DEVICE (&pgPgmDevice, REF_DEV_ADDRESS_NOTIFICATION);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now, add this address to the interface
|
|||
|
//
|
|||
|
if (pLocalAddress = PgmAllocMem (sizeof(tADDRESS_ON_INTERFACE), PGM_TAG('0')))
|
|||
|
{
|
|||
|
PgmZeroMemory (pLocalAddress, sizeof (tADDRESS_ON_INTERFACE));
|
|||
|
pLocalAddress->IpAddress = IpAddr;
|
|||
|
InsertTailList (&pLocalInterface->Addresses, &pLocalAddress->Linkage);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// If we had just added the interface, there is no point
|
|||
|
// in keeping an empty context around!
|
|||
|
//
|
|||
|
if (IsListEmpty (&pLocalInterface->Addresses))
|
|||
|
{
|
|||
|
RemoveEntryList (&pLocalInterface->Linkage);
|
|||
|
PgmFreeMem (pLocalInterface);
|
|||
|
}
|
|||
|
|
|||
|
PgmUnlock (&PgmDynamicConfig, OldIrq);
|
|||
|
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_PNP, "TdiAddressArrival",
|
|||
|
"STATUS_INSUFFICIENT_RESOURCES[Address] -- [%d.%d.%d.%d] on <%wZ>\n",
|
|||
|
(IpAddr>>24)&0xFF,(IpAddr>>16)&0xFF,(IpAddr>>8)&0xFF,IpAddr&0xFF,
|
|||
|
pDeviceName);
|
|||
|
|
|||
|
PGM_DEREFERENCE_DEVICE (&pgPgmDevice, REF_DEV_ADDRESS_NOTIFICATION);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now, check if we have any receivers waiting for an address
|
|||
|
//
|
|||
|
pEntry = &PgmDynamicConfig.ReceiverAddressHead;
|
|||
|
while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.ReceiverAddressHead)
|
|||
|
{
|
|||
|
pAddress = CONTAINING_RECORD (pEntry, tADDRESS_CONTEXT, Linkage);
|
|||
|
PgmLock (pAddress, OldIrq1);
|
|||
|
|
|||
|
if ((PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS)) &&
|
|||
|
(pAddress->Flags & PGM_ADDRESS_WAITING_FOR_NEW_INTERFACE) &&
|
|||
|
(pAddress->Flags & PGM_ADDRESS_LISTEN_ON_ALL_INTERFACES))
|
|||
|
{
|
|||
|
PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO, TRUE);
|
|||
|
|
|||
|
if (pAddressToDeref)
|
|||
|
{
|
|||
|
PgmUnlock (pAddress, OldIrq1);
|
|||
|
PgmUnlock (&PgmDynamicConfig, OldIrq);
|
|||
|
|
|||
|
PGM_DEREFERENCE_ADDRESS (pAddressToDeref, REF_ADDRESS_SET_INFO);
|
|||
|
|
|||
|
PgmLock (&PgmDynamicConfig, OldIrq);
|
|||
|
PgmLock (pAddress, OldIrq1);
|
|||
|
}
|
|||
|
pAddressToDeref = pAddress;
|
|||
|
|
|||
|
status = ReceiverAddMCastIf (pAddress, IpAddr, &OldIrq, &OldIrq1);
|
|||
|
|
|||
|
if (NT_SUCCESS (status))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_ADDRESS, "TdiAddressArrival",
|
|||
|
"ReceiverAddMCastIf for pAddress=<%x> succeeded for IP=<%x>\n",
|
|||
|
pAddress, IpAddr);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "TdiAddressArrival",
|
|||
|
"ReceiverAddMCastIf for pAddress=<%x> returned <%x>, IP=<%x>\n",
|
|||
|
pAddress, status, IpAddr);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
PgmUnlock (pAddress, OldIrq1);
|
|||
|
}
|
|||
|
|
|||
|
PgmUnlock (&PgmDynamicConfig, OldIrq);
|
|||
|
|
|||
|
if (pAddressToDeref)
|
|||
|
{
|
|||
|
PGM_DEREFERENCE_ADDRESS (pAddressToDeref, REF_ADDRESS_SET_INFO);
|
|||
|
}
|
|||
|
|
|||
|
PGM_DEREFERENCE_DEVICE (&pgPgmDevice, REF_DEV_ADDRESS_NOTIFICATION);
|
|||
|
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiAddressArrival",
|
|||
|
"\t[%d.%d.%d.%d] on <%wZ>\n",
|
|||
|
(IpAddr>>24)&0xFF,(IpAddr>>16)&0xFF,(IpAddr>>8)&0xFF,IpAddr&0xFF,
|
|||
|
pDeviceName);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
|
|||
|
VOID
|
|||
|
TdiAddressDeletion(
|
|||
|
PTA_ADDRESS Addr,
|
|||
|
PUNICODE_STRING pDeviceName,
|
|||
|
PTDI_PNP_CONTEXT Context
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles an IP address going away.
|
|||
|
It is called by TDI when an address is deleted.
|
|||
|
If it's an address we care about we'll clean up appropriately.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN Addr -- IP address that's going.
|
|||
|
IN pDeviceName -- Unicode string Ptr for Device whose address is changing
|
|||
|
IN Context -- Tdi PnP context
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Nothing!
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
tIPADDRESS IpAddr;
|
|||
|
LIST_ENTRY *pEntry;
|
|||
|
LIST_ENTRY *pEntry2;
|
|||
|
PGMLockHandle OldIrq, OldIrq1;
|
|||
|
tSEND_SESSION *pSend;
|
|||
|
tADDRESS_CONTEXT *pAddress;
|
|||
|
NTSTATUS status;
|
|||
|
BOOLEAN fFound;
|
|||
|
tADDRESS_CONTEXT *pAddressToDeref = NULL;
|
|||
|
tLOCAL_INTERFACE *pLocalInterface = NULL;
|
|||
|
tADDRESS_ON_INTERFACE *pLocalAddress = NULL;
|
|||
|
ULONG IpInterfaceContext;
|
|||
|
|
|||
|
if (Addr->AddressType != TDI_ADDRESS_TYPE_IP)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
IpAddr = ntohl(((PTDI_ADDRESS_IP)&Addr->Address[0])->in_addr);
|
|||
|
|
|||
|
PgmLock (&PgmDynamicConfig, OldIrq);
|
|||
|
|
|||
|
fFound = FALSE;
|
|||
|
pEntry = &PgmDynamicConfig.LocalInterfacesList;
|
|||
|
while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.LocalInterfacesList)
|
|||
|
{
|
|||
|
pLocalInterface = CONTAINING_RECORD (pEntry, tLOCAL_INTERFACE, Linkage);
|
|||
|
pEntry2 = &pLocalInterface->Addresses;
|
|||
|
while ((pEntry2 = pEntry2->Flink) != &pLocalInterface->Addresses)
|
|||
|
{
|
|||
|
pLocalAddress = CONTAINING_RECORD (pEntry2, tADDRESS_ON_INTERFACE, Linkage);
|
|||
|
if (pLocalAddress->IpAddress == IpAddr)
|
|||
|
{
|
|||
|
IpInterfaceContext = pLocalInterface->IpInterfaceContext;
|
|||
|
RemoveEntryList (&pLocalAddress->Linkage);
|
|||
|
PgmFreeMem (pLocalAddress);
|
|||
|
|
|||
|
//
|
|||
|
// If this is the last address on this interface, clean up!
|
|||
|
//
|
|||
|
if (IsListEmpty (&pLocalInterface->Addresses))
|
|||
|
{
|
|||
|
RemoveEntryList (&pLocalInterface->Linkage);
|
|||
|
PgmFreeMem (pLocalInterface);
|
|||
|
pLocalInterface = NULL;
|
|||
|
}
|
|||
|
|
|||
|
fFound = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (fFound)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!fFound)
|
|||
|
{
|
|||
|
PgmUnlock (&PgmDynamicConfig, OldIrq);
|
|||
|
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_PNP, "TdiAddressDeletion",
|
|||
|
"\tAddress [%d.%d.%d.%d] NOT notified on <%wZ>\n",
|
|||
|
(IpAddr>>24)&0xFF,(IpAddr>>16)&0xFF,(IpAddr>>8)&0xFF,IpAddr&0xFF,
|
|||
|
pDeviceName);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
pEntry = &PgmDynamicConfig.SenderAddressHead;
|
|||
|
while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.SenderAddressHead)
|
|||
|
{
|
|||
|
pAddress = CONTAINING_RECORD (pEntry, tADDRESS_CONTEXT, Linkage);
|
|||
|
if (pAddress->SenderMCastOutIf == IpAddr)
|
|||
|
{
|
|||
|
PgmLock (pAddress, OldIrq1);
|
|||
|
pAddress->Flags |= PGM_ADDRESS_FLAG_INVALID_OUT_IF;
|
|||
|
|
|||
|
pEntry2 = &pAddress->AssociatedConnections;
|
|||
|
while ((pEntry2 = pEntry2->Flink) != &pAddress->AssociatedConnections)
|
|||
|
{
|
|||
|
pSend = CONTAINING_RECORD (pEntry2, tSEND_SESSION, Linkage);
|
|||
|
if (!(pSend->SessionFlags & PGM_SESSION_TERMINATED_ABORT))
|
|||
|
{
|
|||
|
pSend->SessionFlags |= PGM_SESSION_TERMINATED_ABORT;
|
|||
|
|
|||
|
if (pAddress->evDisconnect)
|
|||
|
{
|
|||
|
PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_DISCONNECT, TRUE);
|
|||
|
PGM_REFERENCE_SESSION_SEND (pSend, REF_SESSION_DISCONNECT, FALSE);
|
|||
|
|
|||
|
PgmUnlock (pAddress, OldIrq1);
|
|||
|
PgmUnlock (&PgmDynamicConfig, OldIrq);
|
|||
|
|
|||
|
if (pAddressToDeref)
|
|||
|
{
|
|||
|
PGM_DEREFERENCE_ADDRESS (pAddressToDeref, REF_ADDRESS_DISCONNECT);
|
|||
|
}
|
|||
|
pAddressToDeref = pAddress;
|
|||
|
|
|||
|
status = (*pAddress->evDisconnect) (pAddress->DiscEvContext,
|
|||
|
pSend->ClientSessionContext,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
TDI_DISCONNECT_ABORT);
|
|||
|
|
|||
|
PGM_DEREFERENCE_SESSION_SEND (pSend, REF_SESSION_DISCONNECT);
|
|||
|
|
|||
|
PgmLock (&PgmDynamicConfig, OldIrq);
|
|||
|
PgmLock (pAddress, OldIrq1);
|
|||
|
|
|||
|
pEntry = &PgmDynamicConfig.SenderAddressHead;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
PgmUnlock (pAddress, OldIrq1);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// See which receivers were actively listening on this interface
|
|||
|
// If this was an interface for an active session, then we need to
|
|||
|
// restart listening on all interfaces if no interface(s) had been
|
|||
|
// specified by the user.
|
|||
|
//
|
|||
|
#ifdef IP_FIX
|
|||
|
if (!pLocalInterface)
|
|||
|
{
|
|||
|
StopListeningOnInterface (IpInterfaceContext, &OldIrq);
|
|||
|
}
|
|||
|
#else
|
|||
|
StopListeningOnInterface (IpAddr, &OldIrq);
|
|||
|
#endif // IP_FIX
|
|||
|
|
|||
|
PgmUnlock (&PgmDynamicConfig, OldIrq);
|
|||
|
|
|||
|
if (pAddressToDeref)
|
|||
|
{
|
|||
|
PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_DISCONNECT);
|
|||
|
}
|
|||
|
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiAddressDeletion",
|
|||
|
"\t[%d.%d.%d.%d] on <%wZ>\n",
|
|||
|
(IpAddr>>24)&0xFF,(IpAddr>>16)&0xFF,(IpAddr>>8)&0xFF,IpAddr&0xFF,
|
|||
|
pDeviceName);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
|
|||
|
VOID
|
|||
|
TdiBindHandler(
|
|||
|
TDI_PNP_OPCODE PnPOpCode,
|
|||
|
PUNICODE_STRING pDeviceName,
|
|||
|
PWSTR MultiSZBindList
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is the handler for TDI to notify clients of bind notifications
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN PnPOpCode -- Notification code
|
|||
|
IN pDeviceName -- Unicode string Ptr for Device whose address is changing
|
|||
|
IN MultiSZBindList -- Current list of bindings
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - Final status of the set event operation
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
switch (PnPOpCode)
|
|||
|
{
|
|||
|
case (TDI_PNP_OP_ADD):
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiBindHandler",
|
|||
|
"\t[ADD]: Device=<%wZ>\n", pDeviceName);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case (TDI_PNP_OP_DEL):
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiBindHandler",
|
|||
|
"\t[DEL]: Device=<%wZ>\n", pDeviceName);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case (TDI_PNP_OP_PROVIDERREADY):
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiBindHandler",
|
|||
|
"\t[PROVIDERREADY]: Device=<%wZ>\n", pDeviceName);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case (TDI_PNP_OP_NETREADY):
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiBindHandler",
|
|||
|
"\t[NETREADY]: Device=<%wZ>\n", pDeviceName);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
default:
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiBindHandler",
|
|||
|
"\t[?=%x]: Device=<%wZ>\n", PnPOpCode, pDeviceName);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
TdiPnPPowerHandler(
|
|||
|
IN PUNICODE_STRING pDeviceName,
|
|||
|
IN PNET_PNP_EVENT pPnPEvent,
|
|||
|
IN PTDI_PNP_CONTEXT Context1,
|
|||
|
IN PTDI_PNP_CONTEXT Context2
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is the handler called by TDI notify its clients of Power notifications
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN pDeviceName -- Unicode string Ptr for Device whose address is changing
|
|||
|
IN PnPEvent -- Event notification
|
|||
|
IN Context1 --
|
|||
|
IN Context2 --
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - Final status of the set event operation
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
switch (pPnPEvent->NetEvent)
|
|||
|
{
|
|||
|
case (NetEventQueryPower):
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_PATH, DBG_PNP, "TdiPnPPowerHandler",
|
|||
|
"[QueryPower]: Device=<%wZ>\n", pDeviceName);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case (NetEventSetPower):
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_PATH, DBG_PNP, "TdiPnPPowerHandler",
|
|||
|
"[SetPower]: Device=<%wZ>\n", pDeviceName);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case (NetEventQueryRemoveDevice):
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiPnPPowerHandler",
|
|||
|
"[QueryRemoveDevice]: Device=<%wZ>\n", pDeviceName);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case (NetEventCancelRemoveDevice):
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiPnPPowerHandler",
|
|||
|
"[CancelRemoveDevice]: Device=<%wZ>\n", pDeviceName);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case (NetEventReconfigure):
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_PATH, DBG_PNP, "TdiPnPPowerHandler",
|
|||
|
"[Reconfigure]: Device=<%wZ>\n", pDeviceName);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case (NetEventBindList):
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_PATH, DBG_PNP, "TdiPnPPowerHandler",
|
|||
|
"[BindList]: Device=<%wZ>\n", pDeviceName);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case (NetEventPnPCapabilities):
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_PATH, DBG_PNP, "TdiPnPPowerHandler",
|
|||
|
"[PnPCapabilities]: Device=<%wZ>\n", pDeviceName);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
default:
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiPnPPowerHandler",
|
|||
|
"[?=%d]: Device=<%wZ>\n", (ULONG) pPnPEvent->NetEvent, pDeviceName);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
return (STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SetTdiHandlers(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called at DriverEntry to register our handlers with TDI
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - Final status of the set event operation
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
UNICODE_STRING ucPgmClientName;
|
|||
|
TDI_CLIENT_INTERFACE_INFO TdiClientInterface;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Register our Handlers with TDI
|
|||
|
//
|
|||
|
RtlInitUnicodeString (&ucPgmClientName, WC_PGM_CLIENT_NAME);
|
|||
|
ucPgmClientName.MaximumLength = sizeof (WC_PGM_CLIENT_NAME);
|
|||
|
PgmZeroMemory (&TdiClientInterface, sizeof(TdiClientInterface));
|
|||
|
|
|||
|
TdiClientInterface.MajorTdiVersion = TDI_CURRENT_MAJOR_VERSION;
|
|||
|
TdiClientInterface.MinorTdiVersion = TDI_CURRENT_MINOR_VERSION;
|
|||
|
TdiClientInterface.ClientName = &ucPgmClientName;
|
|||
|
TdiClientInterface.AddAddressHandlerV2 = TdiAddressArrival;
|
|||
|
TdiClientInterface.DelAddressHandlerV2 = TdiAddressDeletion;
|
|||
|
TdiClientInterface.BindingHandler = TdiBindHandler;
|
|||
|
TdiClientInterface.PnPPowerHandler = TdiPnPPowerHandler;
|
|||
|
|
|||
|
status = TdiRegisterPnPHandlers (&TdiClientInterface, sizeof(TdiClientInterface), &TdiClientHandle);
|
|||
|
if (!NT_SUCCESS (status))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_PNP, "SetTdiHandlers",
|
|||
|
"TdiRegisterPnPHandlers ==> <%x>\n", status);
|
|||
|
return (status);
|
|||
|
}
|
|||
|
|
|||
|
TdiEnumerateAddresses(TdiClientHandle);
|
|||
|
|
|||
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_PNP, "SetTdiHandlers",
|
|||
|
"\tSUCCEEDed\n");
|
|||
|
|
|||
|
return (status);
|
|||
|
}
|
|||
|
|