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.
3714 lines
105 KiB
3714 lines
105 KiB
//=============================================================================
|
|
// Copyright (c) 1997 Microsoft Corporation
|
|
// Module Name: If.c
|
|
//
|
|
// Abstract:
|
|
// This module implements some of the Igmp API's related with interfaces.
|
|
// _AddInterface, _DeleteInterface, _EnableInterface, _DisableInterface,
|
|
// _BindInterface, _UnbindInterface, _ConnectRasClient, _DisconectRasClient,
|
|
// _SetInterfaceConfigInfo, _GetInterfaceConfigInfo.
|
|
//
|
|
// Author: K.S.Lokesh (lokeshs@) 11-1-97
|
|
//=============================================================================
|
|
|
|
|
|
#include "pchigmp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _AddInterface
|
|
//
|
|
// This api is called to add an interface to Igmp. The interface can be a Proxy
|
|
// or an Igmp router(v1/v2). Further, the interface can be a RAS or DemandDial
|
|
// or a Permanent interface. This routine creates the interface entry and
|
|
// associated structures including timers.
|
|
//
|
|
// Locks: Runs completely in ListLock and ExclusiveIfLock.
|
|
// Calls: _AddIfEntry()
|
|
// Return Values: ERROR_CAN_NOT_COMPLETE, Error, NO_ERROR.
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
AddInterface(
|
|
IN PWCHAR pwszInterfaceName,//not used
|
|
IN ULONG IfIndex,
|
|
IN NET_INTERFACE_TYPE dwIfType,
|
|
IN DWORD dwMediaType,
|
|
IN WORD wAccessType,
|
|
IN WORD wConnectionType,
|
|
IN PVOID pvConfig,
|
|
IN ULONG ulStructureVersion,
|
|
IN ULONG ulStructureSize,
|
|
IN ULONG ulStructureCount
|
|
)
|
|
{
|
|
DWORD Error=NO_ERROR;
|
|
CHAR str[60];
|
|
|
|
|
|
if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
|
|
// make sure it is not an unsupported igmp version structure
|
|
if (ulStructureVersion>=IGMP_CONFIG_VERSION_600) {
|
|
Trace1(ERR, "Unsupported IGMP version structure: %0x",
|
|
ulStructureVersion);
|
|
IgmpAssertOnError(FALSE);
|
|
LeaveIgmpApi();
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
switch (dwIfType) {
|
|
case PERMANENT: //lan
|
|
lstrcpy(str, "PERMANENT(IGMP_IF_NOT_RAS)"); break;
|
|
case DEMAND_DIAL:
|
|
lstrcpy(str, "DEMAND_DIAL(IGMP_IF_RAS_ROUTER)");break;
|
|
case LOCAL_WORKSTATION_DIAL:
|
|
lstrcpy(str, "LOCAL_WORKSTATION_DIAL(IGMP_IF_RAS_SERVER)"); break;
|
|
}
|
|
|
|
Trace2(ENTER, "entering AddInterface(): IfIndex:%0x IfType:%s",
|
|
IfIndex, str);
|
|
|
|
|
|
|
|
// entire procedure runs in IfListLock and exclusive IfLock.
|
|
|
|
ACQUIRE_IF_LIST_LOCK("_AddInterface");
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE(IfIndex, "_AddInterface");
|
|
|
|
|
|
//
|
|
// create the interface entry
|
|
//
|
|
Error = AddIfEntry(IfIndex, dwIfType, (PIGMP_MIB_IF_CONFIG)pvConfig,
|
|
ulStructureVersion, ulStructureSize
|
|
);
|
|
|
|
|
|
|
|
RELEASE_IF_LIST_LOCK("_AddInterface");
|
|
RELEASE_IF_LOCK_EXCLUSIVE(IfIndex, "_AddInterface");
|
|
|
|
Trace2(LEAVE1, "leaving AddInterface(%0x): %d\n", IfIndex, Error);
|
|
if (Error!=NO_ERROR) {
|
|
Trace1(ERR, "Error adding interface:%0x to IGMP\n", IfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
}
|
|
LeaveIgmpApi();
|
|
return Error;
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _AddIfEntry
|
|
//
|
|
// Creates and initializes a new interface entry and associated data structures.
|
|
//
|
|
// Called by: _AddInterface().
|
|
// Locks: Assumes IfListLock and exclusive IfLock throughout.
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
AddIfEntry(
|
|
DWORD IfIndex,
|
|
NET_INTERFACE_TYPE dwExternalIfType,
|
|
PIGMP_MIB_IF_CONFIG pConfigExt,
|
|
ULONG ulStructureVersion,
|
|
ULONG ulStructureSize
|
|
)
|
|
{
|
|
DWORD Error = NO_ERROR, IfType;
|
|
PIF_TABLE_ENTRY pite = NULL;
|
|
PLIST_ENTRY ple, phead;
|
|
PIGMP_IF_TABLE pIfTable = g_pIfTable;
|
|
BOOL bProxy;
|
|
|
|
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
//
|
|
// fail if the interface exists.
|
|
//
|
|
pite = GetIfByIndex(IfIndex);
|
|
|
|
if (pite != NULL) {
|
|
Trace1(ERR, "interface %0x already exists", IfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
// convert iftype to igmp iftype
|
|
|
|
switch (dwExternalIfType) {
|
|
|
|
case PERMANENT :
|
|
IfType = IGMP_IF_NOT_RAS;
|
|
break;
|
|
|
|
case DEMAND_DIAL:
|
|
IfType = IGMP_IF_RAS_ROUTER;
|
|
break;
|
|
|
|
case LOCAL_WORKSTATION_DIAL:
|
|
{
|
|
IfType = IGMP_IF_RAS_SERVER;
|
|
|
|
|
|
// currently there can be at most one ras table entry
|
|
|
|
if (g_RasIfIndex!=0) {
|
|
Trace2(ERR,
|
|
"Error. Cannot have more than one ras server IF(%0x:%0x)",
|
|
g_RasIfIndex, IfIndex
|
|
);
|
|
IgmpAssertOnError(FALSE);
|
|
Error = ERROR_CAN_NOT_COMPLETE;
|
|
Logerr0(RAS_IF_EXISTS, Error);
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case REMOTE_WORKSTATION_DIAL :
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
|
|
default :
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
|
|
} //end switch (IfType)
|
|
|
|
|
|
// Validate the interface config
|
|
|
|
Error = ValidateIfConfig(pConfigExt, IfIndex, IfType,
|
|
ulStructureVersion, ulStructureSize
|
|
);
|
|
if (Error!=NO_ERROR)
|
|
GOTO_END_BLOCK1;
|
|
|
|
|
|
//
|
|
// allocate memory for the new interface and Zero it.
|
|
// Fields that are to be initialized to 0 or NULL are commented out.
|
|
//
|
|
pite = IGMP_ALLOC(sizeof(IF_TABLE_ENTRY), 0x2, IfIndex);
|
|
PROCESS_ALLOC_FAILURE3(pite,
|
|
"error %d allocating %d bytes for interface %0x", Error,
|
|
sizeof(IF_TABLE_ENTRY), IfIndex,
|
|
GOTO_END_BLOCK1);
|
|
Trace2(CONFIG, "IfEntry %0x for IfIndex:%0x", (ULONG_PTR)pite, IfIndex);
|
|
|
|
ZeroMemory(pite, sizeof(IF_TABLE_ENTRY));
|
|
|
|
|
|
//
|
|
// set the interface type
|
|
//
|
|
pite->IfType = (UCHAR)IfType;
|
|
|
|
|
|
//
|
|
// if proxy, make sure that a proxy interface does not already exist
|
|
//
|
|
if ( IS_CONFIG_IGMPPROXY(pConfigExt) ){
|
|
|
|
bProxy = TRUE;
|
|
|
|
|
|
//
|
|
// multiple proxy interfaces cannot exist
|
|
//
|
|
if (g_ProxyIfIndex!=0) {
|
|
|
|
Error = ERROR_CAN_NOT_COMPLETE;
|
|
Trace1(IF, "Cannot create multiple proxy interfaces. "
|
|
"If %d is Proxy", g_ProxyIfIndex);
|
|
Logerr0(PROXY_IF_EXISTS, Error);
|
|
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
}
|
|
|
|
else {
|
|
bProxy = FALSE;
|
|
}
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
|
|
if (Error != NO_ERROR) {
|
|
IGMP_FREE_NOT_NULL(pite);
|
|
|
|
return Error;
|
|
}
|
|
|
|
|
|
//
|
|
// initialize fields for the interface
|
|
//
|
|
InitializeListHead(&pite->LinkByAddr);
|
|
InitializeListHead(&pite->LinkByIndex);
|
|
InitializeListHead(&pite->HTLinkByIndex);
|
|
InitializeListHead(&pite->ListOfSameIfGroups);
|
|
InitializeListHead(&pite->ListOfSameIfGroupsNew);
|
|
InitializeListHead(&pite->Config.ListOfStaticGroups);
|
|
//pite->NumGIEntriesInNewList = 0;
|
|
|
|
|
|
// IfType already set before
|
|
|
|
pite->IfIndex = IfIndex;
|
|
|
|
|
|
// Ip addr set when interface is bound
|
|
//pite->IpAddr = 0;
|
|
|
|
|
|
// set interface status (neither bound, enabled or activated)
|
|
pite->Status = IF_CREATED_FLAG;
|
|
|
|
|
|
|
|
// copy the interface config
|
|
|
|
CopyinIfConfig(&pite->Config, pConfigExt, IfIndex);
|
|
|
|
|
|
|
|
// initialize the Info struct, and If bindings to 0/NULL
|
|
//pite->pBinding = NULL;
|
|
//ZeroMemory(&pite->Info, sizeof(IF_INFO));
|
|
|
|
|
|
|
|
//
|
|
// Create RAS table if it is a RAS server interface
|
|
//
|
|
if ( IS_RAS_SERVER_IF(pite->IfType)) {
|
|
InitializeRasTable(IfIndex, pite);
|
|
}
|
|
else {
|
|
//pite->pRasTable = NULL;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// initialize the sockets to invalid_socket
|
|
//
|
|
pite->SocketEntry.Socket = INVALID_SOCKET;
|
|
pite->SocketEntry.pSocketEventsEntry = NULL;
|
|
InitializeListHead(&pite->SocketEntry.LinkByInterfaces);
|
|
|
|
|
|
|
|
// set (non)query timer to not created.
|
|
//Other fields set in activate interface.
|
|
//pite->QueryTimer.Status = 0;
|
|
//pite->NonQueryTimer.Status = 0;
|
|
|
|
|
|
//pite->pPrevIfGroupEnumPtr = NULL;
|
|
//pite->PrevIfGroupEnumSignature = 0;
|
|
pite->StaticGroupSocket = INVALID_SOCKET;
|
|
|
|
|
|
|
|
// insert the interface in the hash table at the end.
|
|
|
|
InsertTailList(&pIfTable->HashTableByIndex[IF_HASH_VALUE(IfIndex)],
|
|
&pite->HTLinkByIndex);
|
|
|
|
|
|
//
|
|
// insert the interface into the list ordered by index
|
|
//
|
|
{
|
|
PIF_TABLE_ENTRY piteTmp;
|
|
|
|
phead = &pIfTable->ListByIndex;
|
|
for (ple=phead->Flink; ple!=phead; ple=ple->Flink) {
|
|
|
|
piteTmp = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, LinkByIndex);
|
|
if (pite->IfIndex < piteTmp->IfIndex)
|
|
break;
|
|
}
|
|
}
|
|
|
|
InsertTailList(ple, &pite->LinkByIndex);
|
|
|
|
|
|
|
|
// changes to the interface table fields.
|
|
|
|
pIfTable->NumInterfaces++;
|
|
|
|
|
|
|
|
// the interface will be inserted into list ordered by IpAddr
|
|
// when it is activated.
|
|
|
|
|
|
|
|
//
|
|
// create proxy HT, and set proxy info in global structure.
|
|
//
|
|
if (bProxy) {
|
|
|
|
DWORD dwSize = PROXY_HASH_TABLE_SZ * sizeof(LIST_ENTRY);
|
|
DWORD i;
|
|
PLIST_ENTRY pProxyHashTable;
|
|
|
|
|
|
BEGIN_BREAKOUT_BLOCK2 {
|
|
|
|
pProxyHashTable = pite->pProxyHashTable = IGMP_ALLOC(dwSize, 0x4,
|
|
IfIndex);
|
|
|
|
PROCESS_ALLOC_FAILURE2(pProxyHashTable,
|
|
"error %d allocating %d bytes for interface table",
|
|
Error, dwSize, GOTO_END_BLOCK2);
|
|
|
|
for (i=0; i<PROXY_HASH_TABLE_SZ; i++) {
|
|
InitializeListHead(pProxyHashTable+i);
|
|
}
|
|
|
|
|
|
InterlockedExchangePointer(&g_pProxyIfEntry, pite);
|
|
InterlockedExchange(&g_ProxyIfIndex, IfIndex);
|
|
|
|
pite->CreationFlags |= CREATED_PROXY_HASH_TABLE;
|
|
|
|
} END_BREAKOUT_BLOCK2;
|
|
}
|
|
|
|
|
|
//
|
|
// set ras info in global structure. Ras table already created before.
|
|
//
|
|
if (IS_RAS_SERVER_IF(pite->IfType)) {
|
|
InterlockedExchangePointer(&g_pRasIfEntry, pite);
|
|
InterlockedExchange(&g_RasIfIndex, IfIndex);
|
|
}
|
|
|
|
|
|
if ( (Error!=NO_ERROR)&&(pite!=NULL) )
|
|
DeleteIfEntry(pite);
|
|
|
|
|
|
return Error;
|
|
|
|
} //end _AddIfEntry
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _DeleteInterface
|
|
//
|
|
// Deletes the interface, deactivating if it is activated.
|
|
//
|
|
// Calls: _DeleteIfEntry()
|
|
// Locks: Exclusive SocketsLock, IfListLock, Exclusive IfLock
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
DeleteInterface(
|
|
IN DWORD IfIndex
|
|
)
|
|
{
|
|
DWORD Error = NO_ERROR;
|
|
PIF_TABLE_ENTRY pite = NULL;
|
|
|
|
|
|
if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
|
|
Trace1(ENTER, "entering DeleteInterface: %0x", IfIndex);
|
|
|
|
|
|
//
|
|
// acquire exclusive SocketsLock, IfListLock, Exclusive IfLock
|
|
//
|
|
ACQUIRE_SOCKETS_LOCK_EXCLUSIVE("_DeleteInterface");
|
|
ACQUIRE_IF_LIST_LOCK("_DeleteInterface");
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE(IfIndex, "_DeleteInterface");
|
|
|
|
|
|
|
|
// retrieve the interface specified
|
|
|
|
pite = GetIfByIndex(IfIndex);
|
|
|
|
if (pite == NULL) {
|
|
Trace1(ERR,
|
|
"_DeleteInterface() called for non existing interface(%0x)", IfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// delete the interface if found.
|
|
else {
|
|
|
|
Error = DeleteIfEntry(pite);
|
|
|
|
//DebugCheck deldel remove #if dbg
|
|
#if DBG
|
|
DebugScanMemoryInterface(IfIndex);
|
|
#endif
|
|
}
|
|
|
|
|
|
RELEASE_SOCKETS_LOCK_EXCLUSIVE("_DeleteInterface");
|
|
RELEASE_IF_LIST_LOCK("_DeleteInterface");
|
|
RELEASE_IF_LOCK_EXCLUSIVE(IfIndex, "_DeleteInterface");
|
|
|
|
Trace2(LEAVE, "Leaving DeleteInterface(%0x): %d\n", IfIndex, Error);
|
|
|
|
LeaveIgmpApi();
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _DeleteIfEntry
|
|
//
|
|
// Assumes exclusive IF lock. Marks the interface as deleted, and removes it
|
|
// from all global lists. Then queues a work item to do a lazy delete of
|
|
// the Interface structures without having to take the exclusive IF lock.
|
|
// If Ras interface, the work item will delete the Ras clients also.
|
|
//
|
|
// Called by: _DeleteInterface() or _AddIfEntry()
|
|
// Calls:
|
|
// _WF_CompleteIfDeactivateDelete (this calls _DeActivateInterfaceComplete())
|
|
// Lock:
|
|
// runs in exclusive SocketLock, IfListLock, exclusive IfLock
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
DeleteIfEntry (
|
|
PIF_TABLE_ENTRY pite
|
|
)
|
|
{
|
|
DWORD dwRetval, Error = NO_ERROR;
|
|
BOOL bProxy = IS_PROTOCOL_TYPE_PROXY(pite);
|
|
|
|
|
|
//
|
|
// Set deleted flag for the interface
|
|
//
|
|
pite->Status |= DELETED_FLAG;
|
|
|
|
|
|
//
|
|
// remove the interface from the InterfaceHashTable and IfIndex lists.
|
|
//
|
|
RemoveEntryList(&pite->LinkByIndex);
|
|
RemoveEntryList(&pite->HTLinkByIndex);
|
|
|
|
|
|
//
|
|
// if activated, remove the interface from the list of activated interfaces
|
|
// and if proxy or ras server, remove from global table.
|
|
//
|
|
|
|
// do not replace the below with IS_IF_ACTIVATED, as deleted flag is set
|
|
if (pite->Status&IF_ACTIVATED_FLAG)
|
|
RemoveEntryList(&pite->LinkByAddr);
|
|
|
|
if (bProxy) {
|
|
InterlockedExchangePointer(&g_pProxyIfEntry, NULL);
|
|
InterlockedExchange(&g_ProxyIfIndex, 0);
|
|
}
|
|
|
|
if (g_pRasIfEntry == pite) {
|
|
InterlockedExchangePointer(&g_pRasIfEntry, NULL);
|
|
InterlockedExchange(&g_RasIfIndex, 0);
|
|
}
|
|
|
|
|
|
//
|
|
// From now on, the interface cannot be accessed from any global list
|
|
// and is as good as deleted. The only way it can be accessed is
|
|
// through group list enumeration and timers getting fired, or input on
|
|
// socket.
|
|
//
|
|
|
|
|
|
//
|
|
// if Interface activated, deactivate it
|
|
// Note: deleted flag is already set.
|
|
//
|
|
|
|
if (pite->Status&IF_ACTIVATED_FLAG) {
|
|
|
|
//
|
|
// I have already removed the interface from the list of activated
|
|
// interfaces
|
|
//
|
|
|
|
|
|
//
|
|
// Call MGM to release the interface ownership. If proxy then
|
|
// deregister proxy protocol from Mgm. If RAS, deregister all clients
|
|
//
|
|
|
|
DeActivationDeregisterFromMgm(pite);
|
|
|
|
|
|
//
|
|
// queue work item to deactivate and delete the interface.
|
|
//
|
|
// _WF_CompleteIfDeactivateDelete will delete the Ras clients,
|
|
// GI entries, and deinitialize pite structure. It will call
|
|
// _CompleteIfDeletion() in the end.
|
|
//
|
|
|
|
CompleteIfDeactivateDelete(pite);
|
|
}
|
|
|
|
//
|
|
// if it is not activated, then go ahead and delete it completely.
|
|
//
|
|
else {
|
|
|
|
CompleteIfDeletion(pite);
|
|
}
|
|
|
|
|
|
// decrement the total number of interfaces
|
|
|
|
g_pIfTable->NumInterfaces--;
|
|
|
|
|
|
return NO_ERROR;
|
|
|
|
} //end _DeleteIfEntry
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _CompleteIfDeletion
|
|
//
|
|
// Frees memory with the static groups, frees
|
|
// rasTable, proxyHashTable, binding and pite.
|
|
//
|
|
// Called by:
|
|
// _DeleteIfEntry() if interface is not activated.
|
|
// _DeActivateInterfaceComplete() if the pite deleted flag is set.
|
|
//------------------------------------------------------------------------------
|
|
VOID
|
|
CompleteIfDeletion (
|
|
PIF_TABLE_ENTRY pite
|
|
)
|
|
{
|
|
if (pite==NULL)
|
|
return;
|
|
|
|
|
|
//
|
|
// delete all static groups.
|
|
//
|
|
{
|
|
PIF_STATIC_GROUP pStaticGroup;
|
|
PLIST_ENTRY pHead, ple;
|
|
|
|
pHead = &pite->Config.ListOfStaticGroups;
|
|
for (ple=pHead->Flink; ple!=pHead; ) {
|
|
pStaticGroup = CONTAINING_RECORD(ple, IF_STATIC_GROUP, Link);
|
|
ple = ple->Flink;
|
|
IGMP_FREE(pStaticGroup);
|
|
}
|
|
}
|
|
|
|
|
|
// if ras server, then delete ras table.
|
|
|
|
if ( IS_RAS_SERVER_IF(pite->IfType) ) {
|
|
|
|
IGMP_FREE(pite->pRasTable);
|
|
}
|
|
|
|
|
|
//
|
|
// if proxy interface, then delete the proxy Hash Table
|
|
//
|
|
if (IS_PROTOCOL_TYPE_PROXY(pite)) {
|
|
if ( (pite->CreationFlags&CREATED_PROXY_HASH_TABLE)
|
|
&& pite->pProxyHashTable
|
|
) {
|
|
|
|
// clean the hash table entries
|
|
{
|
|
DWORD i;
|
|
PPROXY_GROUP_ENTRY ppge;
|
|
PLIST_ENTRY pHead, ple,
|
|
pProxyHashTable = pite->pProxyHashTable;
|
|
|
|
|
|
for (i=0; i<PROXY_HASH_TABLE_SZ; i++) {
|
|
pHead = &pProxyHashTable[i];
|
|
|
|
for (ple=pHead->Flink; ple!=pHead; ) {
|
|
|
|
ppge = CONTAINING_RECORD(ple, PROXY_GROUP_ENTRY, HT_Link);
|
|
ple=ple->Flink;
|
|
|
|
// delete all sources
|
|
{
|
|
PLIST_ENTRY pHeadSrc, pleSrc;
|
|
PPROXY_SOURCE_ENTRY pSourceEntry;
|
|
|
|
pHeadSrc = &ppge->ListSources;
|
|
for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; ) {
|
|
|
|
pSourceEntry = CONTAINING_RECORD(pleSrc,
|
|
PROXY_SOURCE_ENTRY, LinkSources);
|
|
pleSrc = pleSrc->Flink;
|
|
|
|
IGMP_FREE(pSourceEntry);
|
|
}
|
|
}
|
|
|
|
IGMP_FREE(ppge);
|
|
}
|
|
|
|
InitializeListHead(pHead);
|
|
}
|
|
}
|
|
|
|
IGMP_FREE_NOT_NULL(pite->pProxyHashTable);
|
|
}
|
|
}
|
|
|
|
// delete the bindings
|
|
|
|
IGMP_FREE_NOT_NULL(pite->pBinding);
|
|
|
|
|
|
// delete the interface table entry
|
|
|
|
IGMP_FREE(pite);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _ActivateInterface
|
|
//
|
|
// an interface is activated: when it is bound, enabled by routerMgr & in config
|
|
// When activated,
|
|
// (1) call is made to MGM to take interface ownership,
|
|
// (2) static groups are appropriately joined, and socket for it created if req.
|
|
// (3) Igmprtr: query timer and input socket is activated.
|
|
// Note: it is already put in the list of activated IFs(ordered by IpAddr)
|
|
//
|
|
// Locks: assumes socketLock, IfListLock, exclusive IfLock
|
|
// Called by: _BindIfEntry, _EnableIfEntry,
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
ActivateInterface (
|
|
PIF_TABLE_ENTRY pite
|
|
)
|
|
{
|
|
DWORD IfIndex = pite->IfIndex;
|
|
PIGMP_IF_CONFIG pConfig = &pite->Config;
|
|
PIF_INFO pInfo = &pite->Info;
|
|
PIGMP_TIMER_ENTRY pQueryTimer = &pite->QueryTimer,
|
|
pNonQueryTimer = &pite->NonQueryTimer;
|
|
LONGLONG llCurTime = GetCurrentIgmpTime();
|
|
BOOL bProxy = IS_PROTOCOL_TYPE_PROXY(pite);
|
|
DWORD Error = NO_ERROR;
|
|
PLIST_ENTRY pHead, ple;
|
|
PIF_STATIC_GROUP pStaticGroup;
|
|
|
|
|
|
Trace2(ENTER, "entering ActivateInterface(%0x:%d.%d.%d.%d)",
|
|
IfIndex, PRINT_IPADDR(pite->IpAddr));
|
|
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
//
|
|
// set time when it is activated
|
|
//
|
|
pite->Info.TimeWhenActivated = llCurTime;
|
|
|
|
|
|
|
|
//
|
|
// create sockets for interface
|
|
//
|
|
Error = CreateIfSockets(pite);
|
|
|
|
if (Error != NO_ERROR) {
|
|
|
|
Trace2(IF, "error %d initializing sockets for interface %0x", Error,
|
|
pite->IfIndex);
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
pite->CreationFlags |= SOCKETS_CREATED;
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------
|
|
// PROXY INTERFACE PROCESSING (break at end)
|
|
//------------------------------------------
|
|
if (bProxy) {
|
|
|
|
|
|
//
|
|
// set status to activated here so that the MGM (*,*) join callbacks will
|
|
// be successful.
|
|
//
|
|
pite->Status |= IF_ACTIVATED_FLAG;
|
|
|
|
|
|
|
|
//
|
|
// register the protocol with mgm
|
|
//
|
|
Error = RegisterProtocolWithMgm(PROTO_IP_IGMP_PROXY);
|
|
if (Error!=NO_ERROR)
|
|
GOTO_END_BLOCK1;
|
|
pite->CreationFlags |= REGISTERED_PROTOCOL_WITH_MGM;
|
|
|
|
|
|
|
|
//
|
|
// enumerate all existing groups from MGM
|
|
//
|
|
{
|
|
DWORD dwBufferSize, dwNumEntries, dwRetval, i;
|
|
MGM_ENUM_TYPES MgmEnumType = 0;
|
|
SOURCE_GROUP_ENTRY BufferSGEntries[20];
|
|
HANDLE hMgmEnum;
|
|
|
|
|
|
// start enumeration
|
|
|
|
dwBufferSize = sizeof(SOURCE_GROUP_ENTRY)*20;
|
|
|
|
Error = MgmGroupEnumerationStart(g_MgmProxyHandle, MgmEnumType,
|
|
&hMgmEnum);
|
|
if (Error!=NO_ERROR) {
|
|
Trace1(ERR, "MgmGroupEnumerationStart() returned error:%d",
|
|
Error);
|
|
IgmpAssertOnError(FALSE);
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
|
|
// get group entries from mgm
|
|
// and insert group into Proxy's group list / increment refcount
|
|
|
|
do {
|
|
|
|
|
|
dwRetval = MgmGroupEnumerationGetNext(hMgmEnum, &dwBufferSize,
|
|
(PBYTE)BufferSGEntries,
|
|
&dwNumEntries);
|
|
|
|
|
|
for (i=0; i<dwNumEntries; i++) {
|
|
|
|
ProcessProxyGroupChange(BufferSGEntries[i].dwSourceAddr,
|
|
BufferSGEntries[i].dwGroupAddr,
|
|
ADD_FLAG, NOT_STATIC_GROUP);
|
|
}
|
|
|
|
} while (dwRetval==ERROR_MORE_DATA);
|
|
|
|
|
|
|
|
// end enumeration
|
|
|
|
dwRetval = MgmGroupEnumerationEnd(hMgmEnum);
|
|
if (dwRetval!=NO_ERROR) {
|
|
Trace1(ERR, "MgmGroupEnumerationEnd() returned error:%d",
|
|
dwRetval);
|
|
IgmpAssertOnError(FALSE);
|
|
}
|
|
} //end block:enumerate existing groups
|
|
|
|
|
|
|
|
//
|
|
// take interface ownership
|
|
//
|
|
Error = MgmTakeInterfaceOwnership(g_MgmProxyHandle, IfIndex, 0);
|
|
|
|
if (Error!=NO_ERROR) {
|
|
Trace1(MGM, "MgmTakeInterfaceOwnership rejected for interface %0x",
|
|
IfIndex);
|
|
Logerr0(MGM_TAKE_IF_OWNERSHIP_FAILED, Error);
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
else {
|
|
Trace1(MGM, "MgmTakeInterfaceOwnership successful for interface %0x",
|
|
IfIndex);
|
|
}
|
|
|
|
pite->CreationFlags |= TAKEN_INTERFACE_OWNERSHIP_WITH_MGM;
|
|
|
|
|
|
|
|
//
|
|
// proxy does a (*,*) join
|
|
//
|
|
Error = MgmAddGroupMembershipEntry(g_MgmProxyHandle, 0, 0, 0, 0,
|
|
IfIndex, 0, MGM_JOIN_STATE_FLAG);
|
|
if (Error!=NO_ERROR) {
|
|
Trace1(ERR,
|
|
"Proxy failed to add *,* entry to MGM on interface %0x",
|
|
IfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
Trace0(MGM, "proxy added *,* entry to MGM");
|
|
pite->CreationFlags|= DONE_STAR_STAR_JOIN;
|
|
|
|
|
|
//
|
|
// do static joins
|
|
//
|
|
pHead = &pite->Config.ListOfStaticGroups;
|
|
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
|
|
DWORD i;
|
|
|
|
pStaticGroup = CONTAINING_RECORD(ple, IF_STATIC_GROUP, Link);
|
|
for (i=0; i<pStaticGroup->NumSources; i++) {
|
|
ProcessProxyGroupChange(pStaticGroup->Sources[i], pStaticGroup->GroupAddr,
|
|
ADD_FLAG, STATIC_GROUP);
|
|
}
|
|
|
|
if (pStaticGroup->NumSources==0)
|
|
ProcessProxyGroupChange(0, pStaticGroup->GroupAddr,
|
|
ADD_FLAG, STATIC_GROUP);
|
|
}
|
|
|
|
|
|
GOTO_END_BLOCK1;
|
|
|
|
} // done processing for a proxy interface
|
|
|
|
|
|
|
|
//-----------------------------------------
|
|
// IGMP ROUTER INTERFACE
|
|
//-----------------------------------------
|
|
|
|
|
|
//
|
|
// take interface ownership
|
|
//
|
|
Error = MgmTakeInterfaceOwnership(g_MgmIgmprtrHandle, IfIndex, 0);
|
|
|
|
if (Error!=NO_ERROR) {
|
|
Trace1(MGM, "TakeInterfaceOwnership rejected for interface %0x",
|
|
IfIndex);
|
|
Logerr0(MGM_TAKE_IF_OWNERSHIP_FAILED, Error);
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
pite->CreationFlags |= TAKEN_INTERFACE_OWNERSHIP_WITH_MGM;
|
|
|
|
|
|
//
|
|
// see if any other MCast protocol is owning that interface
|
|
// this affects whether a non-querier registers group with Mgm or not
|
|
//
|
|
{
|
|
DWORD dwProtoId, dwComponentId;
|
|
|
|
MgmGetProtocolOnInterface(IfIndex, 0, &dwProtoId, &dwComponentId);
|
|
if (dwProtoId==PROTO_IP_IGMP) {
|
|
SET_MPROTOCOL_ABSENT_ON_IGMPRTR(pite);
|
|
}
|
|
else {
|
|
SET_MPROTOCOL_PRESENT_ON_IGMPRTR(pite);
|
|
}
|
|
}
|
|
|
|
//
|
|
// when interface is activated, it is by default enabled by mgm.
|
|
//
|
|
MGM_ENABLE_IGMPRTR(pite);
|
|
|
|
|
|
//
|
|
// if ras server interface, then register all the ras clients as they
|
|
// would not have been registered
|
|
//
|
|
if (IS_RAS_SERVER_IF(pite->IfType)) {
|
|
|
|
PRAS_TABLE_ENTRY prte;
|
|
|
|
// join all ras clients
|
|
pHead = &pite->pRasTable->ListByAddr;
|
|
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
|
|
|
|
prte = CONTAINING_RECORD(ple, RAS_TABLE_ENTRY, LinkByAddr);
|
|
|
|
Error = MgmTakeInterfaceOwnership(g_MgmIgmprtrHandle, IfIndex,
|
|
prte->NHAddr);
|
|
|
|
if (Error!=NO_ERROR) {
|
|
Trace2(MGM,
|
|
"TakeInterfaceOwnership rejected for interface %0x "
|
|
"NHAddr(%d.%d.%d.%d)",
|
|
IfIndex, PRINT_IPADDR(prte->NHAddr));
|
|
Logerr0(MGM_TAKE_IF_OWNERSHIP_FAILED, Error);
|
|
}
|
|
else {
|
|
prte->CreationFlags |= TAKEN_INTERFACE_OWNERSHIP_WITH_MGM;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// INITIALIZE THE INFO STRUCTURE AND SET THE TIMERS
|
|
//
|
|
|
|
//
|
|
// start as querier with version specified in the config
|
|
//
|
|
pInfo->QuerierState = RTR_QUERIER;
|
|
|
|
pInfo->QuerierIpAddr = pite->IpAddr;
|
|
|
|
pInfo->LastQuerierChangeTime = llCurTime;
|
|
|
|
|
|
//
|
|
// how many startup queries left to be sent
|
|
//
|
|
pInfo->StartupQueryCountCurrent = pConfig->StartupQueryCount;
|
|
{
|
|
MIB_IFROW TmpIfEntry;
|
|
|
|
TmpIfEntry.dwIndex = IfIndex;
|
|
if (GetIfEntry(&TmpIfEntry ) == NO_ERROR)
|
|
pInfo->PacketSize = TmpIfEntry.dwMtu;
|
|
else
|
|
pInfo->PacketSize = INPUT_PACKET_SZ;
|
|
}
|
|
|
|
|
|
//
|
|
// initialize the query timer
|
|
//
|
|
pQueryTimer->Function = T_QueryTimer;
|
|
pQueryTimer->Context = &pQueryTimer->Context;
|
|
pQueryTimer->Timeout = pConfig->StartupQueryInterval;
|
|
pQueryTimer->Status = TIMER_STATUS_CREATED;
|
|
|
|
//
|
|
// initialize non query timer
|
|
//
|
|
pNonQueryTimer->Function = T_NonQueryTimer;
|
|
pNonQueryTimer->Context = &pNonQueryTimer->Context;
|
|
pNonQueryTimer->Timeout = pConfig->OtherQuerierPresentInterval;
|
|
pNonQueryTimer->Status = TIMER_STATUS_CREATED;
|
|
|
|
|
|
//
|
|
// take timer lock and insert timers into the list
|
|
//
|
|
ACQUIRE_TIMER_LOCK("_ActivateInterface");
|
|
|
|
//
|
|
// insert querier timer in the list
|
|
//
|
|
#if DEBUG_TIMER_TIMERID
|
|
SET_TIMER_ID(pQueryTimer, 110, IfIndex, 0, 0);
|
|
#endif;
|
|
|
|
InsertTimer(pQueryTimer, pQueryTimer->Timeout, TRUE, DBG_Y);
|
|
|
|
RELEASE_TIMER_LOCK("_ActivateInterface");
|
|
|
|
|
|
|
|
//
|
|
// activate Input socket
|
|
//
|
|
Error = WSAEventSelect(pite->SocketEntry.Socket,
|
|
pite->SocketEntry.pSocketEventsEntry->InputEvent,
|
|
FD_READ
|
|
);
|
|
|
|
if (Error != NO_ERROR) {
|
|
Trace3(IF, "WSAEventSelect returned %d for interface %0x (%d.%d.%d.%d)",
|
|
Error, IfIndex, PRINT_IPADDR(pite->IpAddr));
|
|
Logerr1(EVENTSELECT_FAILED, "%I", pite->IpAddr, 0);
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
//
|
|
// set the activated flag here so that the joins will work
|
|
//
|
|
pite->Status |= IF_ACTIVATED_FLAG;
|
|
|
|
|
|
if (pInfo->StartupQueryCountCurrent) {
|
|
|
|
//
|
|
// send the initial general query
|
|
//
|
|
SEND_GEN_QUERY(pite);
|
|
|
|
|
|
// decrement the number of startupQueryCount left to be sent
|
|
pInfo->StartupQueryCountCurrent--;
|
|
}
|
|
|
|
|
|
//
|
|
// do static joins (no static joins for ras server interface)
|
|
//
|
|
if (!IS_RAS_SERVER_IF(pite->IfType))
|
|
{
|
|
PGROUP_TABLE_ENTRY pge;
|
|
PGI_ENTRY pgie;
|
|
DWORD GroupAddr;
|
|
SOCKADDR_IN saLocalIf;
|
|
|
|
//
|
|
// socket for static groups already created in _CreateIfSockets
|
|
// irrespective of whether there are any static groups
|
|
//
|
|
|
|
|
|
pHead = &pite->Config.ListOfStaticGroups;
|
|
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
|
|
|
|
pStaticGroup = CONTAINING_RECORD(ple, IF_STATIC_GROUP, Link);
|
|
|
|
|
|
// IGMP_HOST_JOIN
|
|
|
|
if (pStaticGroup->Mode==IGMP_HOST_JOIN) {
|
|
|
|
DWORD i;
|
|
|
|
if (pStaticGroup->NumSources==0
|
|
|| pStaticGroup->FilterType==EXCLUSION)
|
|
{
|
|
JoinMulticastGroup(pite->StaticGroupSocket,
|
|
pStaticGroup->GroupAddr,
|
|
pite->IfIndex,
|
|
pite->IpAddr,
|
|
0
|
|
);
|
|
}
|
|
|
|
for (i=0; i<pStaticGroup->NumSources; i++) {
|
|
if (pStaticGroup->FilterType==INCLUSION) {
|
|
JoinMulticastGroup(pite->StaticGroupSocket,
|
|
pStaticGroup->GroupAddr,
|
|
pite->IfIndex,
|
|
pite->IpAddr,
|
|
pStaticGroup->Sources[i]
|
|
);
|
|
}
|
|
else {
|
|
BlockSource(pite->StaticGroupSocket,
|
|
pStaticGroup->GroupAddr,
|
|
pite->IfIndex,
|
|
pite->IpAddr,
|
|
pStaticGroup->Sources[i]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// IGMPRTR_MGM_ONLY
|
|
|
|
else {
|
|
BOOL bCreate = TRUE;
|
|
DWORD i;
|
|
|
|
GroupAddr = pStaticGroup->GroupAddr;
|
|
|
|
ACQUIRE_GROUP_LOCK(GroupAddr, "_ActivateInterface");
|
|
|
|
pge = GetGroupFromGroupTable(GroupAddr, &bCreate, 0);
|
|
pgie = GetGIFromGIList(pge, pite, 0,
|
|
pStaticGroup->NumSources==0?STATIC_GROUP:NOT_STATIC_GROUP,
|
|
&bCreate, 0);
|
|
for (i=0; i<pStaticGroup->NumSources; i++) {
|
|
GetSourceEntry(pgie, pStaticGroup->Sources[i],
|
|
pStaticGroup->FilterType,
|
|
&bCreate, STATIC, MGM_YES);
|
|
}
|
|
RELEASE_GROUP_LOCK(GroupAddr, "_ActivateInterface");
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
|
|
if (Error!=NO_ERROR) {
|
|
|
|
DeActivationDeregisterFromMgm(pite);
|
|
|
|
DeActivateInterfaceComplete(pite);
|
|
|
|
pite->Status &= ~IF_ACTIVATED_FLAG;
|
|
|
|
if (bProxy) {
|
|
Logerr1(ACTIVATION_FAILURE_PROXY, "%d",IfIndex, Error);
|
|
}
|
|
else {
|
|
Logerr2(ACTIVATION_FAILURE_RTR, "%d%d",
|
|
GET_IF_VERSION(pite), IfIndex, Error);
|
|
}
|
|
}
|
|
|
|
else {
|
|
if (bProxy) {
|
|
Loginfo1(INTERFACE_PROXY_ACTIVATED, "%d",
|
|
IfIndex, NO_ERROR);
|
|
}
|
|
else {
|
|
Loginfo2(INTERFACE_RTR_ACTIVATED, "%d%d",
|
|
GET_IF_VERSION(pite), IfIndex, NO_ERROR);
|
|
}
|
|
Trace1(START, "IGMP activated on interface:%0x", IfIndex);
|
|
}
|
|
|
|
|
|
Trace1(LEAVE, "leaving ActivateInterface():%d\n", Error);
|
|
|
|
return Error;
|
|
|
|
} //end _ActivateInterface
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _DeActivateDeregisterFromMgm
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
DeActivationDeregisterFromMgm(
|
|
PIF_TABLE_ENTRY pite
|
|
)
|
|
{
|
|
HANDLE hMgmHandle = IS_PROTOCOL_TYPE_PROXY(pite)
|
|
? g_MgmProxyHandle: g_MgmIgmprtrHandle;
|
|
DWORD Error=NO_ERROR, IfIndex=pite->IfIndex;
|
|
PLIST_ENTRY pHead, ple;
|
|
|
|
//
|
|
// Call MGM to release the interface ownership
|
|
//
|
|
if (pite->CreationFlags&TAKEN_INTERFACE_OWNERSHIP_WITH_MGM) {
|
|
|
|
Error = MgmReleaseInterfaceOwnership(hMgmHandle, IfIndex,0);
|
|
if (Error!=NO_ERROR) {
|
|
Trace2(ERR, "MgmReleaseInterfaceOwnership returned error(%d) for If(%0x)",
|
|
Error, IfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
}
|
|
else
|
|
pite->CreationFlags &= ~TAKEN_INTERFACE_OWNERSHIP_WITH_MGM;
|
|
}
|
|
|
|
|
|
//
|
|
// if releasing proxy interface, then deregister proxy from mgm
|
|
//
|
|
|
|
if (IS_PROTOCOL_TYPE_PROXY(pite)
|
|
&& (pite->CreationFlags®ISTERED_PROTOCOL_WITH_MGM))
|
|
{
|
|
Error = MgmDeRegisterMProtocol(g_MgmProxyHandle);
|
|
|
|
if (Error!=NO_ERROR) {
|
|
Trace1(ERR, "MgmDeRegisterMProtocol(proxy) returned error(%d)",
|
|
Error);
|
|
IgmpAssertOnError(FALSE);
|
|
|
|
}
|
|
else
|
|
pite->CreationFlags &= ~REGISTERED_PROTOCOL_WITH_MGM;
|
|
}
|
|
|
|
//
|
|
// delete all proxy alert entries
|
|
//
|
|
if (IS_PROTOCOL_TYPE_PROXY(pite)) {
|
|
|
|
ACQUIRE_PROXY_ALERT_LOCK("_DeActivationDeregisterMgm");
|
|
|
|
{
|
|
for (ple=g_ProxyAlertsList.Flink; ple!=&g_ProxyAlertsList; ) {
|
|
PPROXY_ALERT_ENTRY pProxyAlertEntry
|
|
= CONTAINING_RECORD(ple, PROXY_ALERT_ENTRY, Link);
|
|
ple = ple->Flink;
|
|
IGMP_FREE(pProxyAlertEntry);
|
|
}
|
|
}
|
|
|
|
InitializeListHead(&g_ProxyAlertsList);
|
|
RELEASE_PROXY_ALERT_LOCK("_DeActivationDeregisterMgm");
|
|
}
|
|
|
|
//
|
|
// if ras interface, then call mgm to release ownership of all ras clients
|
|
//
|
|
if (IS_RAS_SERVER_IF(pite->IfType)) {
|
|
PRAS_TABLE_ENTRY prte;
|
|
|
|
pHead = &pite->pRasTable->ListByAddr;
|
|
|
|
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
|
|
|
|
prte = CONTAINING_RECORD(ple, RAS_TABLE_ENTRY, LinkByAddr);
|
|
|
|
if (prte->CreationFlags & TAKEN_INTERFACE_OWNERSHIP_WITH_MGM) {
|
|
|
|
Error = MgmReleaseInterfaceOwnership(g_MgmIgmprtrHandle, IfIndex,
|
|
prte->NHAddr);
|
|
|
|
if (Error!=NO_ERROR) {
|
|
Trace3(ERR,
|
|
"error:%d _MgmReleaseInterfaceOwnership() for If:%0x, "
|
|
"NHAddr:%d.%d.%d.%d",
|
|
Error, IfIndex, PRINT_IPADDR(prte->NHAddr));
|
|
IgmpAssertOnError(FALSE);
|
|
}
|
|
|
|
prte->CreationFlags &= ~TAKEN_INTERFACE_OWNERSHIP_WITH_MGM;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return Error;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// DeActivateInterfaceInitial
|
|
//
|
|
// deregister from MGM. Then create a new interface entry structure which
|
|
// replaces the old one in all the lists. Now the old interface entry and
|
|
// all its associated structures can be lazily deleted.
|
|
// Also update the global Proxy and Ras table pointers.
|
|
//
|
|
// Called by _UnBindIfEntry(), _DisableIfEntry()
|
|
//------------------------------------------------------------------------------
|
|
|
|
PIF_TABLE_ENTRY
|
|
DeActivateInterfaceInitial (
|
|
PIF_TABLE_ENTRY piteOld
|
|
)
|
|
{
|
|
DWORD IfIndex = piteOld->IfIndex;
|
|
PIF_TABLE_ENTRY piteNew;
|
|
DWORD dwRetval, Error=NO_ERROR;
|
|
PLIST_ENTRY pHead, ple, pleNext;
|
|
|
|
|
|
Trace0(ENTER1, "Entering _DeActivateInterfaceInitial()");
|
|
|
|
|
|
//
|
|
// deregister from Mgm
|
|
//
|
|
DeActivationDeregisterFromMgm(piteOld);
|
|
|
|
|
|
//
|
|
// allocate memory for the new interface
|
|
//
|
|
piteNew = IGMP_ALLOC(sizeof(IF_TABLE_ENTRY), 0x8, IfIndex);
|
|
|
|
PROCESS_ALLOC_FAILURE3(piteNew,
|
|
"error %d allocating %d bytes for interface %0x",
|
|
Error, sizeof(IF_TABLE_ENTRY), IfIndex,
|
|
return NULL);
|
|
|
|
|
|
|
|
// copy the old pite fields to the new pite
|
|
CopyMemory(piteNew, piteOld, sizeof(IF_TABLE_ENTRY));
|
|
|
|
|
|
// copy the old static groups to the new pite
|
|
InitializeListHead(&piteNew->Config.ListOfStaticGroups);
|
|
pHead = &piteOld->Config.ListOfStaticGroups;
|
|
for (ple=pHead->Flink; ple!=pHead; ple=pleNext) {
|
|
|
|
pleNext = ple->Flink;
|
|
RemoveEntryList(ple);
|
|
InsertTailList(&piteNew->Config.ListOfStaticGroups,
|
|
ple);
|
|
}
|
|
|
|
|
|
// set the status
|
|
MGM_DISABLE_IGMPRTR(piteNew);
|
|
|
|
|
|
|
|
// LinkByAddr (not inserted in this list as the IF is deactivated)
|
|
InitializeListHead(&piteNew->LinkByAddr);
|
|
|
|
|
|
//
|
|
// insert the new entry before the old entry, and remove the old
|
|
// entry from the list of IFs ordered by index and from hash table
|
|
//
|
|
|
|
InsertTailList(&piteOld->LinkByIndex, &piteNew->LinkByIndex);
|
|
RemoveEntryList(&piteOld->LinkByIndex);
|
|
|
|
InsertTailList(&piteOld->HTLinkByIndex, &piteNew->HTLinkByIndex);
|
|
RemoveEntryList(&piteOld->HTLinkByIndex);
|
|
|
|
|
|
|
|
// initialize GI list to empty
|
|
InitializeListHead(&piteNew->ListOfSameIfGroups);
|
|
InitializeListHead(&piteNew->ListOfSameIfGroupsNew);
|
|
piteNew->NumGIEntriesInNewList = 0;
|
|
|
|
|
|
|
|
// set binding of piteOld to NULL so that it doesnt get deleted
|
|
piteOld->pBinding = NULL;
|
|
|
|
|
|
// reset the Info fields
|
|
ZeroMemory(&piteNew->Info, sizeof(IF_INFO));
|
|
|
|
|
|
//
|
|
// create a new RAS table if it is a RAS server interface, and set ras
|
|
// pointer in global table. I could have reused the ras table, but dont
|
|
// so that resetting the fields is cleaner.
|
|
//
|
|
if ( IS_RAS_SERVER_IF(piteNew->IfType)) {
|
|
|
|
PRAS_TABLE_ENTRY prte;
|
|
|
|
InitializeRasTable(IfIndex, piteNew);
|
|
|
|
//
|
|
// recreate all ras client entries
|
|
//
|
|
pHead = &piteOld->pRasTable->ListByAddr;
|
|
|
|
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
|
|
|
|
prte = CONTAINING_RECORD(ple, RAS_TABLE_ENTRY, LinkByAddr);
|
|
|
|
CreateRasClient(piteNew, &prte, prte->NHAddr);
|
|
}
|
|
|
|
InterlockedExchangePointer(&g_pRasIfEntry, piteNew);
|
|
}
|
|
|
|
|
|
//
|
|
// if proxy, then update the entry in the global table
|
|
// I reuse the proxy hash table. set it to null in piteOld so that it is not
|
|
// delete there.
|
|
//
|
|
if (g_pProxyIfEntry == piteOld) {
|
|
InterlockedExchangePointer(&g_pProxyIfEntry, piteNew);
|
|
|
|
|
|
// clean the hash table entries
|
|
{
|
|
DWORD i;
|
|
PPROXY_GROUP_ENTRY ppge;
|
|
PLIST_ENTRY pProxyHashTable = piteOld->pProxyHashTable;
|
|
|
|
if (piteOld->CreationFlags&CREATED_PROXY_HASH_TABLE) {
|
|
|
|
for (i=0; i<PROXY_HASH_TABLE_SZ; i++) {
|
|
pHead = &pProxyHashTable[i];
|
|
|
|
for (ple=pHead->Flink; ple!=pHead; ) {
|
|
|
|
ppge = CONTAINING_RECORD(ple, PROXY_GROUP_ENTRY, HT_Link);
|
|
ple=ple->Flink;
|
|
|
|
// delete all sources
|
|
{
|
|
PLIST_ENTRY pHeadSrc, pleSrc;
|
|
PPROXY_SOURCE_ENTRY pSourceEntry;
|
|
|
|
pHeadSrc = &ppge->ListSources;
|
|
for (pleSrc=pHeadSrc->Flink; pleSrc!=pHeadSrc; ) {
|
|
|
|
pSourceEntry = CONTAINING_RECORD(pleSrc,
|
|
PROXY_SOURCE_ENTRY, LinkSources);
|
|
pleSrc = pleSrc->Flink;
|
|
|
|
IGMP_FREE(pSourceEntry);
|
|
}
|
|
}
|
|
|
|
IGMP_FREE(ppge);
|
|
}
|
|
|
|
InitializeListHead(pHead);
|
|
}
|
|
}
|
|
}
|
|
|
|
piteOld->pProxyHashTable = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// socket is created when the interface is activated
|
|
//
|
|
|
|
piteNew->SocketEntry.Socket = INVALID_SOCKET;
|
|
//piteNew->SocketEntry.pSocketEventsEntry = NULL;
|
|
//InitializeListHead(&piteNew->SocketEntry.LinkByInterfaces);
|
|
|
|
|
|
// initialize the new timers
|
|
piteNew->QueryTimer.Status = 0;
|
|
piteNew->NonQueryTimer.Status = 0;
|
|
|
|
|
|
piteNew->pPrevIfGroupEnumPtr = NULL;
|
|
piteNew->PrevIfGroupEnumSignature = 0;
|
|
piteNew->StaticGroupSocket = INVALID_SOCKET;
|
|
|
|
|
|
// creationFlags already copied.
|
|
piteNew->CreationFlags &= ~CREATION_FLAGS_DEACTIVATION_CLEAR;
|
|
|
|
|
|
|
|
Trace0(LEAVE1, "Leaving _DeActivateInterfaceInitial()");
|
|
return piteNew;
|
|
|
|
}//end _DeActivateInterfaceInitial
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _DeActivateInterfaceComplete
|
|
//
|
|
// If ras server, then for each ras client queues a work item to delete it.
|
|
// the last ras client will delete the pite entry.
|
|
// Deletes the GI entries, and calls _CompleteIfDeletion() if deleted flag
|
|
// or DeactivateDelete flag set on the IF entry.
|
|
// This routine assumes that the interface has been removed from any global
|
|
// lists that it needs to be removed from, and that the appropriate flags have
|
|
// been set. The only way they can still be used is by timers getting fired or
|
|
// by input on socket.
|
|
//
|
|
// Called by:
|
|
// _ActivateInterface:(if it fails), only in this case pite is not deleted.
|
|
// _DeleteIfEntry -->
|
|
// _DeActivationDeregisterFromMgm & _WF_CompleteIfDeactivateDelete
|
|
// _UnbindIfEntry & _DisableIfEntry -->
|
|
// _DeActivateInterfaceInitial & _WF_CompleteIfDeactivateDelete
|
|
// Lock:
|
|
// If called when interface is being deleted, then no interface locks required.
|
|
// else assumes exclusive interface lock.
|
|
// requires exclusive sockets list lock in either case.
|
|
//------------------------------------------------------------------------------
|
|
VOID
|
|
DeActivateInterfaceComplete (
|
|
PIF_TABLE_ENTRY pite
|
|
)
|
|
{
|
|
DWORD IfIndex = pite->IfIndex;
|
|
DWORD Error = NO_ERROR, dwRetval;
|
|
PLIST_ENTRY pHead, ple;
|
|
PGI_ENTRY pgie;
|
|
BOOL bProxy = IS_PROTOCOL_TYPE_PROXY(pite);;
|
|
|
|
|
|
Trace1(ENTER1, "Entering _DeActivateInterfaceComplete(%d)", IfIndex);
|
|
|
|
|
|
//
|
|
// do all deactivation here which is common for all interfaces
|
|
// whether ras server or not.
|
|
//
|
|
|
|
|
|
|
|
//
|
|
// unbind sockets from Input event and then close the sockets
|
|
//
|
|
if (pite->SocketEntry.Socket!=INVALID_SOCKET) {
|
|
|
|
//
|
|
// proxy does not bind its socket to input event as it
|
|
// does not want to receive any packets
|
|
//
|
|
if (!bProxy)
|
|
WSAEventSelect(pite->SocketEntry.Socket,
|
|
pite->SocketEntry.pSocketEventsEntry->InputEvent, 0);
|
|
|
|
}
|
|
|
|
if (pite->CreationFlags&SOCKETS_CREATED)
|
|
DeleteIfSockets(pite);
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// IS_RAS_SERVER_IF
|
|
/////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// go through the list of Ras clients. Mark them as deleted, remove them
|
|
// from all global lists, and set work item to delete them.
|
|
//
|
|
if (IS_RAS_SERVER_IF(pite->IfType)) {
|
|
|
|
PRAS_TABLE prt = pite->pRasTable;
|
|
PRAS_TABLE_ENTRY prte;
|
|
|
|
|
|
// go through the list of all Ras clients and set them to be deleted
|
|
|
|
pHead = &prt->ListByAddr;
|
|
for (ple=pHead->Flink; ple!=pHead; ) {
|
|
|
|
prte = CONTAINING_RECORD(ple, RAS_TABLE_ENTRY, LinkByAddr);
|
|
|
|
ple=ple->Flink;
|
|
|
|
|
|
//
|
|
// if ras client has deleted flag already set, then ignore it.
|
|
//
|
|
if (!(prte->Status&IF_DELETED_FLAG)) {
|
|
|
|
//
|
|
// set deleted flag for the ras client, so that no one else will
|
|
// try to access it
|
|
prte->Status |= IF_DELETED_FLAG;
|
|
|
|
|
|
//
|
|
// remove the RAS client from the Ras table lists so that no one
|
|
// will access it.
|
|
//
|
|
RemoveEntryList(&prte->HTLinkByAddr);
|
|
RemoveEntryList(&prte->LinkByAddr);
|
|
|
|
|
|
//
|
|
// clean up the ras client
|
|
//
|
|
DeleteRasClient(prte);
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// delete the timers from pite entry
|
|
//
|
|
|
|
ACQUIRE_TIMER_LOCK("_DeActivateInterfaceComplete");
|
|
|
|
if (IS_TIMER_ACTIVE(pite->QueryTimer))
|
|
RemoveTimer(&pite->QueryTimer, DBG_Y);
|
|
|
|
if (IS_TIMER_ACTIVE(pite->NonQueryTimer))
|
|
RemoveTimer(&pite->NonQueryTimer, DBG_Y);
|
|
|
|
RELEASE_TIMER_LOCK("_DeActivateInterfaceComplete");
|
|
|
|
|
|
|
|
pite->CreationFlags = 0;
|
|
prt->RefCount--;
|
|
|
|
|
|
//
|
|
// deleting the pite entry(if deleted flag is set), and ras table will
|
|
// be done by the work item which deletes the last Ras client
|
|
// (when refcount==0) however if there are no ras clients, then I will
|
|
// have to do the cleanup here
|
|
//
|
|
|
|
if ( ((pite->Status&IF_DELETED_FLAG)
|
|
||(pite->Status&IF_DEACTIVATE_DELETE_FLAG))
|
|
&&(prt->RefCount==0) )
|
|
{
|
|
CompleteIfDeletion(pite);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------
|
|
// NOT IS_RAS_SERVER_IF: PROXY IF
|
|
//------------------------------------------------------------
|
|
|
|
// PROXY INTERFACE. Just clean the hash table, and delete interface if req
|
|
|
|
else if ( (!IS_RAS_SERVER_IF(pite->IfType)) && bProxy) {
|
|
|
|
|
|
// the proxy hashTable will be deleted if
|
|
// necessary in _CompleteIfDeletion().
|
|
|
|
|
|
//
|
|
// delete the interface if either IF_DELETED_FLAG or
|
|
// IF_DEACTIVATE_DELETE_FLAG set. (interface not deleted when cleaning
|
|
// up because activate interface failed
|
|
//
|
|
if ( (pite->Status&IF_DELETED_FLAG)
|
|
||(pite->Status&IF_DEACTIVATE_DELETE_FLAG) )
|
|
{
|
|
CompleteIfDeletion(pite);
|
|
}
|
|
}
|
|
|
|
//----------------------
|
|
// NOT PROXY interface
|
|
//----------------------
|
|
|
|
else if ( !IS_RAS_SERVER_IF(pite->IfType) ) {
|
|
|
|
//
|
|
// take exclusive lock on the If_Group List and remove all timers.
|
|
// From now on no one can enter from outside and no one is inside
|
|
// as all timers have been removed.
|
|
|
|
// have to take the if_group_list lock to make sure that no
|
|
// one is changing it.
|
|
ACQUIRE_IF_GROUP_LIST_LOCK(pite->IfIndex, "_DeActivateInterfaceComplete");
|
|
|
|
//
|
|
// Remove all timers
|
|
//
|
|
|
|
ACQUIRE_TIMER_LOCK("_DeActivateInterfaceComplete");
|
|
|
|
|
|
// delete all timers contained in GI entries and the sources
|
|
|
|
pHead = &pite->ListOfSameIfGroups;
|
|
DeleteAllTimers(pHead, NOT_RAS_CLIENT);
|
|
pHead = &pite->ListOfSameIfGroupsNew;
|
|
DeleteAllTimers(pHead, NOT_RAS_CLIENT);
|
|
pite->NumGIEntriesInNewList = 0;
|
|
|
|
|
|
|
|
// delete query timer
|
|
|
|
if (IS_TIMER_ACTIVE(pite->QueryTimer))
|
|
RemoveTimer(&pite->QueryTimer, DBG_Y);
|
|
|
|
if (IS_TIMER_ACTIVE(pite->NonQueryTimer))
|
|
RemoveTimer(&pite->NonQueryTimer, DBG_Y);
|
|
|
|
|
|
RELEASE_TIMER_LOCK("_DeActivateInterfaceComplete");
|
|
|
|
|
|
RELEASE_IF_GROUP_LIST_LOCK(pite->IfIndex, "_DeActivateInterfaceComplete");
|
|
|
|
|
|
//
|
|
// revisit the list and delete all GI entries. Need to take
|
|
// exclusive lock on the group bucket before deleting the GI entry
|
|
// No need to lock the If-Group list as deleted flag already set and
|
|
// no one can visit the list from outside or inside(all timers removed).
|
|
//
|
|
DeleteAllGIEntries(pite);
|
|
|
|
|
|
//
|
|
// if deleted flag set, then also delete the interface
|
|
//
|
|
|
|
if ( (pite->Status&IF_DELETED_FLAG)
|
|
||(pite->Status&IF_DEACTIVATE_DELETE_FLAG) )
|
|
{
|
|
CompleteIfDeletion(pite);
|
|
}
|
|
|
|
} //deactivated if: Not(ras server if)
|
|
|
|
|
|
// do not use pite, or prt from here as they are deleted.
|
|
|
|
if (bProxy)
|
|
Loginfo1(PROXY_DEACTIVATED, "%d",IfIndex, NO_ERROR);
|
|
else
|
|
Loginfo1(RTR_DEACTIVATED, "%d",IfIndex, NO_ERROR);
|
|
|
|
Trace1(LEAVE, "leaving _DeActivateInterfaceComplete(%d)", IfIndex);
|
|
|
|
} //end _DeActivateInterfaceComplete
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// EnableInterface
|
|
//
|
|
// sets the status to enabled. If interface is also bound and enabled in
|
|
// config, then activate the interface.
|
|
//
|
|
// Locks: SocketsLock, IfListLock, Exclusive IfLock
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
EnableInterface(
|
|
IN DWORD IfIndex
|
|
)
|
|
{
|
|
DWORD Error = NO_ERROR;
|
|
|
|
|
|
if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
|
|
Trace1(ENTER1, "entering _EnableInterface(%0x):", IfIndex);
|
|
Trace1(IF, "enabling interface %0x", IfIndex);
|
|
|
|
|
|
//
|
|
// enable the interface
|
|
//
|
|
ACQUIRE_SOCKETS_LOCK_EXCLUSIVE("_EnableInterface");
|
|
ACQUIRE_IF_LIST_LOCK("_EnableInterface");
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE(IfIndex, "_EnableInterface");
|
|
|
|
|
|
Error = EnableIfEntry(IfIndex, TRUE);
|
|
|
|
|
|
RELEASE_SOCKETS_LOCK_EXCLUSIVE("_EnableInterface");
|
|
RELEASE_IF_LIST_LOCK("_EnableInterface");
|
|
RELEASE_IF_LOCK_EXCLUSIVE(IfIndex, "_EnableInterface");
|
|
|
|
|
|
|
|
Trace2(LEAVE1, "leaving _EnableInterface(%0x): %d\n", IfIndex, Error);
|
|
if (Error!=NO_ERROR) {
|
|
Trace1(ERR, "Error enabling interface:%0x\n", IfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
}
|
|
|
|
LeaveIgmpApi();
|
|
|
|
return Error;
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _EnableInterface_ConfigChanged
|
|
//
|
|
// Set the status to enabled. If it is also bound, activate the interface.
|
|
//
|
|
// Locks: Runs entirely in Exclusive interface lock.
|
|
// Calls: EnableIfEntry() with mode config
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
EnableInterface_ConfigChanged(
|
|
DWORD IfIndex
|
|
)
|
|
{
|
|
DWORD Error=NO_ERROR;
|
|
|
|
|
|
Trace1(ENTER, "entering _EnableInterface_ConfigChanged(%d):", IfIndex);
|
|
|
|
Trace1(IF,
|
|
"Enabling Interface(%0x) due to change made by _SetInterfaceConfigInfo",
|
|
IfIndex);
|
|
|
|
|
|
//
|
|
// enable the interface
|
|
//
|
|
|
|
Error = EnableIfEntry(IfIndex, FALSE); // FALSE->change made by config
|
|
|
|
|
|
Trace2(LEAVE, "leaving _EnableInterface_ConfigChanged(%d): %d\n",
|
|
IfIndex, Error);
|
|
|
|
return Error;
|
|
|
|
} //end _DeActivateInterfaceInitial
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// BindInterface //
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
BindInterface(
|
|
IN DWORD IfIndex,
|
|
IN PVOID pBinding
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Sets the binding for the interface and activates it if it is also enabled.
|
|
Return Value
|
|
ERROR_INVALID_PARAMETER
|
|
NO_ERROR
|
|
Lock:
|
|
runs entirely in Interface Exclusive lock
|
|
Calls:
|
|
BindIfEntry()
|
|
--*/
|
|
{
|
|
DWORD Error=NO_ERROR;
|
|
|
|
|
|
if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
|
|
Trace1(ENTER1, "entering BindInterface: %0x", IfIndex);
|
|
Trace1(IF, "binding interface %0x", IfIndex);
|
|
|
|
|
|
// pBinding should not be NULL
|
|
|
|
if (pBinding == NULL) {
|
|
|
|
Trace0(IF, "error: binding struct pointer is NULL");
|
|
Trace1(LEAVE, "leaving BindInterface: %0x", ERROR_INVALID_PARAMETER);
|
|
|
|
LeaveIgmpApi();
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// now bind the interface in the interface table
|
|
//
|
|
|
|
//
|
|
// take sockets lock, as activate interface might be called, and
|
|
// sockets lock should be taken before interface lock
|
|
//
|
|
ACQUIRE_SOCKETS_LOCK_EXCLUSIVE("_BindInterface");
|
|
ACQUIRE_IF_LIST_LOCK("_BindInterface");
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE(IfIndex, "_BindInterface");
|
|
|
|
|
|
Error = BindIfEntry(IfIndex, pBinding);
|
|
|
|
|
|
RELEASE_SOCKETS_LOCK_EXCLUSIVE("_BindInterface");
|
|
RELEASE_IF_LIST_LOCK("_BindInterface");
|
|
RELEASE_IF_LOCK_EXCLUSIVE(IfIndex, "_BindInterface");
|
|
|
|
|
|
|
|
Trace2(LEAVE1, "leaving _BindInterface(%x): %d\n", IfIndex, Error);
|
|
if (Error!=NO_ERROR){
|
|
Trace1(ERR, "Error binding interface(%0x)\n", IfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
}
|
|
LeaveIgmpApi();
|
|
|
|
return Error;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _BindIfEntry
|
|
//
|
|
// Binds the ip addresses to the interface. The lowest of the ip addresses is
|
|
// picked up as the de-facto address for that interface. If the interface is
|
|
// already bound, it makes sure that the bindings are consistent. Currently
|
|
// you cannot change the bindings of an interface.
|
|
// If the interface is already enabled, then it is also activated.
|
|
//
|
|
// Locks:
|
|
// assumes exclusive interface lock.
|
|
// Called by: _BindInterface().
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
BindIfEntry(
|
|
DWORD IfIndex,
|
|
PIP_ADAPTER_BINDING_INFO pBinding
|
|
)
|
|
{
|
|
PIF_TABLE_ENTRY pite = NULL;
|
|
DWORD i, j, dwSize;
|
|
IPADDR MinAddr;
|
|
PIGMP_IF_BINDING pib;
|
|
PIGMP_IP_ADDRESS paddr;
|
|
BOOL bFound;
|
|
DWORD Error = NO_ERROR;
|
|
INT cmp;
|
|
|
|
|
|
pib = NULL;
|
|
|
|
|
|
//
|
|
// retrieve the interface entry
|
|
//
|
|
|
|
pite = GetIfByIndex(IfIndex);
|
|
|
|
if (pite == NULL) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
//
|
|
// If the interface is already bound, check to see if he is giving
|
|
// us a different binding. If he is, then it is an error.
|
|
//
|
|
// return from this case. dont break.
|
|
|
|
if (IS_IF_BOUND(pite)) {
|
|
|
|
Trace1(IF, "interface %0x is already bound", IfIndex);
|
|
|
|
pib = pite->pBinding;
|
|
|
|
Error = NO_ERROR;
|
|
|
|
|
|
// number of address bindings before and now should be same
|
|
|
|
if(pib->AddrCount != pBinding->AddressCount){
|
|
Trace1(IF, "interface %0x is bound and has different binding",
|
|
IfIndex);
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
//
|
|
// make sure that all address bindings are consistent
|
|
//
|
|
paddr = (PIGMP_IP_ADDRESS)((pib) + 1);
|
|
|
|
for(i = 0; i < pBinding->AddressCount; i++) {
|
|
bFound = FALSE;
|
|
|
|
for(j = 0; j < pBinding->AddressCount; j++) {
|
|
if((paddr[j].IpAddr == pBinding->Address[i].Address) &&
|
|
(paddr[j].SubnetMask == pBinding->Address[i].Mask))
|
|
{
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!bFound) {
|
|
Trace1(IF,
|
|
"interface %0x is bound and has different binding",
|
|
IfIndex);
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// make sure there is at least one address. However, unnumbered
|
|
// RAS server interfaces might have no IP addresses.
|
|
//
|
|
if ( (pBinding->AddressCount==0)&&(!IS_RAS_ROUTER_IF(pite->IfType)) ) {
|
|
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
if (pBinding->AddressCount!=0) {
|
|
//
|
|
// allocate memory to store the binding
|
|
//
|
|
dwSize = sizeof(IGMP_IF_BINDING) +
|
|
pBinding->AddressCount * sizeof(IGMP_IP_ADDRESS);
|
|
|
|
|
|
pib = IGMP_ALLOC(dwSize, 0x10, IfIndex);
|
|
|
|
PROCESS_ALLOC_FAILURE3(pib,
|
|
"error %d allocating %d bytes for binding on interface %0x",
|
|
Error, dwSize, IfIndex, GOTO_END_BLOCK1);
|
|
|
|
|
|
//
|
|
// copy the bindings
|
|
//
|
|
|
|
pib->AddrCount = pBinding->AddressCount;
|
|
paddr = IGMP_BINDING_FIRST_ADDR(pib);
|
|
MinAddr = ~0;
|
|
|
|
for (i=0; i<pib->AddrCount; i++,paddr++) {
|
|
|
|
paddr->IpAddr = pBinding->Address[i].Address;
|
|
paddr->SubnetMask = pBinding->Address[i].Mask;
|
|
|
|
if (INET_CMP(MinAddr, paddr->IpAddr, cmp)>0)
|
|
MinAddr = paddr->IpAddr;
|
|
}
|
|
|
|
|
|
//
|
|
// set the Interface effective address to the smallest bound address
|
|
//
|
|
pite->IpAddr = MinAddr;
|
|
pite->Config.IpAddr = MinAddr;
|
|
|
|
|
|
//
|
|
// save the binding in the interface entry
|
|
//
|
|
pite->pBinding = pib;
|
|
}
|
|
|
|
// dont have to do the below as they are already set to those values
|
|
else {
|
|
pite->IpAddr = pite->Config.IpAddr = 0;
|
|
pite->pBinding = NULL;
|
|
}
|
|
|
|
//
|
|
// mark the interface as being bound
|
|
//
|
|
pite->Status |= IF_BOUND_FLAG;
|
|
|
|
|
|
|
|
//
|
|
// if interface is also enabled, it is now active
|
|
// so activate it
|
|
//
|
|
|
|
if (IS_IF_ENABLED_BOUND(pite)) {
|
|
|
|
//
|
|
// place interface on the list of active interfaces
|
|
//
|
|
Error = InsertIfByAddr(pite);
|
|
|
|
|
|
//
|
|
// error if another numbered interface with same IpAddr already exists
|
|
//
|
|
if (Error != NO_ERROR) {
|
|
Trace2(IF, "error %d inserting interface %0x in active list",
|
|
Error, IfIndex);
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
//
|
|
// Activate the Interface
|
|
//
|
|
Error = ActivateInterface(pite);
|
|
|
|
//
|
|
// if could not activate the interface then undo the binding
|
|
//
|
|
if (Error != NO_ERROR) {
|
|
|
|
Trace1(ERR,
|
|
"Unbinding interface(%0x) because it could not be activated",
|
|
IfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
RemoveEntryList(&pite->LinkByAddr);
|
|
|
|
Error = ERROR_CAN_NOT_COMPLETE;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
}
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
|
|
//
|
|
// if there was any error, then set the status to unbound (pite is null
|
|
// if interface was not found)
|
|
//
|
|
if (Error!=NO_ERROR) {
|
|
|
|
if (pite!=NULL)
|
|
{
|
|
pite->Status &= ~IF_BOUND_FLAG;
|
|
pite->pBinding = NULL;
|
|
|
|
pite->IpAddr = pite->Config.IpAddr = 0;
|
|
}
|
|
|
|
IGMP_FREE_NOT_NULL(pib);
|
|
}
|
|
|
|
return Error;
|
|
|
|
} //end BindIfEntry
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// UnBindInterface //
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
UnBindInterface(
|
|
IN DWORD IfIndex
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Calls UnBindIfEntry to unbind the interface.
|
|
Calls:
|
|
UnBindIfEntry();
|
|
Locks:
|
|
Runs completely in exclusive interface lock
|
|
--*/
|
|
{
|
|
|
|
DWORD Error=NO_ERROR;
|
|
|
|
if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
|
|
|
|
Trace1(ENTER, "entering UnBindInterface(%0x):", IfIndex);
|
|
|
|
|
|
//
|
|
// unbind the interface
|
|
//
|
|
|
|
//
|
|
// take sockets lock, as activate interface might be called, and
|
|
// sockets lock should be taken before interface lock
|
|
//
|
|
ACQUIRE_SOCKETS_LOCK_EXCLUSIVE("_UnBindInterface");
|
|
ACQUIRE_IF_LIST_LOCK("_UnBindInterface");
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE(IfIndex, "_UnBindInterface");
|
|
|
|
|
|
Error = UnBindIfEntry(IfIndex);
|
|
|
|
|
|
RELEASE_SOCKETS_LOCK_EXCLUSIVE("_UnBindInterface");
|
|
RELEASE_IF_LIST_LOCK("_UnBindInterface");
|
|
RELEASE_IF_LOCK_EXCLUSIVE(IfIndex, "_UnBindInterface");
|
|
|
|
|
|
Trace2(LEAVE, "leaving UnBindInterface(%0x): %d\n", IfIndex, Error);
|
|
|
|
LeaveIgmpApi();
|
|
|
|
return Error;
|
|
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _UnBindIfEntry
|
|
//
|
|
// If the interface is activated, deactivates it. Removes the binding.
|
|
//
|
|
// MayCall: _DeActivateInterfaceComplete().
|
|
// Locks: assumes exclusive interface lock.
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
UnBindIfEntry(
|
|
DWORD IfIndex
|
|
)
|
|
{
|
|
DWORD Error = NO_ERROR, dwRetval;
|
|
PIF_TABLE_ENTRY pite, piteNew;
|
|
DWORD bProxy;
|
|
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
//
|
|
// retrieve the interface specified
|
|
//
|
|
pite = GetIfByIndex(IfIndex);
|
|
|
|
if (pite == NULL) {
|
|
Trace1(ERR, "_UnbindInterface called for non existing interface(%0x)",
|
|
IfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
//
|
|
// quit if the interface is already unbound
|
|
//
|
|
if (!IS_IF_BOUND(pite)) {
|
|
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
Trace1(ERR, "interface %0x is already unbound", IfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
//
|
|
// clear the "bound" flag
|
|
//
|
|
pite->Status &= ~IF_BOUND_FLAG;
|
|
|
|
|
|
//
|
|
// unbind IF
|
|
//
|
|
|
|
IGMP_FREE(pite->pBinding);
|
|
pite->pBinding = NULL;
|
|
|
|
|
|
//
|
|
// if IF activated (ie also enabled), deactivate it
|
|
// note: check for activated flag, and not for enabled flag
|
|
//
|
|
if (IS_IF_ACTIVATED(pite)) {
|
|
|
|
// unset activated flag
|
|
|
|
pite->Status &= ~IF_ACTIVATED_FLAG;
|
|
|
|
|
|
// remove the interface from the list of activated interfaces
|
|
|
|
RemoveEntryList(&pite->LinkByAddr);
|
|
|
|
|
|
piteNew = DeActivateInterfaceInitial(pite);
|
|
|
|
|
|
//
|
|
// queue work item to deactivate and delete the interface.
|
|
//
|
|
// CompleteIfDeactivateDelete will delete the Ras clients, GI entries,
|
|
// and deinitialize pite structure
|
|
//
|
|
|
|
//
|
|
// set flag to indicate that the interface is being deleted following
|
|
// partial deactivation
|
|
//
|
|
pite->Status |= IF_DEACTIVATE_DELETE_FLAG;
|
|
|
|
|
|
CompleteIfDeactivateDelete(pite);
|
|
|
|
|
|
#ifdef WORKER_DBG
|
|
Trace2(WORKER, "Queuing IgmpWorker function: %s in %s",
|
|
"_WF_CompleteIfDeactivateDelete:", "_UnBindIfEntry");
|
|
#endif
|
|
|
|
}
|
|
|
|
else {
|
|
pite->IpAddr = pite->Config.IpAddr = 0;
|
|
}
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
|
|
return Error;
|
|
|
|
} //end _UnBindIfEntry
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Function: _EnableIfEntry
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
EnableIfEntry(
|
|
DWORD IfIndex,
|
|
BOOL bChangedByRtrmgr // changed by rtrmg or SetInterfaceConfigInfo
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Sets the status to enabled. If the interface is also bound, then activates
|
|
the interface.
|
|
Called by:
|
|
EnableInterface().
|
|
MayCall:
|
|
ActivateIfEntry()
|
|
Locks:
|
|
Assumes exclusive interface lock.
|
|
--*/
|
|
{
|
|
DWORD Error = NO_ERROR;
|
|
PLIST_ENTRY ple, phead;
|
|
PIF_TABLE_ENTRY pite = NULL;
|
|
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
//
|
|
// retrieve the interface
|
|
//
|
|
pite = GetIfByIndex(IfIndex);
|
|
|
|
if (pite == NULL) {
|
|
Trace1(IF, "could not find interface %0x",IfIndex);
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
if (bChangedByRtrmgr) {
|
|
//
|
|
// quit if the interface is already enabled by the router manager
|
|
//
|
|
if (IS_IF_ENABLED_BY_RTRMGR(pite)) {
|
|
Trace1(IF, "interface %0x is already enabled by the router manager",
|
|
IfIndex);
|
|
Error = NO_ERROR;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
// set the flag to enabled by router manager
|
|
|
|
pite->Status |= IF_ENABLED_FLAG;
|
|
|
|
// print trace if enabled flag not set in the Config.
|
|
if (!IS_IF_ENABLED_IN_CONFIG(pite)) {
|
|
Trace1(IF,
|
|
"Interface(%0x) enabled by router manager but not enabled"
|
|
"in the Config", pite->IfIndex);
|
|
}
|
|
}
|
|
|
|
else {
|
|
//
|
|
// quit if the interface is already enabled in config
|
|
//
|
|
if (IS_IF_ENABLED_IN_CONFIG(pite)) {
|
|
Trace1(IF, "interface %0x is already enabled in Config",
|
|
IfIndex);
|
|
Error = NO_ERROR;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
// set the config flag to enabled
|
|
|
|
pite->Config.Flags |= IGMP_INTERFACE_ENABLED_IN_CONFIG;
|
|
|
|
|
|
// print trace if interface not enabled by router manager
|
|
|
|
if (!IS_IF_ENABLED_BY_RTRMGR(pite)) {
|
|
Trace1(IF,
|
|
"Interface(%0x) enabled in config but not enabled by router manager",
|
|
IfIndex);
|
|
Error = NO_ERROR;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// if interface is already bound, it should be activated
|
|
// if the bInterfaceEnabled flag is also set in config (by the UI)
|
|
//
|
|
|
|
if (IS_IF_ENABLED_BOUND(pite)) {
|
|
|
|
|
|
//
|
|
// place interface on the list of active interfaces
|
|
//
|
|
Error = InsertIfByAddr(pite);
|
|
|
|
|
|
//
|
|
// error if another interface with same ip address already exists
|
|
//
|
|
if (Error != NO_ERROR) {
|
|
Trace2(IF, "error %d inserting interface %0x in active list",
|
|
Error, IfIndex);
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
//
|
|
// Activate the Interface
|
|
//
|
|
Error = ActivateInterface(pite);
|
|
|
|
//
|
|
// if could not activate the interface then disable it again
|
|
//
|
|
if (Error != NO_ERROR) {
|
|
|
|
Trace1(ERR,
|
|
"Disabling interface(%0x) because it could not be activated",
|
|
IfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
RemoveEntryList(&pite->LinkByAddr);
|
|
|
|
Error = ERROR_CAN_NOT_COMPLETE;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
}
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
|
|
|
|
//
|
|
// if an error occured somewhere, set the interface back to the previous
|
|
// disabled state.(pite may be null if interface was not found).
|
|
//
|
|
if ((Error!=NO_ERROR)&&(pite!=NULL)) {
|
|
|
|
if (bChangedByRtrmgr)
|
|
pite->Status &= ~IF_ENABLED_FLAG;
|
|
else
|
|
pite->Config.Flags &= ~IGMP_INTERFACE_ENABLED_IN_CONFIG;
|
|
}
|
|
|
|
|
|
return Error;
|
|
|
|
}//end EnableIfEntry
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _DisableInterface
|
|
//
|
|
// If interface is activated, then deactivates it. Finally sets the disabled flag
|
|
// Locks: Runs completely in exclusive interface lock.
|
|
// Calls: _DisableIfEntry()
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
DisableInterface(
|
|
IN DWORD IfIndex
|
|
)
|
|
{
|
|
DWORD Error=NO_ERROR;
|
|
|
|
if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
|
|
Trace1(ENTER, "entering DisableInterface(%0x):", IfIndex);
|
|
|
|
|
|
//
|
|
// disable the interface
|
|
//
|
|
ACQUIRE_SOCKETS_LOCK_EXCLUSIVE("_DisableInterface");
|
|
ACQUIRE_IF_LIST_LOCK("_DisableInterface");
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE(IfIndex, "_DisableInterface");
|
|
|
|
|
|
Error = DisableIfEntry(IfIndex, TRUE);
|
|
|
|
|
|
RELEASE_SOCKETS_LOCK_EXCLUSIVE("_DisableInterface");
|
|
RELEASE_IF_LIST_LOCK("_DisableInterface");
|
|
RELEASE_IF_LOCK_EXCLUSIVE(IfIndex, "_DisableInterface");
|
|
|
|
|
|
Trace2(LEAVE, "leaving DisableInterface(%0x): %d\n", IfIndex, Error);
|
|
LeaveIgmpApi();
|
|
|
|
return Error;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _DisableInterface_ConfigChanged
|
|
//
|
|
//If interface is activated, then deactivates it. Finally sets the disabled flag
|
|
//
|
|
// Locks: assumes IfLists lock and exclusive If lock.
|
|
// Calls: _DisableIfEntry() with mode config
|
|
// Called by: _SetInterfaceConfigInfo()
|
|
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
DisableInterface_ConfigChanged(
|
|
DWORD IfIndex
|
|
)
|
|
{
|
|
DWORD Error=NO_ERROR;
|
|
|
|
Trace1(ENTER1, "entering _DisableInterface_ConfigChanged(%d):", IfIndex);
|
|
|
|
Trace1(IF,
|
|
"disabling interface(%0x) due to change made by _SetInterfaceConfigInfo",
|
|
IfIndex);
|
|
|
|
|
|
Error = DisableIfEntry(IfIndex, FALSE); // false->disabling from config
|
|
|
|
|
|
Trace2(LEAVE, "leaving _DisableInterface_ConfigChanged(%d): %d\n",
|
|
IfIndex, Error);
|
|
|
|
return Error;
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _DisableIfEntry
|
|
//
|
|
// if interface is activated, then calls DeActivateInterfaceComplete(). Removes
|
|
// the enabled flag.
|
|
// Locks: Assumes exclusive interface lock.
|
|
// Called by: _DisableInterface()
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
DisableIfEntry(
|
|
DWORD IfIndex,
|
|
BOOL bChangedByRtrmgr
|
|
)
|
|
{
|
|
DWORD Error = NO_ERROR;
|
|
PIF_TABLE_ENTRY pite, piteNew;
|
|
BOOL bProxy;
|
|
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
//
|
|
// retrieve the interface to be disabled
|
|
//
|
|
pite = GetIfByIndex(IfIndex);
|
|
|
|
if (pite == NULL) {
|
|
Trace1(IF, "could not find interface %0x", IfIndex);
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
if (bChangedByRtrmgr) {
|
|
//
|
|
// quit if already disabled by router manager
|
|
//
|
|
if (!IS_IF_ENABLED_BY_RTRMGR(pite)) {
|
|
Trace1(IF, "interface %0x already disabled by router manager",
|
|
IfIndex);
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
}
|
|
|
|
else {
|
|
//
|
|
// quit if already disabled in Config
|
|
//
|
|
if (!IS_IF_ENABLED_IN_CONFIG(pite)) {
|
|
Trace1(IF, "interface %0x already disabled in config",
|
|
IfIndex);
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// clear the enabled flag
|
|
//
|
|
if (bChangedByRtrmgr)
|
|
pite->Status &= ~IF_ENABLED_FLAG;
|
|
else
|
|
pite->Config.Flags &= ~IGMP_INTERFACE_ENABLED_IN_CONFIG;
|
|
|
|
|
|
|
|
//
|
|
// if IF activated (ie also enabled), deactivate it
|
|
// note: check for activated flag, and not for enabled flag
|
|
//
|
|
|
|
if (IS_IF_ACTIVATED(pite)) {
|
|
|
|
// unset activated flag
|
|
|
|
pite->Status &= ~IF_ACTIVATED_FLAG;
|
|
|
|
|
|
// remove the interface from the list of activated interfaces
|
|
|
|
RemoveEntryList(&pite->LinkByAddr);
|
|
|
|
|
|
piteNew = DeActivateInterfaceInitial(pite);
|
|
|
|
|
|
//
|
|
// queue work item to deactivate and delete the interface.
|
|
//
|
|
// CompleteIfDeactivateDelete will delete the Ras clients, GI entries,
|
|
// and deinitialize pite structure
|
|
//
|
|
|
|
//
|
|
// set flag to indicate that the interface is being deleted following
|
|
// partial deactivation
|
|
//
|
|
pite->Status |= IF_DEACTIVATE_DELETE_FLAG;
|
|
|
|
|
|
CompleteIfDeactivateDelete(pite);
|
|
|
|
#ifdef WORKER_DBG
|
|
Trace2(WORKER, "Queuing IgmpWorker function: %s in %s",
|
|
"_WF_CompleteIfDeactivateDelete:", "_DisableIfEntry");
|
|
#endif
|
|
}
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
|
|
return Error;
|
|
|
|
} //end _DisableIfEntry
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _CreateRasClient
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
CreateRasClient (
|
|
PIF_TABLE_ENTRY pite,
|
|
PRAS_TABLE_ENTRY *pprteNew,
|
|
DWORD NHAddr
|
|
)
|
|
{
|
|
DWORD Error=NO_ERROR;
|
|
PLIST_ENTRY pHead, ple;
|
|
PRAS_TABLE prt = pite->pRasTable;
|
|
PRAS_TABLE_ENTRY prteCur, prte;
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
//
|
|
// Create new Ras client entry and initialize the fields
|
|
//
|
|
|
|
prte = IGMP_ALLOC(sizeof(RAS_TABLE_ENTRY), 0x20, pite->IfIndex);
|
|
PROCESS_ALLOC_FAILURE2(prte,
|
|
"error %d allocating %d bytes in CreateRasClient()",
|
|
Error, sizeof(RAS_TABLE_ENTRY),
|
|
GOTO_END_BLOCK1);
|
|
|
|
*pprteNew = prte;
|
|
|
|
|
|
prte->NHAddr = NHAddr;
|
|
prte->IfTableEntry = pite;
|
|
InitializeListHead(&prte->ListOfSameClientGroups);
|
|
|
|
|
|
// increment refcount for the ras table
|
|
prt->RefCount++;
|
|
|
|
|
|
//
|
|
// insert into HashTable
|
|
//
|
|
InsertTailList(&prt->HashTableByAddr[RAS_HASH_VALUE(NHAddr)],
|
|
&prte->HTLinkByAddr);
|
|
|
|
|
|
//
|
|
// insert the client into list of clients ordered by IpAddr
|
|
//
|
|
pHead = &prt->ListByAddr;
|
|
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
|
|
prteCur = CONTAINING_RECORD(ple, RAS_TABLE_ENTRY, LinkByAddr);
|
|
if (NHAddr>prteCur->NHAddr)
|
|
break;
|
|
}
|
|
InsertTailList(&prt->ListByAddr, &prte->LinkByAddr);
|
|
|
|
|
|
//
|
|
// Set Interface stats to 0
|
|
//
|
|
ZeroMemory(&prte->Info, sizeof(RAS_CLIENT_INFO));
|
|
|
|
|
|
prte->Status = IF_CREATED_FLAG;
|
|
prte->CreationFlags = 0;
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
return Error;
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _ConnectRasClient
|
|
//
|
|
// Called when a new RAS client dials up to the RAS server.
|
|
// A new entry is created in the RAS table.
|
|
// Locks: shared interface lock
|
|
// exclusive RAS table lock.
|
|
// Note:
|
|
// Ras client entry is created even if the interface is not activated
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
APIENTRY
|
|
ConnectRasClient (
|
|
ULONG IfIndex,
|
|
PVOID pvNHAddr
|
|
)
|
|
{
|
|
PIF_TABLE_ENTRY pite = NULL;
|
|
PRAS_TABLE prt;
|
|
PRAS_TABLE_ENTRY prte, prteCur;
|
|
PLIST_ENTRY pHead, ple;
|
|
DWORD Error = NO_ERROR;
|
|
PIP_LOCAL_BINDING pNHAddrBinding = (PIP_LOCAL_BINDING)pvNHAddr;
|
|
DWORD NHAddr = pNHAddrBinding->Address;
|
|
|
|
|
|
// mightdo
|
|
// currently rtrmgr passes 0 for IfIndex. so I set it to the value required
|
|
IfIndex = g_RasIfIndex;
|
|
|
|
|
|
Trace2(ENTER, "Entering ConnectRasClient(%d.%d.%d.%d):IfIndex(%0x)\n",
|
|
PRINT_IPADDR(NHAddr), IfIndex);
|
|
if (!EnterIgmpApi()) return ERROR_CAN_NOT_COMPLETE;
|
|
|
|
|
|
//
|
|
// take a shared lock on the interface
|
|
//
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE(IfIndex, "_ConnectRasClient");
|
|
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
//
|
|
// retrieve the RAS interface entry
|
|
//
|
|
pite = g_pRasIfEntry;
|
|
|
|
if ( (pite==NULL)||(g_RasIfIndex!=IfIndex) ) {
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
//
|
|
// check that it is a RAS server Interface
|
|
//
|
|
if (!IS_RAS_SERVER_IF(pite->IfType)) {
|
|
Error = ERROR_CAN_NOT_COMPLETE;
|
|
Trace2(ERR,
|
|
"Illegal attempt to connect Ras client(%d.%d.%d.%d) to non-Ras"
|
|
"interface(%0x)", PRINT_IPADDR(NHAddr), IfIndex
|
|
);
|
|
IgmpAssertOnError(FALSE);
|
|
Logerr2(CONNECT_FAILED, "%I%d", NHAddr,
|
|
pite->IfIndex, Error);
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
//
|
|
// if error, return from here
|
|
//
|
|
if (Error!=NO_ERROR) {
|
|
|
|
RELEASE_IF_LOCK_EXCLUSIVE(IfIndex, "_ConnectRasClient");
|
|
|
|
LeaveIgmpApi();
|
|
return Error;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// get pointer to RasTable, write lock RasTable and release interface lock
|
|
//
|
|
prt = pite->pRasTable;
|
|
|
|
|
|
BEGIN_BREAKOUT_BLOCK2 {
|
|
|
|
//
|
|
// check if a RAS client with similar address already exists
|
|
//
|
|
prte = GetRasClientByAddr(NHAddr, prt);
|
|
|
|
if (prte!=NULL) {
|
|
Trace1(ERR,
|
|
"Ras client(%d.%d.%d.%d) already exists. _ConnectRasClient failed",
|
|
PRINT_IPADDR(NHAddr)
|
|
);
|
|
IgmpAssertOnError(FALSE);
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
GOTO_END_BLOCK2;
|
|
}
|
|
|
|
|
|
//
|
|
// Create new Ras client entry and initialize the fields
|
|
//
|
|
|
|
prte = IGMP_ALLOC(sizeof(RAS_TABLE_ENTRY), 0x40, IfIndex);
|
|
|
|
PROCESS_ALLOC_FAILURE2(prte,
|
|
"error %d allocating %d bytes in _ConnectRasClient()",
|
|
Error, sizeof(RAS_TABLE_ENTRY),
|
|
GOTO_END_BLOCK2);
|
|
|
|
|
|
prte->NHAddr = NHAddr;
|
|
prte->IfTableEntry = pite;
|
|
InitializeListHead(&prte->ListOfSameClientGroups);
|
|
|
|
|
|
// increment refcount for the ras table
|
|
prt->RefCount++;
|
|
|
|
|
|
//
|
|
// insert into HashTable
|
|
//
|
|
InsertTailList(&prt->HashTableByAddr[RAS_HASH_VALUE(NHAddr)],
|
|
&prte->HTLinkByAddr);
|
|
|
|
|
|
//
|
|
// insert the client into list of clients ordered by IpAddr
|
|
//
|
|
pHead = &prt->ListByAddr;
|
|
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
|
|
prteCur = CONTAINING_RECORD(ple, RAS_TABLE_ENTRY, LinkByAddr);
|
|
if (NHAddr>prteCur->NHAddr)
|
|
break;
|
|
}
|
|
InsertTailList(&prt->ListByAddr, &prte->LinkByAddr);
|
|
|
|
|
|
//
|
|
// Set Interface stats to 0
|
|
//
|
|
ZeroMemory(&prte->Info, sizeof(RAS_CLIENT_INFO));
|
|
|
|
|
|
prte->Status = IF_CREATED_FLAG;
|
|
prte->CreationFlags = 0;
|
|
|
|
//
|
|
// call MGM to take ownership of this (interface, NHAddr)
|
|
// This call is not made if the interface is not activated.
|
|
//
|
|
|
|
if (IS_IF_ACTIVATED(pite)) {
|
|
|
|
Error = MgmTakeInterfaceOwnership(g_MgmIgmprtrHandle, IfIndex, NHAddr);
|
|
if (Error!=NO_ERROR) {
|
|
Trace2(MGM,
|
|
"_TakeInterfaceOwnership rejected for interface %0x NHAddr(%d.%d.%d.%d)",
|
|
IfIndex, PRINT_IPADDR(NHAddr));
|
|
Logerr0(MGM_TAKE_IF_OWNERSHIP_FAILED, Error);
|
|
}
|
|
else {
|
|
prte->CreationFlags |= TAKEN_INTERFACE_OWNERSHIP_WITH_MGM;
|
|
}
|
|
}
|
|
// register ras client with MGM when the interface is activated.
|
|
else {
|
|
Trace3(ERR,
|
|
"ras client(%d.%d.%d.%d) connected to an inactive ras server(%0x:%d)",
|
|
PRINT_IPADDR(NHAddr), IfIndex, pite->Status);
|
|
}
|
|
|
|
} END_BREAKOUT_BLOCK2;
|
|
|
|
|
|
RELEASE_IF_LOCK_EXCLUSIVE(IfIndex, "_ConnectRasClient");
|
|
|
|
|
|
LeaveIgmpApi();
|
|
Trace2(LEAVE, "Leaving _ConnectRasClient(%d.%d.%d.%d):%d\n",
|
|
PRINT_IPADDR(NHAddr), Error);
|
|
return Error;
|
|
|
|
} //end _ConnectRasClient
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _DisconnectRasClient
|
|
//
|
|
// Takes shared interface lock. retrieves the Ras interface, takes write
|
|
// lock on the ras table, and then releases the shared interface lock.
|
|
//
|
|
// Removes the RasClient Entry from the Ras table so that no one can access
|
|
// it through a RAS table. Then queues a work item that will delete all
|
|
// GI entries.
|
|
//
|
|
// Calls: _DeleteRasClient()
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DisconnectRasClient (
|
|
DWORD IfIndex,
|
|
PVOID pvNHAddr
|
|
)
|
|
{
|
|
PIF_TABLE_ENTRY pite = NULL;
|
|
PRAS_TABLE prt;
|
|
PRAS_TABLE_ENTRY prte, prteCur;
|
|
DWORD Error = NO_ERROR;
|
|
PLIST_ENTRY pHead, ple;
|
|
PGI_ENTRY pgie;
|
|
PIP_LOCAL_BINDING pNHAddrBinding = (PIP_LOCAL_BINDING)pvNHAddr;
|
|
DWORD NHAddr = pNHAddrBinding->Address;
|
|
|
|
// mightdo
|
|
// currently rtrmgr passes 0 for IfIndex. so I set it to the value required
|
|
IfIndex = g_RasIfIndex;
|
|
|
|
|
|
Trace2(ENTER, "Entering DisconnectRasClient for IfIndex(%0x), NextHop(%d.%d.%d.%d)",
|
|
IfIndex, PRINT_IPADDR(NHAddr));
|
|
|
|
if (!EnterIgmpApi()) return ERROR_CAN_NOT_COMPLETE;
|
|
|
|
|
|
//
|
|
// take an exclusive lock on the interface
|
|
//
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE(IfIndex, "_DisconnectRasClient");
|
|
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
//
|
|
// retrieve the RAS interface entry from the global structure.
|
|
//
|
|
if ( (g_RasIfIndex!=IfIndex) || (g_pRasIfEntry==NULL) ) {
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
Trace2(ERR,
|
|
"attempt to disconnect Ras client(%d.%d.%d.%d) from non-Ras "
|
|
"interface(%0x)", PRINT_IPADDR(NHAddr), IfIndex
|
|
);
|
|
IgmpAssertOnError(FALSE);
|
|
Logerr2(DISCONNECT_FAILED, "%I%d", NHAddr,
|
|
IfIndex, Error);
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
pite = g_pRasIfEntry;
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
//
|
|
// if error, return from here.
|
|
//
|
|
if (Error!=NO_ERROR) {
|
|
|
|
RELEASE_IF_LOCK_EXCLUSIVE(IfIndex, "_DisconnectRasClient");
|
|
|
|
LeaveIgmpApi();
|
|
return Error;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// get pointer to RasTable
|
|
//
|
|
prt = pite->pRasTable;
|
|
|
|
|
|
BEGIN_BREAKOUT_BLOCK2 {
|
|
|
|
//
|
|
// retrieve ras client
|
|
//
|
|
prte = GetRasClientByAddr(NHAddr, prt);
|
|
if (prte==NULL) {
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
Trace2(ERR,
|
|
"Illegal attempt to disconnect non-existing Ras client(%d.%d.%d.%d) "
|
|
"from Ras interface(%0x)", PRINT_IPADDR(NHAddr), IfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
Logerr2(DISCONNECT_FAILED, "%I%d", NHAddr,
|
|
pite->IfIndex, Error);
|
|
GOTO_END_BLOCK2;
|
|
}
|
|
|
|
//
|
|
// break if ras client has deleted flag set
|
|
//
|
|
if ( (prte->Status&IF_DELETED_FLAG) ) {
|
|
Error = ERROR_CAN_NOT_COMPLETE;
|
|
GOTO_END_BLOCK2;
|
|
}
|
|
|
|
|
|
//
|
|
// set deleted flag for the ras client, so that no one else will
|
|
// try to access it
|
|
prte->Status |= IF_DELETED_FLAG;
|
|
|
|
|
|
//
|
|
// remove the RAS client from the Ras table lists so that no one will
|
|
// access it.
|
|
//
|
|
RemoveEntryList(&prte->HTLinkByAddr);
|
|
RemoveEntryList(&prte->LinkByAddr);
|
|
|
|
|
|
//
|
|
// release RasClient virtual interface
|
|
//
|
|
if (prte->CreationFlags & TAKEN_INTERFACE_OWNERSHIP_WITH_MGM)
|
|
{
|
|
Error = MgmReleaseInterfaceOwnership(g_MgmIgmprtrHandle, pite->IfIndex,
|
|
prte->NHAddr);
|
|
if (Error!=NO_ERROR) {
|
|
Trace2(ERR,
|
|
"Error: _MgmReleaseInterfaceOwnership for If:%0x, NHAddr:%d.%d.%d.%d",
|
|
pite->IfIndex, PRINT_IPADDR(prte->NHAddr));
|
|
IgmpAssertOnError(FALSE);
|
|
}
|
|
|
|
prte->CreationFlags &= ~TAKEN_INTERFACE_OWNERSHIP_WITH_MGM;
|
|
}
|
|
|
|
//
|
|
// remove the ras client's GI entries from the ras server interface
|
|
// list
|
|
//
|
|
|
|
ACQUIRE_IF_GROUP_LIST_LOCK(IfIndex, "_DisconectRasClient");
|
|
pHead = &prte->ListOfSameClientGroups;
|
|
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
|
|
pgie = CONTAINING_RECORD(ple, GI_ENTRY, LinkBySameClientGroups);
|
|
RemoveEntryList(&pgie->LinkBySameIfGroups);
|
|
InitializeListHead(&pgie->LinkBySameIfGroups);
|
|
}
|
|
RELEASE_IF_GROUP_LIST_LOCK(IfIndex, "_DisconnectRasClient");
|
|
|
|
|
|
|
|
//
|
|
// Delete ras client. The refcount is not changed
|
|
// so the prte, prt, pite fields will be valid.
|
|
//
|
|
DeleteRasClient(prte);
|
|
|
|
} END_BREAKOUT_BLOCK2;
|
|
|
|
|
|
// release the interface lock
|
|
|
|
RELEASE_IF_LOCK_EXCLUSIVE(IfIndex, "_DisconnectRasClient");
|
|
|
|
|
|
Trace3(LEAVE,
|
|
"Leaving _DisconnectRasClient(%d) for IfIndex(%0x), NextHop(%d.%d.%d.%d)\n",
|
|
Error, IfIndex, PRINT_IPADDR(NHAddr)
|
|
);
|
|
LeaveIgmpApi();
|
|
|
|
return Error;
|
|
|
|
} //end _DisconnectRasClient
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _SetInterfaceConfigInfo
|
|
//
|
|
// Resets the interface config. The router parameters might have changed.
|
|
// Also proxy<-->router transition might have taken place.
|
|
//
|
|
// Locks: takes IfLists lock initiallly itself just in case the interface had to
|
|
// be disabled. Runs completely in exclusive interface lock.
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
SetInterfaceConfigInfo(
|
|
IN DWORD IfIndex,
|
|
IN PVOID pvConfig,
|
|
IN ULONG ulStructureVersion,
|
|
IN ULONG ulStructureSize,
|
|
IN ULONG ulStructureCount
|
|
)
|
|
{
|
|
DWORD Error=NO_ERROR;
|
|
PIGMP_IF_CONFIG pConfigDst;
|
|
PIGMP_MIB_IF_CONFIG pConfigSrc;
|
|
PIF_TABLE_ENTRY pite = NULL;
|
|
DWORD OldState, OldProtoType, NewProtoType;
|
|
BOOL bIgmpProtocolChanged=FALSE, bEnabledStateChanged=FALSE;
|
|
BOOL bOldStateEnabled=FALSE;
|
|
|
|
|
|
if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
|
|
Trace1(ENTER, "entering SetInterfaceConfigInfo(%d)", IfIndex);
|
|
// make sure it is not an unsupported igmp version structure
|
|
if (ulStructureVersion>=IGMP_CONFIG_VERSION_600) {
|
|
Trace1(ERR, "Unsupported IGMP version structure: %0x",
|
|
ulStructureVersion);
|
|
IgmpAssertOnError(FALSE);
|
|
LeaveIgmpApi();
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
ACQUIRE_SOCKETS_LOCK_EXCLUSIVE("_SetInterfaceConfigInfo");
|
|
ACQUIRE_IF_LIST_LOCK("_SetInterfaceConfigInfo");
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE(IfIndex, "_SetInterfaceConfigInfo");
|
|
|
|
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
if (pvConfig==NULL) {
|
|
Error = ERROR_CAN_NOT_COMPLETE;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
pConfigSrc = (PIGMP_MIB_IF_CONFIG)pvConfig;
|
|
|
|
|
|
//
|
|
// find the interface specified
|
|
//
|
|
pite = GetIfByIndex(IfIndex);
|
|
|
|
if (pite == NULL) {
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
//
|
|
// validate the new config values
|
|
//
|
|
Error = ValidateIfConfig(pConfigSrc, IfIndex, pite->IfType,
|
|
ulStructureVersion, ulStructureSize
|
|
);
|
|
if (Error!=NO_ERROR)
|
|
GOTO_END_BLOCK1;
|
|
|
|
|
|
pConfigDst = &pite->Config;
|
|
|
|
|
|
//
|
|
// make sure you are not setting multiple proxy interfaces
|
|
//
|
|
if (IS_CONFIG_IGMPPROXY(pConfigSrc)
|
|
&&!IS_CONFIG_IGMPPROXY(pConfigDst)
|
|
&& (g_ProxyIfIndex!=0) )
|
|
{
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
Trace1(ERR, "Cannot set multiple Proxy interfaces. Proxy exists on %d",
|
|
g_ProxyIfIndex);
|
|
IgmpAssertOnError(FALSE);
|
|
Logerr0(PROXY_IF_EXISTS, Error);
|
|
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
//
|
|
// Process change in IgmpProtocolType (between proxy and router)
|
|
// (no special processing for changes between ver-1 and ver-2)
|
|
//
|
|
if (pConfigSrc->IgmpProtocolType != pConfigDst->IgmpProtocolType)
|
|
{
|
|
bIgmpProtocolChanged = TRUE;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
else
|
|
bIgmpProtocolChanged = FALSE;
|
|
|
|
|
|
OldProtoType = pConfigDst->IgmpProtocolType;
|
|
|
|
|
|
//
|
|
// if interface enabled state has changed, then process that change
|
|
// I dont have to look for version changes, etc
|
|
//
|
|
if (IGMP_ENABLED_FLAG_SET(pConfigSrc->Flags)
|
|
!= IGMP_ENABLED_FLAG_SET(pConfigDst->Flags))
|
|
{
|
|
|
|
bEnabledStateChanged = TRUE;
|
|
|
|
pite->Info.OtherVerPresentTimeWarn = 0;
|
|
|
|
bOldStateEnabled = IGMP_ENABLED_FLAG_SET(pConfigDst->Flags);
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
else
|
|
bEnabledStateChanged = FALSE;
|
|
|
|
|
|
|
|
|
|
// copy the new config
|
|
|
|
if (IS_IF_ACTIVATED(pite))
|
|
CopyinIfConfigAndUpdate(pite, pConfigSrc, IfIndex);
|
|
else
|
|
CopyinIfConfig(&pite->Config, pConfigSrc, IfIndex);
|
|
|
|
NewProtoType = pConfigDst->IgmpProtocolType;
|
|
|
|
/*
|
|
//
|
|
// if changing from V1 <-> V2
|
|
//
|
|
if ( ((OldProtoType==IGMP_ROUTER_V1) && (NewProtoType==IGMP_ROUTER_V2))
|
|
|| ((OldProtoType==IGMP_ROUTER_V2) && (NewProtoType==IGMP_ROUTER_V1)) )
|
|
{
|
|
pite->Info.OtherVerPresentTimeWarn = 0;
|
|
}
|
|
*/
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
|
|
|
|
//
|
|
// change the protocol and check for state changes.
|
|
// This function will effectively delete the interface with the old
|
|
// protocol and create a new interface with the new protocol.
|
|
//
|
|
if ( (bIgmpProtocolChanged)&&(Error==NO_ERROR) )
|
|
ProcessIfProtocolChange(IfIndex, pConfigSrc);
|
|
|
|
|
|
//
|
|
// Process State Change: enable or disable interface
|
|
//
|
|
else if ( (bEnabledStateChanged)&&(Error==NO_ERROR) ) {
|
|
|
|
//
|
|
// disable the interface and then copy in the new config
|
|
//
|
|
if (bOldStateEnabled) {
|
|
|
|
// old state enabled, new state disabled
|
|
|
|
DisableInterface_ConfigChanged(IfIndex);
|
|
|
|
//
|
|
// copy the config
|
|
//
|
|
// get the pite entry again, as disable creates a new one
|
|
//
|
|
|
|
pite = GetIfByIndex(IfIndex);
|
|
CopyinIfConfig(&pite->Config, pConfigSrc, IfIndex);
|
|
|
|
|
|
}
|
|
//
|
|
// copy the new config before enabling it
|
|
//
|
|
else {
|
|
|
|
CopyinIfConfig(&pite->Config, pConfigSrc, IfIndex);
|
|
|
|
//
|
|
// set the enable state to false, so that the below call can
|
|
// enable the interface.
|
|
//
|
|
pite->Config.Flags &= ~IGMP_INTERFACE_ENABLED_IN_CONFIG;
|
|
|
|
|
|
// old state disabled, new state enabled
|
|
|
|
EnableInterface_ConfigChanged(IfIndex);
|
|
}
|
|
}
|
|
|
|
|
|
RELEASE_SOCKETS_LOCK_EXCLUSIVE("_SetInterfaceConfigInfo");
|
|
RELEASE_IF_LIST_LOCK("_SetInterfaceConfigInfo");
|
|
RELEASE_IF_LOCK_EXCLUSIVE(IfIndex, "_SetInterfaceConfigInfo");
|
|
|
|
|
|
|
|
Trace2(LEAVE, "leaving SetInterfaceConfigInfo(%d):%d\n", IfIndex, Error);
|
|
|
|
LeaveIgmpApi();
|
|
|
|
return Error;
|
|
|
|
} //end _SetInterfaceConfigInfo
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _ProcessProtocolChange
|
|
//
|
|
// Called when the interface protocol has changed (proxy<->router).
|
|
// First disables the old interface so that all old protocol data is cleaned up.
|
|
// then sets the new config, and enables the interface again (if it was
|
|
// enabled before). This process takes care of creation/deletion of sockets, etc
|
|
//
|
|
// Locks: no locks when called. Except for _Disable(_Enable)Interface, all work
|
|
// is done inside an exclusive IfLock.
|
|
// Calls: _DisableInterface(), _EnableInterface() if required.
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
ProcessIfProtocolChange(
|
|
DWORD IfIndex,
|
|
PIGMP_MIB_IF_CONFIG pConfigSrc
|
|
)
|
|
{
|
|
DWORD Error=NO_ERROR, dwDisabled;
|
|
PIGMP_IF_CONFIG pConfigDst;
|
|
PIF_TABLE_ENTRY pite = NULL;
|
|
|
|
|
|
Trace1(ENTER, "Entered _ProcessIfProtocolChange(%d)", IfIndex);
|
|
|
|
|
|
//
|
|
// disable the interface so that all protocol specific data is lost
|
|
//
|
|
dwDisabled = DisableIfEntry(IfIndex, TRUE);
|
|
|
|
|
|
//
|
|
// find the interface specified and copy the config info. The config
|
|
// has already been validated.
|
|
//
|
|
|
|
ACQUIRE_IF_LOCK_EXCLUSIVE(IfIndex, "_ProcessIfProtocolChange");
|
|
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
// get interface again
|
|
|
|
pite = GetIfByIndex(IfIndex);
|
|
|
|
if (pite == NULL) {
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
pConfigDst = &pite->Config;
|
|
|
|
|
|
|
|
//
|
|
// if old interface was Proxy, then remove it from the Global Struct
|
|
// and delete the Proxy_HT related structures
|
|
//
|
|
if (IS_PROTOCOL_TYPE_PROXY(pite)) {
|
|
|
|
// _DisableIfEntry would have deleted all the entries in the proxy
|
|
// Hash table
|
|
|
|
IGMP_FREE(pite->pProxyHashTable);
|
|
|
|
InterlockedExchange(&g_ProxyIfIndex, 0);
|
|
InterlockedExchangePointer(&g_pProxyIfEntry, NULL);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// copy the new config values
|
|
//
|
|
CopyinIfConfig(&pite->Config, pConfigSrc, IfIndex);
|
|
|
|
|
|
|
|
//
|
|
// if new interface is Proxy, then add it to the Global Struct
|
|
// and create the Proxy_HT structures
|
|
//
|
|
|
|
if (IS_PROTOCOL_TYPE_PROXY(pite)) {
|
|
|
|
DWORD dwSize = PROXY_HASH_TABLE_SZ * sizeof(LIST_ENTRY);
|
|
DWORD i;
|
|
PLIST_ENTRY pProxyHashTable;
|
|
|
|
pProxyHashTable = pite->pProxyHashTable = IGMP_ALLOC(dwSize, 0x80,IfIndex);
|
|
|
|
PROCESS_ALLOC_FAILURE2(pProxyHashTable,
|
|
"error %d allocating %d bytes for interface table",
|
|
Error, dwSize,
|
|
GOTO_END_BLOCK1);
|
|
|
|
|
|
for (i=0; i<PROXY_HASH_TABLE_SZ; i++) {
|
|
InitializeListHead(pProxyHashTable+i);
|
|
}
|
|
|
|
|
|
InterlockedExchangePointer(&g_pProxyIfEntry, pite);
|
|
InterlockedExchange(&g_ProxyIfIndex, IfIndex);
|
|
|
|
pite->CreationFlags |= CREATED_PROXY_HASH_TABLE;
|
|
|
|
}
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
|
|
RELEASE_IF_LOCK_EXCLUSIVE(IfIndex, "_ProcessIfProtocolChange");
|
|
|
|
|
|
//
|
|
// enable the interface if the new state requires
|
|
// it to be enabled.
|
|
//
|
|
if ( (Error==NO_ERROR) && (dwDisabled==NO_ERROR) )
|
|
Error = EnableIfEntry(IfIndex, TRUE);
|
|
|
|
|
|
Trace2(LEAVE, "Leaving _ProcessIfProtocolChange(%d): %d\n",
|
|
IfIndex, Error);
|
|
return Error;
|
|
|
|
} //end _ProcessIfProtocolChange
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _GetInterfaceConfigInfo
|
|
//
|
|
// The Router Manager calls us with a NULL config and ZERO size. We return
|
|
// the required size to it. It then allocates the needed memory and calls
|
|
// us a second time with a valid buffer. We validate parameters each time
|
|
// and copy out our config if we can
|
|
//
|
|
// Return Value
|
|
// ERROR_INSUFFICIENT_BUFFER If the size of the buffer is too small
|
|
// ERROR_INVALID_PARAMETER ERROR_INVALID_DATA NO_ERROR
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
WINAPI
|
|
GetInterfaceConfigInfo(
|
|
IN DWORD IfIndex,
|
|
IN OUT PVOID pvConfig,
|
|
IN OUT PDWORD pdwSize,
|
|
IN OUT PULONG pulStructureVersion,
|
|
IN OUT PULONG pulStructureSize,
|
|
IN OUT PULONG pulStructureCount
|
|
)
|
|
{
|
|
|
|
DWORD Error = NO_ERROR;
|
|
PIF_TABLE_ENTRY pite = NULL;
|
|
PIGMP_MIB_IF_CONFIG pConfigDst;
|
|
PIGMP_IF_CONFIG pConfigSrc;
|
|
|
|
|
|
if (!EnterIgmpApi()) { return ERROR_CAN_NOT_COMPLETE; }
|
|
Trace3(ENTER1,
|
|
"entering _GetInterfaceConfigInfo(%d): ConfigPrt(%08x) SizePrt(%08x)",
|
|
IfIndex, pvConfig, pdwSize
|
|
);
|
|
|
|
|
|
ACQUIRE_IF_LOCK_SHARED(IfIndex, "_GetInterfaceConfigInfo");
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
//
|
|
// check the arguments
|
|
//
|
|
if (pdwSize == NULL) {
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
//
|
|
// find the interface specified
|
|
//
|
|
pite = GetIfByIndex(IfIndex);
|
|
|
|
if (pite == NULL) {
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
pConfigSrc = &pite->Config;
|
|
|
|
|
|
// get the size of the interface config
|
|
|
|
|
|
//
|
|
// check the buffer size
|
|
//
|
|
|
|
if (*pdwSize < pConfigSrc->ExtSize) {
|
|
Error = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else {
|
|
|
|
|
|
pConfigDst = (PIGMP_MIB_IF_CONFIG)pvConfig;
|
|
|
|
|
|
//
|
|
// copy the interface config, and set the IP address
|
|
//
|
|
CopyoutIfConfig(pConfigDst, pite);
|
|
|
|
}
|
|
|
|
*pdwSize = pConfigSrc->ExtSize;
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
|
|
RELEASE_IF_LOCK_SHARED(IfIndex, "_GetInterfaceConfigInfo");
|
|
|
|
if (pulStructureCount)
|
|
*pulStructureCount = 1;
|
|
if (pulStructureSize && pdwSize)
|
|
*pulStructureSize = *pdwSize;
|
|
if (pulStructureVersion)
|
|
*pulStructureVersion = IGMP_CONFIG_VERSION_500;
|
|
|
|
Trace2(LEAVE1, "leaving _GetInterfaceConfigInfo(%d): %d\n", IfIndex, Error);
|
|
LeaveIgmpApi();
|
|
|
|
return Error;
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
InterfaceStatus(
|
|
ULONG IfIndex,
|
|
BOOL bIfActive,
|
|
DWORD dwStatusType,
|
|
PVOID pvStatusInfo
|
|
)
|
|
{
|
|
DWORD Error = NO_ERROR;
|
|
|
|
switch(dwStatusType)
|
|
{
|
|
case RIS_INTERFACE_ADDRESS_CHANGE:
|
|
{
|
|
PIP_ADAPTER_BINDING_INFO pBindInfo
|
|
= (PIP_ADAPTER_BINDING_INFO)pvStatusInfo;
|
|
|
|
if(pBindInfo->AddressCount)
|
|
{
|
|
Error = BindInterface(IfIndex, pvStatusInfo);
|
|
}
|
|
else
|
|
{
|
|
Error = UnBindInterface(IfIndex);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case RIS_INTERFACE_ENABLED:
|
|
{
|
|
Error = EnableInterface(IfIndex);
|
|
break;
|
|
}
|
|
|
|
case RIS_INTERFACE_DISABLED:
|
|
{
|
|
Error = DisableInterface(IfIndex);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
IgmpMibIfConfigSize(
|
|
PIGMP_MIB_IF_CONFIG pConfig
|
|
)
|
|
{
|
|
DWORD Size = sizeof(IGMP_MIB_IF_CONFIG);
|
|
|
|
if (pConfig->NumStaticGroups && !IS_CONFIG_IGMP_V3(pConfig)) {
|
|
Size += pConfig->NumStaticGroups*sizeof(IGMP_STATIC_GROUP);
|
|
}
|
|
else if (pConfig->NumStaticGroups && IS_CONFIG_IGMP_V3(pConfig)) {
|
|
|
|
DWORD i;
|
|
PSTATIC_GROUP_V3 pStaticGroupV3 = GET_FIRST_STATIC_GROUP_V3(pConfig);
|
|
|
|
for (i=0; i<pConfig->NumStaticGroups; i++) {
|
|
DWORD EntrySize = sizeof(STATIC_GROUP_V3)
|
|
+ pStaticGroupV3->NumSources*sizeof(IPADDR);
|
|
Size += EntrySize;
|
|
pStaticGroupV3 = (PSTATIC_GROUP_V3)
|
|
((PCHAR)(pStaticGroupV3) + EntrySize);
|
|
}
|
|
}
|
|
|
|
return Size;
|
|
}
|
|
|