299 lines
8.5 KiB
C
299 lines
8.5 KiB
C
/*
|
|
File autonet.c
|
|
|
|
Contains routines that allow the ipx router to automatically select an
|
|
internal network number.
|
|
|
|
Paul Mayfield, 11/21/97.
|
|
*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <winsvc.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <raserror.h>
|
|
#include <dim.h>
|
|
#include <rtm.h>
|
|
#include <ipxrtprt.h>
|
|
#include <rmrtm.h>
|
|
#include <mprlog.h>
|
|
#include <rtinfo.h>
|
|
#include <ipxrtdef.h>
|
|
#include <mprerror.h>
|
|
#include <adapter.h>
|
|
#include <fwif.h>
|
|
#include <rtutils.h>
|
|
#include "ipxanet.h"
|
|
#include "utils.h"
|
|
|
|
// Sends debug output to a debugger terminal
|
|
DWORD OutputDebugger (LPSTR pszError, ...) {
|
|
#if DBG
|
|
va_list arglist;
|
|
char szBuffer[1024], szTemp[1024];
|
|
|
|
va_start(arglist, pszError);
|
|
vsprintf(szTemp, pszError, arglist);
|
|
va_end(arglist);
|
|
|
|
sprintf(szBuffer, "IPXAUTO: %s", szTemp);
|
|
|
|
|
|
OutputDebugStringA(szBuffer);
|
|
#endif
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
DWORD dwTraceId = 0;
|
|
ULONG ulRandSeed = 0;
|
|
|
|
DWORD InitTrace() {
|
|
if (dwTraceId)
|
|
return NO_ERROR;
|
|
|
|
dwTraceId = TraceRegisterExA ("ipxautonet", 0);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
DWORD SetIpxInternalNetNumber(DWORD dwNetNum);
|
|
|
|
// New helper functions from adptif
|
|
DWORD FwIsStarted (OUT PBOOL pbIsStarted);
|
|
DWORD IpxDoesRouteExist (IN PUCHAR puNetwork, OUT PBOOL pbRouteFound);
|
|
DWORD IpxGetAdapterConfig(OUT LPDWORD lpdwInternalNetNum,
|
|
OUT LPDWORD lpdwAdapterCount);
|
|
|
|
// Outputs an error to the tracing facility
|
|
VOID AutoTraceError(DWORD dwErr) {
|
|
char buf[1024];
|
|
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,NULL,dwErr,(DWORD)0,buf,1024,NULL);
|
|
TracePrintfA (dwTraceId, buf);
|
|
}
|
|
|
|
// Seeds the random number generator
|
|
DWORD SeedRandomGenerator() {
|
|
DWORD dwTick;
|
|
|
|
// Generate a unique number to seed the random number generator with
|
|
dwTick = GetTickCount();
|
|
ulRandSeed = dwTick ^ (dwTick << ((GetCurrentProcessId() % 16)));
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
// Returns a random number between 11 and 2^32
|
|
// Currently, the rand() function generates a random number between 0 and 0x7fff.
|
|
// What we do to generate the random number is generate 8 random numbers each 4 bits
|
|
// wide and then paste them together.
|
|
DWORD RandomNetNumber() {
|
|
DWORD dw[4], dwRand = 0, i;
|
|
|
|
// Generate the numbers
|
|
dw[0] = RtlRandom(&ulRandSeed) & 0xff;
|
|
dw[1] = RtlRandom(&ulRandSeed) & 0xff;
|
|
dw[2] = RtlRandom(&ulRandSeed) & 0xff;
|
|
dw[3] = RtlRandom(&ulRandSeed) & 0xff;
|
|
|
|
// Paste the numbers together
|
|
for (i = 0; i < 4; i++)
|
|
dwRand |= dw[i] << (i*8);
|
|
|
|
// If by some small chance, an illegal value was choosen,
|
|
// correct it.
|
|
if (dwRand < 11)
|
|
dwRand += 11;
|
|
|
|
return dwRand;
|
|
}
|
|
|
|
//
|
|
// Function: QueryStackForRouteExistance
|
|
//
|
|
// Asks the stack to check it's route table for the existance of the given network.
|
|
// If no route exists in its table, the stack will send out a rip broadcast to be
|
|
// doubly sure that the network does not exist.
|
|
//
|
|
// This function blocks until it completes.
|
|
//
|
|
// Params:
|
|
// dwNetwork host-ordered network number to query
|
|
// pbRouteExists set to TRUE if a route to the given network exists. false,
|
|
// if the rip broadcast that the stack sends times out.
|
|
//
|
|
DWORD QueryStackForRouteExistance(IN DWORD dwNetwork, OUT PBOOL pbRouteExists) {
|
|
UCHAR puNetwork[4];
|
|
DWORD dwErr;
|
|
|
|
// Prepare the network number
|
|
PUTULONG2LONG(puNetwork, dwNetwork);
|
|
|
|
// Initialize
|
|
*pbRouteExists = FALSE;
|
|
|
|
if ((dwErr = IpxDoesRouteExist (puNetwork, pbRouteExists)) != NO_ERROR)
|
|
return dwErr;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Function: QueryRtmForRouteExistance
|
|
//
|
|
// Discovers whether a route to a given network exists in rtm.
|
|
//
|
|
// This function blocks until it completes.
|
|
//
|
|
// Params:
|
|
// dwNetwork host-ordered network number to query
|
|
// pbRouteExists set to TRUE if a route to the route exists -- false, otherwise
|
|
//
|
|
DWORD QueryRtmForRouteExistance(IN DWORD dwNetwork, OUT PBOOL pbRouteExists) {
|
|
*pbRouteExists = RtmIsRoute (RTM_PROTOCOL_FAMILY_IPX, &dwNetwork, NULL);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Function: PnpAutoSelectInternalNetNumber
|
|
//
|
|
// Selects a new internal network number for this router and plumbs that network
|
|
// number into the stack and the router.
|
|
//
|
|
// Depending on whether the forwarder and ipxrip are enabled, it will validate the
|
|
// newly selected net number against the stack or rtm.
|
|
//
|
|
// Params:
|
|
// dwNetwork host-ordered network number to query
|
|
// pbRouteExists set to TRUE if a route to the route exists -- false, otherwise
|
|
//
|
|
DWORD PnpAutoSelectInternalNetNumber(DWORD dwGivenTraceId) {
|
|
DWORD i, j, dwErr, dwNewNet;
|
|
BOOL bNetworkFound = FALSE, bFwStarted;
|
|
|
|
TracePrintfA (dwTraceId, "PnpAutoSelectInternalNetNumber: Entered");
|
|
|
|
// Find out if the forwarder and ipx rip have been started
|
|
if ((dwErr = FwIsStarted(&bFwStarted)) != NO_ERROR)
|
|
return dwErr;
|
|
TracePrintfA (dwTraceId, "PnpAutoSelectInternalNetNumber: Forwarder %s started",
|
|
(bFwStarted) ? "has already been" : "has not been");
|
|
|
|
__try {
|
|
// Initialize the random number generator
|
|
if ((dwErr = SeedRandomGenerator()) != NO_ERROR)
|
|
return dwErr;
|
|
|
|
// Discover a unique network number
|
|
do {
|
|
// Randomly select a new net number
|
|
dwNewNet = RandomNetNumber();
|
|
|
|
// Find out if the given network exists
|
|
if (bFwStarted) {
|
|
if ((dwErr = QueryRtmForRouteExistance (dwNewNet, &bNetworkFound)) != NO_ERROR)
|
|
return dwErr;
|
|
}
|
|
else {
|
|
if ((dwErr = QueryStackForRouteExistance (dwNewNet, &bNetworkFound)) != NO_ERROR)
|
|
return dwErr;
|
|
}
|
|
|
|
// Send some debug output
|
|
TracePrintfA (dwTraceId, "PnpAutoSelectInternalNetNumber: 0x%08x %s", dwNewNet, (bNetworkFound) ? "already exists." : "has been selected.");
|
|
} while (bNetworkFound);
|
|
|
|
// Set the internal network number to the discovered unique net number. This call
|
|
// uses inetcfg to programmatically set the net network number.
|
|
if ((dwErr = SetIpxInternalNetNumber(dwNewNet)) != NO_ERROR)
|
|
return dwErr;
|
|
}
|
|
__finally {
|
|
if (dwErr != NO_ERROR)
|
|
AutoTraceError(dwErr);
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
BOOL NetNumIsValid (DWORD dwNum) {
|
|
return ((dwNum != 0) && (dwNum != 0xffffffff));
|
|
}
|
|
|
|
//
|
|
// Function: AutoValidateInternalNetNum
|
|
//
|
|
// Queries the stack to learn the internal network number and then
|
|
// returns whether this number is valid for running an ipx router.
|
|
//
|
|
// Params:
|
|
// pbIsValid set to TRUE if internal net num is valid -- false, otherwise
|
|
//
|
|
DWORD AutoValidateInternalNetNum(OUT PBOOL pbIsValid, IN DWORD dwGlobalTraceId) {
|
|
DWORD dwErr, dwIntNetNum, dwAdapterCount;
|
|
|
|
InitTrace();
|
|
TracePrintfA (dwTraceId, "AutoValidateInternalNetNum: Entered");
|
|
|
|
// Get the current internal network number
|
|
if ((dwErr = IpxGetAdapterConfig(&dwIntNetNum, &dwAdapterCount)) != NO_ERROR) {
|
|
TracePrintfA (dwTraceId, "AutoValidateInternalNetNum: couldn't get adapter config %x", dwErr);
|
|
AutoTraceError(dwErr);
|
|
return dwErr;
|
|
}
|
|
|
|
// Check the validity of the internal net number. If it's a valid
|
|
// number, don't mess with it.
|
|
*pbIsValid = !!(NetNumIsValid(dwIntNetNum));
|
|
|
|
TracePrintfA (dwTraceId, "AutoValidateInternalNetNum: Net Number 0x%x is %s", dwIntNetNum,
|
|
(*pbIsValid) ? "valid" : "not valid");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Function: AutoWaitForValidNetNum
|
|
//
|
|
// Puts the calling thread to sleep until a valid internal network number
|
|
// has been plumbed into the system.
|
|
//
|
|
// Params:
|
|
// dwTimeout timeout in seconds
|
|
// pbIsValid if provided, returns whether number is valid
|
|
//
|
|
DWORD AutoWaitForValidIntNetNum (IN DWORD dwTimeout,
|
|
IN OUT OPTIONAL PBOOL pbIsValid) {
|
|
DWORD dwErr, dwNum, dwCount, dwGran = 250;
|
|
|
|
// Initialize optional params
|
|
if (pbIsValid)
|
|
*pbIsValid = TRUE;
|
|
|
|
// Convert the timeout to milliseconds
|
|
dwTimeout *= 1000;
|
|
|
|
while (dwTimeout > dwGran) {
|
|
// Get the current internal network number
|
|
if ((dwErr = IpxGetAdapterConfig(&dwNum, &dwCount)) != NO_ERROR)
|
|
return dwErr;
|
|
|
|
if (NetNumIsValid (dwNum)) {
|
|
if (pbIsValid)
|
|
*pbIsValid = TRUE;
|
|
break;
|
|
}
|
|
|
|
Sleep (dwGran);
|
|
dwTimeout -= dwGran;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|