//============================================================================= // 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; iCreationFlags |= 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; iFlink; 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; iCreationFlags |= 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; iNumSources; 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; iNumSources; 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; iNumSources; 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; iFlink; 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; iAddrCount; 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; iCreationFlags |= 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; iNumStaticGroups; i++) { DWORD EntrySize = sizeof(STATIC_GROUP_V3) + pStaticGroupV3->NumSources*sizeof(IPADDR); Size += EntrySize; pStaticGroupV3 = (PSTATIC_GROUP_V3) ((PCHAR)(pStaticGroupV3) + EntrySize); } } return Size; }