/**********************************************************************/ /** Microsoft Windows **/ /** Copyright(c) Microsoft Corp., 1994 **/ /**********************************************************************/ /* chic.c Contains VxD code that is specific to Chicago FILE HISTORY: Johnl 14-Mar-1994 Created */ #include #include #include #include #include #include #ifdef CHICAGO //******************* Pageable Routine Declarations **************** // // any digit 0 to 9 and '.' are legal characters in an ipaddr // #define IS_IPADDR_CHAR( ch ) ( (ch >= '0' && ch <= '9') || (ch == '.') ) #define MAX_ADAPTER_DESCRIPTION_LENGTH 128 const char szXportName[] = "MSTCP"; // // asking ndis to open,read,close for every single parameter slows down // bootup: don't open if it's already open // NDIS_HANDLE GlobalNdisHandle = NULL; // // This flag is set to TRUE when the first adapter is initialized. It // indicates that NBT globals (such as node type, scode ID etc) have // had the opportunity to be set by DHCP. // BOOL fGlobalsInitialized = FALSE; // // As each adapter gets added, the Lana offset is added // UCHAR iLanaOffset = 0; VOID GetMacAddr( ULONG IpAddress, UCHAR MacAddr[] ); BOOL StopAllNameQueries( tDEVICECONTEXT *pDeviceContext ); BOOL CancelAllDelayedEvents( tDEVICECONTEXT *pDeviceContext ); extern tTIMERQ TimerQ; BOOL GetNdisParam( LPSTR pszKey, ULONG * pVal, NDIS_PARAMETER_TYPE ParameterType ); //******************* Pageable Routine Declarations **************** #ifdef ALLOC_PRAGMA #pragma CTEMakePageable(PAGE, IPNotification) #pragma CTEMakePageable(PAGE, DestroyDeviceObject) #pragma CTEMakePageable(PAGE, SaveNameDnsServerAddrs) #pragma CTEMakePageable(PAGE, GetDnsServerAddress) #pragma CTEMakePageable(PAGE, GetNameServerAddress) #pragma CTEMakePageable(PAGE, GetMacAddr) #pragma CTEMakePageable(PAGE, VxdReadIniString) #pragma CTEMakePageable(PAGE, GetProfileInt) #pragma CTEMakePageable(PAGE, VxdOpenNdis) #pragma CTEMakePageable(PAGE, GetNdisParam) #pragma CTEMakePageable(PAGE, VxdCloseNdis) #pragma CTEMakePageable(PAGE, StopAllNameQueries) #pragma CTEMakePageable(PAGE, VxdUnload) #pragma CTEMakePageable(PAGE, ReleaseNbtConfigMem) #endif /******************************************************************* NAME: IPNotification SYNOPSIS: Called by the IP driver when a new Lana needs to be created or destroyed for an IP address. ENTRY: pDevNode - Plug'n'Play context IpAddress - New ip address IpMask - New ip mask fNew - Are we creating or destroying this Lana? NOTES: This routine is only used by Chicago HISTORY: Johnl 17-Mar-1994 Created ********************************************************************/ TDI_STATUS IPNotification( ULONG IpAddress, ULONG IpMask, PVOID pDevNode, USHORT IPContext, BOOL fNew ) { NTSTATUS status = STATUS_SUCCESS; ULONG IpNS[COUNT_NS_ADDR]; ULONG IpDns[COUNT_NS_ADDR]; int iLana; UCHAR RequestedLana; int i; int iEmpty; UCHAR PreviousNodeType; UCHAR MacAddr[6]; CTEPagedCode(); KdPrint(("IPNotification entered\r\n")); if ( !IpAddress ) { return TDI_SUCCESS ; } if ( fNew ) { // // parameters nodetype, scope and bcastaddr are systemwide, not per // adapter: so read only once. // if ( !fGlobalsInitialized ) { PreviousNodeType = NodeType; // // This will re-read the DHCPable parameters now that we have // a potential DHCP source // VxdOpenNdis(); ReadParameters2( pNbtGlobConfig, NULL ); VxdCloseNdis(); if (PreviousNodeType & PROXY) { NodeType |= PROXY; } fGlobalsInitialized = TRUE; } // // Get the name servers for this device context (ip address) // GetNameServerAddress( IpAddress, IpNS); // // Get the DNS servers for this device context (ip address) // GetDnsServerAddress( IpAddress, IpDns); // // Find a free spot in our Lana table // for ( iEmpty = 0; iEmpty < NBT_MAX_LANAS; iEmpty++) { if (LanaTable[iEmpty].pDeviceContext == NULL) goto Found; } // // Lana table is full so bail // CDbgPrint(DBGFLAG_ERROR,("IPNotification: LanaTable full\r\n")); return STATUS_INSUFFICIENT_RESOURCES; Found: GetMacAddr( IpAddress, MacAddr ); status = CreateDeviceObject( pNbtGlobConfig, htonl( IpAddress ), htonl( IpMask ), IpNS[0], IpNS[1], IpDns[0], IpDns[1], MacAddr, 0 ); if (status != STATUS_SUCCESS) { CDbgPrint(DBGFLAG_ERROR,("IPNotification: CreateDeviceObject Failed\r\n")); return status; } // // We first try and ask for a specific Lana from vnetbios based on // our Lanabase and how many other Lanas we've already added. If // this fails, then we will ask for Any Lana. If the LANABASE // parameter is not specified, then request Any Lana. // if ( LanaBase != VXD_ANY_LANA ) RequestedLana = LanaBase + iLanaOffset++ ; else RequestedLana = VXD_ANY_LANA; RetryRegister: if ( (iLana = RegisterLana2( pDevNode, RequestedLana )) == 0xff ) { if ( RequestedLana == VXD_ANY_LANA ) { // // We couldn't get *any* lanas so bail // CDbgPrint(DBGFLAG_ERROR,("IPNotification: RegisterLana2 Failed\r\n")); DestroyDeviceObject( pNbtGlobConfig, htonl(IpAddress)); return STATUS_INSUFFICIENT_RESOURCES; } else { // // Somebody may already have this Lana so beg for another one // RequestedLana = VXD_ANY_LANA; goto RetryRegister; } } KdPrint(("IPNotification: using Lana %d\r\n", iLana )); LanaTable[iEmpty].pDeviceContext = (tDEVICECONTEXT*)pNbtGlobConfig->DeviceContexts.Blink ; LanaTable[iEmpty].pDeviceContext->iLana = iLana; // // remove our child (redir, that is!) and reenumerate our devnode // so redir knows we are there! // ReconfigureDevnode( pDevNode ); } else { status = DestroyDeviceObject( pNbtGlobConfig, htonl(IpAddress) ); } return status; } /******************************************************************* NAME: DestroyDeviceObject SYNOPSIS: Destroys the specified device ENTRY: pConfig - Global config structure IpAddr - Destroy the adapter with this address NOTES: This routine is only used by Chicago HISTORY: Johnl 17-Mar-1994 Created ********************************************************************/ NTSTATUS DestroyDeviceObject( tNBTCONFIG *pConfig, ULONG IpAddr ) { LIST_ENTRY * pEntry; LIST_ENTRY * pHead; tDEVICECONTEXT * pDeviceContext; tDEVICECONTEXT * pTmpDeviceContext; tDEVICECONTEXT * pNextDeviceContext; tCLIENTELE * pClientEle; tADDRESSELE * pAddress; tNAMEADDR * pNameAddr; tCONNECTELE * pConnEle; tLOWERCONNECTION * pLowerConn; PRCV_CONTEXT prcvCont; tRCVELE * pRcvEle ; tTIMERQENTRY * pTimer; COMPLETIONCLIENT pClientCompletion; PVOID Context; tDGRAM_SEND_TRACKING * pTracker; CTELockHandle OldIrq; int i; CTEPagedCode(); // // Find which device is going away // Also, find out a device object that is still active: we need that info // to update some of the address ele's. // pDeviceContext = NULL; pNextDeviceContext = NULL; for ( pEntry = pConfig->DeviceContexts.Flink; pEntry != &pConfig->DeviceContexts; pEntry = pEntry->Flink ) { pTmpDeviceContext = CONTAINING_RECORD( pEntry, tDEVICECONTEXT, Linkage); if ( pTmpDeviceContext->IpAddress == IpAddr ) pDeviceContext = pTmpDeviceContext; else pNextDeviceContext = pTmpDeviceContext; } if (pDeviceContext == NULL) return STATUS_INVALID_PARAMETER; // // don't accept anymore ncbs on this device // pDeviceContext->fDeviceUp = FALSE; // // Close all the connections // NbtNewDhcpAddress( pDeviceContext, 0, 0); if ( --NbtConfig.AdapterCount == 1) NbtConfig.MultiHomed = FALSE; ASSERT(IsListEmpty(&pDeviceContext->LowerConnFreeHead)); // // if we are destroying the last device then // if ( NbtConfig.AdapterCount == 0) { // // Kill off all of the Receive any from any NCBs // while ( !IsListEmpty( &pDeviceContext->RcvAnyFromAnyHead )) { pEntry = RemoveHeadList( &pDeviceContext->RcvAnyFromAnyHead ) ; prcvCont = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ; ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ; CTEIoComplete( prcvCont->pNCB, STATUS_NETWORK_NAME_DELETED, 0 ) ; } // // Kill off all of the Receive any datagrams from any // while ( !IsListEmpty(&pDeviceContext->RcvDGAnyFromAnyHead)) { pEntry = RemoveHeadList( &pDeviceContext->RcvDGAnyFromAnyHead ) ; pRcvEle = CONTAINING_RECORD( pEntry, tRCVELE, Linkage ) ; CTEIoComplete( pRcvEle->pIrp, STATUS_NETWORK_NAME_DELETED, 0 ) ; CTEMemFree( pRcvEle ) ; } } // // if any name queries are in progress, stop them now // StopAllNameQueries( pDeviceContext ); CancelAllDelayedEvents( pDeviceContext ); // // walk through all names and see if any is being registered on this // device context: if so, stop and complete it! // for (i=0;i < NbtConfig.pLocalHashTbl->lNumBuckets ;i++ ) { pHead = &NbtConfig.pLocalHashTbl->Bucket[i]; pEntry = pHead->Flink; while (pEntry != pHead) { pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage); pEntry = pEntry->Flink; if (pNameAddr->NameTypeState & STATE_RESOLVING) { pTimer = pNameAddr->pTimer; // // if the name registration was started for this name on this device // context, stop the timer. (Completion routine will take care of // doing registration on other device contexts if applicable) // if (pTimer) { pTracker = pTimer->Context; ASSERT(pTracker->pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT); if (pTracker->pDeviceContext == pDeviceContext) { ASSERT(pTracker->pNameAddr == pNameAddr) pNameAddr->pTimer = NULL; CTESpinLock(&NbtConfig.JointLock,OldIrq); StopTimer(pTimer,&pClientCompletion,&Context); CTESpinFree(&NbtConfig.JointLock,OldIrq); if (pClientCompletion) { (*pClientCompletion)(Context,STATUS_NETWORK_NAME_DELETED); } DbgPrint("DestroyDeviceObject: stopped name reg timer") ; } } } } } // // walk through all the client ele's this device context has and clean // up all the mess this clientele created! // for ( i = 0 ; i <= pDeviceContext->cMaxNames ; i++ ) { pClientEle = pDeviceContext->pNameTable[i]; if ( !pClientEle ) continue; VxdCleanupAddress( pDeviceContext, NULL, pClientEle, (UCHAR)i, TRUE ); } // // close all the TDI handles // CloseAddressesWithTransport(pDeviceContext); // // if a call was started, but aborted then we could have some memory here! // while (!IsListEmpty(&pDeviceContext->UpConnectionInUse)) { pEntry = RemoveHeadList(&pDeviceContext->UpConnectionInUse); pConnEle = CONTAINING_RECORD(pEntry,tCONNECTELE,Linkage); CTEMemFree( pConnEle ); } while (!IsListEmpty(&pDeviceContext->LowerConnection)) { pEntry = RemoveHeadList(&pDeviceContext->LowerConnection); pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage); CTEMemFree( pLowerConn ); } // // Remove the device from our Lana table and Vnetbios // for ( i = 0; i < NBT_MAX_LANAS; i++) { if (LanaTable[i].pDeviceContext == pDeviceContext) { DeregisterLana(LanaTable[i].pDeviceContext->iLana); LanaTable[i].pDeviceContext = NULL; KdPrint(("DestroyDeviceObject: deregistered Lana %d\r\n",pDeviceContext->iLana)); break; } } RemoveEntryList( &pDeviceContext->Linkage); // // Walk through the AddressHead list. If any addresses exist and they // point to old device context, put the next device context. Also, update // adapter mask to reflect that this device context is now gone. // KdPrint(("DestroyDeviceObject: setting AddrEle,NameAddr fields\r\n")); pHead = pEntry = &NbtConfig.AddressHead; while ((pEntry = pEntry->Flink) != pHead) { pAddress = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage); ASSERT (pAddress->Verify == NBT_VERIFY_ADDRESS); if (pAddress->pDeviceContext == pDeviceContext) { pAddress->pDeviceContext = pNextDeviceContext; } pAddress->pNameAddr->AdapterMask &= ~pDeviceContext->AdapterNumber; } if (pDeviceContext->pNameTable) CTEMemFree( pDeviceContext->pNameTable ); if (pDeviceContext->pSessionTable) CTEMemFree( pDeviceContext->pSessionTable ); CTEMemFree( pDeviceContext ); return STATUS_SUCCESS; } /******************************************************************* NAME: SaveNameDnsServerAddrs SYNOPSIS: Get the name server and dns server addrs from the registry and save it in Nbtconfig. We do this so that when a new adapter comes in or lease gets renewed (particularly the latter), we don't have to go read the registry becuase it may not be safe to do so. This routine will have to be modified if setup ever changes to allow configuration of name/dns servers per lana. ENTRY: Nothing HISTORY: Koti 20-Nov-1994 Created ********************************************************************/ VOID SaveNameDnsServerAddrs( VOID ) { UCHAR i ; PUCHAR pchSrv = "NameServer$" ; PUCHAR pchDnsSrv = "NameServer" ; PUCHAR pchSrvNum; LPTSTR pchString ; PUCHAR pchCurrent, pchNext; BOOL fOneMore=TRUE; ULONG IpNameServers[COUNT_NS_ADDR]; CTEPagedCode(); // // Get Name Server ipaddrs // pchSrvNum = pchSrv + 10 ; // to overwrite '$' with 1,2,3 etc. for ( i = 0; i < COUNT_NS_ADDR; i++) { IpNameServers[i] = LOOP_BACK;; *pchSrvNum = '1' + i; // call GetNdisParam directly so that we don't query dhcp here // if ( !CTEReadIniString( NULL, pchSrv, &pchString ) ) // if ( GetNdisParam( pchSrv, (ULONG *)&pchString, NdisParameterString ) ) { if ( ConvertDottedDecimalToUlong( pchString, &IpNameServers[i] )) { DbgPrint("SaveNameDnsServerAddrs: bad name srv addr\r\n") ; IpNameServers[i] = LOOP_BACK; } CTEFreeMem( pchString ) ; } } // // store the name server ipaddrs (potentially 0 if not defined in registry) // NbtConfig.lRegistryNameServerAddress = IpNameServers[0]; NbtConfig.lRegistryBackupServer = IpNameServers[1]; // // Now get Dns Server ipaddrs // // // initialize all of them to worst case // for ( i = 0; i < COUNT_NS_ADDR; i++) { IpNameServers[i] = LOOP_BACK; } // call GetNdisParam directly so that we don't query dhcp here // if ( !CTEReadIniString( NULL, pchDnsSrv, &pchString ) ) // if ( GetNdisParam( pchDnsSrv, (ULONG *)&pchString, NdisParameterString ) ) { // // we are generating (upto) COUNT_NS_ADDR pointers each pointing to // one ipaddr. The string in system.ini looks like: // NameServer = 11.101.4.26,200.200.200.200,1.2.3.4,1.91.245.10 // pchNext = pchCurrent = pchString; if ( IS_IPADDR_CHAR(*pchCurrent) ) // make sure at least one ipaddr defnd { i = 0; while( (i < COUNT_NS_ADDR) && fOneMore ) { while( IS_IPADDR_CHAR(*pchNext) ) pchNext++; if ( *pchNext == ',' ) // ',' is the separator between 2 addrs { *pchNext = '\0'; pchNext++; } else { fOneMore = FALSE; // reached end of line } // // as long as at least the first one ipaddr gets converted properly, // ignore errors in others // if ( ConvertDottedDecimalToUlong( pchCurrent, &IpNameServers[i] )) { DbgPrint("SaveNameDnsServerAddrs: bad dns srv addr\r\n") ; IpNameServers[i] = LOOP_BACK; } i++; pchCurrent = pchNext; // go, convert the next one } } if( pchString != NULL ) { CTEFreeMem( pchString ) ; } } // // store the dns server ipaddrs (potentially 0 if not defined in registry) // NbtConfig.lRegistryDnsServerAddress = IpNameServers[0]; NbtConfig.lRegistryDnsBackupServer = IpNameServers[1]; } /******************************************************************* NAME: GetDnsServerAddress SYNOPSIS: Gets the DNS server ipaddrs from the registry. Or, if DHCP is installed and the DNS server addresses aren't found, we get them from DHCP ENTRY: IpAddr - If we can get from DHCP, get form this address pIpDnsServer - Receives addresses if found (otherwise 0) NOTES: This routine is only used by Snowball HISTORY: Koti 18-Oct-1994 Created ********************************************************************/ void GetDnsServerAddress( ULONG IpAddr, PULONG pIpDnsServer) { UCHAR i ; UINT OptId; TDI_STATUS tdistatus ; ULONG Buff[COUNT_NS_ADDR] ; ULONG Size; CTEPagedCode(); for ( i = 0; i < COUNT_NS_ADDR; i++) { pIpDnsServer[i] = LOOP_BACK ; } pIpDnsServer[0] = NbtConfig.lRegistryDnsServerAddress; pIpDnsServer[1] = NbtConfig.lRegistryDnsBackupServer; // // if it was defined in the registry, we are done // if ( pIpDnsServer[0] != LOOP_BACK || pIpDnsServer[1] != LOOP_BACK ) { return; } // // it was not defined in the registry: try getting them from DHCP // Size = sizeof( Buff ) ; OptId = 6; // DNS Option tdistatus = DhcpQueryOption( IpAddr, OptId, &Buff, &Size ) ; switch ( tdistatus ) { case TDI_SUCCESS: case TDI_BUFFER_OVERFLOW: // May be more then one our buffer will hold for ( i = 0; i < COUNT_NS_ADDR; i++ ) { if ( Size >= (sizeof(ULONG)*(i+1))) pIpDnsServer[i] = htonl(Buff[i]) ; } break ; case TDI_INVALID_PARAMETER: // Option not found break; default: ASSERT( FALSE ) ; break ; } KdPrint(("GetDnsServerAddress: Primary: %x, backup: %x\r\n", pIpDnsServer[0], pIpDnsServer[1] )) ; } /******************************************************************* NAME: GetNameServerAddress SYNOPSIS: Gets the Win server for the specified Lana. Or, if DHCP is installed and the Name server addresses aren't found, we get them from DHCP ENTRY: IpAddr - If we can get from DHCP, get form this address pIpNameServer - Receives addresses if found (otherwise 0) NOTES: This routine is only used by Snowball HISTORY: Johnl 21-Oct-1993 Created ********************************************************************/ void GetNameServerAddress( ULONG IpAddr, PULONG pIpNameServer) { UCHAR i ; UINT OptId; TDI_STATUS tdistatus ; ULONG Buff[COUNT_NS_ADDR] ; ULONG Size; CTEPagedCode(); for ( i = 0; i < COUNT_NS_ADDR; i++) { pIpNameServer[i] = LOOP_BACK ; } pIpNameServer[0] = NbtConfig.lRegistryNameServerAddress; pIpNameServer[1] = NbtConfig.lRegistryBackupServer; // // if it was defined in the registry, we are done // if ( pIpNameServer[0] != LOOP_BACK || pIpNameServer[1] != LOOP_BACK ) { return; } // // not defined in the registry: try to get it from dhcp // OptId = 44; // NBNS Option Size = sizeof( Buff ) ; tdistatus = DhcpQueryOption( IpAddr, OptId, &Buff, &Size ) ; switch ( tdistatus ) { case TDI_SUCCESS: case TDI_BUFFER_OVERFLOW: // May be more then one our buffer will hold for ( i = 0; i < COUNT_NS_ADDR; i++ ) { if ( Size >= (sizeof(ULONG)*(i+1))) pIpNameServer[i] = htonl(Buff[i]) ; } break ; case TDI_INVALID_PARAMETER: // Option not found break ; default: ASSERT( FALSE ) ; break ; } KdPrint(("GetNameServerAddress: Primary: %x, backup: %x\r\n", pIpNameServer[0], pIpNameServer[1] )) ; } /******************************************************************* NAME: GetMacAddr SYNOPSIS: Gets the mac address for the give ipaddr ENTRY: IpAddress - the address for which to find mac addr MacAddr - the array where to store mac addr HISTORY: Koti 19-Oct-1994 Created ********************************************************************/ VOID GetMacAddr( ULONG IpAddress, UCHAR MacAddr[] ) { TDI_STATUS tdistatus ; int i, j, k ; uchar Context[CONTEXT_SIZE] ; TDIObjectID ID ; TDIEntityID EList[MAX_TDI_ENTITIES] ; ULONG Size ; UINT NumReturned ; NDIS_BUFFER ndisbuff ; IFEntry *ifeAdapterInfo[MAX_TDI_ENTITIES]; UINT AdptNum; CTEPagedCode(); // // initialize to 0, in case things don't work out // memset( MacAddr, 0, 6 ) ; // // The first thing to do is get the list of available entities, and make // sure that there are some interface entities present. // ID.toi_entity.tei_entity = GENERIC_ENTITY; ID.toi_entity.tei_instance = 0; ID.toi_class = INFO_CLASS_GENERIC; ID.toi_type = INFO_TYPE_PROVIDER; ID.toi_id = ENTITY_LIST_ID; Size = sizeof(EList); InitNDISBuff( &ndisbuff, &EList, Size, NULL ) ; memset(Context, 0, CONTEXT_SIZE); tdistatus = TdiVxdQueryInformationEx( 0, &ID, &ndisbuff, &Size, Context); if (tdistatus != TDI_SUCCESS) { CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Querying entity list failed\r\n")) ; return; } NumReturned = (uint)Size/sizeof(TDIEntityID); AdptNum = 0; // // first find out info about the adapters // for (i = 0; i < NumReturned; i++) { // // if this entity/instance describes an adapter // if ( EList[i].tei_entity == IF_ENTITY ) { DWORD isMib; ID.toi_entity.tei_entity = EList[i].tei_entity ; ID.toi_entity.tei_instance = EList[i].tei_instance; ID.toi_class = INFO_CLASS_GENERIC ; ID.toi_type = INFO_TYPE_PROVIDER; ID.toi_id = ENTITY_TYPE_ID ; Size = sizeof( isMib ); InitNDISBuff( &ndisbuff, &isMib, Size, NULL ) ; memset(Context, 0, CONTEXT_SIZE); tdistatus = TdiVxdQueryInformationEx( 0, &ID, &ndisbuff, &Size, Context); if ( tdistatus != TDI_SUCCESS ) { CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Getting isMib failed\r\n")) ; return ; } // // Does this entity support MIB // if (isMib != IF_MIB) { CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: skipping non-MIB entity\r\n")) ; continue; } // // MIB requests supported - query the adapter info // Size = sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1; ifeAdapterInfo[AdptNum] = (IFEntry *)CTEAllocInitMem(Size); if ( ifeAdapterInfo[AdptNum] == NULL ) { CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Couldn't allocate AdapterInfo buffer\r\n")) ; for ( k=0; k= IPStats.ipsi_numaddr ) ; // // We have the IP address table for this IP driver. Look for // our IP address // for ( j = 0 ; j < IPStats.ipsi_numaddr ; j++ ) { // // find our ipaddress // if ( pIAE[j].iae_addr != IpAddress ) { continue ; } // // now find out the mac address for this ipaddr // for ( k=0; kif_index == pIAE[j].iae_index ) { CTEMemCopy( MacAddr, ifeAdapterInfo[k]->if_physaddr, 6 ); break; } } } if (pIAE) { CTEFreeMem( pIAE ) ; } } } for ( k=0; kParameterData.StringData.Length + 1 ) ; if ( lpstr ) { strcpy( lpstr, Param->ParameterData.StringData.Buffer ); *pVal = (ULONG) lpstr; fRet = TRUE; } } else { *pVal = Param->ParameterData.IntegerData; fRet = TRUE; } } return fRet ; } /******************************************************************* NAME: VxdCloseNdis SYNOPSIS: Close the handle that we opened in VxdOpenNdis ENTRY: Nothing (GlobalNdisHandle is global) HISTORY: Koti Nov. 20, 94 ********************************************************************/ VOID VxdCloseNdis( VOID ) { CTEPagedCode(); ASSERT(GlobalNdisHandle); if (GlobalNdisHandle != NULL) { NdisCloseConfiguration(GlobalNdisHandle); GlobalNdisHandle = NULL; } } /******************************************************************* NAME: StopAllNameQueries SYNOPSIS: This routine is called when the device context is going away. It finds out all the name queries that are in progress (started by someone on this device context) and stops them. ENTRY: pDeviceContext - the device context that is going away. RETURNS: TRUE if at least one name query was found and stopped FALSE if there wasn't any query in progress HISTORY: Koti Nov. 19, 94 ********************************************************************/ BOOL StopAllNameQueries( tDEVICECONTEXT *pDeviceContext ) { tDGRAM_SEND_TRACKING *pTracker; NBT_WORK_ITEM_CONTEXT *Context; PVOID pClientCompletion; PVOID pClientContext; tNAMEADDR *pNameAddr; tTIMERQENTRY *pTimer; PLIST_ENTRY pHead; PLIST_ENTRY pEntry; CTELockHandle OldIrq; CTEPagedCode(); // // first check to see if any names are on the pending list: all name // queries over the network will be here (WINS, broadcast, DNS) // CTESpinLock(&NbtConfig.JointLock,OldIrq); pHead = &NbtConfig.PendingNameQueries; pEntry = pHead->Flink; while (pEntry != pHead) { pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage); pEntry = pEntry->Flink; pTimer = pNameAddr->pTimer; if (pTimer) { pTracker = (tDGRAM_SEND_TRACKING *)pTimer->Context; ASSERT (pTracker->pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT); if (pTracker->pDeviceContext == pDeviceContext) { StopTimer(pTimer,(COMPLETIONCLIENT *)&pClientCompletion,&Context); if (pClientCompletion) { // // Remove from the pending list // RemoveEntryList(&pNameAddr->Linkage); InitializeListHead(&pNameAddr->Linkage); pNameAddr->pTimer = NULL; NbtDereferenceName(pNameAddr); // // complete client's ncb. If requests were queued on // the same name by other clients, this will start new // name queries for those clients // CTESpinFree(&NbtConfig.JointLock,OldIrq); CompleteClientReq(pClientCompletion, (tDGRAM_SEND_TRACKING *)Context, STATUS_NETWORK_NAME_DELETED); CTESpinLock(&NbtConfig.JointLock,OldIrq); DbgPrint("StopAllNameQueries: stopped net name query") ; } } } } CTESpinFree(&NbtConfig.JointLock,OldIrq); // // now check if any names are on the lmhosts queue: all name queries // waiting for lmhosts (and/or hosts) parsing will be here // Context = NULL; if (LmHostQueries.ResolvingNow && LmHostQueries.Context) { Context = (NBT_WORK_ITEM_CONTEXT *)LmHostQueries.Context; pTracker = Context->pTracker; ASSERT (pTracker->pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT); if (pTracker->pDeviceContext == pDeviceContext) { LmHostQueries.Context = NULL; pClientCompletion = Context->ClientCompletion; pClientContext = Context->pClientContext; // name did not resolve, so delete from table RemoveName(pTracker->pNameAddr); DereferenceTracker(pTracker); CompleteClientReq(pClientCompletion, pClientContext, STATUS_NETWORK_NAME_DELETED); DbgPrint("StopAllNameQueries: stopped lmhosts query in progress") ; } } // // now walk through the queued items and cancel all the relevant ones // pHead = &LmHostQueries.ToResolve; pEntry = pHead->Flink; while (pEntry != pHead) { Context = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List); pEntry = pEntry->Flink; pTracker = Context->pTracker; ASSERT (pTracker->pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT); if (pTracker->pDeviceContext == pDeviceContext) { RemoveEntryList(&Context->Item.List); pClientCompletion = Context->ClientCompletion; pClientContext = Context->pClientContext; // name did not resolve, so delete from table RemoveName(pTracker->pNameAddr); DereferenceTracker(pTracker); CompleteClientReq(pClientCompletion, pClientContext, STATUS_NETWORK_NAME_DELETED); DbgPrint("StopAllNameQueries: cancelled lmhosts queries in queue") ; } } } /******************************************************************* NAME: VxdUnload SYNOPSIS: This is where we are asked to unload. We destroy all the device objects and then unload ourselves if the message came from vtcp. ENTRY: pchModuleName - name of the module that is going away. We take action only if vtcp is going away (in which case, pchModuleName is "MSTCP") RETURNS: STATUS_SUCCESS if things went ok HISTORY: Koti Oct 5, 94 ********************************************************************/ NTSTATUS VxdUnload( LPSTR pchModuleName ) { LIST_ENTRY * pEntry; tDEVICECONTEXT * pDeviceContext; NTSTATUS status; CTEPagedCode(); KdPrint(("VxdUnload entered\r\n")); if ( (pchModuleName == NULL) || (strcmp(pchModuleName,szXportName) != 0) ) { CDbgPrint(DBGFLAG_ERROR,("VxdUnload: Unload msg not from MSTCP\r\n")); return STATUS_SUCCESS; } // // all devices will be destroyed by the time VxdUnload is called: this is // just being paranoid // for ( pEntry = pNbtGlobConfig->DeviceContexts.Flink; pEntry != &pNbtGlobConfig->DeviceContexts; ) { pDeviceContext = CONTAINING_RECORD( pEntry, tDEVICECONTEXT, Linkage); pEntry = pEntry->Flink; status = DestroyDeviceObject(pNbtGlobConfig, pDeviceContext->IpAddress); if (status != STATUS_SUCCESS) { ASSERT(0); } } // // events such as name refresh etc. have been scheduled to be executed // later: cancel all those // CancelAllDelayedEvents( NULL ); // // Tell IP not to use the handler anymore // IPRegisterAddrChangeHandler( IPNotification, FALSE); ReleaseNbtConfigMem(); // // we don't provide any service, so don't pass our name // CTEUnload( (char *)NULL ); } /******************************************************************* NAME: ReleaseNbtConfigMem SYNOPSIS: This is where we release all the memory that was allocated at init/run time via ifs mgr. We also stop the various timers. HISTORY: Koti Oct 14, 94 ********************************************************************/ VOID ReleaseNbtConfigMem( VOID ) { PLIST_ENTRY pHead, pEntry; tTIMERQENTRY *pTimerEntry; tDGRAM_SEND_TRACKING *pTrack; tADDRESSELE *pAddress; tCLIENTELE *pClientEle; tCONNECTELE *pConnEle; tLOWERCONNECTION *pLowerConn; tNAMEADDR *pNameAddr; CTELockHandle OldIrq; int i; KdPrint(("ReleaseNbtConfigMem entered\r\n")); CTEPagedCode(); // // stop the timer that used to look for timed-out ncb's // StopTimeoutTimer(); // // if any other timers are active, stop them // if (!IsListEmpty(&TimerQ.ActiveHead)) { pHead = &TimerQ.ActiveHead; pEntry = pHead->Flink; while( pEntry != pHead ) { pTimerEntry = CONTAINING_RECORD(pEntry,tTIMERQENTRY,Linkage); pEntry = pEntry->Flink; CTESpinLock(&NbtConfig.JointLock,OldIrq); StopTimer(pTimerEntry,NULL,NULL); CTESpinFree(&NbtConfig.JointLock,OldIrq); } } // // free all the timers on the free list // while (!IsListEmpty(&TimerQ.FreeHead)) { pEntry = RemoveHeadList(&TimerQ.FreeHead); pTimerEntry = CONTAINING_RECORD(pEntry,tTIMERQENTRY,Linkage); CTEMemFree(pTimerEntry); } // free the various buffers if ( pFileBuff ) CTEMemFree( pFileBuff ); if ( NbtConfig.pHosts ) CTEMemFree( NbtConfig.pHosts ); if (NbtConfig.pScope) CTEMemFree( NbtConfig.pScope ); if (NbtConfig.pLmHosts) CTEMemFree(NbtConfig.pLmHosts); if (NbtConfig.pDomainName) CTEMemFree(NbtConfig.pDomainName); if (NbtConfig.pDNSDomains) CTEMemFree(NbtConfig.pDNSDomains); // // NbtDereferenceAddress might have freed the addresses. But if // ReleaseNameOnNet returned pending we wouldn't have freed the addressele // yet, waiting for NameReleaseDone to be called. Well, we are about to // be unloaded so free such instances now! // while (!IsListEmpty(&NbtConfig.AddressHead)) { pEntry = RemoveHeadList(&NbtConfig.AddressHead); pAddress = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage); while (!IsListEmpty(&pAddress->ClientHead)) { pEntry = RemoveHeadList(&pAddress->ClientHead); pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage); while (!IsListEmpty(&pClientEle->ConnectActive)) { pEntry = RemoveHeadList(&pClientEle->ConnectActive); pConnEle = CONTAINING_RECORD(pEntry,tCONNECTELE,Linkage); pLowerConn = pConnEle->pLowerConnId; if (pLowerConn) CTEMemFree(pLowerConn); CTEMemFree(pConnEle); } CTEMemFree(pClientEle); } CTEMemFree( pAddress ); } // free the DomainList while (!IsListEmpty(&DomainNames.DomainList)) { pEntry = RemoveHeadList(&DomainNames.DomainList); pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage); if (pNameAddr->pIpList) CTEMemFree(pNameAddr->pIpList); CTEMemFree(pNameAddr); } // free pLocalHashTbl if (NbtConfig.pLocalHashTbl) { // // we should have freed all the entries by now. It's possible though // that we sent a name release which returned pending, so we are // still hanging on to the nameaddr. If there is any such instance, // free it now (when else? we are about to be unloaded now!) // for(i=0;ilNumBuckets;i++) { while (!IsListEmpty(&(NbtConfig.pLocalHashTbl->Bucket[i]))) { pEntry = RemoveHeadList(&(NbtConfig.pLocalHashTbl->Bucket[i])); pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage); CTEMemFree(pNameAddr); } } CTEMemFree( NbtConfig.pLocalHashTbl ); } // free pRemoteHashTbl if (NbtConfig.pRemoteHashTbl) { for(i=0;ilNumBuckets;i++) { while (!IsListEmpty(&(NbtConfig.pRemoteHashTbl->Bucket[i]))) { pEntry = RemoveHeadList(&(NbtConfig.pRemoteHashTbl->Bucket[i])); pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage); CTEMemFree(pNameAddr); } } CTEMemFree( NbtConfig.pRemoteHashTbl ); } // free up the DgramTrackerFreeQ while (!IsListEmpty(&NbtConfig.DgramTrackerFreeQ)) { pEntry = RemoveHeadList(&NbtConfig.DgramTrackerFreeQ); pTrack = CONTAINING_RECORD(pEntry,tDGRAM_SEND_TRACKING,Linkage); CTEMemFree( pTrack ); } // // shouldn't see any pending name queries at this point, but just in case! // while (!IsListEmpty(&NbtConfig.PendingNameQueries)) { pEntry = RemoveHeadList(&NbtConfig.PendingNameQueries); pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage); CTEMemFree( pNameAddr ); } // free the SessionBufferFreeList list (allocated, not used) while( !IsListEmpty(&NbtConfig.SessionBufferFreeList) ) { pEntry = RemoveHeadList(&NbtConfig.SessionBufferFreeList); CTEMemFree( pEntry ); } // free SendContextFreeList (allocated, not used) while( !IsListEmpty(&NbtConfig.SendContextFreeList) ) { pEntry = RemoveHeadList(&NbtConfig.SendContextFreeList); CTEMemFree( pEntry ); } // free RcvContextFreeList (allocated, not used) while( !IsListEmpty(&NbtConfig.RcvContextFreeList) ) { pEntry = RemoveHeadList(&NbtConfig.RcvContextFreeList); CTEMemFree( pEntry ); } #ifdef DBG if( !IsListEmpty(&DbgMemList) ) { KdPrint(("ReleaseNbtConfigMem: memory leak!\r\n")); if (DbgLeakCheck) { ASSERT(0); } } #endif } #endif // CHICAGO