|
|
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
ntos\tdi\isn\fwd\netbios.c
Abstract: Netbios packet processing
Author:
Vadim Eydelman
Revision History:
--*/ #include "precomp.h"
LIST_ENTRY NetbiosQueue; KSPIN_LOCK NetbiosQueueLock; WORK_QUEUE_ITEM NetbiosWorker; BOOLEAN NetbiosWorkerScheduled=FALSE; ULONG NetbiosPacketsQuota; ULONG MaxNetbiosPacketsQueued = DEF_MAX_NETBIOS_PACKETS_QUEUED;
/*++
******************************************************************* P r o c e s s N e t b i o s Q u e u e
Routine Description: Process packets in the netbios broadcast queue (sends them on all interfaces in sequence) Arguments: Context - unused Return Value: None
******************************************************************* --*/ VOID ProcessNetbiosQueue ( PVOID Context ) { KIRQL oldIRQL; LIST_ENTRY tempQueue;
KeAcquireSpinLock (&NetbiosQueueLock, &oldIRQL); // Check if there is something in the queue
if (!IsListEmpty (&NetbiosQueue)) { // Move the queue to local variable
InsertHeadList (&NetbiosQueue, &tempQueue); RemoveEntryList (&NetbiosQueue); InitializeListHead (&NetbiosQueue);
KeReleaseSpinLock (&NetbiosQueueLock, oldIRQL); do { PLIST_ENTRY cur; PPACKET_TAG pktTag;
cur = RemoveHeadList (&tempQueue); pktTag = CONTAINING_RECORD (cur, PACKET_TAG, PT_QueueLink); // Check if this packet has to be sent on other
// interfaces
if (!(pktTag->PT_Flags&PT_NB_DESTROY)) { PINTERFACE_CB dstIf = pktTag->PT_InterfaceReference; PUCHAR dataPtr = pktTag->PT_Data; UINT rtCount = *(dataPtr+IPXH_XPORTCTL); PUCHAR netListPtr; UINT i; if (dstIf==NULL) { // This is a brand new packet: not sent on any
// interface yet
USHORT dstSock = GETUSHORT (dataPtr+IPXH_DESTSOCK); // Check if we have a static route for this name
// (offset to name depends on packet dest socket)
if (dstSock==IPX_NETBIOS_SOCKET) dstIf = FindNBDestination (dataPtr+NB_NAME); else if (dstSock==IPX_SMB_NAME_SOCKET) dstIf = FindNBDestination (dataPtr+SMB_NAME); else dstIf = NULL;
if (dstIf!=NULL) { // Static route found, make sure this packet
// won't be sent on any other interface
pktTag->PT_Flags |= PT_NB_DESTROY; InterlockedIncrement (&NetbiosPacketsQuota); // Make sure the packet has not traversed
// this network already
for (i=0, netListPtr=dataPtr+IPXH_HDRSIZE; i<rtCount; i++,netListPtr+=4) { if (GETULONG (netListPtr)==dstIf->ICB_Network) break; } // Make sure we are allowed to send on this
// interface
if ((dstIf!=InternalInterface) && (i==rtCount) // Has not already traversed
// this network
&& IS_IF_ENABLED (dstIf) && ((dstIf->ICB_NetbiosDeliver==FWD_NB_DELIVER_ALL) || (dstIf->ICB_NetbiosDeliver ==FWD_NB_DELIVER_STATIC) || ((dstIf->ICB_NetbiosDeliver ==FWD_NB_DELIVER_IF_UP) && (dstIf->ICB_Stats.OperationalState ==FWD_OPER_STATE_UP)))) { NOTHING; } else { // We have static route, but can't send it,
// no point to propagate in on other interfaces
// as well
ReleaseInterfaceReference (dstIf); dstIf = NULL; goto FreePacket; } } else { // no static route
goto FindNextInterface; } } else { // not a brand new packet (already sent on some
// interfaces)
FindNextInterface:
// Loop through the interface list till we find
// the one on which we can send
while ((dstIf=GetNextInterfaceReference (dstIf))!=NULL) { // Check if we allowed to send on this interface
if (IS_IF_ENABLED (dstIf) && ((dstIf->ICB_NetbiosDeliver==FWD_NB_DELIVER_ALL) || ((dstIf->ICB_NetbiosDeliver ==FWD_NB_DELIVER_IF_UP) && (dstIf->ICB_Stats.OperationalState ==FWD_OPER_STATE_UP)))) { // Make sure the packet has not traversed
// this network already
for (i=0, netListPtr=dataPtr+IPXH_HDRSIZE; i<rtCount; i++,netListPtr+=4) { if (GETULONG (netListPtr)==dstIf->ICB_Network) break; } // Network was not in the list
if (i==rtCount) break; } } } // Save the destination interface in the packet
pktTag->PT_InterfaceReference = dstIf; // Go ahead and send if we have a valid destination
if (dstIf!=NULL) { SendPacket (dstIf, pktTag); // The rest does not apply: if the packet was sent or
// failed, it will be queued back to NetbiosQueue;
// if it was queued to interface to be connected,
// a copy of it will be queued to NetbiosQueue
continue; } // else no more destinations to send this packet on
} else { // Packet has to be destroyed
if (pktTag->PT_InterfaceReference!=NULL) ReleaseInterfaceReference (pktTag->PT_InterfaceReference); }
FreePacket: IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION, ("IpxFwd: No more interfaces for nb packet %08lx.\n", pktTag)); if (MeasuringPerformance && (pktTag->PT_PerfCounter!=0)) { LARGE_INTEGER PerfCounter = KeQueryPerformanceCounter (NULL); PerfCounter.QuadPart -= pktTag->PT_PerfCounter; KeAcquireSpinLock (&PerfCounterLock, &oldIRQL); PerfBlock.TotalNbPacketProcessingTime += PerfCounter.QuadPart; PerfBlock.NbPacketCounter += 1; if (PerfBlock.MaxNbPacketProcessingTime < PerfCounter.QuadPart) PerfBlock.MaxNbPacketProcessingTime = PerfCounter.QuadPart; KeReleaseSpinLock (&PerfCounterLock, oldIRQL); } if (!(pktTag->PT_Flags&PT_NB_DESTROY)) InterlockedIncrement (&NetbiosPacketsQuota); FreePacket (pktTag); } while (!IsListEmpty (&tempQueue));
KeAcquireSpinLock (&NetbiosQueueLock, &oldIRQL); if (IsListEmpty (&NetbiosQueue) || !EnterForwarder ()) { NetbiosWorkerScheduled = FALSE; } else { ExQueueWorkItem (&NetbiosWorker, DelayedWorkQueue); } } KeReleaseSpinLock (&NetbiosQueueLock, oldIRQL); LeaveForwarder (); }
/*++
******************************************************************* P r o c e s s N e t b i o s P a c k e t
Routine Description: Processes received netbios broadcast packet (checks network list and source filter, updates input statistics) Arguments: srcIf - interfae on which packet was received pktTag - netbios packet Return Value: None
******************************************************************* --*/ VOID ProcessNetbiosPacket ( PINTERFACE_CB srcIf, PPACKET_TAG pktTag ) { PUCHAR dataPtr, dataPtr2; UINT rtCount; UINT i, j; KIRQL oldIRQL; ULONG ulNetwork;
dataPtr = pktTag->PT_Data; rtCount = *(dataPtr+IPXH_XPORTCTL);
//
// pmay: 264339: Make sure valid networks are listed
//
// We used to only verify that the source network was not
// contained in the list. Now, we verify that 0 and 0xfffffff
// are also absent.
//
for (i = 0, dataPtr += IPXH_HDRSIZE; i < rtCount; i++, dataPtr += 4) { ulNetwork = GETULONG (dataPtr); if ((srcIf->ICB_Network == ulNetwork) || (ulNetwork == 0xffffffff) || (ulNetwork == 0x0)) { break; } }
//
// pmay: 272193
//
// nwlnknb on nt4 puts status bits into the first router slot in
// the type 20 payload. As a consequence, the router has to
// ignore the first slot when validating the router table so that nt4
// client bcasts aren't dropped at the router.
//
if (rtCount == 0) { j = 1; dataPtr2 = dataPtr + 4; } else { j = i; dataPtr2 = dataPtr; }
//
// pmay: 264331
//
// Make sure the rest of the networks listed are zero
//
for (; j < 8; j++, dataPtr2 += 4) { ulNetwork = GETULONG (dataPtr2); if (ulNetwork != 0x0) { break; } }
// We scaned the whole list and we haven't found it
if ((i == rtCount) && (j == 8)) { FILTER_ACTION action; action = FltFilter (pktTag->PT_Data, GETUSHORT (pktTag->PT_Data+IPXH_LENGTH), srcIf->ICB_FilterInContext, NULL); // Apply the input filter
if (action==FILTER_PERMIT) { InterlockedIncrement (&srcIf->ICB_Stats.NetbiosReceived); InterlockedIncrement (&srcIf->ICB_Stats.InDelivers); PUTULONG (srcIf->ICB_Network, dataPtr); *(pktTag->PT_Data+IPXH_XPORTCTL) += 1; IPX_NODE_CPY (pktTag->PT_Target.MacAddress, BROADCAST_NODE); // Initialize the packet
pktTag->PT_InterfaceReference = NULL; // not yet sent on any
// interfaces
pktTag->PT_Flags = 0; // No flags
QueueNetbiosPacket (pktTag); IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION, ("IpxFwd: Queued nb packet %08lx from if %ld.\n", pktTag, srcIf->ICB_Index)); } else { ASSERT (action==FILTER_DENY_IN); IpxFwdDbgPrint (DBG_NETBIOS, DBG_WARNING, ("IpxFwd: Filtered out nb packet %08lx" " from if %ld.\n", pktTag, srcIf->ICB_Index)); InterlockedIncrement (&NetbiosPacketsQuota); InterlockedIncrement (&srcIf->ICB_Stats.InFiltered); FreePacket (pktTag); } } else { IpxFwdDbgPrint (DBG_NETBIOS, DBG_WARNING, ("IpxFwd: Source net is already in nb packet %08lx" " from if %ld.\n", pktTag, srcIf->ICB_Index)); InterlockedIncrement (&NetbiosPacketsQuota); InterlockedIncrement (&srcIf->ICB_Stats.InDiscards); FreePacket (pktTag); } ReleaseInterfaceReference (srcIf);
}
/*++
******************************************************************* D e l e t e N e t b i o s Q u e u e
Routine Description: Deletes the netbios bradcast queue Arguments: None Return Value: None
******************************************************************* --*/ VOID DeleteNetbiosQueue ( void ) { while (!IsListEmpty (&NetbiosQueue)) { PPACKET_TAG pktTag = CONTAINING_RECORD (NetbiosQueue.Flink, PACKET_TAG, PT_QueueLink); RemoveEntryList (&pktTag->PT_QueueLink); if (pktTag->PT_InterfaceReference!=NULL) { ReleaseInterfaceReference (pktTag->PT_InterfaceReference); } FreePacket (pktTag); } }
|