diff options
Diffstat (limited to 'private/ntos/tdi/isn/fwd/send.c')
-rw-r--r-- | private/ntos/tdi/isn/fwd/send.c | 1253 |
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 (); +} + + |