|
|
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
wannet.c
Abstract:
Wan net allocation module
Author:
Stefan Solomon 11/03/1995
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
extern DWORD (WINAPI * RmCreateGlobalRoute)(PUCHAR Network); extern HANDLE g_hRouterLog;
ULONG LastUsedRandSeed;
//
// Variable keeping the initialization state of the IPXCP Configuration Database
//
BOOL WanConfigDbaseInitialized = FALSE;
// WAN net pool entry structure
typedef struct _NET_ENTRY {
BOOL InUse; UCHAR Network[4];
} NET_ENTRY, *PNET_ENTRY;
// Structure represents a pool of
// wan net numbers. This pool dynamically
// grows and shrinks as clients dial
// in and hang up
typedef struct _WAN_NET_POOL { DWORD dwMaxSize; DWORD dwCurSize; DWORD dwInUseCount; NET_ENTRY * pEntries; } WAN_NET_POOL, *PWAN_NET_POOL;
#define WANNET_DEFAULT_SIZE 10
#define WANNET_DEFAULT_GROW 100
#define WANNET_MAXSIZE 64000
//
// WAN net numbers pool
//
WAN_NET_POOL WanNetPool = {WANNET_MAXSIZE, 0, 0, NULL};
//
// Global WAN net
//
//UCHAR GlobalConfig.RParams.GlobalWanNet[4] = {0,0,0,0};
ULONG GlobalWanNetIndex; // when global wan net comes from pool - the index
DWORD InitWanNetConfigDbase(VOID);
DWORD WanNetAlloc(PUCHAR Network, PULONG AllocatedNetworkIndexp);
DWORD CreateWanNetPool(VOID);
DWORD GrowWanNetPool (WAN_NET_POOL * pPool);
DWORD CreateGlobalWanNet(VOID);
VOID DestroyWanNetPool(VOID);
VOID DestroyGlobalWanNet(VOID);
DWORD AllocWanNetFromPool(PUCHAR Network, PULONG AllocatedNetworkIndexp);
VOID FreeWanNetToPool(ULONG AllocatedNetworkIndex);
DWORD GetRandomNetNumber(PUCHAR Network);
/*++
Function: GetWanNetNumber
Descr: This function is called by IPXCP or IPXWAN to get a network number from the pool.
Parameters:
Network AllocatedNetworkIndex - if the value returned by this param is not INVALID_NETWORK_INDEX then the caller must call ReleaseWanNetNumber to free the net to the pool. InterfaceType
Returns NO_ERROR - a network has been successfully allocated
--*/
DWORD GetWanNetNumber(IN OUT PUCHAR Network, IN OUT PULONG AllocatedNetworkIndexp, IN ULONG InterfaceType) { DWORD rc;
memcpy(Network, nullnet, 4); *AllocatedNetworkIndexp = INVALID_NETWORK_INDEX;
// if this a router <-> router connection and we are configured for
// Unnumbered RIP -> return 0.
if((InterfaceType == IF_TYPE_WAN_ROUTER) || (InterfaceType == IF_TYPE_PERSONAL_WAN_ROUTER)) {
if(GlobalConfig.EnableUnnumberedWanLinks) {
return NO_ERROR; } }
ACQUIRE_DATABASE_LOCK;
if(!WanConfigDbaseInitialized) {
if((rc = InitWanNetConfigDbase()) != NO_ERROR) {
RELEASE_DATABASE_LOCK; return rc; } }
// check the interface type
if((InterfaceType == IF_TYPE_WAN_WORKSTATION) && GlobalConfig.RParams.EnableGlobalWanNet) {
memcpy(Network, GlobalConfig.RParams.GlobalWanNet, 4); *AllocatedNetworkIndexp = INVALID_NETWORK_INDEX;
rc = NO_ERROR; } else { rc = WanNetAlloc(Network, AllocatedNetworkIndexp); }
RELEASE_DATABASE_LOCK;
return rc; }
/*++
Function: ReleaseWanNetNumber
Descr: This function will be called by ipxcp to release the net number used for configuring the WAN link. The call is issued when the WAN link gets disconnected.
--*/
VOID ReleaseWanNetNumber(ULONG AllocatedNetworkIndex) { ACQUIRE_DATABASE_LOCK;
SS_ASSERT(WanConfigDbaseInitialized); SS_ASSERT(AllocatedNetworkIndex != INVALID_NETWORK_INDEX);
FreeWanNetToPool(AllocatedNetworkIndex);
RELEASE_DATABASE_LOCK;
return; }
/*++
Function: InitWanNetConfigDatabase
Descr: Configures the database of network numbers used for incoming WAN links.
Remark: This function is called from the GetWanNetNumber (see below) when IPXCP has an incoming call and the router has been started and the database hasn't been configured yet.
Remark2: >> called with database lock held <<
--*/
DWORD InitWanNetConfigDbase(VOID) { DWORD rc;
// create wan net pool
if(!GlobalConfig.EnableAutoWanNetAllocation) {
if((rc = CreateWanNetPool()) != NO_ERROR) {
return rc; } }
// create global wan net
if(GlobalConfig.RParams.EnableGlobalWanNet) {
if((rc = CreateGlobalWanNet()) != NO_ERROR) {
return rc; } }
WanConfigDbaseInitialized = TRUE;
return NO_ERROR; }
/*++
Function: DestroyWanNetConfigDatabase
Descr: Frees resources allocated for the wan net config database
Remark: called when the router stops
--*/
VOID DestroyWanNetConfigDatabase(VOID) { if(!WanConfigDbaseInitialized) {
return; }
// destroy wan net pool
if(!GlobalConfig.EnableAutoWanNetAllocation) {
DestroyWanNetPool(); }
WanConfigDbaseInitialized = FALSE; }
/*++
Function: WanNetAlloc
Descr:
Remark: >> called with database lock held <<
--*/
DWORD WanNetAlloc(IN OUT PUCHAR Network, IN OUT PULONG AllocatedNetworkIndexp) { DWORD rc;
if(GlobalConfig.EnableAutoWanNetAllocation) {
// try a number of times to generate a unique net number
rc = GetRandomNetNumber(Network); *AllocatedNetworkIndexp = INVALID_NETWORK_INDEX; } else { rc = AllocWanNetFromPool(Network, AllocatedNetworkIndexp); }
return rc; }
/*++
Function: CreateWanNetPool
Descr:
Remark: >> called with database lock held <<
--*/
DWORD CreateWanNetPool(VOID) { ULONG i; PNET_ENTRY nep; PWSTR nesp; ULONG wannet; UCHAR asc[9]; PUCHAR ascp;
// Create the pool of WAN network numbers to be used in configuring
// incoming WAN links.
if ((GlobalConfig.WanNetPoolStr.Buffer!=NULL) && (GlobalConfig.WanNetPoolStr.Length >0)) { DWORD strsz = 0; nesp = GlobalConfig.WanNetPoolStr.Buffer; strsz = 0; while (*nesp!=0) { strsz += 1; wannet = wcstoul (nesp, NULL, 16); if ((wannet==0) || (wannet==0xFFFFFFFF)) break; nesp += wcslen (nesp) + 1; } if ((*nesp!=0) || (strsz!=(GlobalConfig.WanNetPoolSize)) || ((GlobalConfig.WanNetPoolSize) > WANNET_MAXSIZE)) {
TraceIpx(WANNET_TRACE, "Invalid wan net pool config WanNetPoolSize =%d\n," " entries: ", (GlobalConfig.WanNetPoolSize)); nesp = GlobalConfig.WanNetPoolStr.Buffer; while (*nesp!=0) { TraceIpx(WANNET_TRACE|TRACE_NO_STDINFO, "%ls ", nesp); nesp += wcslen (nesp) + 1; }
return ERROR_CAN_NOT_COMPLETE; } } else { if (((GlobalConfig.FirstWanNet) == 0) || ((GlobalConfig.FirstWanNet) == 0xFFFFFFFF) || ((GlobalConfig.WanNetPoolSize) > WANNET_MAXSIZE)) {
TraceIpx(WANNET_TRACE, "Invalid wan net pool config, FirstWanNet=%x, WanNetPoolSize =%d\n", GlobalConfig.FirstWanNet, GlobalConfig.WanNetPoolSize);
return ERROR_CAN_NOT_COMPLETE; } }
// If the WanNetPoolSize is 0, then assume any size
if ((GlobalConfig.WanNetPoolSize == 0) || (GlobalConfig.WanNetPoolSize > WANNET_MAXSIZE)) { GlobalConfig.WanNetPoolSize = WANNET_MAXSIZE; }
// Initialize the wan net pool
WanNetPool.dwMaxSize = GlobalConfig.WanNetPoolSize; WanNetPool.dwCurSize = 0; WanNetPool.dwInUseCount = 0; WanNetPool.pEntries = NULL;
return GrowWanNetPool (&WanNetPool); }
//
// This function resizes the wan net pool to accomodate additional
// callers.
//
DWORD GrowWanNetPool (WAN_NET_POOL * pPool) { PWCHAR pszNetList = GlobalConfig.WanNetPoolStr.Buffer; PNET_ENTRY pNewEntries, pCur; DWORD i, dwNewSize, dwNewNet; UCHAR uNetwork[9], *puNetwork; uNetwork[8] = 0; puNetwork = uNetwork;
// Enforce that we aren't going to grow beyond our bounds
if (pPool->dwCurSize >= pPool->dwMaxSize) return ERROR_CAN_NOT_COMPLETE;
// Initialize the new size
if (! pPool->dwCurSize) dwNewSize = WANNET_DEFAULT_SIZE; else dwNewSize = pPool->dwCurSize + WANNET_DEFAULT_GROW;
// Truncate the new size to the maximum size
if (dwNewSize > pPool->dwMaxSize) dwNewSize = pPool->dwMaxSize;
// Initailize a new array of entries
pNewEntries = GlobalAlloc(GPTR, sizeof(NET_ENTRY) * dwNewSize); if (pNewEntries == NULL) { SS_ASSERT(FALSE); return ERROR_NOT_ENOUGH_MEMORY; }
// Copy over the old entries
if (pPool->dwCurSize) CopyMemory (pNewEntries, pPool->pEntries, pPool->dwCurSize * sizeof(NET_ENTRY));
// Go through the new entries verifying them on the network
for(i = pPool->dwCurSize, pCur = &(pNewEntries[pPool->dwCurSize]); i < dwNewSize; i++, pCur++) { // If the user hadn't given a specific list of addresses,
// then add test the next numeric network number
if ((pszNetList == NULL) || (*pszNetList == L'\0')) dwNewNet = GlobalConfig.FirstWanNet + i;
// Otherwise, get the next number from the list
else { dwNewNet = wcstoul (pszNetList, NULL, 16); pszNetList += wcslen (pszNetList) + 1; }
// check if this network number is unique. Generate an warning log
// if it isn't
PUTULONG2LONG(pCur->Network, dwNewNet); if(IsRoute(pCur->Network) || (dwNewNet == 0xFFFFFFFF) || (dwNewNet == 0)) { NetToAscii(puNetwork, pCur->Network); RouterLogWarningW( g_hRouterLog, ROUTERLOG_IPXCP_WAN_NET_POOL_NETWORK_NUMBER_CONFLICT, 1, (PWCHAR*)&puNetwork, NO_ERROR);
TraceIpx(WANNET_TRACE, "InitWanNetConfigDbase: Configured WAN pool network %.2x%.2x%.2x%.2x is in use!\n", pCur->Network[0], pCur->Network[1], pCur->Network[2], pCur->Network[3]); pCur->InUse = TRUE; pPool->dwInUseCount++; } else pCur->InUse = FALSE; }
// Free the old pool and assign the new one
GlobalFree (pPool->pEntries); pPool->pEntries = pNewEntries; pPool->dwCurSize = dwNewSize;
return NO_ERROR; }
/*++
Function: CreateGlobalWanNet
Descr:
Remark: >> called with database lock held <<
--*/
DWORD CreateGlobalWanNet(VOID) { DWORD rc; ULONG i;
if(GlobalConfig.EnableAutoWanNetAllocation) {
// create the global wan net "automatically".
// We do that by trying to use the system timer value
rc = GetRandomNetNumber(GlobalConfig.RParams.GlobalWanNet); } else { rc = AllocWanNetFromPool(GlobalConfig.RParams.GlobalWanNet, &GlobalWanNetIndex); }
if(rc == NO_ERROR) {
// add the global wan net to the routing table if router is started
// if the router is not started, it will get the global wan net when
// it will issue the IpxcpBind call
if(RouterStarted) {
rc =(*RmCreateGlobalRoute)(GlobalConfig.RParams.GlobalWanNet); } }
return rc; }
VOID DestroyWanNetPool(VOID) { WAN_NET_POOL DefaultPool = {WANNET_MAXSIZE, 0, 0, NULL}; if (WanNetPool.dwCurSize) { if (WanNetPool.pEntries) GlobalFree (WanNetPool.pEntries); WanNetPool = DefaultPool; } }
DWORD AllocWanNetFromPool(PUCHAR Network, PULONG NetworkIndexp) { ULONG i; PNET_ENTRY nep; DWORD rc;
// First, see if we have to grow the pool
if (WanNetPool.dwInUseCount >= WanNetPool.dwCurSize) GrowWanNetPool (&WanNetPool);
// get a net from the pool
for(i=0, nep=WanNetPool.pEntries; i<WanNetPool.dwCurSize; i++, nep++) {
if(!nep->InUse) {
nep->InUse = TRUE; WanNetPool.dwInUseCount++; memcpy(Network, nep->Network, 4); *NetworkIndexp = i;
rc = NO_ERROR; goto Exit; } }
// can't find a free net pool entry
*NetworkIndexp = INVALID_NETWORK_INDEX; rc = ERROR_CAN_NOT_COMPLETE;
Exit:
return rc; }
VOID FreeWanNetToPool(ULONG AllocatedNetworkIndex) { PNET_ENTRY nep;
if(AllocatedNetworkIndex >= WanNetPool.dwCurSize) {
return; }
nep = &(WanNetPool.pEntries[AllocatedNetworkIndex]);
SS_ASSERT(nep->InUse);
nep->InUse = FALSE; WanNetPool.dwInUseCount--;
return; }
DWORD randn(DWORD seed) { seed = seed * 1103515245 + 12345; return seed; }
DWORD GetRandomNetNumber(PUCHAR Network) { DWORD rc = ERROR_CAN_NOT_COMPLETE; ULONG i, seed, high, low, netnumber;
for(i=0; i<100000; i++) {
seed = GetTickCount();
// check if this isn't the same seed as last used
if(seed == LastUsedRandSeed) {
seed++; }
LastUsedRandSeed = seed;
// generate a sequence of two random numbers using the time tick count
// as seed
low = randn(seed) >> 16; high = randn(randn(seed)) & 0xffff0000;
netnumber = high + low;
PUTULONG2LONG(Network, netnumber);
if(!IsRoute(Network)) {
rc = NO_ERROR; break; } }
return rc; }
//
// Reconfigures the wannet database
//
DWORD WanNetReconfigure() {
ACQUIRE_DATABASE_LOCK; // Destroy the current pool
DestroyWanNetPool();
// Mark everything as unintialized
WanConfigDbaseInitialized = FALSE;
RELEASE_DATABASE_LOCK; return NO_ERROR; }
|