/**********************************************************************/ /** Microsoft Windows **/ /** Copyright(c) Microsoft Corp., 1993 **/ /**********************************************************************/ /* Init.c Contains VxD initialization code FILE HISTORY: Johnl 24-Mar-1993 Created */ #include #include #include #include #include #include int Init( void ) ; int RegisterLana( int Lana ) ; NTSTATUS NbtReadRegistry( OUT tNBTCONFIG *pConfig ) ; extern char DNSSectionName[]; // Section where we find DNS domain name VOID GetDNSInfo( VOID ); ULONG GetDhcpOption( PUCHAR ValueName, ULONG DefaultValue ); VOID ParseDomainNames( PUCHAR *ppDomainName, PUCHAR *ppDNSDomains ); //******************* Pageable Routine Declarations **************** #ifdef ALLOC_PRAGMA #pragma CTEMakePageable(INIT, Init) #pragma CTEMakePageable(PAGE, NbtReadRegistry) #pragma CTEMakePageable(PAGE, GetDNSInfo) #pragma CTEMakePageable(PAGE, CreateDeviceObject) #pragma CTEMakePageable(PAGE, GetDhcpOption) #endif //******************* Pageable Routine Declarations **************** // // Initialized in VNBT_Device_Init with the protocol(s) this driver sits // on. Note that we currently only support one. This should *not* be in // the initialization data segments. // TDIDispatchTable * TdiDispatch ; UCHAR LanaBase ; BOOL fInInit = TRUE ; // // Used in conjunction with the CHECK_INT_TABLE macro // #ifdef DEBUG BYTE abVecTbl[256] ; DWORD DebugFlags = DBGFLAG_ALL | DBGFLAG_KDPRINTS ; char DBOut[4096] ; int iCurPos = 0 ; void NbtDebugOut( char * str ) { if ( DebugFlags & (DBGFLAG_AUX_OUTPUT | DBGFLAG_ERROR) ) CTEPrint( str ) ; iCurPos += strlen( str ) + 1 ; if ( iCurPos >= sizeof(DBOut) ) iCurPos = 0; } #endif // DEBUG #pragma BEGIN_INIT // // While reading initialization parameters, we may need to go to // the DHCP driver. This communicates to the init routine which device // we are currently interested in. // 0xfffffff means get the requested option for any IP address. // // MUST BE IN NETWORK ORDER!!! // ULONG CurrentIP = 0xffffffff ; /******************************************************************* NAME: Init SYNOPSIS: Performs all driver initialization RETURNS: TRUE if initialization successful, FALSE otherwise NOTES: HISTORY: Johnl 24-Mar-1993 Created ********************************************************************/ int Init( void ) { NTSTATUS status ; int i ; ULONG ulTmp ; int Retval; Retval = FALSE; if ( CTEInitialize() ) { DbgPrint("Init: CTEInitialize succeeded\n\r") ; } else goto fail_init; INIT_NULL_PTR_CHECK() ; #ifdef DEBUG InitializeListHead(&DbgMemList); DbgLeakCheck = 0; #endif #ifdef CHICAGO // // Tell TDI who to call if someone underneath unloads // CTESetUnloadNotifyProc( (CTENotifyRtn)VxdUnload ); // // prepare to read a bunch of parms from the registry // VxdOpenNdis(); #endif CTERefillMem() ; CTEZeroMemory( pNbtGlobConfig, sizeof(*pNbtGlobConfig)); status = NbtReadRegistry( pNbtGlobConfig ) ; if ( !NT_SUCCESS( status ) ) { DbgPrint("Init: NbtReadRegistry failed\n\r") ; goto fail_init; } InitializeListHead(&pNbtGlobConfig->DelayedEvents); InitializeListHead(&pNbtGlobConfig->BlockingNcbs); status = InitNotOs() ; if ( !NT_SUCCESS( status ) ) { DbgPrint("Init: InitNotOs failed\n\r") ; goto fail_init; } status = InitTimersNotOs() ; if ( !NT_SUCCESS( status ) ) { DbgPrint("Init: InitTimersNotOs failed\n\r") ; StopInitTimers() ; goto fail_init; } #ifdef CHICAGO // // if name server and/or dns server are defined in registry, read them now // SaveNameDnsServerAddrs(); // // Register an IP notification routine when new adapters are added or // DHCP brings up an address // if ( !IPRegisterAddrChangeHandler( IPNotification, TRUE)) { DbgPrint("Init: Failed to register with IP driver\r\n") ; StopInitTimers() ; goto fail_init; } #else // // Find all the active Lanas // if ( !GetActiveLanasFromIP() ) { DbgPrint("Init: Failed to get addresses from IP driver\r\n") ; StopInitTimers() ; goto fail_init; } #endif // // find out where hosts file is, what's the domain name etc. // GetDNSInfo(); // // Get the NCB timeout timer going // if ( !CheckForTimedoutNCBs( NULL, NULL) ) { DbgPrint("Init: CheckForTimedoutNCBs failed\n\r") ; StopInitTimers() ; goto fail_init; } fInInit = FALSE ; CTERefillMem() ; Retval = TRUE ; fail_init: #ifdef CHICAGO VxdCloseNdis(); #endif return( Retval ); } //---------------------------------------------------------------------------- NTSTATUS NbtReadRegistry( OUT tNBTCONFIG *pConfig ) /*++ Routine Description: This routine is called to get information from the registry, starting at RegistryPath to get the parameters. Arguments: pNbtConfig - ptr to global configuration strucuture for NBT Return Value: NTSTATUS - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES otherwise. --*/ { NTSTATUS Status = STATUS_SUCCESS ; int i; CTEPagedCode(); // // Initialize the Configuration data structure // CTEZeroMemory(pConfig,sizeof(tNBTCONFIG)); ReadParameters( pConfig, NULL ); // // Allocate necessary memory for lmhosts support if a lmhosts file // was specified (was read from .ini file in ReadParameters) // if ( pConfig->pLmHosts ) { if ( !VxdInitLmHostsSupport( pConfig->pLmHosts, 260 /*strlen(pConfig->pLmHosts)+1*/ )) { return STATUS_INSUFFICIENT_RESOURCES ; } pConfig->EnableLmHosts = TRUE ; } else { pConfig->EnableLmHosts = FALSE ; } // keep the size around for allocating memory, so that when we run over // OSI, only this value should change (in theory at least) pConfig->SizeTransportAddress = sizeof(TDI_ADDRESS_IP); // fill in the node type value that is put into all name service Pdus // that go out identifying this node type switch (NodeType) { case BNODE: pConfig->PduNodeType = 0; break; case PNODE: pConfig->PduNodeType = 1 << 13; break; case MNODE: pConfig->PduNodeType = 1 << 14; break; case MSNODE: pConfig->PduNodeType = 3 << 13; break; } LanaBase = (UCHAR) CTEReadSingleIntParameter( NULL, VXD_LANABASE_NAME, VXD_DEF_LANABASE, 0 ) ; CTEZeroMemory( LanaTable, NBT_MAX_LANAS * sizeof( LANA_ENTRY )) ; return Status; } /******************************************************************* NAME: GetDNSInfo SYNOPSIS: Gets path to windows dir, then appends hosts to it RETURNS: Nothing NOTES: If something goes wrong, path is set to NULL HISTORY: Koti 13-July-1994 Created ********************************************************************/ VOID GetDNSInfo( VOID ) { PUCHAR pszWinPath; PUCHAR pszHosts="hosts"; PUCHAR pszHostsPath=NULL; #ifdef CHICAGO PUCHAR pszParmName="Domain"; PUCHAR pszParm2Name = "SearchList"; #else PUCHAR pszParmName="DomainName"; PUCHAR pszParm2Name = "DNSDomains"; #endif PUCHAR pszDomName; PUCHAR pchTmp; int len; CTEPagedCode(); NbtConfig.pHosts = NULL; // // Remember, pszWinPath has '\' at the end: (i.e. Get_Config_Directory // returns pointer to "c:\windows\" ) // pszWinPath = VxdWindowsPath(); // // doc implies Get_Config_Directory can't fail! But we are paranoid... // if (pszWinPath == NULL) { pszHostsPath = NULL; return; } len = strlen(pszWinPath) + strlen(pszHosts) + 1; // // allocate memory to hold "c:\windows\hosts" or whatever // pszHostsPath = CTEAllocInitMem( len ); if (pszHostsPath == NULL) return; strcpy(pszHostsPath, pszWinPath); strcat(pszHostsPath, pszHosts); NbtConfig.pHosts = pszHostsPath; NbtConfig.pDomainName = NULL; // // chicago gets the string from the registry, snowball from system.ini // NbtConfig.pDNSDomains = NULL; #ifdef CHICAGO if ( !CTEReadIniString( NULL, pszParmName, &pchTmp ) ) { NbtConfig.pDomainName = pchTmp; } if ( !CTEReadIniString( NULL, pszParm2Name, &pchTmp ) ) { if (pchTmp[0] != '\0') { NbtConfig.pDNSDomains = pchTmp; } else { CTEMemFree(pchTmp); } } #else pchTmp = GetProfileString( pszParmName, NULL, DNSSectionName ); if ( pchTmp != NULL ) { if ( pszDomName = CTEAllocInitMem( strlen( pchTmp ) + 1 ) ) { strcpy( pszDomName, pchTmp ) ; NbtConfig.pDomainName = pszDomName; } } pchTmp = GetProfileString( pszParm2Name, NULL, DNSSectionName ); if ( pchTmp != NULL && pchTmp[0] != '\0') { if ( pszDomName = CTEAllocInitMem( strlen( pchTmp ) + 1) ) { strcpy( pszDomName, pchTmp ) ; NbtConfig.pDNSDomains = pszDomName; } } #endif ParseDomainNames( &NbtConfig.pDomainName, &NbtConfig.pDNSDomains); return; } /******************************************************************* NAME: ParseDomainNames SYNOPSIS: Extracts heirarchical domain names from the primary DNS domain name, and prepends any found to the domains list. ENTRY: ppDomainName - pointer to pointer to primary DNS domain name ppDNSDomains - pointer to pointer to other DNS domain names EXIT: *ppDNSDomains updated with pointer to new DNS domains list if any other heirarchical levels found in *ppDomainName. RETURNS: nothing NOTES: HISTORY: EarleH 10-Jan-1996 Created ********************************************************************/ VOID ParseDomainNames( PUCHAR *ppDomainName, PUCHAR *ppDNSDomains ) { PUCHAR pStr; UINT iCount; PUCHAR pDomainName = *ppDomainName, pDNSDomains = *ppDNSDomains, pNewDNSDomains; if ( pDomainName != NULL ) { for ( iCount = 0, pStr = pDomainName ; pStr[0] != '\0' ; pStr++ ) { if ( pStr[0] == '.' ) { iCount += strlen ( pStr ); } } if ( pDNSDomains != NULL ) { iCount += strlen ( pDNSDomains ); if ( iCount ) { iCount++; // for the separator } } if (iCount++) // ++ for the terminator { pNewDNSDomains = CTEAllocInitMem( iCount ); if ( pNewDNSDomains != NULL ) { pNewDNSDomains[0] = '\0'; for ( pStr = pDomainName ; pStr[0] != '\0' ; pStr++ ) { if ( pStr[0] == '.' ) { pStr++; if ( pNewDNSDomains[0] != '\0' ) { strcat ( pNewDNSDomains, "," ); } strcat ( pNewDNSDomains, pStr ); } } if ( pDNSDomains != NULL ) { strcat ( pNewDNSDomains, "," ); strcat ( pNewDNSDomains, pDNSDomains ); CTEMemFree( pDNSDomains ); } if ( pNewDNSDomains[0] != '\0' ) { *ppDNSDomains = pNewDNSDomains; } else { *ppDNSDomains = NULL; } } } } } #pragma END_INIT #ifndef CHICAGO #pragma BEGIN_INIT #endif /******************************************************************* NAME: CreateDeviceObject SYNOPSIS: Initializes the device list of the global configuration structure ENTRY: pConfig - Pointer to global config structure IpAddr - IP Address for this adapter IpMask - IP Mask for this adapter IpNameServer - IP Address of the name server for this adapter IpBackupServer - IP Address of the backup name server for this adapter IpDnsServer - IP Address of the dns server for this adapter IpDnsBackupServer - IP Address of the backup dns server MacAddr - hardware address of the adapter for this IP addr IpIndex - Index of the IP Address in the IP Driver's address table (used for setting address by DHCP) EXIT: The device list in pConfig will be fully initialized RETURNS: STATUS_SUCCESS if successful, error otherwise NOTES: HISTORY: Johnl 14-Apr-1993 Created ********************************************************************/ NTSTATUS CreateDeviceObject( IN tNBTCONFIG *pConfig, IN ULONG IpAddr, IN ULONG IpMask, IN ULONG IpNameServer, IN ULONG IpBackupServer, IN ULONG IpDnsServer, IN ULONG IpDnsBackupServer, IN UCHAR MacAddr[], IN UCHAR IpIndex ) { NTSTATUS status; tDEVICECONTEXT * pDeviceContext, *pDevtmp; ULONG ulTmp ; NCB * pNCB ; DHCPNotify dn ; PLIST_ENTRY pEntry; ULONG Adapter; ULONG PreviousNodeType; CTEPagedCode(); pDeviceContext = CTEAllocInitMem(sizeof( tDEVICECONTEXT )) ; if ( !pDeviceContext ) return STATUS_INSUFFICIENT_RESOURCES ; // // zero out the data structure // CTEZeroMemory( pDeviceContext, sizeof(tDEVICECONTEXT) ); // put a verifier value into the structure so that we can check that // we are operating on the right data when the OS passes a device context // to NBT pDeviceContext->Verify = NBT_VERIFY_DEVCONTEXT; // // we aren't up yet: don't want ncb's coming in before we are ready! // pDeviceContext->fDeviceUp = FALSE; // setup the spin lock); CTEInitLock(&pDeviceContext->SpinLock); pDeviceContext->LockNumber = DEVICE_LOCK; pDeviceContext->lNameServerAddress = IpNameServer ; pDeviceContext->lBackupServer = IpBackupServer ; pDeviceContext->lDnsServerAddress = IpDnsServer ; pDeviceContext->lDnsBackupServer = IpDnsBackupServer ; // copy the mac addresss CTEMemCopy(&pDeviceContext->MacAddress.Address[0], MacAddr, 6); // // if the node type is set to Bnode by default then switch to Hnode if // there are any WINS servers configured. // PreviousNodeType = NodeType; if ((NodeType & DEFAULT_NODE_TYPE) && (IpNameServer || IpBackupServer)) { NodeType = MSNODE; if (PreviousNodeType & PROXY) NodeType |= PROXY; } // // start the refresh timer (if we had already started it, this function // just returns success) // status = StartRefreshTimer(); if ( !NT_SUCCESS( status ) ) { CTEFreeMem( pDeviceContext ) ; return( status ) ; } // initialize the pDeviceContext data structure. There is one of // these data structured tied to each "device" that NBT exports // to higher layers (i.e. one for each network adapter that it // binds to. // The initialization sets the forward link equal to the back link equal // to the list head InitializeListHead(&pDeviceContext->UpConnectionInUse); InitializeListHead(&pDeviceContext->LowerConnection); InitializeListHead(&pDeviceContext->LowerConnFreeHead); InitializeListHead(&pDeviceContext->RcvAnyFromAnyHead); InitializeListHead(&pDeviceContext->RcvDGAnyFromAnyHead); InitializeListHead(&pDeviceContext->PartialRcvHead) ; InitializeListHead(&pDeviceContext->DelayedEvents); // // Pick an adapter number that hasn't been used yet // Adapter = 1; for ( pEntry = pConfig->DeviceContexts.Flink; pEntry != &pConfig->DeviceContexts; pEntry = pEntry->Flink ) { pDevtmp = CONTAINING_RECORD( pEntry, tDEVICECONTEXT, Linkage ); if ( !(pDevtmp->AdapterNumber & Adapter) ) break; Adapter <<= 1; } pDeviceContext->AdapterNumber = Adapter ; pDeviceContext->IPIndex = IpIndex ; NbtConfig.AdapterCount++ ; if ( NbtConfig.AdapterCount > 1 ) { NbtConfig.MultiHomed = TRUE ; } // // Allocate our name table and session table watching for both a // minimum and a maximum size. // pDeviceContext->cMaxNames = (UCHAR) min( pConfig->lRegistryMaxNames, MAX_NCB_NUMS ) ; pDeviceContext->cMaxSessions = (UCHAR) min( pConfig->lRegistryMaxSessions, MAX_NCB_NUMS ) ; // // Add one to the table size for the zeroth element (used for permanent // name in the name table). The user accessible table goes from 1 to n // if ( !(pDeviceContext->pNameTable = (tCLIENTELE**) CTEAllocInitMem((USHORT)((pDeviceContext->cMaxNames+1) * sizeof(tADDRESSELE*)))) || !(pDeviceContext->pSessionTable = (tCONNECTELE**) CTEAllocInitMem((pDeviceContext->cMaxSessions+1) * sizeof(tCONNECTELE*)))) { return STATUS_INSUFFICIENT_RESOURCES ; } CTEZeroMemory( &pDeviceContext->pNameTable[0], (pDeviceContext->cMaxNames+1)*sizeof(tCLIENTELE*)) ; CTEZeroMemory( &pDeviceContext->pSessionTable[0], (pDeviceContext->cMaxSessions+1)*sizeof(tCONNECTELE*) ) ; pDeviceContext->iNcbNum = 1 ; pDeviceContext->iLSNum = 1 ; // add this new device context on to the List in the configuration // data structure InsertTailList(&pConfig->DeviceContexts,&pDeviceContext->Linkage); // // IpAddr can be 0 only in wfw case (when dhcp hasn't yet obtained one) // (in case of chicago, we will never come this far if ipaddr is 0) // if (!IpAddr) { pDeviceContext->IpAddress = 0; goto Skip_tdiaddr_init; } // // open the required address objects with the underlying transport provider // status = NbtCreateAddressObjects( IpAddr, IpMask, pDeviceContext); if (!NT_SUCCESS(status)) { KdPrint(("Failed to create the Address Object, status=%lC\n",status)); return(status); } // this call must converse with the transport underneath to create // connections and associate them with the session address object status = NbtInitConnQ( &pDeviceContext->LowerConnFreeHead, sizeof(tLOWERCONNECTION), NBT_NUM_INITIAL_CONNECTIONS, pDeviceContext); if (!NT_SUCCESS(status)) { CDbgPrint( DBGFLAG_ERROR, ("CreateDeviceObject: NbtInitConnQ Failed!")) ; return(status); } // // Add the permanent name for this adapter // status = NbtAddPermanentName( pDeviceContext ) ; if ( !NT_SUCCESS( status )) { return status ; } Skip_tdiaddr_init: // // ok, we are ready to function! (we are setting this to TRUE even if // there is no ipaddr yet (in case of wfw only) so that rdr,srv etc. can // add names without error // pDeviceContext->fDeviceUp = TRUE; #ifndef CHICAGO // // Set up a DHCP notification for this device in case the IP address // changes // dn.dn_pfnNotifyRoutine = AddrChngNotification ; dn.dn_pContext = pDeviceContext ; status = DhcpSetInfo( DHCP_SET_NOTIFY_HANDLER, pDeviceContext->IPIndex, &dn, sizeof( dn )) ; if ( status ) { ASSERT(0); CDbgPrint( DBGFLAG_ERROR, ("CreateDeviceObject: Warning - Setting Dhcp notification handler failed")) ; } #endif //!CHICAGO return(STATUS_SUCCESS); } /******************************************************************* NAME: GetDhcpOption SYNOPSIS: Checks to see if the passed .ini parameter is a potential DHCP option. If it is, it calls DHCP to get the option. This routine is called when retrieving parameters from the .ini file if the parameter is not found. ENTRY: ValueName - String of .ini parameter name DefaultValue - Value to return if not a DHCP option or DHCP didn't have the option RETURNS: DHCP option value or DefaultValue if an error occurred. If the requested parameter is a string option (such as scopeid), then a pointer to an allocated string is returned. NOTES: Name Server address is handled in GetNameServerAddress HISTORY: Johnl 17-Dec-1993 Created ********************************************************************/ #define OPTION_NETBIOS_SCOPE_OPTION 47 #define OPTION_NETBIOS_NODE_TYPE 46 #define OPTION_BROADCAST_ADDRESS 28 struct { PUCHAR pchParamName ; ULONG DhcpOptionID ; } OptionMapping[] = { { WS_NODE_TYPE, OPTION_NETBIOS_NODE_TYPE }, { NBT_SCOPEID, OPTION_NETBIOS_SCOPE_OPTION }, { WS_ALLONES_BCAST, OPTION_BROADCAST_ADDRESS } } ; #define NUM_OPTIONS (sizeof(OptionMapping)/sizeof(OptionMapping[0])) ULONG GetDhcpOption( PUCHAR ValueName, ULONG DefaultValue ) { int i ; ULONG Val ; TDI_STATUS tdistatus ; ULONG Size ; INT OptionId ; PUCHAR pStrVal ; CTEPagedCode(); // // Is this parameter a DHCP option? // for ( i = 0 ; i < NUM_OPTIONS ; i++ ) { if ( !strcmp( OptionMapping[i].pchParamName, ValueName )) goto FoundOption ; } return DefaultValue ; FoundOption: switch ( OptionId = OptionMapping[i].DhcpOptionID ) { case OPTION_NETBIOS_SCOPE_OPTION: // String options go here // // Get the size of the string resource, then get the option // Size = MAX_SCOPE_LENGTH+1 ; pStrVal = CTEAllocInitMem( Size ); if (pStrVal == NULL) { DbgPrint("GetDhcpOption: failed to allocate memory") ; return 0 ; } tdistatus = DhcpQueryOption( CurrentIP, OptionId, pStrVal, &Size ) ; if ( tdistatus == TDI_SUCCESS ) { DbgPrint("GetDhcpOption: Successfully retrieved option ID ") ; DbgPrintNum( OptionId ) ; DbgPrint("\r\n") ; return (ULONG) pStrVal ; } else { DbgPrint("GetDhcpOption: returned error = 0x ") ; DbgPrintNum( tdistatus ) ; DbgPrint("\r\n") ; CTEMemFree( pStrVal ) ; return 0 ; } default: // ULONG options go here Size = sizeof( Val ) ; tdistatus = DhcpQueryOption( CurrentIP, OptionId, &Val, &Size ) ; break ; } switch ( tdistatus ) { case TDI_SUCCESS: case TDI_BUFFER_OVERFLOW: // May be more then one, only take the 1st DbgPrint("GetDhcpOption: Successfully retrieved option ID ") ; DbgPrintNum( OptionId ) ; DbgPrint("\r\n") ; return Val ; case TDI_INVALID_PARAMETER: // Option not found DbgPrint("GetDhcpOption: Failed to retrieve option ID ") ; DbgPrintNum( OptionId ) ; DbgPrint("\r\n") ; return DefaultValue ; default: ASSERT( FALSE ) ; break ; } return DefaultValue ; } #ifndef CHICAGO #pragma END_INIT #endif