/*++ Copyright (c) 1995 Microsoft Corporation Module Name: misc.c Abstract: Miscellaneous management functions Author: Stefan Solomon 03/13/1995 Revision History: --*/ #include "precomp.h" #pragma hdrstop UCHAR bcastnode[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; VOID SetAdapterBindingInfo(PIPX_ADAPTER_BINDING_INFO abip, PACB acbp); VOID RMCreateLocalRoute(PICB icbp); VOID RMDeleteLocalRoute(PICB icbp); VOID ExternalBindInterfaceToAdapter(PICB icbp); VOID ExternalUnbindInterfaceFromAdapter(ULONG InterfaceIndex); /*++ Function: GetTocEntry Descr: Returns a pointer to the specified table of contents entry in the interface info block. --*/ PIPX_TOC_ENTRY GetTocEntry(PIPX_INFO_BLOCK_HEADER InterfaceInfop, ULONG InfoEntryType) { PIPX_TOC_ENTRY tocep; UINT i; for(i=0, tocep = InterfaceInfop->TocEntry; iTocEntriesCount; i++, tocep++) { if(tocep->InfoType == InfoEntryType) { return tocep; } } return NULL; } /*++ Function: GetInfoEntry Descr: Returns a pointer to the specified info entry in the interface control block. If more then one entries, returns a pointer to the first one. --*/ LPVOID GetInfoEntry(PIPX_INFO_BLOCK_HEADER InterfaceInfop, ULONG InfoEntryType) { PIPX_TOC_ENTRY tocep; if(tocep = GetTocEntry(InterfaceInfop, InfoEntryType)) { return((LPVOID)((PUCHAR)InterfaceInfop + tocep->Offset)); } else { return NULL; } } /*++ Function: UpdateStaticIfEntries Descr: Compares the entries in the interface info block with the stored static entries. Deletes the entries not present in the interface info blolck and adds the new entries --*/ DWORD UpdateStaticIfEntries( PICB icbp, HANDLE EnumHandle, // handle for the get next enumeration ULONG StaticEntrySize, ULONG NewStaticEntriesCount, // number of new static entries LPVOID NewStaticEntry, // start of the new entries array ULONG (*GetNextStaticEntry)(HANDLE EnumHandle, LPVOID entry), ULONG (*DeleteStaticEntry)(ULONG IfIndex, LPVOID entry), ULONG (*CreateStaticEntry)(PICB icbp, LPVOID entry)) { PUCHAR EntryIsNew, nsep, OldStaticEntry; BOOL found; UINT i; // delete non-present entries and add the new entries // array of flags to mark the new entries if((EntryIsNew = GlobalAlloc(GPTR, NewStaticEntriesCount)) == NULL) { return 1; } memset(EntryIsNew, 1, NewStaticEntriesCount); if((OldStaticEntry = GlobalAlloc(GPTR, StaticEntrySize)) == NULL) { GlobalFree(EntryIsNew); return 1; } if(EnumHandle) { while(!GetNextStaticEntry(EnumHandle, OldStaticEntry)) { // compare it with each new static static entry until we find a match found = FALSE; for(i = 0, nsep = NewStaticEntry; i delete it DeleteStaticEntry(icbp->InterfaceIndex, OldStaticEntry); } } } // all compared and old non-present ones deleted // now, add all the new ones for(i=0, nsep = NewStaticEntry; iInterfaceIndex, acbp->AdapterIndex); if(icbp->acbp != NULL) { Trace(BIND_TRACE, "BindInterfaceToAdapter: interface # %d already bound !!!", icbp->InterfaceIndex); //SS_ASSERT(FALSE); return; } // Make sure that the adapter is not currently claimed by any // interface either. // if ((acbp->icbp) && (acbp->icbp->acbp == acbp)) { Trace( BIND_TRACE, "BindInterfaceToAdapter: adapter # %d already bound to int # %d!!", acbp->AdapterIndex, acbp->icbp->InterfaceIndex); return; } // internal bind the adapter control block and the interface control block icbp->acbp = acbp; acbp->icbp = icbp; // if a connection was requested on this if, mark that it has been done if(icbp->ConnectionRequestPending) { icbp->ConnectionRequestPending = FALSE; } if(!icbp->InterfaceReachable) { // we should never hit this code path in normal operation // However, should anybody atempt and succeed a dial (manually?) on an // interface marked unreachable, we should reset our state // icbp->InterfaceReachable = TRUE; if(icbp->AdminState == ADMIN_STATE_ENABLED) { // enable all static routes for this interface EnableStaticRoutes(icbp->InterfaceIndex); // enable external interfaces. Implicitly, this will enable static services // bound to this interface to be advertised ExternalEnableInterface(icbp->InterfaceIndex); } } if (icbp->AdminState==ADMIN_STATE_ENABLED) { icbp->OperState = OPER_STATE_UP; // create a local route entry in RTM for the connected interface RMCreateLocalRoute(icbp); } ExternalBindInterfaceToAdapter(icbp); // if the interface is a local client type (i.e. host doing manual dial from // the local machine, try to update the internal routing table if(icbp->MIBInterfaceType == IF_TYPE_ROUTER_WORKSTATION_DIALOUT) { if((rc = RtProtRequestRoutesUpdate(icbp->InterfaceIndex)) == NO_ERROR) { icbp->UpdateReq.RoutesReqStatus = UPDATE_PENDING; } else { Trace(UPDATE_TRACE, "BindInterfaceToAdapter: Routing Update is Disabled"); } if((rc = RtProtRequestServicesUpdate(icbp->InterfaceIndex)) == NO_ERROR) { icbp->UpdateReq.ServicesReqStatus = UPDATE_PENDING; } else { Trace(UPDATE_TRACE, "BindInterfaceToAdapter: Services Update is Disabled"); } } } /*++ Function: UnbindInterfaceFromAdapter Descr: Unbind the Rip, Sap and Forwarder interfaces with this index from the respective adapter --*/ VOID UnbindInterfaceFromAdapter(PICB icbp) { PACB acbp; ULONG new_if_oper_state; acbp = icbp->acbp; if (acbp==NULL) { Trace(BIND_TRACE, "UnbindInterfaceFromAdapter:Interface # %d is not bound to any adapter", icbp->InterfaceIndex); return; } Trace(BIND_TRACE, "UnbindInterfaceFromAdapter: Unbind interface # %d from adapter # %d", icbp->InterfaceIndex, acbp->AdapterIndex); switch(icbp->MIBInterfaceType) { case IF_TYPE_PERSONAL_WAN_ROUTER: case IF_TYPE_WAN_WORKSTATION: case IF_TYPE_WAN_ROUTER: case IF_TYPE_ROUTER_WORKSTATION_DIALOUT: if (icbp->AdminState==ADMIN_STATE_ENABLED) { icbp->OperState = OPER_STATE_SLEEPING; break; } default: icbp->OperState = OPER_STATE_DOWN; break; } if (icbp->AdminState==ADMIN_STATE_ENABLED) { // delete local route and ext unbind RMDeleteLocalRoute(icbp); } ExternalUnbindInterfaceFromAdapter(icbp->InterfaceIndex); // if there were updates going on they will get cancelled automatically // by the respective routing protocols. // We just have to reset the update state in the ICB ResetUpdateRequest(icbp); // Now we can unbind the adapter from interface acbp->icbp = NULL; icbp->acbp = NULL; } /*++ Function: GetNextInterfaceIndex Descr: Returns the next available interface index. There are a number of policies to consider here. The one we'll use is to keep the interface index a small number and to return the first unused interface index between 1 and MAX_INTERFACE_INDEX. Note: Called with database locked --*/ ULONG GetNextInterfaceIndex(VOID) { PICB icbp; PLIST_ENTRY lep; ULONG i; if((icbp = GetInterfaceByIndex(1)) == NULL) { return 1; } lep = icbp->IndexListLinkage.Flink; i = 2; while(lep != &IndexIfList) { icbp = CONTAINING_RECORD(lep, ICB, IndexListLinkage); if(i < icbp->InterfaceIndex) { return i; } i = icbp->InterfaceIndex + 1; if(i == MAX_INTERFACE_INDEX) { // abort SS_ASSERT(FALSE); return i; } lep = icbp->IndexListLinkage.Flink; } SS_ASSERT(i < MAX_INTERFACE_INDEX); return i; } VOID SetAdapterBindingInfo(PIPX_ADAPTER_BINDING_INFO abip, PACB acbp) { abip->AdapterIndex = acbp->AdapterIndex; memcpy(abip->Network, acbp->AdapterInfo.Network, 4); memcpy(abip->LocalNode, acbp->AdapterInfo.LocalNode, 6); if(acbp->AdapterInfo.NdisMedium != NdisMediumWan) { memcpy(abip->RemoteNode, bcastnode, 6); } else { memcpy(abip->RemoteNode, acbp->AdapterInfo.RemoteNode, 6); } abip->MaxPacketSize = acbp->AdapterInfo.MaxPacketSize; abip->LinkSpeed = acbp->AdapterInfo.LinkSpeed; } VOID ExternalBindInterfaceToAdapter(PICB icbp) { PACB acbp; IPX_ADAPTER_BINDING_INFO abi; acbp = icbp->acbp; SetAdapterBindingInfo(&abi, acbp); FwBindFwInterfaceToAdapter(icbp->InterfaceIndex, &abi); BindRoutingProtocolsIfsToAdapter(icbp->InterfaceIndex, &abi); } VOID ExternalUnbindInterfaceFromAdapter(ULONG InterfaceIndex) { UnbindRoutingProtocolsIfsFromAdapter(InterfaceIndex); FwUnbindFwInterfaceFromAdapter(InterfaceIndex); } VOID ExternalEnableInterface(ULONG InterfaceIndex) { RoutingProtocolsEnableIpxInterface(InterfaceIndex); FwEnableFwInterface(InterfaceIndex); } VOID ExternalDisableInterface(ULONG InterfaceIndex) { FwDisableFwInterface(InterfaceIndex); RoutingProtocolsDisableIpxInterface(InterfaceIndex); } VOID RMCreateLocalRoute(PICB icbp) { PADAPTER_INFO aip; // check if a network number has been assigned to this interface aip = &(icbp->acbp->AdapterInfo); if(!memcmp(aip->Network, nullnet, 4)) { // no net number return; } // if the interface is a remote workstation and global wan net exists, // we are done. if((icbp->MIBInterfaceType == IF_TYPE_WAN_WORKSTATION) && EnableGlobalWanNet && !LanOnlyMode) { SS_ASSERT(!memcmp(aip->Network, GlobalWanNet, 4)); return; } CreateLocalRoute(icbp); } VOID RMDeleteLocalRoute(PICB icbp) { PADAPTER_INFO aip; // check if a network number has been assigned to this interface aip = &(icbp->acbp->AdapterInfo); if(!memcmp(aip->Network, nullnet, 4)) { // no net number return; } // if the interface is a remote workstation and global wan net exists, // we are done. if((icbp->MIBInterfaceType == IF_TYPE_WAN_WORKSTATION) && EnableGlobalWanNet && !LanOnlyMode) { SS_ASSERT(!memcmp(aip->Network, GlobalWanNet, 4)); return; } DeleteLocalRoute(icbp); } VOID AdminEnable(PICB icbp) { PACB acbp; IPX_ADAPTER_BINDING_INFO aii; if(icbp->AdminState == ADMIN_STATE_ENABLED) { return; } icbp->AdminState = ADMIN_STATE_ENABLED; InterfaceEnabled (icbp->hDIMInterface, PID_IPX, TRUE); if(icbp->acbp != NULL) { // bound to adapter icbp->OperState = OPER_STATE_UP; RMCreateLocalRoute(icbp); } else { switch(icbp->MIBInterfaceType) { case IF_TYPE_PERSONAL_WAN_ROUTER: case IF_TYPE_WAN_WORKSTATION: case IF_TYPE_WAN_ROUTER: case IF_TYPE_ROUTER_WORKSTATION_DIALOUT: icbp->OperState = OPER_STATE_SLEEPING; break; default: icbp->OperState = OPER_STATE_DOWN; break; } } // if REACHABLE, resume advertising routes and services if(icbp->InterfaceReachable) { // enable all static routes for this interface EnableStaticRoutes(icbp->InterfaceIndex); // enable external interfaces. Implicitly, this will enable static services // bound to this interface to be advertised ExternalEnableInterface(icbp->InterfaceIndex); } } VOID AdminDisable(PICB icbp) { if(icbp->AdminState == ADMIN_STATE_DISABLED) { return; } icbp->AdminState = ADMIN_STATE_DISABLED; InterfaceEnabled (icbp->hDIMInterface, PID_IPX, FALSE); icbp->OperState = OPER_STATE_DOWN; if(icbp->acbp != NULL) RMDeleteLocalRoute(icbp); // disable all static routes for this interface DisableStaticRoutes(icbp->InterfaceIndex); // disable external interfaces. Implicitly, static services bound to this // interface will stop being advertised. ExternalDisableInterface(icbp->InterfaceIndex); } NET_INTERFACE_TYPE MapIpxToNetInterfaceType(PICB icbp) { NET_INTERFACE_TYPE NetInterfaceType; switch(icbp->MIBInterfaceType) { case IF_TYPE_WAN_ROUTER: case IF_TYPE_PERSONAL_WAN_ROUTER: NetInterfaceType = DEMAND_DIAL; break; case IF_TYPE_ROUTER_WORKSTATION_DIALOUT: NetInterfaceType = LOCAL_WORKSTATION_DIAL; break; case IF_TYPE_WAN_WORKSTATION: NetInterfaceType = REMOTE_WORKSTATION_DIAL; break; default: NetInterfaceType = PERMANENT; break; } return NetInterfaceType; } /*++ Function: I_SetFilters Descr: Internal parses the traffic filter info block and sets the filter driver info. --*/ /* DWORD I_SetFilters(ULONG InterfaceIndex, ULONG FilterMode, // inbound or outbound LPVOID FilterInfop) { PIPX_TRAFFIC_FILTER_GLOBAL_INFO gip; PIPX_TOC_ENTRY tocep; LPVOID FilterDriverInfop; ULONG FilterDriverInfoSize; DWORD rc; if(FilterInfop == NULL) { // remove all filters rc = SetFilters(InterfaceIndex, FilterMode, // in or outbound, 0, 0, NULL, 0); return rc; } gip = GetInfoEntry((PIPX_INFO_BLOCK_HEADER)FilterInfop, IPX_TRAFFIC_FILTER_GLOBAL_INFO_TYPE); if(gip == NULL) { return ERROR_CAN_NOT_COMPLETE; } FilterDriverInfop = GetInfoEntry((PIPX_INFO_BLOCK_HEADER)FilterInfop, IPX_TRAFFIC_FILTER_INFO_TYPE); if(FilterDriverInfop == NULL) { rc = SetFilters(InterfaceIndex, FilterMode, // in or outbound, 0, // pass or don't pass 0, // filter size NULL, 0); return rc; } tocep = GetTocEntry((PIPX_INFO_BLOCK_HEADER)FilterInfop, IPX_TRAFFIC_FILTER_INFO_TYPE); FilterDriverInfoSize = tocep->Count * tocep->InfoSize; rc = SetFilters(InterfaceIndex, FilterMode, // in or outbound, gip->FilterAction, // pass or don't pass tocep->InfoSize, // filter size FilterDriverInfop, FilterDriverInfoSize); return rc; } */ /*++ Function: I_GetFilters Descr: Internal builds the traffic filters info block from the filter driver information. --*/ /* typedef struct _FILTERS_INFO_HEADER { IPX_INFO_BLOCK_HEADER Header; IPX_TOC_ENTRY TocEntry; IPX_TRAFFIC_FILTER_GLOBAL_INFO GlobalInfo; } FILTERS_INFO_HEADER, *PFILTERS_INFO_HEADER; DWORD I_GetFilters(ULONG InterfaceIndex, ULONG FilterMode, LPVOID FilterInfop, PULONG FilterInfoSize) { DWORD rc; ULONG FilterAction; ULONG FilterSize; PFILTERS_INFO_HEADER fhp; LPVOID FilterDriverInfop; ULONG FilterDriverInfoSize = 0; PIPX_TOC_ENTRY tocep; if((FilterInfop == NULL) || (*FilterInfoSize == 0)) { // we are asked for size rc = GetFilters(InterfaceIndex, FilterMode, &FilterAction, &FilterSize, NULL, &FilterDriverInfoSize); if((rc != NO_ERROR) && (rc != ERROR_INSUFFICIENT_BUFFER)) { return ERROR_CAN_NOT_COMPLETE; } if(FilterDriverInfoSize) { // there are filters *FilterInfoSize = sizeof(FILTERS_INFO_HEADER) + FilterDriverInfoSize; return ERROR_INSUFFICIENT_BUFFER; } else { // NO filters exist *FilterInfoSize = 0; return NO_ERROR; } } if(*FilterInfoSize <= sizeof(FILTERS_INFO_HEADER)) { return ERROR_INSUFFICIENT_BUFFER; } FilterDriverInfoSize = *FilterInfoSize - sizeof(FILTERS_INFO_HEADER); FilterDriverInfop = (LPVOID)((PUCHAR)FilterInfop + sizeof(FILTERS_INFO_HEADER)); rc = GetFilters(InterfaceIndex, FilterMode, &FilterAction, &FilterSize, FilterDriverInfop, &FilterDriverInfoSize); if(rc != NO_ERROR) { if(rc == ERROR_MORE_DATA) { *FilterInfoSize = sizeof(FILTERS_INFO_HEADER) + FilterDriverInfoSize; return ERROR_INSUFFICIENT_BUFFER; } else { return ERROR_CAN_NOT_COMPLETE; } } // got it fhp = (PFILTERS_INFO_HEADER)FilterInfop; fhp->Header.Version = IPX_ROUTER_VERSION_1; fhp->Header.Size = *FilterInfoSize; fhp->Header.TocEntriesCount = 2; tocep = fhp->Header.TocEntry; tocep->InfoType = IPX_TRAFFIC_FILTER_GLOBAL_INFO_TYPE; tocep->InfoSize = sizeof(IPX_TRAFFIC_FILTER_GLOBAL_INFO); tocep->Count = 1; tocep->Offset = (ULONG)((PUCHAR)&(fhp->GlobalInfo) - (PUCHAR)FilterInfop); tocep++; tocep->InfoType = IPX_TRAFFIC_FILTER_INFO_TYPE; tocep->InfoSize = FilterSize; tocep->Count = FilterDriverInfoSize / FilterSize; tocep->Offset = sizeof(FILTERS_INFO_HEADER); fhp->GlobalInfo.FilterAction = FilterAction; return NO_ERROR; } */