summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/isn/fwd/send.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/tdi/isn/fwd/send.c')
-rw-r--r--private/ntos/tdi/isn/fwd/send.c1253
1 files changed, 1253 insertions, 0 deletions
diff --git a/private/ntos/tdi/isn/fwd/send.c b/private/ntos/tdi/isn/fwd/send.c
new file mode 100644
index 000000000..35c3ea2d6
--- /dev/null
+++ b/private/ntos/tdi/isn/fwd/send.c
@@ -0,0 +1,1253 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ntos\tdi\isn\fwd\send.c
+
+Abstract:
+ Send routines
+
+Author:
+
+ Vadim Eydelman
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+
+
+ULONG SpoofingTimeout=DEF_SPOOFING_TIMEOUT;
+LIST_ENTRY SpoofingQueue;
+KSPIN_LOCK SpoofingQueueLock;
+WORK_QUEUE_ITEM SpoofingWorker;
+BOOLEAN SpoofingWorkerActive = FALSE;
+ULONG DontSuppressNonAgentSapAdvertisements = 0;
+
+#define IsLocalSapNonAgentAdvertisement(hdr,data,ln,ifCB) ( \
+ (DontSuppressNonAgentSapAdvertisements==0) \
+ && (GETUSHORT(hdr+IPXH_DESTSOCK)==IPX_SAP_SOCKET) \
+ && (GETUSHORT(hdr+IPXH_SRCSOCK)!=IPX_SAP_SOCKET) \
+ && (ln>=IPXH_HDRSIZE+2) \
+ && (GETUSHORT(data)==2) \
+ && ((IPX_NODE_CMP(hdr+IPXH_DESTNODE,BROADCAST_NODE)==0) \
+ || (IPX_NODE_CMP(hdr+IPXH_DESTNODE,ifCB->ICB_RemoteNode)==0)) \
+)
+
+/*++
+*******************************************************************
+ D o S e n d
+
+Routine Description:
+ Prepares and sends packet. Interface lock must be help while
+ callin this routine
+Arguments:
+ dstIf - over which interface to send
+ pktTag - packet to send
+Return Value:
+ result returned by IPX
+
+*******************************************************************
+--*/
+NDIS_STATUS
+DoSend (
+ PINTERFACE_CB dstIf,
+ PPACKET_TAG pktTag,
+ KIRQL oldIRQL
+ ) {
+ NDIS_STATUS status;
+ PNDIS_PACKET pktDscr;
+ PNDIS_BUFFER bufDscr, aDscr;
+ UINT dataLen;
+ ULONG dstNet = GETULONG (pktTag->PT_Data+IPXH_DESTNET);
+
+ if (dstIf!=InternalInterface) {
+ ADAPTER_CONTEXT_TO_LOCAL_TARGET (dstIf->ICB_AdapterContext,
+ &pktTag->PT_Target);
+ }
+ else {
+ CONSTANT_ADAPTER_CONTEXT_TO_LOCAL_TARGET (
+ VIRTUAL_NET_ADAPTER_CONTEXT,
+ &pktTag->PT_Target);
+ }
+
+#if DBG
+ // Keep track of packets being processed by IPX stack
+ InsertTailList (&dstIf->ICB_InSendQueue, &pktTag->PT_QueueLink);
+#endif
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+
+ if (pktTag->PT_Flags&PT_SOURCE_IF)
+ ReleaseInterfaceReference (pktTag->PT_SourceIf);
+ pktTag->SEND_RESERVED[0] = pktTag->SEND_RESERVED[1] = 0;
+ pktDscr = CONTAINING_RECORD(pktTag, NDIS_PACKET, ProtocolReserved);
+ NdisQueryPacket(pktDscr, NULL, NULL, &bufDscr, NULL);
+#if DBG
+ { // Verify packet integrity
+ PUCHAR dataPtr;
+ UINT bufLen;
+ ASSERT (NDIS_BUFFER_LINKAGE (bufDscr)==NULL);
+ NdisQueryBuffer (bufDscr, &dataPtr, &bufLen);
+ ASSERT (dataPtr==pktTag->PT_Data);
+ ASSERT (bufLen==pktTag->PT_Segment->PS_SegmentList->SL_BlockSize);
+ }
+#endif
+ // Prepare packet for IPX stack (mac header buffer goes in
+ // front and packet length adjusted to reflect the size of the data
+ dataLen = GETUSHORT(pktTag->PT_Data+IPXH_LENGTH);
+ NdisAdjustBufferLength(bufDscr, dataLen);
+ NdisChainBufferAtFront(pktDscr, pktTag->PT_MacHdrBufDscr);
+
+
+ if (EnterForwarder ()) {// To make sure that we won't unload
+ // until IPX driver has a chance to call us back
+ status = IPXSendProc (&pktTag->PT_Target, pktDscr, dataLen, 0);
+
+ if (status!=NDIS_STATUS_PENDING) {
+ LeaveForwarder (); // No callback
+
+ // Restore original packet structure
+ NdisUnchainBufferAtFront (pktDscr, &aDscr);
+#if DBG
+ // Make sure IPX stack did not mess our packet
+ ASSERT (aDscr==pktTag->PT_MacHdrBufDscr);
+ NdisQueryPacket(pktDscr, NULL, NULL, &aDscr, NULL);
+ ASSERT (aDscr==bufDscr);
+ ASSERT (NDIS_BUFFER_LINKAGE (aDscr)==NULL);
+#endif
+ // Restore original packet size
+ NdisAdjustBufferLength(bufDscr,
+ pktTag->PT_Segment->PS_SegmentList->SL_BlockSize);
+#if DBG
+ // Remove packet from temp queue
+ KeAcquireSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, &oldIRQL);
+ RemoveEntryList (&pktTag->PT_QueueLink);
+ KeReleaseSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, oldIRQL);
+#endif
+ }
+ }
+ else {
+ // We are going down, restore the packet
+ NdisUnchainBufferAtFront (pktDscr, &aDscr);
+ NdisAdjustBufferLength(bufDscr,
+ pktTag->PT_Segment->PS_SegmentList->SL_BlockSize);
+ NdisRecalculatePacketCounts (pktDscr);
+ status = STATUS_UNSUCCESSFUL;
+#if DBG
+ KeAcquireSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, &oldIRQL);
+ RemoveEntryList (&pktTag->PT_QueueLink);
+ KeReleaseSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, oldIRQL);
+#endif
+ }
+ return status;
+}
+
+
+/*++
+*******************************************************************
+ P r o c e s s S e n t P a c k e t
+
+Routine Description:
+ Process completed sent packets
+Arguments:
+ dstIf - interface over which packet was sent
+ pktTag - completed packet
+ status - result of send operation
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+ProcessSentPacket (
+ PINTERFACE_CB dstIf,
+ PPACKET_TAG pktTag,
+ NDIS_STATUS status
+ ) {
+ KIRQL oldIRQL;
+
+ // Packet processing is completed -> can take more packets
+ InterlockedIncrement (&dstIf->ICB_PendingQuota);
+
+ if (*(pktTag->PT_Data+IPXH_PKTTYPE) == IPX_NETBIOS_TYPE) {
+ // Continue processing netbios packets
+ if (status==NDIS_STATUS_SUCCESS) {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: NB Packet %08lx sent.", pktTag));
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDelivers);
+ InterlockedIncrement (&dstIf->ICB_Stats.NetbiosSent);
+ }
+ else {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_ERROR,
+ ("IpxFwd: NB Packet %08lx send failed with error: %08lx.\n",
+ pktTag, status));
+ }
+ // Queue nb packet for further processing (broadcast on all interfaces)
+ QueueNetbiosPacket (pktTag);
+ }
+ else {
+ // Destroy completed packet
+ if (status==NDIS_STATUS_SUCCESS) {
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDelivers);
+ IpxFwdDbgPrint (DBG_SEND, DBG_INFORMATION,
+ ("IpxFwd: Packet %08lx sent.", pktTag));
+ }
+ else {
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
+ IpxFwdDbgPrint (DBG_SEND, DBG_ERROR,
+ ("IpxFwd: Packet %08lx send failed with error: %08lx.\n",
+ pktTag, status));
+ }
+ ReleaseInterfaceReference (dstIf);
+ if (MeasuringPerformance
+ && (pktTag->PT_PerfCounter!=0)) {
+ LARGE_INTEGER PerfCounter = KeQueryPerformanceCounter (NULL);
+ PerfCounter.QuadPart -= pktTag->PT_PerfCounter;
+ KeAcquireSpinLock (&PerfCounterLock, &oldIRQL);
+ ASSERT (PerfCounter.QuadPart<ActivityTreshhold);
+ PerfBlock.TotalPacketProcessingTime += PerfCounter.QuadPart;
+ PerfBlock.PacketCounter += 1;
+ if (PerfBlock.MaxPacketProcessingTime < PerfCounter.QuadPart)
+ PerfBlock.MaxPacketProcessingTime = PerfCounter.QuadPart;
+ KeReleaseSpinLock (&PerfCounterLock, oldIRQL);
+ }
+ FreePacket (pktTag);
+ }
+}
+
+/*++
+*******************************************************************
+ S e n d P a c k e t
+
+Routine Description:
+ Enqueues packets to be sent by IPX stack
+Arguments:
+ dstIf - over which interface to send
+ pktTag - packet to send
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+SendPacket (
+ PINTERFACE_CB dstIf,
+ PPACKET_TAG pktTag
+ ) {
+ NDIS_STATUS status;
+ KIRQL oldIRQL;
+
+
+ ASSERT (dstIf->ICB_Index!=FWD_INTERNAL_INTERFACE_INDEX);
+ // Make sure we have not exceded the quota of pending packets on the interface
+ if (InterlockedDecrement (&dstIf->ICB_PendingQuota)>=0) {
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ // Decide what to do with the packet based on the interface state
+ switch (dstIf->ICB_Stats.OperationalState) {
+ case FWD_OPER_STATE_UP:
+ if (*(pktTag->PT_Data + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
+ NOTHING;
+ else {
+ PUTULONG (dstIf->ICB_Network, pktTag->PT_Data+IPXH_DESTNET);
+ }
+ status = DoSend (dstIf, pktTag, oldIRQL);
+ IpxFwdDbgPrint (DBG_SEND, DBG_INFORMATION,
+ ("IpxFwd: Sent external packet %08lx on if %ld.\n",
+ pktTag, dstIf->ICB_Index));
+ break;
+ case FWD_OPER_STATE_SLEEPING:
+ if ((*(pktTag->PT_Data+IPXH_PKTTYPE)!=0)
+ || (GETUSHORT(pktTag->PT_Data+IPXH_LENGTH)!=IPXH_HDRSIZE+2)
+ || (*(pktTag->PT_Data+IPXH_HDRSIZE+1)!='?')) {
+ // Queue this packet on the interface until it is connected
+ // by Router Manager (DIM) if this is not a NCP keepalive
+ // (watchdog)
+ InsertTailList (&dstIf->ICB_ExternalQueue, &pktTag->PT_QueueLink);
+ if (!IS_IF_CONNECTING (dstIf)) {
+ // Ask for connection if interface is not in the connection
+ // queue yet
+ QueueConnectionRequest (dstIf,
+ CONTAINING_RECORD (pktTag,
+ NDIS_PACKET,
+ ProtocolReserved),
+ pktTag->PT_Data,
+ oldIRQL);
+ IpxFwdDbgPrint (DBG_DIALREQS, DBG_WARNING,
+ ("IpxFwd: Queued dd request on if %ld (ifCB:%08lx)"
+ " for packet to %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%02x%02x"
+ " from %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%02x%02x\n",
+ dstIf->ICB_Index, dstIf,
+ *(pktTag->PT_Data+6),*(pktTag->PT_Data+7),
+ *(pktTag->PT_Data+8),*(pktTag->PT_Data+9),
+ *(pktTag->PT_Data+10),*(pktTag->PT_Data+11),
+ *(pktTag->PT_Data+12),*(pktTag->PT_Data+13),
+ *(pktTag->PT_Data+14),*(pktTag->PT_Data+15),
+ *(pktTag->PT_Data+16),*(pktTag->PT_Data+17),
+ *(pktTag->PT_Data+18),*(pktTag->PT_Data+19),
+ *(pktTag->PT_Data+20),*(pktTag->PT_Data+21),
+ *(pktTag->PT_Data+22),*(pktTag->PT_Data+23),
+ *(pktTag->PT_Data+24),*(pktTag->PT_Data+25),
+ *(pktTag->PT_Data+26),*(pktTag->PT_Data+27),
+ *(pktTag->PT_Data+28),*(pktTag->PT_Data+29)));
+ }
+ else
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ IpxFwdDbgPrint (DBG_SEND, DBG_INFORMATION,
+ ("IpxFwd: Queued external packet %08lx on if %ld.\n",
+ pktTag, dstIf->ICB_Index));
+ if (*(pktTag->PT_Data + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
+ NOTHING;
+ else if (!(pktTag->PT_Flags&PT_NB_DESTROY)) {
+ // If this nb packet is not to be destroyed after this
+ // send, we have to make a copy of it to send on
+ // other interfaces while the original is waiting
+ // for connection
+ PPACKET_TAG newPktTag;
+ DuplicatePacket (pktTag, newPktTag);
+ if (newPktTag!=NULL) {
+ UINT bytesCopied;
+ PNDIS_PACKET packet = CONTAINING_RECORD (pktTag,
+ NDIS_PACKET,
+ ProtocolReserved);
+ PNDIS_PACKET newPacket = CONTAINING_RECORD (newPktTag,
+ NDIS_PACKET,
+ ProtocolReserved);
+ NdisCopyFromPacketToPacket (newPacket, 0,
+ GETUSHORT(pktTag->PT_Data+IPXH_LENGTH),
+ packet, 0, &bytesCopied);
+
+ ASSERT (bytesCopied==GETUSHORT(pktTag->PT_Data+IPXH_LENGTH));
+ IpxFwdDbgPrint (DBG_NETBIOS,
+ DBG_INFORMATION,
+ ("IpxFwd: Duplicated queued nb packet"
+ " %08lx -> %08lx on if %ld.\n",
+ pktTag, newPktTag, dstIf->ICB_Index));
+ AcquireInterfaceReference (dstIf);
+ newPktTag->PT_InterfaceReference = dstIf;
+ newPktTag->PT_PerfCounter = pktTag->PT_PerfCounter;
+ QueueNetbiosPacket (newPktTag);
+ // The original copy will have to be
+ // destroyed after it is sent on the
+ // connected interface
+ pktTag->PT_Flags |= PT_NB_DESTROY;
+ }
+ }
+ status = NDIS_STATUS_PENDING;
+ break;
+ }
+ else { // Process keepalives
+ LONGLONG curTime;
+ KeQuerySystemTime ((PLARGE_INTEGER)&curTime);
+ if (((curTime-dstIf->ICB_DisconnectTime)/10000000) < SpoofingTimeout) {
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ IpxFwdDbgPrint (DBG_SPOOFING, DBG_INFORMATION,
+ ("IpxFwd: Queueing reply to keepalive from server"
+ " on if %ld (ifCB %lx)"
+ " at %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%02x%02x.\n",
+ dstIf->ICB_Index, dstIf,
+ *(pktTag->PT_Data+IPXH_SRCNET),*(pktTag->PT_Data+IPXH_SRCNET+1),
+ *(pktTag->PT_Data+IPXH_SRCNET+2),*(pktTag->PT_Data+IPXH_SRCNET+3),
+ *(pktTag->PT_Data+IPXH_SRCNODE),*(pktTag->PT_Data+IPXH_SRCNODE+1),
+ *(pktTag->PT_Data+IPXH_SRCNODE+2),*(pktTag->PT_Data+IPXH_SRCNODE+3),
+ *(pktTag->PT_Data+IPXH_SRCNODE+4),*(pktTag->PT_Data+IPXH_SRCNODE+5),
+ *(pktTag->PT_Data+IPXH_SRCSOCK),*(pktTag->PT_Data+IPXH_SRCNODE+1)));
+ // Spoof the packet if timeout has not been exceeded
+ KeAcquireSpinLock (&SpoofingQueueLock, &oldIRQL);
+ InsertTailList (&SpoofingQueue, &pktTag->PT_QueueLink);
+ if (!SpoofingWorkerActive
+ && EnterForwarder()) {
+ SpoofingWorkerActive = TRUE;
+ ExQueueWorkItem (&SpoofingWorker, DelayedWorkQueue);
+ }
+ KeReleaseSpinLock (&SpoofingQueueLock, oldIRQL);
+ // We will actually send this packet though
+ // in other direction, so mark it as pending
+ // to prevent ProcessSentPacket to be called
+ status = NDIS_STATUS_PENDING;
+ break;
+ }
+ // else don't spoof (fall through and fail the packet)
+ }
+ case FWD_OPER_STATE_DOWN:
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ status = NDIS_STATUS_ADAPTER_NOT_READY;
+ IpxFwdDbgPrint (DBG_SEND, DBG_WARNING,
+ ("IpxFwd: Failed external packet %08lx on if %ld(down?).\n",
+ pktTag, dstIf->ICB_Index));
+ break;
+ default:
+ ASSERTMSG ("Invalid operational state ", FALSE);
+ }
+ }
+ else {
+ IpxFwdDbgPrint (DBG_SEND, DBG_WARNING,
+ ("IpxFwd: Could not send packet %08lx on if %ld (quota exceeded).\n",
+ pktTag, dstIf->ICB_Index));
+ status = NDIS_STATUS_RESOURCES;
+ }
+
+ if (status!=NDIS_STATUS_PENDING)
+ ProcessSentPacket (dstIf, pktTag, status);
+}
+
+/*++
+*******************************************************************
+ F w S e n d C o m p l e t e
+
+Routine Description:
+ Called by IPX stack when send completes asynchronously
+Arguments:
+ pktDscr - descriptor of the completed packet
+ status - result of send operation
+Return Value:
+ None
+
+*******************************************************************
+--*/
+VOID
+IpxFwdSendComplete (
+ PNDIS_PACKET pktDscr,
+ NDIS_STATUS status
+ ) {
+ PPACKET_TAG pktTag;
+ PNDIS_BUFFER bufDscr;
+
+ pktTag = (PPACKET_TAG)pktDscr->ProtocolReserved;
+
+ NdisUnchainBufferAtFront (pktDscr, &bufDscr);
+ ASSERT (bufDscr==pktTag->PT_MacHdrBufDscr);
+
+ NdisQueryPacket(pktDscr,
+ NULL,
+ NULL,
+ &bufDscr,
+ NULL);
+ NdisAdjustBufferLength(bufDscr,
+ pktTag->PT_Segment->PS_SegmentList->SL_BlockSize);
+ NdisRecalculatePacketCounts (pktDscr);
+#if DBG
+ {
+ KIRQL oldIRQL;
+ KeAcquireSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, &oldIRQL);
+ RemoveEntryList (&pktTag->PT_QueueLink);
+ KeReleaseSpinLock (&pktTag->PT_InterfaceReference->ICB_Lock, oldIRQL);
+ }
+#endif
+ ProcessSentPacket (pktTag->PT_InterfaceReference, pktTag, status);
+ LeaveForwarder (); // Entered before calling IpxSendPacket
+}
+
+
+/*++
+*******************************************************************
+
+ F w I n t e r n a l S e n d
+
+Routine Description:
+ Filter and routes packets sent by IPX stack
+Arguments:
+ LocalTarget - the NicId and next hop router MAC address
+ Context - preferred interface on which to send
+ Packet - packet to be sent
+ ipxHdr - pointer to ipx header inside the packet
+ PacketLength - length of the packet
+ fIterate - a flag to indicate if this is a packet for the
+ iteration of which the Fwd takes responsibility
+ - typically type 20 NetBIOS frames
+Return Value:
+
+ STATUS_SUCCESS - if the preferred NIC was OK and packet passed filtering
+ STATUS_NETWORK_UNREACHABLE - if the preferred was not OK or packet failed filtering
+ STATUS_PENDING - packet was queued until connection is established
+*******************************************************************
+--*/
+NTSTATUS
+IpxFwdInternalSend (
+ IN OUT PIPX_LOCAL_TARGET LocalTarget,
+ IN ULONG Context,
+ IN PNDIS_PACKET pktDscr,
+ IN PUCHAR ipxHdr,
+ IN PUCHAR data,
+ IN ULONG PacketLength,
+ IN BOOLEAN fIterate
+ ) {
+ PINTERFACE_CB dstIf = NULL, // Initialized to indicate
+ // first path through the iteration
+ // as well as the fact the we do not
+ // know it initially
+ stDstIf; // Static destination for
+ // NetBIOS names
+ PFWD_ROUTE fwRoute = NULL;
+ ULONG dstNet;
+ USHORT dstSock;
+ NTSTATUS status;
+
+ if (!EnterForwarder())
+ return STATUS_NETWORK_UNREACHABLE;
+
+ if (IS_IF_ENABLED(InternalInterface)
+ && ((*(ipxHdr+IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
+ || InternalInterface->ICB_NetbiosAccept)) {
+
+ do { // Big loop used to iterate over interfaces
+ status = STATUS_SUCCESS; // Assume success
+ if (!fIterate) {
+ dstNet = GETULONG (ipxHdr+IPXH_DESTNET);
+
+ if (Context!=INVALID_CONTEXT_VALUE) {
+ if (Context!=VIRTUAL_NET_FORWARDER_CONTEXT) {
+ // IPX driver supplied interface context, just verify that it
+ // exists and can be used to reach the destination network
+ dstIf = InterfaceContextToReference ((PVOID)Context,
+ LocalTarget->NicId);
+ }
+ else {
+ dstIf = InternalInterface;
+ AcquireInterfaceReference (dstIf);
+ }
+ if (dstIf!=NULL) {
+ // It does exist
+ // First process direct connections
+ if ((dstNet==0)
+ || (dstNet==dstIf->ICB_Network)) {
+ NOTHING;
+ }
+ else { // Network is not connected directly
+ PINTERFACE_CB dstIf2;
+ // Verify the route
+ dstIf2 = FindDestination (dstNet,
+ ipxHdr+IPXH_DESTNODE,
+ &fwRoute);
+ if (dstIf==dstIf2) {
+ // Route OK, release the extra interface reference
+ ReleaseInterfaceReference (dstIf2);
+ }
+ else {
+ // Route not OK, release interface/route references
+ InterlockedIncrement (&InternalInterface->ICB_Stats.InNoRoutes);
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
+ ("IpxFwd: Failed direct internal send on"
+ " if %ld to %08lx:%02x%02x%02x%02x%02x%02x"
+ " (no route).\n",
+ dstIf->ICB_Index, dstNet,
+ LocalTarget->MacAddress[0],
+ LocalTarget->MacAddress[1],
+ LocalTarget->MacAddress[2],
+ LocalTarget->MacAddress[3],
+ LocalTarget->MacAddress[4],
+ LocalTarget->MacAddress[5]));
+ if (dstIf2!=NULL) {
+ ReleaseInterfaceReference (dstIf2);
+ }
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ }
+ }
+ }
+ else {
+ InterlockedIncrement (&InternalInterface->ICB_Stats.InDiscards);
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
+ ("IpxFwd: Invalid interface context (%08lx)"
+ " from IPX driver on internal send to"
+ " %08lx:%02x%02x%02x%02x%02x%02x.\n",
+ Context, dstNet,
+ LocalTarget->MacAddress[0],
+ LocalTarget->MacAddress[1],
+ LocalTarget->MacAddress[2],
+ LocalTarget->MacAddress[3],
+ LocalTarget->MacAddress[4],
+ LocalTarget->MacAddress[5]));
+ status = STATUS_NO_SUCH_DEVICE;
+ break;
+ }
+ }
+ else {// No interface context supplied by IPX driver, have to find the route
+ dstIf = FindDestination (dstNet, ipxHdr+IPXH_DESTNODE,
+ &fwRoute);
+ if (dstIf!=NULL)
+ NOTHING;
+ else {
+ InterlockedIncrement (&InternalInterface->ICB_Stats.InNoRoutes);
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
+ ("IpxFwd: Failed internal send because no route to"
+ " %08lx:%02x%02x%02x%02x%02x%02x exists.\n",
+ LocalTarget->MacAddress[0],
+ LocalTarget->MacAddress[1],
+ LocalTarget->MacAddress[2],
+ LocalTarget->MacAddress[3],
+ LocalTarget->MacAddress[4],
+ LocalTarget->MacAddress[5]));
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ }
+ }
+ InterlockedIncrement (&InternalInterface->ICB_Stats.InDelivers);
+ }
+ else { // Iterative sends
+ dstNet = 0; // Don't care, it must be a local send
+ if (*(ipxHdr+IPXH_PKTTYPE) == IPX_NETBIOS_TYPE) {
+ if (dstIf==NULL) { // First time through internal loop
+ dstSock = GETUSHORT (ipxHdr+IPXH_DESTSOCK);
+
+ // See if we can get a static route for this packet
+ if (dstSock==IPX_NETBIOS_SOCKET)
+ stDstIf = FindNBDestination (data+(NB_NAME-IPXH_HDRSIZE));
+ else if (dstSock==IPX_SMB_NAME_SOCKET)
+ stDstIf = FindNBDestination (data+(SMB_NAME-IPXH_HDRSIZE));
+ else
+ stDstIf = NULL;
+ }
+
+ if ((Context==INVALID_CONTEXT_VALUE) && (dstIf==NULL)) {
+ // First time through the loop, increment counters
+ InterlockedIncrement (&InternalInterface->ICB_Stats.InDelivers);
+ InterlockedIncrement (&InternalInterface->ICB_Stats.NetbiosSent);
+
+ if (stDstIf!=NULL) {
+ dstIf = stDstIf;
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: Allowed internal NB broadcast (1st iteration) on if %d (%lx)"
+ " to static name %.16s.\n",
+ dstIf->ICB_Index, dstIf,
+ (dstSock==IPX_NETBIOS_SOCKET)
+ ? data+(NB_NAME-IPXH_HDRSIZE)
+ : ((dstSock==IPX_SMB_NAME_SOCKET)
+ ? data+(SMB_NAME-IPXH_HDRSIZE)
+ : "Not a name frame")
+ ));
+ }
+ else { // No static route
+ dstIf = GetNextInterfaceReference (NULL);
+ if (dstIf!=NULL)
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: Allowed internal nb broadcast (1st iteration) on if %d (%lx),"
+ " to name %.16s.\n",
+ dstIf->ICB_Index, dstIf,
+ (dstSock==IPX_NETBIOS_SOCKET)
+ ? data+(NB_NAME-IPXH_HDRSIZE)
+ : ((dstSock==IPX_SMB_NAME_SOCKET)
+ ? data+(SMB_NAME-IPXH_HDRSIZE)
+ : "Not a name frame")
+ ));
+ else {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: Nb broadcast no destinations"
+ " to name %.16s.\n",
+ (dstSock==IPX_NETBIOS_SOCKET)
+ ? data+(NB_NAME-IPXH_HDRSIZE)
+ : ((dstSock==IPX_SMB_NAME_SOCKET)
+ ? data+(SMB_NAME-IPXH_HDRSIZE)
+ : "Not a name frame")
+ ));
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ }
+ }
+ }
+ else {
+ // N-th iteration
+ if (stDstIf==NULL) {
+ if (dstIf==NULL)
+ dstIf = InterfaceContextToReference ((PVOID)Context,
+ LocalTarget->NicId);
+ dstIf = GetNextInterfaceReference (dstIf);
+ if (dstIf!=NULL) {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: Allowed internal NB broadcast (1+ iteration)"
+ " on if %d (%lx, ctx: %08lx, nic: %d)"
+ " to name %.16s.\n",
+ dstIf->ICB_Index, dstIf,
+ Context, LocalTarget->NicId,
+ (dstSock==IPX_NETBIOS_SOCKET)
+ ? data+(NB_NAME-IPXH_HDRSIZE)
+ : ((dstSock==IPX_SMB_NAME_SOCKET)
+ ? data+(SMB_NAME-IPXH_HDRSIZE)
+ : "Not a name frame")
+ ));
+ }
+ else {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: NB broadcast no more iterations"
+ " for ctx: %08lx, nic: %d"
+ " to name %.16s.\n",
+ Context, LocalTarget->NicId,
+ (dstSock==IPX_NETBIOS_SOCKET)
+ ? data+(NB_NAME-IPXH_HDRSIZE)
+ : ((dstSock==IPX_SMB_NAME_SOCKET)
+ ? data+(SMB_NAME-IPXH_HDRSIZE)
+ : "Not a name frame")
+ ));
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ }
+ }
+ else {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: Static NB broadcast (1+ iteration)"
+ " on if %d (%lx, ctx: %08lx, nic: %d)"
+ " to name %.16s.\n",
+ stDstIf->ICB_Index, stDstIf,
+ Context, LocalTarget->NicId,
+ (dstSock==IPX_NETBIOS_SOCKET)
+ ? data+(NB_NAME-IPXH_HDRSIZE)
+ : ((dstSock==IPX_SMB_NAME_SOCKET)
+ ? data+(SMB_NAME-IPXH_HDRSIZE)
+ : "Not a name frame")
+ ));
+ ReleaseInterfaceReference (stDstIf);
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ }
+ }
+ }
+ else {
+ if ((dstIf==NULL)
+ && (Context!=INVALID_CONTEXT_VALUE))
+ dstIf = InterfaceContextToReference ((PVOID)Context,
+ LocalTarget->NicId);
+ dstIf = GetNextInterfaceReference (dstIf);
+ if (dstIf!=NULL) {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: Allowed internal iterative send"
+ " on if %d (%lx, ctx: %08lx, nic: %d)"
+ " to %02x%02x%02x%02x%02x%02x.\n",
+ dstIf->ICB_Index, dstIf,
+ Context, LocalTarget->NicId,
+ LocalTarget->MacAddress[0],
+ LocalTarget->MacAddress[1],
+ LocalTarget->MacAddress[2],
+ LocalTarget->MacAddress[3],
+ LocalTarget->MacAddress[4],
+ LocalTarget->MacAddress[5]));
+
+ }
+ else {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_INFORMATION,
+ ("IpxFwd: No destinations to internal iterative send"
+ " for ctx: %08lx, nic: %d"
+ " to %02x%02x%02x%02x%02x%02x.\n",
+ Context, LocalTarget->NicId,
+ LocalTarget->MacAddress[0],
+ LocalTarget->MacAddress[1],
+ LocalTarget->MacAddress[2],
+ LocalTarget->MacAddress[3],
+ LocalTarget->MacAddress[4],
+ LocalTarget->MacAddress[5]));
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ }
+ }
+
+ } // End iterative send processing
+
+ // We were able to find a destination interface
+ if (IS_IF_ENABLED (dstIf)
+ && ((*(ipxHdr+IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
+ || (dstIf->ICB_NetbiosDeliver==FWD_NB_DELIVER_ALL)
+ || ((dstIf->ICB_NetbiosDeliver==FWD_NB_DELIVER_IF_UP)
+ && (dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP))
+ || ((stDstIf!=NULL)
+ && (dstIf->ICB_NetbiosDeliver==FWD_NB_DELIVER_STATIC)))) {
+ KIRQL oldIRQL;
+ FILTER_ACTION action;
+
+ // In/Out filter check and statistics update
+
+ action = FltFilter (ipxHdr, IPXH_HDRSIZE,
+ InternalInterface->ICB_FilterInContext,
+ dstIf->ICB_FilterOutContext);
+ if (action==FILTER_PERMIT) {
+ NOTHING;
+ }
+ else {
+ InterlockedIncrement (&dstIf->ICB_Stats.OutFiltered);
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ }
+
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ // All set, try to send now
+ switch (dstIf->ICB_Stats.OperationalState) {
+ case FWD_OPER_STATE_UP:
+ // Interface is up, let it go right away
+ // Set NIC ID
+ if (dstIf!=InternalInterface) {
+ ADAPTER_CONTEXT_TO_LOCAL_TARGET (
+ dstIf->ICB_AdapterContext,
+ LocalTarget);
+ }
+ else {
+ CONSTANT_ADAPTER_CONTEXT_TO_LOCAL_TARGET (
+ VIRTUAL_NET_ADAPTER_CONTEXT,
+ LocalTarget);
+ }
+ // Set destination node
+ if (IsLocalSapNonAgentAdvertisement (ipxHdr,data,PacketLength,dstIf)) {
+ // Loop back sap ads from non-sap socket
+ IPX_NODE_CPY (&LocalTarget->MacAddress,
+ dstIf->ICB_LocalNode);
+ }
+ else if ((dstNet==0) || (dstNet==dstIf->ICB_Network)) {
+ // Direct connection: send to destination specified
+ // in the header
+ IPX_NODE_CPY (LocalTarget->MacAddress,
+ ipxHdr+IPXH_DESTNODE);
+ }
+ else { // Indirect connection: send to next hop router
+ if (dstIf->ICB_InterfaceType==FWD_IF_PERMANENT) {
+ ASSERT (fwRoute!=NULL);
+ IPX_NODE_CPY (LocalTarget->MacAddress,
+ fwRoute->FR_NextHopAddress);
+ }
+ else {
+ // Only one peer on the other side
+ IPX_NODE_CPY (LocalTarget->MacAddress,
+ dstIf->ICB_RemoteNode);
+ }
+ }
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ // Update statistics
+ InterlockedIncrement (
+ &dstIf->ICB_Stats.OutDelivers);
+ if (*(ipxHdr+IPXH_PKTTYPE)==IPX_NETBIOS_TYPE)
+ InterlockedIncrement (
+ &dstIf->ICB_Stats.NetbiosSent);
+
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_INFORMATION,
+ ("IpxFwd: Allowed internal send:"
+ " %ld-%08lx:%02x%02x%02x%02x%02x%02x.\n",
+ dstIf->ICB_Index, dstNet,
+ LocalTarget->MacAddress[0],
+ LocalTarget->MacAddress[1],
+ LocalTarget->MacAddress[2],
+ LocalTarget->MacAddress[3],
+ LocalTarget->MacAddress[4],
+ LocalTarget->MacAddress[5]));
+ // status = STATUS_SUCCESS; // Let it go
+ break;
+ case FWD_OPER_STATE_SLEEPING:
+ // Interface is disconnected, queue the packet and try to connecte
+ if ((*(ipxHdr+IPXH_PKTTYPE)!=0)
+ || (*(ipxHdr+IPXH_LENGTH)!=IPXH_HDRSIZE+2)
+ || (*(data+1)!='?')) {
+ // Not a keep-alive packet,
+ if (((*(ipxHdr+IPXH_PKTTYPE)!=IPX_NETBIOS_TYPE))
+ || (dstIf->ICB_NetbiosDeliver!=FWD_NB_DELIVER_IF_UP)) {
+ // Not a netbios broadcast or we are allowed to connect
+ // the interface to deliver netbios broadcasts
+ if (InterlockedDecrement (&dstIf->ICB_PendingQuota)>=0) {
+ PINTERNAL_PACKET_TAG pktTag;
+ // Create a queue element to enqueue the packet
+ pktTag = (PINTERNAL_PACKET_TAG)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (INTERNAL_PACKET_TAG),
+ FWD_POOL_TAG);
+ if (pktTag!=NULL) {
+ pktTag->IPT_Packet = pktDscr;
+ pktTag->IPT_Length = PacketLength;
+ pktTag->IPT_DataPtr = ipxHdr;
+ // Save next hop address if after connection is
+ // established we determine that destination net
+ // is not connected directly
+ if (fwRoute!=NULL)
+ IPX_NODE_CPY (pktTag->IPT_Target.MacAddress,
+ fwRoute->FR_NextHopAddress);
+ AcquireInterfaceReference (dstIf); // To make sure interface
+ // block won't go away until we are done with
+ // the packet
+ pktTag->IPT_InterfaceReference = dstIf;
+ InsertTailList (&dstIf->ICB_InternalQueue,
+ &pktTag->IPT_QueueLink);
+ if (!IS_IF_CONNECTING (dstIf)) {
+ QueueConnectionRequest (dstIf, pktDscr, ipxHdr, oldIRQL);
+ IpxFwdDbgPrint (DBG_DIALREQS, DBG_WARNING,
+ ("IpxFwd: Queued dd request on if %ld (ifCB:%08lx)"
+ " for internal packet"
+ " to %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%02x%02x"
+ " from socket:%02x%02x\n",
+ dstIf->ICB_Index, dstIf,
+ *(ipxHdr+6),*(ipxHdr+7),
+ *(ipxHdr+8),*(ipxHdr+9),
+ *(ipxHdr+10),*(ipxHdr+11),
+ *(ipxHdr+12),*(ipxHdr+13),
+ *(ipxHdr+14),*(ipxHdr+15),
+ *(ipxHdr+16),*(ipxHdr+17),
+ *(ipxHdr+28),*(ipxHdr+29)));
+ }
+ else
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_INFORMATION,
+ ("IpxFwd: Queueing internal send packet %08lx on if %ld.\n",
+ pktTag, dstIf->ICB_Index));
+ status = STATUS_PENDING;
+ break;
+ }
+ else {
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_ERROR,
+ ("IpxFwd: Could not allocate"
+ " internal packet tag.\n"));
+ }
+ }
+ InterlockedIncrement (&dstIf->ICB_PendingQuota);
+ }
+ else {
+ IpxFwdDbgPrint (DBG_NETBIOS, DBG_WARNING,
+ ("IpxFwd: Droped internal NB packet"
+ " because FWD_NB_DELIVER_IF_UP.\n"));
+ }
+ }
+ else { // Process keep-alives
+ LONGLONG curTime;
+ KeQuerySystemTime ((PLARGE_INTEGER)&curTime);
+ if (((curTime-dstIf->ICB_DisconnectTime)/10000000) < SpoofingTimeout) {
+ PPACKET_TAG pktTag;
+ // Spoofing timeout has not been exceeded,
+ // Create a reply packet
+ AllocatePacket (WanPacketListId,
+ WanPacketListId,
+ pktTag);
+ if (pktTag!=NULL) {
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ PUTUSHORT (0xFFFF, pktTag->PT_Data+IPXH_CHECKSUM);
+ PUTUSHORT (IPXH_HDRSIZE+2, pktTag->PT_Data+IPXH_LENGTH);
+ *(pktTag->PT_Data+IPXH_XPORTCTL) = 0;
+ *(pktTag->PT_Data+IPXH_PKTTYPE) = 0;
+ memcpy (pktTag->PT_Data+IPXH_DESTADDR,
+ ipxHdr+IPXH_SRCADDR,
+ 12);
+ memcpy (pktTag->PT_Data+IPXH_SRCADDR,
+ ipxHdr+IPXH_DESTADDR,
+ 12);
+ *(pktTag->PT_Data+IPXH_HDRSIZE) = *data;
+ *(pktTag->PT_Data+IPXH_HDRSIZE+1) = 'Y';
+ // Destination for this packet will have to
+ // be the first active LAN adapter in the system
+ // SHOULD BE REMOVED WHEN LOOPBACK SUPPORT US ADDED BY IPX
+
+ pktTag->PT_InterfaceReference = NULL;
+ IpxFwdDbgPrint (DBG_SPOOFING, DBG_INFORMATION,
+ ("IpxFwd: Queueing reply to keepalive from internal server"
+ " at %02x%02x.\n",*(ipxHdr+IPXH_DESTSOCK),*(ipxHdr+IPXH_DESTSOCK+1)));
+ // Enqueue to spoofing queue to be sent back
+ // to the server
+ KeAcquireSpinLock (&SpoofingQueueLock, &oldIRQL);
+ InsertTailList (&SpoofingQueue, &pktTag->PT_QueueLink);
+ // Start worker if not running already
+ if (!SpoofingWorkerActive
+ && EnterForwarder()) {
+ SpoofingWorkerActive = TRUE;
+ ExQueueWorkItem (&SpoofingWorker, DelayedWorkQueue);
+ }
+ KeReleaseSpinLock (&SpoofingQueueLock, oldIRQL);
+ status = STATUS_DROP_SILENTLY;
+ break;
+ }
+ else {
+ IpxFwdDbgPrint (DBG_SPOOFING, DBG_ERROR,
+ ("IpxFwd: Could not allocate"
+ " packet tag for spoofing.\n"));
+ }
+ }
+ else {
+ IpxFwdDbgPrint (DBG_SPOOFING, DBG_WARNING,
+ ("IpxFwd: Internal spoofing"
+ " timeout exceded.\n"));
+ }
+ }
+ case FWD_OPER_STATE_DOWN:
+ // Interface down or send failed
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ if (*(ipxHdr+IPXH_PKTTYPE)!=IPX_NETBIOS_TYPE)
+ InterlockedIncrement (
+ &dstIf->ICB_Stats.OutDiscards);
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
+ ("IpxFwd: Internal send not allowed"
+ " on if %ld (down?).\n", dstIf->ICB_Index));
+ status = STATUS_NETWORK_UNREACHABLE;
+ break;
+ default:
+ ASSERTMSG ("Invalid operational state ", FALSE);
+ }
+ }
+ else {// Interface is disabled
+ if (*(ipxHdr+IPXH_PKTTYPE)!=IPX_NETBIOS_TYPE)
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
+ ("IpxFwd: Internal send not allowed"
+ " on because dst if (or Netbios deliver on it) %ld (ifCB: %08lx) is disabled.\n",
+ dstIf->ICB_Index, dstIf));
+ status = STATUS_NETWORK_UNREACHABLE;
+ }
+
+
+ }
+ while (fIterate && (status!=STATUS_SUCCESS) && (status!=STATUS_PENDING));
+
+ if (dstIf!=NULL)
+ ReleaseInterfaceReference (dstIf);
+ if (fwRoute!=NULL)
+ ReleaseRouteReference (fwRoute);
+ }
+ else { // Internal interface is disabled
+ IpxFwdDbgPrint (DBG_INT_SEND, DBG_WARNING,
+ ("IpxFwd: Internal send not allowed"
+ " because internal if (or Netbios accept on it) is disabled.\n"));
+ InterlockedIncrement (
+ &InternalInterface->ICB_Stats.InDiscards);
+ status = STATUS_NETWORK_UNREACHABLE;
+ }
+
+ LeaveForwarder ();
+ return status;
+}
+
+
+/*++
+*******************************************************************
+
+ P r o c e s s I n t e r n a l Q u e u e
+
+Routine Description:
+ Processes packets in the interface internal queue.
+ Called when connection request completes
+Arguments:
+ dstIf - interface to process
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+ProcessInternalQueue (
+ PINTERFACE_CB dstIf
+ ) {
+ KIRQL oldIRQL;
+ LIST_ENTRY tempQueue;
+
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ InsertHeadList (&dstIf->ICB_InternalQueue, &tempQueue);
+ RemoveEntryList (&dstIf->ICB_InternalQueue);
+ InitializeListHead (&dstIf->ICB_InternalQueue);
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+
+ while (!IsListEmpty (&tempQueue)) {
+ PINTERNAL_PACKET_TAG pktTag;
+ PLIST_ENTRY cur;
+ NTSTATUS status;
+
+ cur = RemoveHeadList (&tempQueue);
+ pktTag = CONTAINING_RECORD (cur, INTERNAL_PACKET_TAG, IPT_QueueLink);
+ InterlockedIncrement (&dstIf->ICB_PendingQuota);
+
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ if (IS_IF_ENABLED(dstIf)
+ && (dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP)) {
+ IPX_NODE_CPY (pktTag->IPT_Target.MacAddress,
+ dstIf->ICB_RemoteNode);
+ ADAPTER_CONTEXT_TO_LOCAL_TARGET (
+ dstIf->ICB_AdapterContext,
+ &pktTag->IPT_Target);
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDelivers);
+ if (*(pktTag->IPT_DataPtr + IPXH_PKTTYPE) == IPX_NETBIOS_TYPE) {
+ InterlockedIncrement (&dstIf->ICB_Stats.NetbiosSent);
+ }
+ status = STATUS_SUCCESS;
+ }
+ else {
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
+ status = STATUS_NETWORK_UNREACHABLE;
+ }
+
+ IPXInternalSendCompletProc (&pktTag->IPT_Target,
+ pktTag->IPT_Packet,
+ pktTag->IPT_Length,
+ status);
+ IpxFwdDbgPrint (DBG_INT_SEND,
+ NT_SUCCESS (status) ? DBG_INFORMATION : DBG_WARNING,
+ ("IpxFwd: Returned internal packet %08lx"
+ " for send on if %ld with status %08lx.\n",
+ pktTag, dstIf->ICB_Index, status));
+ ReleaseInterfaceReference (pktTag->IPT_InterfaceReference);
+ ExFreePool (pktTag);
+ }
+}
+
+
+
+/*++
+*******************************************************************
+
+ P r o c e s s E x t e r n a l Q u e u e
+
+Routine Description:
+ Processes packets in the interface external queue.
+ Called when connection request completes
+Arguments:
+ dstIf - interface to process
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+ProcessExternalQueue (
+ PINTERFACE_CB dstIf
+ ) {
+ KIRQL oldIRQL;
+ LIST_ENTRY tempQueue;
+
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ InsertHeadList (&dstIf->ICB_ExternalQueue, &tempQueue);
+ RemoveEntryList (&dstIf->ICB_ExternalQueue);
+ InitializeListHead (&dstIf->ICB_ExternalQueue);
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+
+ while (!IsListEmpty (&tempQueue)) {
+ PPACKET_TAG pktTag;
+ PLIST_ENTRY cur;
+ NDIS_STATUS status;
+
+ cur = RemoveHeadList (&tempQueue);
+ pktTag = CONTAINING_RECORD (cur, PACKET_TAG, PT_QueueLink);
+
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ if (IS_IF_ENABLED(dstIf)
+ && (dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP)) {
+ IPX_NODE_CPY (pktTag->PT_Target.MacAddress,
+ dstIf->ICB_RemoteNode);
+ if (*(pktTag->PT_Data + IPXH_PKTTYPE) == IPX_NETBIOS_TYPE) {
+ PUTULONG (dstIf->ICB_Network, pktTag->PT_Data+IPXH_DESTNET);
+ }
+ status = DoSend (dstIf, pktTag, oldIRQL);
+ IpxFwdDbgPrint (DBG_SEND, DBG_INFORMATION,
+ ("IpxFwd: Sent queued external packet %08lx if %ld.\n",
+ pktTag, dstIf->ICB_Index));
+ }
+ else {
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ IpxFwdDbgPrint (DBG_SEND, DBG_WARNING,
+ ("IpxFwd: Dropped queued external packet %08lx on dead if %ld.\n",
+ pktTag, dstIf->ICB_Index));
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ if (status!=STATUS_PENDING)
+ ProcessSentPacket (dstIf, pktTag, status);
+ }
+}
+
+
+/*++
+*******************************************************************
+
+ S p o o f e r
+
+Routine Description:
+ Processes packets in spoofing queue
+Arguments:
+ None
+Return Value:
+ None
+*******************************************************************
+--*/
+VOID
+Spoofer (
+ PVOID Context
+ ) {
+ KIRQL oldIRQL;
+ NTSTATUS status;
+ UNREFERENCED_PARAMETER (Context);
+
+ KeAcquireSpinLock (&SpoofingQueueLock, &oldIRQL);
+ // Keep going till queue is empty
+ while (!IsListEmpty (&SpoofingQueue)) {
+ PINTERFACE_CB dstIf;
+ PPACKET_TAG pktTag = CONTAINING_RECORD (SpoofingQueue.Flink,
+ PACKET_TAG,
+ PT_QueueLink);
+ RemoveEntryList (&pktTag->PT_QueueLink);
+ KeReleaseSpinLock (&SpoofingQueueLock, oldIRQL);
+ dstIf = pktTag->PT_InterfaceReference;
+ if (dstIf==NULL) {
+ // Replies for internal server require first active LAN adapter
+ // SHOULD BE REMOVED WHEN LOOPBACK SUPPORT US ADDED BY IPX
+ while ((dstIf=GetNextInterfaceReference (dstIf))!=NULL) {
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ if (IS_IF_ENABLED (dstIf)
+ && (dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP)
+ && (dstIf->ICB_InterfaceType==FWD_IF_PERMANENT)) {
+ pktTag->PT_InterfaceReference = dstIf;
+ IPX_NODE_CPY (&pktTag->PT_Target.MacAddress, dstIf->ICB_LocalNode);
+ status = DoSend (dstIf, pktTag, oldIRQL); // releases spin lock
+ if (status!=STATUS_PENDING)
+ ProcessSentPacket (dstIf, pktTag, status);
+ break;
+ }
+ else
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ }
+ if (dstIf==NULL) {
+ FreePacket (pktTag);
+ }
+
+ }
+ else { // Reply for external server, interface is already known
+ UCHAR addr[12];
+ FILTER_ACTION action;
+ pktTag->PT_Flags &= (~PT_SOURCE_IF);
+
+ // Switch source and destination
+ memcpy (addr, pktTag->PT_Data+IPXH_DESTADDR, 12);
+ memcpy (pktTag->PT_Data+IPXH_DESTADDR,
+ pktTag->PT_Data+IPXH_SRCADDR, 12);
+ memcpy (pktTag->PT_Data+IPXH_SRCADDR, addr, 12);
+ // Say yes in reply
+ *(pktTag->PT_Data+IPXH_HDRSIZE+1) = 'Y';
+
+ action = FltFilter (pktTag->PT_Data,
+ GETUSHORT (pktTag->PT_Data+IPXH_LENGTH),
+ dstIf->ICB_FilterInContext,
+ pktTag->PT_SourceIf->ICB_FilterOutContext);
+ if (action==FILTER_PERMIT) {
+
+ // Release destination if and use source as destination
+ ReleaseInterfaceReference (dstIf);
+ dstIf = pktTag->PT_InterfaceReference = pktTag->PT_SourceIf;
+ // Send the packet if we can
+ KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
+ if (IS_IF_ENABLED (dstIf)
+ && (dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP)) {
+ status = DoSend (dstIf, pktTag, oldIRQL);
+ if (status!=STATUS_PENDING)
+ ProcessSentPacket (dstIf, pktTag, status);
+ }
+ else {
+ KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
+ InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
+ ReleaseInterfaceReference (dstIf);
+ FreePacket (pktTag);
+ }
+ }
+ else {
+ if (action==FILTER_DENY_OUT)
+ InterlockedIncrement (&pktTag->PT_SourceIf->ICB_Stats.OutFiltered);
+ else {
+ ASSERT (action==FILTER_DENY_IN);
+ InterlockedIncrement (&dstIf->ICB_Stats.InFiltered);
+ }
+ ReleaseInterfaceReference (dstIf);
+ ReleaseInterfaceReference (pktTag->PT_SourceIf);
+ FreePacket (pktTag);
+ }
+ }
+ KeAcquireSpinLock (&SpoofingQueueLock, &oldIRQL);
+ } // end while
+ SpoofingWorkerActive = FALSE;
+ KeReleaseSpinLock (&SpoofingQueueLock, oldIRQL);
+ LeaveForwarder ();
+}
+
+