summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/isn/fwd/tables.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/tdi/isn/fwd/tables.c1512
1 files changed, 1512 insertions, 0 deletions
diff --git a/private/ntos/tdi/isn/fwd/tables.c b/private/ntos/tdi/isn/fwd/tables.c
new file mode 100644
index 000000000..baec3cced
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/tables.c
@@ -0,0 +1,1512 @@
+
+#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;
+
+// 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);
+ 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);
+}
+
+/*++
+*******************************************************************
+ 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 = 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)(InterfaceIndexHash+InterfaceHashSize),ULONGLONG);
+
+ ClientNodeHash = (PINTERFACE_CB *)segment;
+ segment = (CHAR *)ALIGN_UP((ULONG)(ClientNodeHash+ClientHashSize),ULONGLONG);
+
+ RouteHash = (PFWD_ROUTE *)segment;
+ segment = (CHAR *)ALIGN_UP((ULONG)(RouteHash + RouteHashSize),ULONGLONG);
+
+ NBRouteHash = (PNB_ROUTE *)segment;
+ segment = (CHAR *)ALIGN_UP((ULONG)(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)(segment+InterfaceSegmentSize),ULONGLONG);
+
+ status = ExInitializeZone (&RouteZone,
+ ALIGN_UP(sizeof (FWD_ROUTE), ULONGLONG),
+ segment,
+ blockSize - (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);
+ else {
+ IpxFwdDbgPrint (DBG_INTF_TABLE, DBG_ERROR,
+ ("IpxFwd: Could not get interface reference %ld.\n", InterfaceIndex));
+ }
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+ return ifCB;
+}
+
+/*++
+*******************************************************************
+ 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)"
+ " to global client table.\n", ifCB->ICB_Index, 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);
+ 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)) {
+ ASSERT (InterfaceIndex==0xFFFFFFFF);
+ fwRoute = GlobalRoute;
+ }
+ else {
+ ASSERT (InterfaceIndex!=0xFFFFFFFF);
+ fwRoute = LocateRoute (Network, &prev);
+ }
+
+ 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);
+ }
+ else {
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+ status = STATUS_UNSUCCESSFUL;
+ goto ExitUpdate;
+ }
+ KeReleaseSpinLock (&InterfaceTableLock, oldIRQL);
+ }
+ else {
+ ifCB = fwRoute->FR_InterfaceReference;
+ AcquireInterfaceReference (ifCB);
+ }
+ }
+ 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);
+ }
+ 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);
+ }
+ 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);
+ }
+ else
+ ifCB = NULL;
+ ReleaseReaderAccess (&RWLock, cookie);
+ return ifCB;
+}
+