windows-nt/Source/XPSP1/NT/net/rras/ipx/adptif/nictable.c
2020-09-26 16:20:57 +08:00

361 lines
10 KiB
C

/*
File NicTable.c
Implements a nic-renaming scheme that allows adaptif to
advertise whatever nic id it chooses to its clients while
maintaining the list of actual nic id's internally.
This functionality was needed in order to Pnp enable the
ipx router. When an adapter is deleted, the stack renumbers
the nicid's so that it maintains a contiguous block of ids
internally. Rather that cause the clients to adptif to
match the stack's renumbering schemes, we handle this
transparently in adptif.
Author: Paul Mayfield, 12/11/97
*/
#include "ipxdefs.h"
#define NicMapDefaultSize 500
#define NicMapDefaultFactor 5
#define MAXIMUM_NIC_MAP_SIZE 25000
// Nic map used to associate nic's with virtual ids
typedef struct _NICMAPNODE {
USHORT usVirtualId;
IPX_NIC_INFO * pNicInfo;
} NICMAPNODE;
// Maintains the mapping from nic id to virtual id.
typedef struct _NICMAP {
DWORD dwMapSize;
DWORD dwNicCount;
DWORD dwMaxNicId;
NICMAPNODE ** ppNics;
USHORT * usVirtMap;
} NICMAP;
// Definition of the global nic id map
NICMAP GlobalNicIdMap;
DWORD nmAddNic (NICMAP * pNicMap, IPX_NIC_INFO * pNicInfo);
// Resizes the nic map to accomodate more nics. This function will
// probably only ever be called to allocate the array the first time.
DWORD nmEnlarge(NICMAP * pNicMap) {
USHORT * usVirtMap;
DWORD i, dwNewSize;
NICMAPNODE ** ppNics;
// Are we enlarging for the first time?
if (!pNicMap->dwMapSize)
dwNewSize = NicMapDefaultSize;
else
dwNewSize = pNicMap->dwMapSize * NicMapDefaultFactor;
// Make sure we aren't too big...
if (dwNewSize > MAXIMUM_NIC_MAP_SIZE) {
// do something critical here!
return ERROR_INSUFFICIENT_BUFFER;
}
// Resize the arrays
usVirtMap = (USHORT*) RtlAllocateHeap(RtlProcessHeap(),
0,
dwNewSize * sizeof(USHORT));
ppNics = (NICMAPNODE **) RtlAllocateHeap(RtlProcessHeap(),
0,
dwNewSize * sizeof(NICMAPNODE*));
if (!usVirtMap || !ppNics)
return ERROR_NOT_ENOUGH_MEMORY;
// Initialize
FillMemory(usVirtMap, dwNewSize * sizeof(USHORT), 0xff);
ZeroMemory(ppNics, dwNewSize * sizeof(IPX_NIC_INFO*));
usVirtMap[0] = 0;
// Initialize the arrays.
for (i = 0; i < pNicMap->dwMapSize; i++) {
usVirtMap[i] = pNicMap->usVirtMap[i];
ppNics[i] = pNicMap->ppNics[i];
}
// Free old data if needed
if (pNicMap->dwMapSize) {
RtlFreeHeap(RtlProcessHeap(), 0, pNicMap->usVirtMap);
RtlFreeHeap(RtlProcessHeap(), 0, pNicMap->ppNics);
}
// Assign the new arrays
pNicMap->usVirtMap = usVirtMap;
pNicMap->ppNics = ppNics;
pNicMap->dwMapSize = dwNewSize;
return NO_ERROR;
}
// Returns the next available nic id
USHORT nmGetNextVirtualNicId(NICMAP * pNicMap, USHORT usPhysId) {
DWORD i;
// If this can be a one->one mapping, make it so
if (pNicMap->usVirtMap[usPhysId] == NIC_MAP_INVALID_NICID)
return usPhysId;
// Otherwise, walk the array until you find free spot
for (i = 2; i < pNicMap->dwMapSize; i++) {
if (pNicMap->usVirtMap[i] == NIC_MAP_INVALID_NICID)
return (USHORT)i;
}
return NIC_MAP_INVALID_NICID;
}
// Cleans up the nic
DWORD nmCleanup (NICMAP * pNicMap) {
DWORD i;
// Cleanup the virtual map
if (pNicMap->usVirtMap)
RtlFreeHeap(RtlProcessHeap(), 0, pNicMap->usVirtMap);
// Cleanup any of the nics stored in the map
if (pNicMap->ppNics) {
for (i = 0; i < pNicMap->dwMapSize; i++) {
if (pNicMap->ppNics[i]) {
if (pNicMap->ppNics[i]->pNicInfo)
RtlFreeHeap(RtlProcessHeap(), 0, pNicMap->ppNics[i]->pNicInfo);
RtlFreeHeap(RtlProcessHeap(), 0, pNicMap->ppNics[i]);
}
}
RtlFreeHeap(RtlProcessHeap(), 0, pNicMap->ppNics);
}
return NO_ERROR;
}
// Initializes the nic
DWORD nmInitialize (NICMAP * pNicMap) {
DWORD dwErr;
__try {
// Enlarge the map to its default size
ZeroMemory(pNicMap, sizeof (NICMAP));
if ((dwErr = nmEnlarge(pNicMap)) != NO_ERROR)
return dwErr;
}
__finally {
if (dwErr != NO_ERROR) {
nmCleanup(pNicMap);
pNicMap->dwMapSize = 0;
}
}
return NO_ERROR;
}
// Maps virtual nic ids to physical ones
USHORT nmGetPhysicalId (NICMAP * pNicMap, USHORT usVirtAdp) {
return pNicMap->usVirtMap[usVirtAdp];
}
// Maps physical nic ids to virtual ones
USHORT nmGetVirtualId (NICMAP * pNicMap, USHORT usPhysAdp) {
if (usPhysAdp == NIC_MAP_INVALID_NICID)
{
return NIC_MAP_INVALID_NICID;
}
if (pNicMap->ppNics[usPhysAdp])
return pNicMap->ppNics[usPhysAdp]->usVirtualId;
return (usPhysAdp == 0) ? 0 : NIC_MAP_INVALID_NICID;
}
// Gets the nic info associated with a physical adapter
IPX_NIC_INFO * nmGetNicInfo (NICMAP * pNicMap, USHORT usPhysAdp) {
if (pNicMap->ppNics[usPhysAdp])
return pNicMap->ppNics[usPhysAdp]->pNicInfo;
return NULL;
}
// Returns the number of nics in the map
DWORD nmGetNicCount (NICMAP * pNicMap) {
return pNicMap->dwNicCount;
}
// Returns the current maximum nic id
DWORD nmGetMaxNicId (NICMAP * pNicMap) {
return pNicMap->dwMaxNicId;
}
// Reconfigures a nic
DWORD nmReconfigure(NICMAP * pNicMap, IPX_NIC_INFO * pSrc) {
IPX_NIC_INFO * pDst = nmGetNicInfo (pNicMap, pSrc->Details.NicId);
if (pDst) {
CopyMemory(pDst, pSrc, sizeof (IPX_NIC_INFO));
pDst->Details.NicId = nmGetVirtualId (pNicMap, pSrc->Details.NicId);
}
else
return nmAddNic(pNicMap, pSrc);
return NO_ERROR;
}
// Adds a nic to the table
DWORD nmAddNic (NICMAP * pNicMap, IPX_NIC_INFO * pNicInfo) {
USHORT i = pNicInfo->Details.NicId, usVirt;
// If the nic already exists, reconfigure it
if (pNicMap->ppNics[i])
return nmReconfigure (pNicMap, pNicInfo);
// Otherwise, add it
pNicMap->ppNics[i] = (NICMAPNODE*) RtlAllocateHeap (RtlProcessHeap(),
0,
(sizeof (NICMAPNODE)));
if (!pNicMap->ppNics[i])
return ERROR_NOT_ENOUGH_MEMORY;
pNicMap->ppNics[i]->pNicInfo = (IPX_NIC_INFO *)
RtlAllocateHeap (RtlProcessHeap(),
0,
sizeof (IPX_NIC_INFO));
if (!pNicMap->ppNics[i]->pNicInfo)
return ERROR_NOT_ENOUGH_MEMORY;
// Initialize it
usVirt = nmGetNextVirtualNicId(pNicMap, i);
pNicMap->ppNics[i]->usVirtualId = usVirt;
pNicMap->ppNics[i]->pNicInfo->Details.NicId = usVirt;
CopyMemory(pNicMap->ppNics[i]->pNicInfo, pNicInfo, sizeof (IPX_NIC_INFO));
pNicMap->usVirtMap[usVirt] = i;
// Update the nic count and maximum nic id
if (i > pNicMap->dwMaxNicId)
pNicMap->dwMaxNicId = i;
pNicMap->dwNicCount++;
return NO_ERROR;
}
// Deletes a nic from the table
DWORD nmDelNic (NICMAP * pNicMap, IPX_NIC_INFO * pNicInfo) {
USHORT i = pNicInfo->Details.NicId, usVirt;
// If the nic doesn't exists do nothing
if (! pNicMap->ppNics[i])
return ERROR_INVALID_INDEX;
// Otherwise, delete it
pNicMap->usVirtMap[pNicMap->ppNics[i]->usVirtualId] = NIC_MAP_INVALID_NICID;
RtlFreeHeap(RtlProcessHeap(), 0, pNicMap->ppNics[i]->pNicInfo);
RtlFreeHeap(RtlProcessHeap(), 0, pNicMap->ppNics[i]);
pNicMap->ppNics[i] = NULL;
// Update the nic count and maximum nic id
if (i >= pNicMap->dwMaxNicId)
pNicMap->dwMaxNicId--;
pNicMap->dwNicCount--;
return NO_ERROR;
}
// Renumbers the nics in the table. dwOpCode is one
// of the NIC_OPCODE_XXX_XXX values
DWORD nmRenumber (NICMAP * pNicMap, USHORT usThreshold, DWORD dwOpCode) {
DWORD i;
// Increment the nic id's if needed
if (dwOpCode == NIC_OPCODE_INCREMENT_NICIDS) {
for (i = pNicMap->dwMaxNicId; i >= usThreshold; i--) {
pNicMap->ppNics[i+1] = pNicMap->ppNics[i];
if (pNicMap->ppNics[i])
pNicMap->usVirtMap[pNicMap->ppNics[i]->usVirtualId] = (USHORT)(i+1);
}
pNicMap->ppNics[usThreshold] = NULL;
}
// Else decrement them
else {
// If there is a nic there, delete it. This should never happen!
if (pNicMap->ppNics[usThreshold])
nmDelNic(pNicMap, pNicMap->ppNics[usThreshold]->pNicInfo);
// Renumber
for (i = usThreshold; i < pNicMap->dwMaxNicId; i++) {
if (pNicMap->ppNics[i+1])
pNicMap->usVirtMap[pNicMap->ppNics[i+1]->usVirtualId] = (USHORT)i;
pNicMap->ppNics[i] = pNicMap->ppNics[i+1];
}
if (pNicMap->ppNics[i])
pNicMap->ppNics[i] = NULL;
}
return NO_ERROR;
}
// Returns whether the nic map is empty
BOOL nmIsEmpty (NICMAP * pNicMap) {
return pNicMap->dwNicCount == 0;
}
// ========================================
// Implementation of the api used by adptif
// ========================================
DWORD NicMapInitialize() {
return nmInitialize(&GlobalNicIdMap);
}
DWORD NicMapCleanup() {
return nmCleanup(&GlobalNicIdMap);
}
USHORT NicMapGetVirtualNicId(USHORT usPhysId) {
return nmGetVirtualId(&GlobalNicIdMap, usPhysId);
}
USHORT NicMapGetPhysicalNicId(USHORT usVirtId) {
return nmGetPhysicalId(&GlobalNicIdMap, usVirtId);
}
DWORD NicMapGetMaxNicId() {
return nmGetMaxNicId(&GlobalNicIdMap);
}
DWORD NicMapGetNicCount() {
return nmGetNicCount(&GlobalNicIdMap);
}
DWORD NicMapAdd (IPX_NIC_INFO * pNic) {
return nmAddNic(&GlobalNicIdMap, pNic);
}
DWORD NicMapDel (IPX_NIC_INFO * pNic) {
return nmDelNic(&GlobalNicIdMap, pNic);
}
DWORD NicMapReconfigure (IPX_NIC_INFO * pNic) {
return nmReconfigure(&GlobalNicIdMap, pNic);
}
DWORD NicMapRenumber(DWORD dwOpCode, USHORT usThreshold) {
return nmRenumber (&GlobalNicIdMap, usThreshold, dwOpCode);
}
IPX_NIC_INFO * NicMapGetNicInfo (USHORT usNicId) {
return nmGetNicInfo (&GlobalNicIdMap, usNicId);
}
BOOL NicMapIsEmpty () {
return nmIsEmpty (&GlobalNicIdMap);
}