|
|
#include "precomp.h"
// Memory zone for interfaces
ZONE_HEADER InterfaceZone; // Segment size in interface sone
ULONG InterfaceSegmentSize= sizeof(INTERFACE_CB)*NUM_INTERFACES_PER_SEGMENT +sizeof (ZONE_SEGMENT_HEADER); KSPIN_LOCK InterfaceZoneLock;
// Interface tables
LIST_ENTRY *InterfaceIndexHash; // Hash by interface index
PINTERFACE_CB *ClientNodeHash; // Hash by node on qlobal net
INTERFACE_CB TheInternalInterface; // The internal interface
PINTERFACE_CB InternalInterface=&TheInternalInterface; KSPIN_LOCK InterfaceTableLock; // Protection for interface hash tables
// Memory Zone for routes
ZONE_HEADER RouteZone; // Segment size in route sone
ULONG RouteSegmentSize=DEF_ROUTE_SEGMENT_SIZE; KSPIN_LOCK RouteZoneLock;
// Route tables
PFWD_ROUTE *RouteHash; PFWD_ROUTE GlobalRoute; ULONG GlobalNetwork;
// NB Route table
PNB_ROUTE *NBRouteHash;
// Reader-writer lock to wait for all readers to drain when
// updating the route tables
RW_LOCK RWLock; // Mutex to serialize writers to route tables
FAST_MUTEX WriterMutex;
// Sizes of the tables
ULONG RouteHashSize; // Must be specified
ULONG InterfaceHashSize=DEF_INTERFACE_HASH_SIZE; ULONG ClientHashSize=DEF_CLIENT_HASH_SIZE; ULONG NBRouteHashSize=DEF_NB_ROUTE_HASH_SIZE;
//*** max send pkts queued limit: over this limit the send pkts get discarded
ULONG MaxSendPktsQueued = MAX_SEND_PKTS_QUEUED; INT WanPacketListId = -1;
// Initial memory block allocated for the tables
CHAR *TableBlock = NULL;
ULONG InterfaceAllocCount = 0; ULONG InterfaceFreeCount = 0;
// Hash functions
#define InterfaceIndexHashFunc(Interface) (Interface%InterfaceHashSize)
#define ClientNodeHashFunc(Node64) ((UINT)(Node64%ClientHashSize))
#define NetworkNumberHashFunc(Network) (Network%RouteHashSize)
#define NetbiosNameHashFunc(Name128) ((UINT)(Name128[0]+Name128[1])%NBRouteHashSize)
/*++
******************************************************************* A l l o c a t e R o u t e
Routine Description: Allocates memory for route from memory zone reserved for route storage. Extends zone if there are no free blocks in currently allocated segements. Arguments: None Return Value: Pointer to allocated route
******************************************************************* --*/ PFWD_ROUTE AllocateRoute ( void ) { PFWD_ROUTE fwRoute; KIRQL oldIRQL;
KeAcquireSpinLock (&RouteZoneLock, &oldIRQL); // Check if there are free blocks in the zone
if (ExIsFullZone (&RouteZone)) { // Try to allocate new segment if not
NTSTATUS status; PVOID segment = ExAllocatePoolWithTag (NonPagedPool, RouteSegmentSize, FWD_POOL_TAG); if (segment==NULL) { KeReleaseSpinLock (&RouteZoneLock, oldIRQL); IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_ERROR, ("IpxFwd: Can't allocate route zone segment.\n")); return NULL; } status = ExExtendZone (&RouteZone, segment, RouteSegmentSize); ASSERTMSG ("Could not extend RouteZone ", NT_SUCCESS (status)); } fwRoute = (PFWD_ROUTE)ExAllocateFromZone (&RouteZone); KeReleaseSpinLock (&RouteZoneLock, oldIRQL); return fwRoute; }
/*++
******************************************************************* F r e e R o u t e
Routine Description: Releases memory allocated for route to route memory zone. Arguments: fwRoute - route block to release Return Value: None ******************************************************************* --*/ VOID FreeRoute ( PFWD_ROUTE fwRoute ) { IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_INFORMATION, ("IpxFwd: Freeing route block %08lx.\n", fwRoute)); ASSERT (fwRoute->FR_InterfaceReference==NULL); ExInterlockedFreeToZone(&RouteZone,fwRoute,&RouteZoneLock); }
/*++
******************************************************************* A l l o c a t e I n t e r f a c e
Routine Description: Allocates memory for interface from memory zone reserved for interface storage. Extends zone if there are no free blocks in currently allocated segements. Arguments: None Return Value: Pointer to allocated route
******************************************************************* --*/ PINTERFACE_CB AllocateInterface ( void ) { PINTERFACE_CB ifCB; KIRQL oldIRQL;
KeAcquireSpinLock (&RouteZoneLock, &oldIRQL); // Check if there are free blocks in the zone
if (ExIsFullZone (&InterfaceZone)) { // Try to allocate new segment if not
NTSTATUS status; PVOID segment = ExAllocatePoolWithTag (NonPagedPool, InterfaceSegmentSize, FWD_POOL_TAG); if (segment==NULL) { KeReleaseSpinLock (&RouteZoneLock, oldIRQL); IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR, ("IpxFwd: Can't allocate interface zone segment.\n")); return NULL; } status = ExExtendZone (&InterfaceZone, segment, InterfaceSegmentSize); ASSERTMSG ("Could not extend InterfaceZone ", NT_SUCCESS (status)); } ifCB = (PINTERFACE_CB)ExAllocateFromZone (&InterfaceZone); KeReleaseSpinLock (&RouteZoneLock, oldIRQL);
InterlockedIncrement(&InterfaceAllocCount); return ifCB; }
/*++
******************************************************************* F r e e I n t e r f a c e
Routine Description: Releases memory allocated for interface to interface memory zone. Arguments: fwRoute - route block to release Return Value: None ******************************************************************* --*/ VOID FreeInterface ( PINTERFACE_CB ifCB ) { KIRQL oldIRQL;
IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING, ("IpxFwd: Freeing icb %08lx.\n", ifCB));
ASSERT(ifCB->ICB_Stats.OperationalState==FWD_OPER_STATE_DOWN); KeAcquireSpinLock (&InterfaceZoneLock, &oldIRQL); ExFreeToZone(&InterfaceZone, ifCB); KeReleaseSpinLock (&InterfaceZoneLock, oldIRQL);
InterlockedIncrement(&InterfaceFreeCount);
}
/*++
******************************************************************* C r e a t e T a b l e s
Routine Description: Allocates and intializes all hash tables and related structures Arguments: None Return Value: STATUS_SUCCESS - tables were created ok STATUS_INSUFFICIENT_RESOURCES - resource allocation failed ******************************************************************* --*/ NTSTATUS CreateTables ( void ) { UINT i; CHAR *segment; NTSTATUS status; ULONG blockSize;
ASSERT (TableBlock==NULL);
blockSize = (ULONG) ROUND_TO_PAGES ( InterfaceHashSize*sizeof(*InterfaceIndexHash) +ClientHashSize*sizeof(*ClientNodeHash) +RouteHashSize*sizeof(*RouteHash) +NBRouteHashSize*sizeof(*NBRouteHash) +InterfaceSegmentSize +RouteSegmentSize );
// Allocate first segment for route zone
TableBlock = segment = (CHAR *)ExAllocatePoolWithTag ( NonPagedPool, blockSize, FWD_POOL_TAG); if (segment!=NULL) { InterfaceIndexHash = (LIST_ENTRY *)segment; segment = (CHAR *)ALIGN_UP((ULONG_PTR)(InterfaceIndexHash+InterfaceHashSize),ULONGLONG);
ClientNodeHash = (PINTERFACE_CB *)segment; segment = (CHAR *)ALIGN_UP((ULONG_PTR)(ClientNodeHash+ClientHashSize),ULONGLONG); RouteHash = (PFWD_ROUTE *)segment; segment = (CHAR *)ALIGN_UP((ULONG_PTR)(RouteHash + RouteHashSize),ULONGLONG);
NBRouteHash = (PNB_ROUTE *)segment; segment = (CHAR *)ALIGN_UP((ULONG_PTR)(NBRouteHash + NBRouteHashSize),ULONGLONG);
status = ExInitializeZone (&InterfaceZone, ALIGN_UP(sizeof (INTERFACE_CB),ULONGLONG), segment, InterfaceSegmentSize); ASSERTMSG ("Could not initalize InterfaceZone ", NT_SUCCESS (status)); segment = (CHAR *)ALIGN_UP((ULONG_PTR)(segment+InterfaceSegmentSize),ULONGLONG);
status = ExInitializeZone (&RouteZone, ALIGN_UP(sizeof (FWD_ROUTE), ULONGLONG), segment, blockSize - (ULONG)(segment - TableBlock));
ASSERTMSG ("Could not initalize RouteZone ", NT_SUCCESS (status)); // No global route yet
GlobalRoute = NULL; GlobalNetwork = 0xFFFFFFFF;
InternalInterface = &TheInternalInterface; InitICB (InternalInterface, FWD_INTERNAL_INTERFACE_INDEX, FWD_IF_PERMANENT, TRUE, FWD_NB_DELIVER_ALL); #if DBG
InitializeListHead (&InternalInterface->ICB_InSendQueue); #endif
KeInitializeSpinLock (&InterfaceTableLock); KeInitializeSpinLock (&InterfaceZoneLock); KeInitializeSpinLock (&RouteZoneLock); InitializeRWLock (&RWLock); ExInitializeFastMutex (&WriterMutex);
// Initialize hash tables buckets
for (i=0; i<InterfaceHashSize; i++) InitializeListHead (&InterfaceIndexHash[i]);
for (i=0; i<ClientHashSize; i++) { ClientNodeHash[i] = NULL; }
for (i=0; i<RouteHashSize; i++) { RouteHash[i] = NULL; }
for (i=0; i<NBRouteHashSize; i++) { NBRouteHash[i] = NULL; } return STATUS_SUCCESS; } else { IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR, ("IpxFwd: Could not allocate table block!\n")); }
return STATUS_INSUFFICIENT_RESOURCES; }
/*++
******************************************************************* D e l e t e T a b l e s
Routine Description: Releases resources allocated for all hash tables Arguments: None Return Value: STATUS_SUCCESS - tables were freed ok ******************************************************************* --*/ NTSTATUS DeleteTables ( void ) { UINT i; PVOID segment;
if (TableBlock==NULL) { IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR, ("Tables already deleted.\n")); return STATUS_SUCCESS; } // First get rid of all routes
// (that should release all references to interface
// control blocks
for (i=0; i<RouteHashSize; i++) { while (RouteHash[i]!=NULL) { PFWD_ROUTE fwRoute = RouteHash[i]; RouteHash[i] = fwRoute->FR_Next; if (fwRoute->FR_InterfaceReference!=GLOBAL_INTERFACE_REFERENCE) { ReleaseInterfaceReference (fwRoute->FR_InterfaceReference); } fwRoute->FR_InterfaceReference = NULL; ReleaseRouteReference (fwRoute); } } // Don't forget about global route
if (GlobalRoute!=NULL) { GlobalRoute->FR_InterfaceReference = NULL; ReleaseRouteReference (GlobalRoute); GlobalRoute = NULL; GlobalNetwork = 0xFFFFFFFF; }
// Now we should be able to release all interfaces
for (i=0; i<InterfaceHashSize; i++) { while (!IsListEmpty (&InterfaceIndexHash[i])) { PINTERFACE_CB ifCB = CONTAINING_RECORD (InterfaceIndexHash[i].Flink, INTERFACE_CB, ICB_IndexHashLink); RemoveEntryList (&ifCB->ICB_IndexHashLink); if (ifCB->ICB_Stats.OperationalState==FWD_OPER_STATE_UP) { switch (ifCB->ICB_InterfaceType) { case FWD_IF_PERMANENT: DeregisterPacketConsumer (ifCB->ICB_PacketListId); break; case FWD_IF_DEMAND_DIAL: case FWD_IF_LOCAL_WORKSTATION: case FWD_IF_REMOTE_WORKSTATION: break; default: ASSERTMSG ("Invalid interface type ", FALSE); break; } if (ifCB->ICB_CashedInterface!=NULL) ReleaseInterfaceReference (ifCB->ICB_CashedInterface); ifCB->ICB_CashedInterface = NULL; if (ifCB->ICB_CashedRoute!=NULL) ReleaseRouteReference (ifCB->ICB_CashedRoute); ifCB->ICB_CashedRoute = NULL; if (ifCB->ICB_Network==GlobalNetwork) DeleteGlobalNetClient (ifCB); IPXCloseAdapterProc (ifCB->ICB_AdapterContext); ReleaseInterfaceReference (ifCB); // Binding reference
}
if (IS_IF_CONNECTING (ifCB)) { SET_IF_NOT_CONNECTING (ifCB); DequeueConnectionRequest (ifCB); }
while (!IsListEmpty (&ifCB->ICB_ExternalQueue)) { PPACKET_TAG pktTag;
pktTag = CONTAINING_RECORD (ifCB->ICB_ExternalQueue.Flink, PACKET_TAG, PT_QueueLink); RemoveEntryList (&pktTag->PT_QueueLink); ReleaseInterfaceReference (pktTag->PT_InterfaceReference); FreePacket (pktTag); }
while (!IsListEmpty (&ifCB->ICB_InternalQueue)) { PINTERNAL_PACKET_TAG pktTag;
pktTag = CONTAINING_RECORD (ifCB->ICB_InternalQueue.Flink, INTERNAL_PACKET_TAG, IPT_QueueLink); RemoveEntryList (&pktTag->IPT_QueueLink); IPXInternalSendCompletProc (&pktTag->IPT_Target, pktTag->IPT_Packet, pktTag->IPT_Length, STATUS_NETWORK_UNREACHABLE); ReleaseInterfaceReference (pktTag->IPT_InterfaceReference); ExFreePool (pktTag); }
ifCB->ICB_Stats.OperationalState = FWD_OPER_STATE_DOWN; if (ifCB->ICB_NBRoutes!=NULL) { DeleteNBRoutes (ifCB->ICB_NBRoutes, ifCB->ICB_NBRouteCount); ifCB->ICB_NBRoutes = NULL; } ReleaseInterfaceReference (ifCB); } }
if (InternalInterface->ICB_NBRoutes!=NULL) { DeleteNBRoutes (InternalInterface->ICB_NBRoutes, InternalInterface->ICB_NBRouteCount); InternalInterface->ICB_NBRoutes = NULL; } if (InternalInterface->ICB_Stats.OperationalState==FWD_OPER_STATE_UP) { InternalInterface->ICB_Stats.OperationalState = FWD_OPER_STATE_DOWN; ReleaseInterfaceReference (InternalInterface); // Binding reference
} ReleaseInterfaceReference (InternalInterface);
// Release extra memory segments used for route table entries
segment = PopEntryList (&RouteZone.SegmentList); while (RouteZone.SegmentList.Next!=NULL) { ExFreePool (segment); segment = PopEntryList (&RouteZone.SegmentList); }
// Release extra memory segments used for interface table entries
segment = PopEntryList (&InterfaceZone.SegmentList); while (InterfaceZone.SegmentList.Next!=NULL) { ExFreePool (segment); segment = PopEntryList (&InterfaceZone.SegmentList); }
ExFreePool (TableBlock); TableBlock = NULL; return STATUS_SUCCESS; }
/*++
******************************************************************* L o c a t e I n t e r f a c e
Routine Description: Finds interface control block in interface index hash table. Optionally returns the insertion point pointer if interface block with given index is not in the table. Arguments: InterfaceIndex - unique id of the interface insertBefore - buffer to place the pointer to hash table element where interface block should be inserted if it is not already in the table Return Value: Pointer to interface control block if found NULL otherwise ******************************************************************* --*/ PINTERFACE_CB LocateInterface ( ULONG InterfaceIndex, PLIST_ENTRY *insertBefore OPTIONAL ) { PLIST_ENTRY cur; PINTERFACE_CB ifCB; PLIST_ENTRY HashList;
ASSERT (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX);
// Find hash bucket
HashList = &InterfaceIndexHash[InterfaceIndexHashFunc(InterfaceIndex)]; cur = HashList->Flink; // Walk the list
while (cur!=HashList) { ifCB = CONTAINING_RECORD(cur, INTERFACE_CB, ICB_IndexHashLink);
if (ifCB->ICB_Index==InterfaceIndex) // Found, return it (insertion point is irrelevant)
return ifCB; else if (ifCB->ICB_Index>InterfaceIndex) // No chance to find it
break; cur = cur->Flink; } // Return insertion point if asked
if (ARGUMENT_PRESENT(insertBefore)) *insertBefore = cur; return NULL; }
/*++
******************************************************************* L o c a t e C l i e n t I n t e r f a c e
Routine Description: Finds interface control block in client node hash bucket. Optionally returns the insertion point pointer if interface block with given node is not in the table Arguments: ClientNode - node address of the client on global network insertBefore - buffer to place the pointer to hash table element where interface block should be inserted if it is not already in the table Return Value: Pointer to interface control block if found NULL otherwise ******************************************************************* --*/ PINTERFACE_CB LocateClientInterface ( ULONGLONG *NodeAddress64, PINTERFACE_CB **prevLink OPTIONAL ) { PINTERFACE_CB cur, *prev;
prev = &ClientNodeHash[ClientNodeHashFunc (*NodeAddress64)]; cur = *prev; while (cur!=NULL) { if (*NodeAddress64==cur->ICB_ClientNode64[0]) break; else if (*NodeAddress64>cur->ICB_ClientNode64[0]) { // No chance to find it
cur = NULL; break; } prev = &cur->ICB_NodeHashLink; cur = cur->ICB_NodeHashLink; } if (ARGUMENT_PRESENT(prevLink)) *prevLink = prev; return cur; }
/*++
******************************************************************* L o c a t e R o u t e
Routine Description: Finds route block in network number hash table. Optionally returns the insertion point pointer if route for given destination netowrk is not in the table Arguments: Network - destination netowork number insertBefore - buffer to place the pointer to hash table element where route block should be inserted if it is not already in the table Return Value: Pointer to route block if found NULL otherwise ******************************************************************* --*/ PFWD_ROUTE LocateRoute ( ULONG Network, PFWD_ROUTE **prevLink OPTIONAL ) { PFWD_ROUTE cur, *prev;
prev = &RouteHash[NetworkNumberHashFunc(Network)]; cur = *prev;
while (cur!=NULL) { if (cur->FR_Network==Network) break; else if (cur->FR_Network>Network) { cur = NULL; // No chance to find it
break; } prev = &cur->FR_Next; cur = *prev; } if (ARGUMENT_PRESENT(prevLink)) *prevLink = prev;
return cur; }
/*++
******************************************************************* L o c a t e N B R o u t e
Routine Description: Finds nb route block in nb name hash table. Optionally returns the insertion point pointer if nb route for given name is not in the table Arguments: Name - netbios name insertBefore - buffer to place the pointer to hash table element where route block should be inserted if it is not already in the table Return Value: Pointer to nb route block if found NULL otherwise ******************************************************************* --*/ PNB_ROUTE LocateNBRoute ( ULONGLONG *Name128, PNB_ROUTE **prevLink OPTIONAL ) { PNB_ROUTE cur, *prev;
prev = &NBRouteHash[NetbiosNameHashFunc(Name128)]; cur = *prev;
while (cur!=NULL) { if ((cur->NBR_Name128[0]==Name128[0]) && (cur->NBR_Name128[1]==Name128[1])) break; else if ((cur->NBR_Name128[0]>Name128[0]) || ((cur->NBR_Name128[0]==Name128[0]) && (cur->NBR_Name128[1]>Name128[1]))) { cur = NULL; // No chance to find it
break; } prev = &cur->NBR_Next; cur = *prev; } if (ARGUMENT_PRESENT(prevLink)) *prevLink = prev;
return cur; }
/*++
******************************************************************* G e t I n t e r f a c e R e f e r e n c e
Routine Description: Returns reference interface based on its index Arguments: InterfaceIndex - unique id of the interface Return Value: Pointer to interface control block if there is one in the table NULL otherwise ******************************************************************* --*/ PINTERFACE_CB GetInterfaceReference ( ULONG InterfaceIndex ) { KIRQL oldIRQL; PINTERFACE_CB ifCB;
KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL); if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) ifCB = LocateInterface (InterfaceIndex, NULL); else ifCB = InternalInterface;
if (ifCB!=NULL) { AcquireInterfaceReference (ifCB); //if (ifCB->ICB_Index > 1)
//IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
// ("IpxFwd: GetInterfaceReference: Aquired if #%ld (%ld) \n", ifCB->ICB_Index, ifCB->ICB_ReferenceCount));
} else { IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR, ("IpxFwd: Could not get interface reference %ld.\n", InterfaceIndex)); } KeReleaseSpinLock (&InterfaceTableLock, oldIRQL); return ifCB; }
//
// Function IncrementNicIds
//
// Increments the nic id of every nic in the interface table
// whose id is greater than or equal to the given threshold.
//
NTSTATUS IncrementNicids (USHORT usThreshold) { KIRQL oldIRQL; PINTERFACE_CB ifCB; PLIST_ENTRY cur; PLIST_ENTRY HashList; ULONG i;
IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION, ("IpxFwd: Incrementing all nic id's >= %d", usThreshold)); KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL); // Walk through all of the hash buckets
for (i = 0; i < InterfaceHashSize; i++) { HashList = &InterfaceIndexHash[i]; cur = HashList->Flink; // Walk the list in this bucket updating as needed
while (cur!=HashList) { ifCB = CONTAINING_RECORD(cur, INTERFACE_CB, ICB_IndexHashLink); if ((ifCB->ICB_NicId != INVALID_NIC_ID) && (ifCB->ICB_NicId >= usThreshold)) { IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION, ("IpxFwd: Incrementing nic id %d", ifCB->ICB_NicId)); ifCB->ICB_NicId++; *((USHORT*)&ifCB->ICB_AdapterContext) = ifCB->ICB_NicId; } cur = cur->Flink; } } KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
return STATUS_SUCCESS; }
//
// Function DecrementNicIds
//
// Decrements the nic id of every nic in the interface table
// whose id is greater than the given threshold.
//
NTSTATUS DecrementNicids (USHORT usThreshold) { KIRQL oldIRQL; PINTERFACE_CB ifCB; PLIST_ENTRY cur; PLIST_ENTRY HashList; ULONG i;
IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION, ("IpxFwd: Decrementing all nic id's > %d", usThreshold));
KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL); // Walk through all of the hash buckets
for (i = 0; i < InterfaceHashSize; i++) { HashList = &InterfaceIndexHash[i]; cur = HashList->Flink; // Walk the list in this bucket updating as needed
while (cur!=HashList) { ifCB = CONTAINING_RECORD(cur, INTERFACE_CB, ICB_IndexHashLink); // If this is a bound interface
if (ifCB->ICB_NicId != INVALID_NIC_ID) { // If it's bound to a nic greater than the threshold, update
// the nicid
if (ifCB->ICB_NicId > usThreshold) { IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION, ("IpxFwd: Decrementing nic id %d", ifCB->ICB_NicId)); ifCB->ICB_NicId--; } // The if with bound to the threshold is now unbound.
else if (ifCB->ICB_NicId == usThreshold) { IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION, ("IpxFwd: Marking interface %d as unbound", ifCB->ICB_Index)); ifCB->ICB_NicId = INVALID_NIC_ID; } *((USHORT*)&ifCB->ICB_AdapterContext) = ifCB->ICB_NicId; } cur = cur->Flink; } } KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
return STATUS_SUCCESS; }
//
// Puts as much of the interface table into the buffer pointed to by
// pRows as there is space.
//
NTSTATUS DoGetIfTable (FWD_INTERFACE_TABLE * pTable, ULONG dwRowBufferSize) { KIRQL oldIRQL; PINTERFACE_CB ifCB; PLIST_ENTRY cur; PLIST_ENTRY HashList; ULONG i, j = 0;
KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
// Walk through all of the hash buckets
for (i = 0; i < InterfaceHashSize; i++) { HashList = &InterfaceIndexHash[i]; cur = HashList->Flink; // Walk the list in this bucket updating as needed
while (cur!=HashList) { ifCB = CONTAINING_RECORD(cur, INTERFACE_CB, ICB_IndexHashLink);
// Validate the size of the return buffer
if (dwRowBufferSize < (sizeof(FWD_INTERFACE_TABLE) + (sizeof(FWD_INTERFACE_TABLE_ROW) * (j + 1)))) { break; }
// Validate the number of rows
if (j >= pTable->dwNumRows) break;
// Copy over the interface information
pTable->pRows[j].dwIndex = ifCB->ICB_Index; pTable->pRows[j].dwNetwork = ifCB->ICB_Network; memcpy (pTable->pRows[j].uNode, ifCB->ICB_LocalNode, 6); memcpy (pTable->pRows[j].uRemoteNode, ifCB->ICB_RemoteNode, 6); pTable->pRows[j].usNicId = ifCB->ICB_NicId; pTable->pRows[j].ucType = ifCB->ICB_InterfaceType; j++;
// Advance the current row and interface
cur = cur->Flink; } } KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
pTable->dwNumRows = j;
return STATUS_SUCCESS; }
/*++
******************************************************************* G e t N e x t I n t e r f a c e R e f e r e n c e
Routine Description: Returns reference to the next interface in the table Reference to the provided interface is released Arguments: ifCB - interface to start with or NULL to start from the beginning of the interface table Return Value: Pointer to interface control block if thare are any more interfaces in the table NULL otherwise ******************************************************************* --*/ PINTERFACE_CB GetNextInterfaceReference ( PINTERFACE_CB ifCB ) { PLIST_ENTRY cur; PLIST_ENTRY HashList; KIRQL oldIRQL;
KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL); if (ifCB!=NULL) { // Find hash bucket
ASSERT (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX); HashList = &InterfaceIndexHash[InterfaceIndexHashFunc(ifCB->ICB_Index)]; if (LocateInterface (ifCB->ICB_Index, &cur)!=NULL) cur = ifCB->ICB_IndexHashLink.Flink; ReleaseInterfaceReference (ifCB); ifCB = NULL; } else cur = HashList = InterfaceIndexHash-1;
if (cur==HashList) { do { HashList += 1; if (HashList==&InterfaceIndexHash[InterfaceHashSize]) { KeReleaseSpinLock (&InterfaceTableLock, oldIRQL); return NULL; } } while (IsListEmpty (HashList)); cur = HashList->Flink; } ifCB = CONTAINING_RECORD (cur, INTERFACE_CB, ICB_IndexHashLink); AcquireInterfaceReference (ifCB); KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
return ifCB; }
/*++
******************************************************************* A d d I n t e r f a c e
Routine Description: Adds interface control block to the table. Arguments: InterfaceIndex - unique if of the interface Info - interface paramters Return Value: STATUS_SUCCESS - interface added ok STATUS_UNSUCCESSFUL - interface is already in the table STATUS_INSUFFICIENT_RESOURCES - can't allocate memory for interface CB ******************************************************************* --*/ NTSTATUS AddInterface ( ULONG InterfaceIndex, UCHAR InterfaceType, BOOLEAN NetbiosAccept, UCHAR NetbiosDeliver ) { PINTERFACE_CB ifCB; PLIST_ENTRY cur; KIRQL oldIRQL; NTSTATUS status = STATUS_SUCCESS;
KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL); if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) { ifCB = LocateInterface (InterfaceIndex, &cur); if (ifCB==NULL) { ifCB = AllocateInterface (); if (ifCB!=NULL) NOTHING; else { status = STATUS_INSUFFICIENT_RESOURCES; goto AddEnd; } } else { IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR, ("IpxFwd: Interface %ld is already in the table!\n", InterfaceIndex)); status = STATUS_UNSUCCESSFUL; goto AddEnd; } } else ifCB = InternalInterface;
InitICB (ifCB, InterfaceIndex,InterfaceType,NetbiosAccept,NetbiosDeliver); #if DBG
InitializeListHead (&ifCB->ICB_InSendQueue); #endif
switch (InterfaceType) { case FWD_IF_PERMANENT: break; case FWD_IF_DEMAND_DIAL: case FWD_IF_LOCAL_WORKSTATION: case FWD_IF_REMOTE_WORKSTATION: ASSERT (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX); if (WanPacketListId==-1) { status = RegisterPacketConsumer ( WAN_PACKET_SIZE, &WanPacketListId); if (!NT_SUCCESS (status)) { WanPacketListId = -1; break; } } ifCB->ICB_PacketListId = WanPacketListId; break; }
if (NT_SUCCESS (status)) { if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) { InsertTailList (cur, &ifCB->ICB_IndexHashLink); } IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING, ("IpxFwd: Adding interface %d (icb: %08lx, plid: %d)\n", InterfaceIndex, ifCB, ifCB->ICB_PacketListId)); } else FreeInterface (ifCB);
AddEnd: KeReleaseSpinLock (&InterfaceTableLock, oldIRQL); return status; }
/*++
******************************************************************* A d d G l o b a l N e t C l i e n t
Routine Description: Adds interface control block to the table of clients on the global network (should be done when client connects) Arguments: ifCB - interface control block to add to the table Return Value: STATUS_SUCCESS - interface was added ok STATUS_UNSUCCESSFUL - another interface with the same node address is already in the table ******************************************************************* --*/ NTSTATUS AddGlobalNetClient ( PINTERFACE_CB ifCB ) { KIRQL oldIRQL; RWCOOKIE cookie; PINTERFACE_CB *prev; NTSTATUS status = STATUS_SUCCESS;
ASSERT (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX);
AcquireReaderAccess (&RWLock, cookie); KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL); if (LocateClientInterface (ifCB->ICB_ClientNode64, &prev)==NULL) { ifCB->ICB_NodeHashLink = *prev; *prev = ifCB; KeReleaseSpinLock (&InterfaceTableLock, oldIRQL); ReleaseReaderAccess (&RWLock, cookie); AcquireInterfaceReference (ifCB); // To make sure that
// interface block does not
// get deleted until it is
// removed from the node table
IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING, ("IpxFwd: Adding interface %ld (icb: %08lx, ref=%ld)" " to global client table.\n", ifCB->ICB_Index, ifCB->ICB_ReferenceCount, ifCB)); } else { KeReleaseSpinLock (&InterfaceTableLock, oldIRQL); ReleaseReaderAccess (&RWLock, cookie); IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR, ("IpxFwd: Interface %ld (icb: %08lx)" " is already in the global client table.\n", ifCB->ICB_Index, ifCB)); status = STATUS_UNSUCCESSFUL; }
return status; }
/*++
******************************************************************* D e l e t e G l o b a l N e t C l i e n t
Routine Description: Removes interface control block from the table of clients on the global network (should be done when client disconnects) Arguments: ifCB - interface control block to remove from the table Return Value: STATUS_SUCCESS - interface was removed ok ******************************************************************* --*/ NTSTATUS DeleteGlobalNetClient ( PINTERFACE_CB ifCB ) { KIRQL oldIRQL; RWCOOKIE cookie; PINTERFACE_CB cur, *prev;
IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING, ("IpxFwd: Deleting interface %ld (icb: %08lx)" " from global client table.\n", ifCB->ICB_Index, ifCB));
ASSERT (ifCB->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX);
AcquireReaderAccess (&RWLock, cookie); KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL); cur = LocateClientInterface (ifCB->ICB_ClientNode64, &prev); ASSERT (cur==ifCB); *prev = ifCB->ICB_NodeHashLink; KeReleaseSpinLock (&InterfaceTableLock, oldIRQL); ReleaseReaderAccess (&RWLock, cookie);
ReleaseInterfaceReference (ifCB); return STATUS_SUCCESS; }
/*++
******************************************************************* D e l e t e I n t e r f a c e
Routine Description: Deletes interface control block (the block is not actually disposed of until all references to it are released). Arguments: InterfaceIndex - unique if of the interface Return Value: STATUS_SUCCESS - interface info retreived ok STATUS_UNSUCCESSFUL - interface is not in the table ******************************************************************* --*/ NTSTATUS DeleteInterface ( ULONG InterfaceIndex ) { PINTERFACE_CB ifCB; KIRQL oldIRQL; NTSTATUS status = STATUS_SUCCESS;
KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL);
if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) ifCB = LocateInterface (InterfaceIndex, NULL); else ifCB = InternalInterface; if (ifCB!=NULL) { if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) { RemoveEntryList (&ifCB->ICB_IndexHashLink); } KeReleaseSpinLock (&InterfaceTableLock, oldIRQL); if (ifCB->ICB_Stats.OperationalState == FWD_OPER_STATE_UP) { IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR, ("IpxFwd: Interface %ld (icb: %08lx) was still bound" " when asked to delete it.\n", ifCB->ICB_Index, ifCB)); UnbindInterface (ifCB); } else if (IS_IF_CONNECTING (ifCB)) { IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR, ("IpxFwd: Interface %ld (icb: %08lx) was still being connected" " when asked to delete it.\n", ifCB->ICB_Index, ifCB)); SET_IF_NOT_CONNECTING (ifCB); DequeueConnectionRequest (ifCB); ProcessInternalQueue (ifCB); ProcessExternalQueue (ifCB); }
ifCB->ICB_Stats.OperationalState = FWD_OPER_STATE_DOWN;
IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING, ("IpxFwd: Deleting interface %ld (icb: %08lx).\n", ifCB->ICB_Index, ifCB));
if (ifCB->ICB_NBRoutes!=NULL) { DeleteNBRoutes (ifCB->ICB_NBRoutes, ifCB->ICB_NBRouteCount); ifCB->ICB_NBRoutes = NULL; }
FltInterfaceDeleted (ifCB); ReleaseInterfaceReference (ifCB); } else { KeReleaseSpinLock (&InterfaceTableLock, oldIRQL); IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR, ("IpxFwd: Could not delete interface %ld because it is not found.\n", InterfaceIndex)); status = STATUS_UNSUCCESSFUL; } return status;
}
/*++
******************************************************************* A d d R o u t e
Routine Description: Adds route to the hash table and finds and stores the reference to the associated interface control block in the route. Arguments: Network - route's destination network NextHopAddress - mac address of next hop router if network is not directly connected TickCount - ticks to reach the destination net HopCount - hopss to reach the destination net InterfaceIndex - index of the associated interface (through which packets destined to the network are to be sent) Return Value: STATUS_SUCCESS - route was added ok STATUS_UNSUCCESSFUL - route is already in the table STATUS_INSUFFICIENT_RESOURCES - can't allocate memory for route block ******************************************************************* --*/ NTSTATUS AddRoute ( ULONG Network, UCHAR *NextHopAddress, USHORT TickCount, USHORT HopCount, ULONG InterfaceIndex ) { PFWD_ROUTE fwRoute; PFWD_ROUTE *prev; NTSTATUS status = STATUS_SUCCESS; KIRQL oldIRQL;
// Assume success, allocate route and intialize it
// (the goal is to spend as little time as possible
// inside exclusive usage zone)
fwRoute = AllocateRoute (); if (fwRoute!=NULL) { fwRoute->FR_Network = Network; IPX_NODE_CPY (fwRoute->FR_NextHopAddress, NextHopAddress); fwRoute->FR_TickCount = TickCount; fwRoute->FR_HopCount = HopCount; fwRoute->FR_ReferenceCount = 0;
if (InterfaceIndex!=0xFFFFFFFF) { // See if interface is there
KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL); if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) fwRoute->FR_InterfaceReference = LocateInterface (InterfaceIndex, NULL); else fwRoute->FR_InterfaceReference = InternalInterface; if (fwRoute->FR_InterfaceReference!=NULL) { AcquireInterfaceReference (fwRoute->FR_InterfaceReference); //if (fwRoute->FR_InterfaceReference->ICB_Index > 1)
//IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
// ("IpxFwd: AddRoute: Aquired if #%ld (%ld) \n",
// fwRoute->FR_InterfaceReference->ICB_Index,
// fwRoute->FR_InterfaceReference->ICB_ReferenceCount));
KeReleaseSpinLock (&InterfaceTableLock, oldIRQL); ExAcquireFastMutex (&WriterMutex); // Check if route is already there
if (LocateRoute (Network, &prev)==NULL) { fwRoute->FR_Next = *prev; *prev = fwRoute; } else { ReleaseInterfaceReference (fwRoute->FR_InterfaceReference); fwRoute->FR_InterfaceReference = NULL; IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_ERROR, ("IpxFwd: Route for net %08lx" " is already in the table!\n", Network)); status = STATUS_UNSUCCESSFUL; }
ExReleaseFastMutex (&WriterMutex); } else { KeReleaseSpinLock (&InterfaceTableLock, oldIRQL); IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_ERROR, ("IpxFwd: Interface %ld for route for net %08lx" " is not in the table!\n", InterfaceIndex, Network)); status = STATUS_UNSUCCESSFUL; } } else { ExAcquireFastMutex (&WriterMutex); // Just check if we do not have it already
if (GlobalRoute==NULL) { fwRoute->FR_InterfaceReference = GLOBAL_INTERFACE_REFERENCE; GlobalNetwork = Network; GlobalRoute = fwRoute; } else { IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_ERROR, ("IpxFwd: Route for global net %08lx" " is already in the table!\n", Network)); status = STATUS_UNSUCCESSFUL; } ExReleaseFastMutex (&WriterMutex); }
if (NT_SUCCESS (status)) { IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_WARNING, ("IpxFwd: Adding route for net %08lx" " (rb: %08lx, NHA: %02x%02x%02x%02x%02x%02x," " if: %ld, icb: %08lx).\n", Network, fwRoute, NextHopAddress[0], NextHopAddress[1], NextHopAddress[2], NextHopAddress[3], NextHopAddress[4], NextHopAddress[5], InterfaceIndex, fwRoute->FR_InterfaceReference)); } else { FreeRoute (fwRoute); } } else status = STATUS_INSUFFICIENT_RESOURCES;
return status; }
/*++
******************************************************************* D e l e t e R o u t e
Routine Description: Deletes route from the hash table and releases the reference to the interface control block associated with the route. Arguments: Network - route's destination network Return Value: STATUS_SUCCESS - route was deleted ok STATUS_UNSUCCESSFUL - route is not in the table ******************************************************************* --*/ NTSTATUS DeleteRoute ( ULONG Network ) { PFWD_ROUTE fwRoute, *prev; NTSTATUS status = STATUS_SUCCESS;
ExAcquireFastMutex (&WriterMutex); if ((GlobalRoute!=NULL) && (GlobalNetwork==Network)) { fwRoute = GlobalRoute; GlobalNetwork = 0xFFFFFFFF; GlobalRoute = NULL; } else if ((fwRoute=LocateRoute (Network, &prev))!=NULL) { *prev = fwRoute->FR_Next; }
if (fwRoute!=NULL) { IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_WARNING, ("IpxFwd: Deleting route for net %08lx (rb: %08lx).\n", Network, fwRoute)); WaitForAllReaders (&RWLock); if (fwRoute->FR_InterfaceReference!=GLOBAL_INTERFACE_REFERENCE) { ReleaseInterfaceReference (fwRoute->FR_InterfaceReference); } fwRoute->FR_InterfaceReference = NULL; ReleaseRouteReference (fwRoute); } else { IpxFwdDbgPrint (DBG_ROUTE_TABLE, DBG_ERROR, ("IpxFwd: Could not delete route for net %08lx because it is not in the table.\n", Network)); status = STATUS_UNSUCCESSFUL; }
ExReleaseFastMutex (&WriterMutex); return status; }
/*++
******************************************************************* U p d a t e R o u t e
Routine Description: Updates route in the hash table Arguments: Network - route's destination network NextHopAddress - mac address of next hop router if network is not directly connected TickCount - ticks to reach the destination net HopCount - hopss to reach the destination net InterfaceIndex - index of the associated interface (through which packets destined to the network are to be sent) Return Value: STATUS_SUCCESS - interface info retreived ok STATUS_UNSUCCESSFUL - interface is not in the table ******************************************************************* --*/ NTSTATUS UpdateRoute ( ULONG Network, UCHAR *NextHopAddress, USHORT TickCount, USHORT HopCount, ULONG InterfaceIndex ) { PFWD_ROUTE fwRoute = NULL, newRoute, *prev; PINTERFACE_CB ifCB = NULL; KIRQL oldIRQL; NTSTATUS status = STATUS_SUCCESS;
ExAcquireFastMutex (&WriterMutex); if ((GlobalRoute!=NULL) && (GlobalNetwork==Network)) { InterfaceIndex = 0xFFFFFFFF; fwRoute = GlobalRoute; } else { ASSERT (InterfaceIndex!=0xFFFFFFFF); fwRoute = LocateRoute (Network, &prev); if ((fwRoute != NULL) && (fwRoute->FR_InterfaceReference == GLOBAL_INTERFACE_REFERENCE)) { status = STATUS_UNSUCCESSFUL; goto ExitUpdate; } }
if (fwRoute!=NULL) { if (InterfaceIndex!=0xFFFFFFFF) { if (fwRoute->FR_InterfaceReference->ICB_Index!=InterfaceIndex) { // Get a reference to new interface
KeAcquireSpinLock (&InterfaceTableLock, &oldIRQL); if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) ifCB = LocateInterface (InterfaceIndex, NULL); else ifCB = InternalInterface; if (ifCB!=NULL) { AcquireInterfaceReference (ifCB); //if (ifCB->ICB_Index > 1)
//IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
// ("IpxFwd: UpdateRoute: Aquired if #%ld (%ld) \n", ifCB->ICB_Index, ifCB->ICB_ReferenceCount));
} else { KeReleaseSpinLock (&InterfaceTableLock, oldIRQL); status = STATUS_UNSUCCESSFUL; goto ExitUpdate; } KeReleaseSpinLock (&InterfaceTableLock, oldIRQL); } else { ifCB = fwRoute->FR_InterfaceReference; AcquireInterfaceReference (ifCB); //if (ifCB->ICB_Index > 1)
//IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
// ("IpxFwd: UpdateRoute(2): Aquired if #%ld (%ld) \n", ifCB->ICB_Index, ifCB->ICB_ReferenceCount));
} } else ifCB = GLOBAL_INTERFACE_REFERENCE; newRoute = AllocateRoute (); if (newRoute!=NULL) { newRoute->FR_Network = Network; IPX_NODE_CPY (newRoute->FR_NextHopAddress, NextHopAddress); newRoute->FR_TickCount = TickCount; newRoute->FR_HopCount = HopCount; newRoute->FR_ReferenceCount = 0; newRoute->FR_InterfaceReference = ifCB; // Lock the table only when updating it
if (InterfaceIndex!=0xFFFFFFFF) { newRoute->FR_Next = fwRoute->FR_Next; *prev = newRoute; } else GlobalRoute = newRoute;
WaitForAllReaders (&RWLock) if (fwRoute->FR_InterfaceReference!=GLOBAL_INTERFACE_REFERENCE) { ReleaseInterfaceReference (fwRoute->FR_InterfaceReference); } fwRoute->FR_InterfaceReference = NULL; ReleaseRouteReference (fwRoute);
} else status = STATUS_INSUFFICIENT_RESOURCES; } else status = STATUS_UNSUCCESSFUL;
ExitUpdate: ExReleaseFastMutex (&WriterMutex); return status; }
/*++
******************************************************************* F i n d D e s t i n a t i o n
Routine Description: Finds destination interface for IPX address and returns reference to its control block. Arguments: Network - destination network Node - destination node (needed in case of global client) Route - buffer to hold reference to route block Return Value: Reference to destination interface CB NULL if route it not found ******************************************************************* --*/ PINTERFACE_CB FindDestination ( IN ULONG Network, IN PUCHAR Node, OUT PFWD_ROUTE *Route ) { PFWD_ROUTE fwRoute; PINTERFACE_CB ifCB; RWCOOKIE cookie;
AcquireReaderAccess (&RWLock, cookie); if ((GlobalRoute!=NULL) && (GlobalNetwork==Network)) { if (Node!=NULL) { // If caller did not specify node,
// we can't find the route
union { ULONGLONG Node64[1]; UCHAR Node[6]; } u; u.Node64[0] = 0; IPX_NODE_CPY (u.Node, Node);
ifCB = LocateClientInterface (u.Node64, NULL); if (ifCB!=NULL) { AcquireRouteReference (GlobalRoute); *Route = GlobalRoute; AcquireInterfaceReference (ifCB); //if (ifCB->ICB_Index > 1)
//IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
// ("IpxFwd: FindDestination: Aquired if #%ld (%ld) \n", ifCB->ICB_Index, ifCB->ICB_ReferenceCount));
} else *Route = NULL; } else { ifCB = NULL; *Route = NULL; } } else { *Route = fwRoute = LocateRoute (Network, NULL); if (fwRoute!=NULL) { AcquireRouteReference (fwRoute); ifCB = fwRoute->FR_InterfaceReference; AcquireInterfaceReference (ifCB); //if (ifCB->ICB_Index > 1)
//IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
// ("IpxFwd: FindDestination(2): Aquired if #%ld (%ld) \n", ifCB->ICB_Index, ifCB->ICB_ReferenceCount));
} else ifCB = NULL; } ReleaseReaderAccess (&RWLock, cookie); return ifCB; }
/*++
******************************************************************* A d d N B R o u t e s
Routine Description: Adds netbios names associated with interface to netbios route hash table Arguments: ifCB - interface with which names are associated Names - array of names Count - number of names in the array routeArray - buffer to place allocated array of routes Return Value: STATUS_SUCCESS - names were added ok STATUS_UNSUCCESSFUL - one of the names is already in the table STATUS_INSUFFICIENT_RESOURCES - can't allocate memory for route array ******************************************************************* --*/ NTSTATUS AddNBRoutes ( PINTERFACE_CB ifCB, FWD_NB_NAME Names[], ULONG Count, PNB_ROUTE *routeArray ) { PNB_ROUTE nbRoutes, *prev; NTSTATUS status = STATUS_SUCCESS;
nbRoutes = (PNB_ROUTE)ExAllocatePoolWithTag ( NonPagedPool, sizeof (NB_ROUTE)*Count, FWD_POOL_TAG); if (nbRoutes!=NULL) { ULONG i;
ExAcquireFastMutex (&WriterMutex);
for (i=0; i<Count; i++) { nbRoutes[i].NBR_Name128[0] = nbRoutes[i].NBR_Name128[1] = 0; NB_NAME_CPY (nbRoutes[i].NBR_Name, &Names[i]); // Check if route is already there
if (LocateNBRoute (nbRoutes[i].NBR_Name128, &prev)==NULL) { nbRoutes[i].NBR_Destination = ifCB; nbRoutes[i].NBR_Next = *prev; *prev = &nbRoutes[i]; IpxFwdDbgPrint (DBG_NBROUTE_TABLE, DBG_WARNING, ("IpxFwd: Adding nb route for name %16s.\n",Names[i])); } else { IpxFwdDbgPrint (DBG_NBROUTE_TABLE, DBG_ERROR, ("IpxFwd: Route for nb name %16s" " is already in the table!\n", Names[i])); break; } } ExReleaseFastMutex (&WriterMutex); if (i==Count) { *routeArray = nbRoutes; status = STATUS_SUCCESS;
} else { status = STATUS_UNSUCCESSFUL; DeleteNBRoutes (nbRoutes, i); } } else { IpxFwdDbgPrint (DBG_NBROUTE_TABLE, DBG_ERROR, ("IpxFwd: Could allocate nb route array for if: %ld" " (icb: %08lx).\n", ifCB->ICB_Index, ifCB)); status = STATUS_INSUFFICIENT_RESOURCES; } return status; }
/*++
******************************************************************* D e l e t e N B R o u t e s
Routine Description: Deletes nb routes in the array from the route table and frees the array Arguments: nbRoutes - array of routes Count - number of routes in the array Return Value: STATUS_SUCCESS - route was deleted ok STATUS_UNSUCCESSFUL - route is not in the table ******************************************************************* --*/ NTSTATUS DeleteNBRoutes ( PNB_ROUTE nbRoutes, ULONG Count ) { PNB_ROUTE *prev; NTSTATUS status = STATUS_SUCCESS; ULONG i;
ExAcquireFastMutex (&WriterMutex); for (i=0; i<Count; i++) { PNB_ROUTE cur = LocateNBRoute (nbRoutes[i].NBR_Name128, &prev); ASSERT (cur==&nbRoutes[i]); *prev = nbRoutes[i].NBR_Next; IpxFwdDbgPrint (DBG_NBROUTE_TABLE, DBG_WARNING, ("IpxFwd: Deleting nb route for name %16s.\n", nbRoutes[i].NBR_Name)); }
WaitForAllReaders (&RWLock); ExReleaseFastMutex (&WriterMutex);
ExFreePool (nbRoutes);
return STATUS_SUCCESS; }
/*++
******************************************************************* F i n d N B D e s t i n a t i o n
Routine Description: Finds destination interface for nb name and returns reference to its control block. Arguments: Name - name to look for Return Value: Reference to destination interface CB NULL if route it not found ******************************************************************* --*/ PINTERFACE_CB FindNBDestination ( IN PUCHAR Name ) { PNB_ROUTE nbRoute; PINTERFACE_CB ifCB; RWCOOKIE cookie; union { ULONGLONG Name128[2]; UCHAR Name[16]; } u; u.Name128[0] = u.Name128[1] = 0; NB_NAME_CPY (u.Name, Name);
AcquireReaderAccess (&RWLock, cookie); nbRoute = LocateNBRoute (u.Name128, NULL); if (nbRoute!=NULL) { ifCB = nbRoute->NBR_Destination; AcquireInterfaceReference (ifCB); //if (ifCB->ICB_Index > 1)
//IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_WARNING,
// ("IpxFwd: FindNBDestination: Aquired if #%ld (%ld) \n", ifCB->ICB_Index, ifCB->ICB_ReferenceCount));
} else ifCB = NULL; ReleaseReaderAccess (&RWLock, cookie); return ifCB; }
|