856 lines
29 KiB
C
856 lines
29 KiB
C
/*++
|
||
|
||
Copyright (c) 1995 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ntos\tdi\isn\fwd\rcvind.c
|
||
|
||
Abstract:
|
||
Receive indication processing
|
||
|
||
Author:
|
||
|
||
Vadim Eydelman
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
#include "precomp.h"
|
||
|
||
#if DBG
|
||
VOID
|
||
DbgFilterReceivedPacket(PUCHAR hdrp);
|
||
#endif
|
||
|
||
// Doesn't allow accepting packets (for routing) from dial-in clients
|
||
BOOLEAN ThisMachineOnly = FALSE;
|
||
|
||
/*++
|
||
*******************************************************************
|
||
F w R e c e i v e
|
||
|
||
Routine Description:
|
||
Called by the IPX stack to indicate that the IPX packet was
|
||
received by the NIC dirver. Only external destined packets are
|
||
indicated by this routine (with the exception of Netbios boradcasts
|
||
that indicated both for internal and external handlers)
|
||
Arguments:
|
||
MacBindingHandle - handle of NIC driver
|
||
MaxReceiveContext - NIC driver context
|
||
RemoteAddress - sender's address
|
||
MacOptions -
|
||
LookaheadBuffer - packet lookahead buffer that contains complete
|
||
IPX header
|
||
LookaheadBufferSize - its size (at least 30 bytes)
|
||
LookaheadBufferOffset - offset of lookahead buffer in the physical
|
||
packet
|
||
Return Value:
|
||
TRUE if we take the MDL chain to return later with NdisReturnPacket
|
||
|
||
*******************************************************************
|
||
--*/
|
||
BOOLEAN
|
||
IpxFwdReceive (
|
||
NDIS_HANDLE MacBindingHandle,
|
||
NDIS_HANDLE MacReceiveContext,
|
||
ULONG_PTR Context,
|
||
PIPX_LOCAL_TARGET RemoteAddress,
|
||
ULONG MacOptions,
|
||
PUCHAR LookaheadBuffer,
|
||
UINT LookaheadBufferSize,
|
||
UINT LookaheadBufferOffset,
|
||
UINT PacketSize,
|
||
PMDL pMdl)
|
||
{
|
||
PINTERFACE_CB srcIf, dstIf;
|
||
PPACKET_TAG pktTag;
|
||
PNDIS_PACKET pktDscr;
|
||
NDIS_STATUS status;
|
||
UINT BytesTransferred;
|
||
LARGE_INTEGER PerfCounter;
|
||
|
||
// check that our configuration process has terminated OK
|
||
if (!EnterForwarder ()) {
|
||
return FALSE;
|
||
}
|
||
|
||
if (!MeasuringPerformance) {
|
||
PerfCounter.QuadPart = 0;
|
||
}
|
||
else {
|
||
#if DBG
|
||
static LONGLONG LastCall = 0;
|
||
KIRQL oldIRQL;
|
||
#endif
|
||
PerfCounter = KeQueryPerformanceCounter (NULL);
|
||
#if DBG
|
||
KeAcquireSpinLock (&PerfCounterLock, &oldIRQL);
|
||
ASSERT (PerfCounter.QuadPart-LastCall<ActivityTreshhold);
|
||
LastCall = PerfCounter.QuadPart;
|
||
KeReleaseSpinLock (&PerfCounterLock, oldIRQL);
|
||
#endif
|
||
}
|
||
|
||
IpxFwdDbgPrint (DBG_RECV, DBG_INFORMATION,
|
||
("IpxFwd: FwdReceive on %0lx,"
|
||
" dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
|
||
Context, GETULONG (LookaheadBuffer+IPXH_DESTNET),
|
||
LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
|
||
LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
|
||
LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
|
||
LookaheadBuffer[IPXH_PKTTYPE]));
|
||
|
||
#if DBG
|
||
DbgFilterReceivedPacket (LookaheadBuffer);
|
||
#endif
|
||
srcIf = InterfaceContextToReference ((PVOID)Context, RemoteAddress->NicId);
|
||
// Check if interface is valid
|
||
if (srcIf!=NULL) {
|
||
USHORT pktlen;
|
||
ULONG dstNet;
|
||
KIRQL oldIRQL;
|
||
|
||
dstNet = GETULONG (LookaheadBuffer + IPXH_DESTNET);
|
||
pktlen = GETUSHORT(LookaheadBuffer + IPXH_LENGTH);
|
||
|
||
// check if we got the whole IPX header in the lookahead buffer
|
||
if ((LookaheadBufferSize >= IPXH_HDRSIZE)
|
||
&& (*(LookaheadBuffer + IPXH_XPORTCTL) < 16)
|
||
&& (pktlen<=PacketSize)) {
|
||
// Lock interface CB to ensure coherency of information in it
|
||
KeAcquireSpinLock(&srcIf->ICB_Lock, &oldIRQL);
|
||
// Check if shoud accept packets on this interface
|
||
if (IS_IF_ENABLED(srcIf)
|
||
&& (srcIf->ICB_Stats.OperationalState!=FWD_OPER_STATE_DOWN)
|
||
&& (!ThisMachineOnly
|
||
|| (srcIf->ICB_InterfaceType
|
||
!=FWD_IF_REMOTE_WORKSTATION))) {
|
||
// Check for looped back packets
|
||
if (IPX_NODE_CMP (RemoteAddress->MacAddress,
|
||
srcIf->ICB_LocalNode)!=0) {
|
||
|
||
// Separate processing of netbios broadcast packets (20)
|
||
if (*(LookaheadBuffer + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE) {
|
||
PFWD_ROUTE dstRoute;
|
||
INT srcListId, dstListId;
|
||
// Temp IPX bug fix, they shou;d ensure that
|
||
// we only get packets that can be routed
|
||
if ((dstNet==srcIf->ICB_Network)
|
||
|| (dstNet==InternalInterface->ICB_Network)) {
|
||
InterlockedIncrement (&srcIf->ICB_Stats.InDiscards);
|
||
KeReleaseSpinLock(&srcIf->ICB_Lock, oldIRQL);
|
||
ReleaseInterfaceReference (srcIf);
|
||
LeaveForwarder ();
|
||
return FALSE;
|
||
}
|
||
// ASSERT (dstNet!=srcIf->ICB_Network);
|
||
// ASSERT ((InternalInterface==NULL)
|
||
// || (InternalInterface->ICB_Network==0)
|
||
// || (dstNet!=InternalInterface->ICB_Network));
|
||
// Check if needed route is in cash
|
||
if ((srcIf->ICB_CashedRoute!=NULL)
|
||
&& (dstNet==srcIf->ICB_CashedRoute->FR_Network)
|
||
// If route was changed or deleted, this will fail
|
||
&& (srcIf->ICB_CashedRoute->FR_InterfaceReference
|
||
==srcIf->ICB_CashedInterface)) {
|
||
dstIf = srcIf->ICB_CashedInterface;
|
||
dstRoute = srcIf->ICB_CashedRoute;
|
||
AcquireInterfaceReference (dstIf);
|
||
AcquireRouteReference (dstRoute);
|
||
IpxFwdDbgPrint (DBG_RECV, DBG_INFORMATION,
|
||
("IpxFwd: Destination in cash.\n"));
|
||
}
|
||
else { // Find and cash the route
|
||
dstIf = FindDestination (dstNet,
|
||
LookaheadBuffer+IPXH_DESTNODE,
|
||
&dstRoute
|
||
);
|
||
|
||
if (dstIf!=NULL) { // If route is found
|
||
IpxFwdDbgPrint (DBG_RECV, DBG_INFORMATION,
|
||
("IpxFwd: Found destination %0lx.\n", dstIf));
|
||
// Don't cash global wan clients and
|
||
// routes to the same net
|
||
if ((dstNet!=GlobalNetwork)
|
||
&& (dstIf!=srcIf)) {
|
||
if (srcIf->ICB_CashedInterface!=NULL)
|
||
ReleaseInterfaceReference (srcIf->ICB_CashedInterface);
|
||
if (srcIf->ICB_CashedRoute!=NULL)
|
||
ReleaseRouteReference (srcIf->ICB_CashedRoute);
|
||
srcIf->ICB_CashedInterface = dstIf;
|
||
srcIf->ICB_CashedRoute = dstRoute;
|
||
AcquireInterfaceReference (dstIf);
|
||
AcquireRouteReference (dstRoute);
|
||
}
|
||
}
|
||
else { // No route
|
||
InterlockedIncrement (&srcIf->ICB_Stats.InNoRoutes);
|
||
KeReleaseSpinLock(&srcIf->ICB_Lock, oldIRQL);
|
||
IpxFwdDbgPrint (DBG_RECV, DBG_WARNING,
|
||
("IpxFwd: No route for packet on interface %ld (icb:%0lx),"
|
||
" dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
|
||
srcIf->ICB_Index, srcIf, dstNet,
|
||
LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
|
||
LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
|
||
LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
|
||
LookaheadBuffer[IPXH_PKTTYPE]));
|
||
ReleaseInterfaceReference (srcIf);
|
||
LeaveForwarder ();
|
||
return FALSE;
|
||
}
|
||
}
|
||
srcListId = srcIf->ICB_PacketListId;
|
||
KeReleaseSpinLock(&srcIf->ICB_Lock, oldIRQL);
|
||
|
||
// Check if destination if can take the packet
|
||
if (IS_IF_ENABLED (dstIf)
|
||
// If interface is UP check packet againts actual size limit
|
||
&& (((dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_UP)
|
||
&& (PacketSize<=dstIf->ICB_Stats.MaxPacketSize))
|
||
// if sleeping (WAN), check we can allocate it from WAN list
|
||
|| ((dstIf->ICB_Stats.OperationalState==FWD_OPER_STATE_SLEEPING)
|
||
&& (PacketSize<=WAN_PACKET_SIZE))
|
||
// otherwise, interface is down and we can't take the packet
|
||
) ){
|
||
FILTER_ACTION action;
|
||
action = FltFilter (LookaheadBuffer, LookaheadBufferSize,
|
||
srcIf->ICB_FilterInContext,
|
||
dstIf->ICB_FilterOutContext);
|
||
if (action==FILTER_PERMIT) {
|
||
InterlockedIncrement (&srcIf->ICB_Stats.InDelivers);
|
||
dstListId = dstIf->ICB_PacketListId;
|
||
// try to get a packet from the rcv pkt pool
|
||
AllocatePacket (srcListId, dstListId, pktTag);
|
||
if (pktTag!=NULL) {
|
||
// Set destination mac in local target if
|
||
// possible
|
||
KeAcquireSpinLock (&dstIf->ICB_Lock, &oldIRQL);
|
||
if (dstIf->ICB_InterfaceType==FWD_IF_PERMANENT) {
|
||
// Permanent interface: send to the next
|
||
// hop router if net is not directly connected
|
||
// or to the dest node otherwise
|
||
if (dstNet!=dstIf->ICB_Network) {
|
||
IPX_NODE_CPY (pktTag->PT_Target.MacAddress,
|
||
dstRoute->FR_NextHopAddress);
|
||
}
|
||
else {
|
||
IPX_NODE_CPY (pktTag->PT_Target.MacAddress,
|
||
LookaheadBuffer+IPXH_DESTNODE);
|
||
}
|
||
}
|
||
else { // Demand dial interface: assumed to be
|
||
// point to point connection -> send to
|
||
// the other party if connection has already
|
||
// been made, otherwise wait till connected
|
||
if (dstIf->ICB_Stats.OperationalState
|
||
== FWD_OPER_STATE_UP) {
|
||
IPX_NODE_CPY (pktTag->PT_Target.MacAddress,
|
||
dstIf->ICB_RemoteNode);
|
||
} // Copy source mac address and nic id in case
|
||
// we need to spoof this packet
|
||
else if ((*(LookaheadBuffer+IPXH_PKTTYPE)==0)
|
||
&& (pktlen==IPXH_HDRSIZE+2)
|
||
&& ((LookaheadBufferSize<IPXH_HDRSIZE+2)
|
||
||(*(LookaheadBuffer+IPXH_HDRSIZE+1)=='?'))) {
|
||
IPX_NODE_CPY (pktTag->PT_Target.MacAddress,
|
||
RemoteAddress->MacAddress);
|
||
pktTag->PT_SourceIf = srcIf;
|
||
AcquireInterfaceReference (srcIf);
|
||
pktTag->PT_Flags |= PT_SOURCE_IF;
|
||
}
|
||
|
||
}
|
||
KeReleaseSpinLock (&dstIf->ICB_Lock, oldIRQL);
|
||
ReleaseRouteReference (dstRoute);
|
||
goto GetPacket;
|
||
}
|
||
else { // Allocation failure
|
||
InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
|
||
}
|
||
}
|
||
else {// Filtered out
|
||
if (action==FILTER_DENY_OUT)
|
||
InterlockedIncrement (&dstIf->ICB_Stats.OutFiltered);
|
||
else {
|
||
ASSERT (action==FILTER_DENY_IN);
|
||
InterlockedIncrement (&srcIf->ICB_Stats.InFiltered);
|
||
}
|
||
IpxFwdDbgPrint (DBG_RECV, DBG_WARNING,
|
||
("IpxFwd: Filtered out"
|
||
" packet on interface %ld (icb:%0lx),"
|
||
" dst-%ld (icb %08lx) %08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
|
||
srcIf->ICB_Index, srcIf, dstIf->ICB_Index, dstIf, dstNet,
|
||
LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
|
||
LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
|
||
LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
|
||
LookaheadBuffer[IPXH_PKTTYPE]));
|
||
}
|
||
}
|
||
else { // Destination interface is down
|
||
InterlockedIncrement (&srcIf->ICB_Stats.InDelivers);
|
||
InterlockedIncrement (&dstIf->ICB_Stats.OutDiscards);
|
||
IpxFwdDbgPrint (DBG_RECV, DBG_WARNING,
|
||
("IpxFwd: Dest interface %ld (icb %08lx) down"
|
||
" for packet on interface %ld (icb:%0lx),"
|
||
" dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
|
||
dstIf->ICB_Index, dstIf, srcIf->ICB_Index, srcIf, dstNet,
|
||
LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
|
||
LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
|
||
LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
|
||
LookaheadBuffer[IPXH_PKTTYPE]));
|
||
}
|
||
ReleaseInterfaceReference (dstIf);
|
||
ReleaseRouteReference (dstRoute);
|
||
}
|
||
else { // if netbios
|
||
// check that this is a netbios bcast packet and
|
||
// didnt exceed the limit of routers to traverse
|
||
// and we can accept it on this interface
|
||
if (srcIf->ICB_NetbiosAccept
|
||
&& (*(LookaheadBuffer + IPXH_XPORTCTL) < 8)) {
|
||
INT srcListId;
|
||
srcListId = srcIf->ICB_PacketListId;
|
||
KeReleaseSpinLock(&srcIf->ICB_Lock, oldIRQL);
|
||
// Check if packet is valid
|
||
if (IPX_NODE_CMP (LookaheadBuffer + IPXH_DESTNODE,
|
||
BROADCAST_NODE)==0) {
|
||
// Check if we haven't exceeded the quota
|
||
if (InterlockedDecrement (&NetbiosPacketsQuota)>=0) {
|
||
// try to get a packet from the rcv pkt pool
|
||
AllocatePacket (srcListId, srcListId, pktTag);
|
||
if (pktTag!=NULL) {
|
||
dstIf = srcIf;
|
||
AcquireInterfaceReference (dstIf);
|
||
goto GetPacket;
|
||
}
|
||
}
|
||
else {// Netbios quota exceded
|
||
IpxFwdDbgPrint (DBG_NETBIOS, DBG_WARNING,
|
||
("IpxFwd: Netbios quota exceded"
|
||
" for packet on interface %ld (icb:%0lx),"
|
||
" dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
|
||
srcIf->ICB_Index, srcIf, dstNet,
|
||
LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
|
||
LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
|
||
LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
|
||
LookaheadBuffer[IPXH_PKTTYPE]));
|
||
InterlockedIncrement (&srcIf->ICB_Stats.InDiscards);
|
||
}
|
||
InterlockedIncrement (&NetbiosPacketsQuota);
|
||
}
|
||
else { // Bad netbios packet
|
||
IpxFwdDbgPrint (DBG_NETBIOS, DBG_WARNING,
|
||
("IpxFwd: Bad nb packet on interface %ld (icb:%0lx),"
|
||
" dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
|
||
srcIf->ICB_Index, srcIf, dstNet,
|
||
LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
|
||
LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
|
||
LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
|
||
LookaheadBuffer[IPXH_PKTTYPE]));
|
||
InterlockedIncrement (&srcIf->ICB_Stats.InHdrErrors);
|
||
}
|
||
}
|
||
else { // Netbios accept disabled or to many routers crossed
|
||
KeReleaseSpinLock(&srcIf->ICB_Lock, oldIRQL);
|
||
InterlockedIncrement (&srcIf->ICB_Stats.InDiscards);
|
||
IpxFwdDbgPrint (DBG_NETBIOS, DBG_WARNING,
|
||
("IpxFwd: NB packet dropped on disabled interface %ld (icb:%0lx),"
|
||
" dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
|
||
srcIf->ICB_Index, srcIf, dstNet,
|
||
LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
|
||
LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
|
||
LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
|
||
LookaheadBuffer[IPXH_PKTTYPE]));
|
||
}
|
||
} // End netbios specific processing (else if netbios)
|
||
}
|
||
else { // Looped back packets discarded without counting
|
||
// (We shouldn't get them in IPX stack does the right job)
|
||
KeReleaseSpinLock(&srcIf->ICB_Lock, oldIRQL);
|
||
}
|
||
}
|
||
else { // Interface is down or disabled
|
||
KeReleaseSpinLock(&srcIf->ICB_Lock, oldIRQL);
|
||
InterlockedIncrement (&srcIf->ICB_Stats.InDiscards);
|
||
IpxFwdDbgPrint (DBG_RECV, DBG_WARNING,
|
||
("IpxFwd: Packet dropped on disabled interface %ld (icb:%0lx),"
|
||
" dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
|
||
srcIf->ICB_Index, srcIf, dstNet,
|
||
LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
|
||
LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
|
||
LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
|
||
LookaheadBuffer[IPXH_PKTTYPE]));
|
||
}
|
||
}
|
||
else { // Obvious header errors (shouldn't IPX do this for us ?
|
||
InterlockedIncrement (&srcIf->ICB_Stats.InHdrErrors);
|
||
IpxFwdDbgPrint (DBG_RECV, DBG_ERROR,
|
||
("IpxFwd: Header errors in packet on interface %ld (icb:%0lx),"
|
||
" dst-%08lx:%02x%02x%02x%02x%02x%02x, type-%02x.\n",
|
||
srcIf->ICB_Index, srcIf, dstNet,
|
||
LookaheadBuffer[IPXH_DESTNODE], LookaheadBuffer[IPXH_DESTNODE+1],
|
||
LookaheadBuffer[IPXH_DESTNODE+2], LookaheadBuffer[IPXH_DESTNODE+3],
|
||
LookaheadBuffer[IPXH_DESTNODE+4], LookaheadBuffer[IPXH_DESTNODE+5],
|
||
LookaheadBuffer[IPXH_PKTTYPE]));
|
||
}
|
||
ReleaseInterfaceReference (srcIf);
|
||
} // We could not locate the interface from IPX supplied context: there
|
||
// is just a little time window when interface is deleted
|
||
// but IPX had already pushed the context on the stack
|
||
else {
|
||
IpxFwdDbgPrint (DBG_RECV, DBG_ERROR,
|
||
("IpxFwd: Receive, type-%02x"
|
||
" - src interface context is invalid.\n",
|
||
LookaheadBuffer[IPXH_PKTTYPE]));
|
||
}
|
||
LeaveForwarder ();
|
||
return FALSE ;
|
||
|
||
GetPacket:
|
||
|
||
InterlockedIncrement (&srcIf->ICB_Stats.InDelivers);
|
||
ReleaseInterfaceReference (srcIf);
|
||
|
||
pktDscr = CONTAINING_RECORD (pktTag, NDIS_PACKET, ProtocolReserved);
|
||
pktTag->PT_InterfaceReference = dstIf;
|
||
pktTag->PT_PerfCounter = PerfCounter.QuadPart;
|
||
|
||
// try to get the packet data
|
||
IPXTransferData(&status,
|
||
MacBindingHandle,
|
||
MacReceiveContext,
|
||
LookaheadBufferOffset, // start of IPX header
|
||
PacketSize, // packet size starting at IPX header
|
||
pktDscr,
|
||
&BytesTransferred);
|
||
|
||
if (status != NDIS_STATUS_PENDING) {
|
||
// complete the frame processing (LeaveForwarder will be called there)
|
||
IpxFwdTransferDataComplete(pktDscr, status, BytesTransferred);
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
/*++
|
||
*******************************************************************
|
||
F w T r a n s f e r D a t a C o m p l e t e
|
||
|
||
Routine Description:
|
||
Called by the IPX stack when NIC driver completes data transger.
|
||
Arguments:
|
||
pktDscr - handle of NIC driver
|
||
status - result of the transfer
|
||
bytesTransferred - number of bytest trasferred
|
||
Return Value:
|
||
None
|
||
|
||
*******************************************************************
|
||
--*/
|
||
VOID
|
||
IpxFwdTransferDataComplete (
|
||
PNDIS_PACKET pktDscr,
|
||
NDIS_STATUS status,
|
||
UINT bytesTransferred)
|
||
{
|
||
PPACKET_TAG pktTag;
|
||
|
||
pktTag = (PPACKET_TAG)(&pktDscr->ProtocolReserved);
|
||
|
||
// If transfer failed, release the packet and interface
|
||
//
|
||
if (status==NDIS_STATUS_SUCCESS)
|
||
{
|
||
if (*(pktTag->PT_Data + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
|
||
{
|
||
// pmay: 260480
|
||
//
|
||
// Increment the transport control field so that
|
||
// the number of routers that this packet has
|
||
// traversed is increased. IpxFwdReceive will drop
|
||
// all packets that have traversed more that 15 routers.
|
||
//
|
||
// Netbios packets will have their transport control
|
||
// fields incremented by ProcessNetbiosPacket
|
||
//
|
||
*(pktTag->PT_Data + IPXH_XPORTCTL) += 1;
|
||
|
||
SendPacket (pktTag->PT_InterfaceReference, pktTag);
|
||
}
|
||
else
|
||
{
|
||
ProcessNetbiosPacket (pktTag->PT_InterfaceReference, pktTag);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
IpxFwdDbgPrint (DBG_RECV, DBG_ERROR,
|
||
("IpxFwd: Trans data failed: packet %08lx on if %08lx!\n",
|
||
pktTag, pktTag->PT_InterfaceReference));
|
||
|
||
// Record the fact that we're discarding
|
||
//
|
||
if (*(pktTag->PT_Data + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
|
||
{
|
||
InterlockedIncrement (
|
||
&pktTag->PT_InterfaceReference->ICB_Stats.OutDiscards);
|
||
}
|
||
|
||
// For netbios packets interface reference is
|
||
// actually a source interface
|
||
else
|
||
{
|
||
InterlockedIncrement (&NetbiosPacketsQuota);
|
||
InterlockedIncrement (
|
||
&pktTag->PT_InterfaceReference->ICB_Stats.InDiscards);
|
||
}
|
||
|
||
ReleaseInterfaceReference (pktTag->PT_InterfaceReference);
|
||
FreePacket (pktTag);
|
||
}
|
||
|
||
LeaveForwarder ();
|
||
return;
|
||
}
|
||
|
||
|
||
/*++
|
||
*******************************************************************
|
||
F w R e c e i v e C o m p l e t e
|
||
|
||
Routine Description:
|
||
|
||
This routine receives control from the IPX driver after one or
|
||
more receive operations have completed and no receive is in progress.
|
||
It is called under less severe time constraints than IpxFwdReceive.
|
||
It is used to process netbios queue
|
||
|
||
Arguments:
|
||
None
|
||
Return Value:
|
||
None
|
||
*******************************************************************
|
||
--*/
|
||
VOID
|
||
IpxFwdReceiveComplete (
|
||
USHORT NicId
|
||
) {
|
||
|
||
// check that our configuration process has terminated OK
|
||
if(!EnterForwarder ()) {
|
||
return;
|
||
}
|
||
IpxFwdDbgPrint (DBG_RECV, DBG_INFORMATION, ("IpxFwd: FwdReceiveComplete.\n"));
|
||
ScheduleNetbiosWorker ();
|
||
LeaveForwarder ();
|
||
}
|
||
|
||
/*++
|
||
*******************************************************************
|
||
I p x F w d I n t e r n a l R e c e i v e
|
||
|
||
Routine Description:
|
||
Called by the IPX stack to indicate that the IPX packet destined
|
||
to local client was received by the NIC dirver.
|
||
Arguments:
|
||
Context - forwarder context associated with
|
||
the NIC (interface block pointer)
|
||
RemoteAddress - sender's address
|
||
LookaheadBuffer - packet lookahead buffer that contains complete
|
||
IPX header
|
||
LookaheadBufferSize - its size (at least 30 bytes)
|
||
Return Value:
|
||
STATUS_SUCCESS - the packet will be delivered to local destination
|
||
STATUS_UNSUCCESSFUL - the packet will be dropped
|
||
|
||
*******************************************************************
|
||
--*/
|
||
NTSTATUS
|
||
IpxFwdInternalReceive (
|
||
IN ULONG_PTR Context,
|
||
IN PIPX_LOCAL_TARGET RemoteAddress,
|
||
IN PUCHAR LookAheadBuffer,
|
||
IN UINT LookAheadBufferSize
|
||
) {
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PINTERFACE_CB srcIf;
|
||
|
||
if (!EnterForwarder ()) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
if (Context!=VIRTUAL_NET_FORWARDER_CONTEXT) {
|
||
// Check if interface context supplied by IPX driver is valid
|
||
srcIf = InterfaceContextToReference ((PVOID)Context, RemoteAddress->NicId);
|
||
}
|
||
else {
|
||
srcIf = InternalInterface;
|
||
AcquireInterfaceReference (srcIf);
|
||
}
|
||
|
||
if (srcIf!=NULL) {
|
||
// Check if we can accept on this interface
|
||
if (IS_IF_ENABLED (srcIf)
|
||
&& (srcIf->ICB_Stats.OperationalState!=FWD_OPER_STATE_DOWN)
|
||
&& ((*(LookAheadBuffer + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE)
|
||
|| srcIf->ICB_NetbiosAccept)) {
|
||
// Check if we can accept on internal interface
|
||
if (IS_IF_ENABLED(InternalInterface)) {
|
||
FILTER_ACTION action;
|
||
action = FltFilter (LookAheadBuffer, LookAheadBufferSize,
|
||
srcIf->ICB_FilterInContext,
|
||
InternalInterface->ICB_FilterOutContext);
|
||
// Check the filter
|
||
if (action==FILTER_PERMIT) {
|
||
// Update source interface statistics
|
||
InterlockedIncrement (&srcIf->ICB_Stats.InDelivers);
|
||
// Handle NB packets separatedly
|
||
if (*(LookAheadBuffer + IPXH_PKTTYPE) != IPX_NETBIOS_TYPE) {
|
||
InterlockedIncrement (
|
||
&InternalInterface->ICB_Stats.OutDelivers);
|
||
IpxFwdDbgPrint (DBG_INT_RECV, DBG_INFORMATION,
|
||
("IpxFwd: FwdInternalReceive,"
|
||
" from %d(%lx)-%.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x,"
|
||
" type-%02x.\n",
|
||
srcIf->ICB_Index, srcIf,
|
||
LookAheadBuffer[IPXH_SRCNET],LookAheadBuffer[IPXH_SRCNET+1],
|
||
LookAheadBuffer[IPXH_SRCNET+2],LookAheadBuffer[IPXH_SRCNET+3],
|
||
LookAheadBuffer[IPXH_SRCNODE],LookAheadBuffer[IPXH_SRCNODE+1],
|
||
LookAheadBuffer[IPXH_SRCNODE+2],LookAheadBuffer[IPXH_SRCNODE+3],
|
||
LookAheadBuffer[IPXH_SRCNODE+4],LookAheadBuffer[IPXH_SRCNODE+5],
|
||
LookAheadBuffer[IPXH_PKTTYPE]));
|
||
}
|
||
else {
|
||
// Check if destination netbios name is staticly assigned to
|
||
// an external interface or netbios delivery options do not
|
||
// allow us to deliver this packet
|
||
PINTERFACE_CB dstIf;
|
||
USHORT dstSock = GETUSHORT (LookAheadBuffer+IPXH_DESTSOCK);
|
||
|
||
InterlockedIncrement (&srcIf->ICB_Stats.NetbiosReceived);
|
||
// First try to find a static name if we have enough data
|
||
// in the lookahead buffer
|
||
if ((dstSock==IPX_NETBIOS_SOCKET)
|
||
&& (LookAheadBufferSize>(NB_NAME+16)))
|
||
dstIf = FindNBDestination (LookAheadBuffer+(NB_NAME-IPXH_HDRSIZE));
|
||
else if ((dstSock==IPX_SMB_NAME_SOCKET)
|
||
&& (LookAheadBufferSize>(SMB_NAME+16)))
|
||
dstIf = FindNBDestination (LookAheadBuffer+(SMB_NAME-IPXH_HDRSIZE));
|
||
else
|
||
dstIf = NULL;
|
||
// Now see, if we can deliver the packet
|
||
if ((((dstIf==NULL) || (dstIf==InternalInterface))
|
||
&& (InternalInterface->ICB_NetbiosDeliver==FWD_NB_DELIVER_ALL))
|
||
|| ((dstIf==InternalInterface)
|
||
&& (InternalInterface->ICB_NetbiosDeliver==FWD_NB_DELIVER_STATIC))) {
|
||
InterlockedIncrement (
|
||
&InternalInterface->ICB_Stats.NetbiosSent);
|
||
InterlockedIncrement (
|
||
&InternalInterface->ICB_Stats.OutDelivers);
|
||
IpxFwdDbgPrint (DBG_INT_RECV, DBG_INFORMATION,
|
||
("IpxFwd: FwdInternalReceive, NB"
|
||
" from %d(%lx)-%.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x\n",
|
||
srcIf->ICB_Index, srcIf,
|
||
LookAheadBuffer[IPXH_SRCNET],LookAheadBuffer[IPXH_SRCNET+1],
|
||
LookAheadBuffer[IPXH_SRCNET+2],LookAheadBuffer[IPXH_SRCNET+3],
|
||
LookAheadBuffer[IPXH_SRCNODE],LookAheadBuffer[IPXH_SRCNODE+1],
|
||
LookAheadBuffer[IPXH_SRCNODE+2],LookAheadBuffer[IPXH_SRCNODE+3],
|
||
LookAheadBuffer[IPXH_SRCNODE+4],LookAheadBuffer[IPXH_SRCNODE+5]));
|
||
}
|
||
else {
|
||
InterlockedIncrement (
|
||
&InternalInterface->ICB_Stats.OutDiscards);
|
||
IpxFwdDbgPrint (DBG_INT_RECV, DBG_WARNING,
|
||
("IpxFwd: FwdInternalReceive, NB dropped because delivery disabled"
|
||
" from %d(%lx)-%.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x\n",
|
||
srcIf->ICB_Index, srcIf,
|
||
LookAheadBuffer[IPXH_SRCNET],LookAheadBuffer[IPXH_SRCNET+1],
|
||
LookAheadBuffer[IPXH_SRCNET+2],LookAheadBuffer[IPXH_SRCNET+3],
|
||
LookAheadBuffer[IPXH_SRCNODE],LookAheadBuffer[IPXH_SRCNODE+1],
|
||
LookAheadBuffer[IPXH_SRCNODE+2],LookAheadBuffer[IPXH_SRCNODE+3],
|
||
LookAheadBuffer[IPXH_SRCNODE+4],LookAheadBuffer[IPXH_SRCNODE+5]));
|
||
status = STATUS_UNSUCCESSFUL;
|
||
}
|
||
if (dstIf!=NULL)
|
||
ReleaseInterfaceReference (dstIf);
|
||
}
|
||
}
|
||
else {// Filtered Out
|
||
if (action==FILTER_DENY_OUT) {
|
||
InterlockedIncrement (
|
||
&InternalInterface->ICB_Stats.OutFiltered);
|
||
status=STATUS_UNSUCCESSFUL;
|
||
}
|
||
else {
|
||
ASSERT (action==FILTER_DENY_IN);
|
||
InterlockedIncrement (&srcIf->ICB_Stats.InFiltered);
|
||
status=STATUS_UNSUCCESSFUL;
|
||
}
|
||
IpxFwdDbgPrint (DBG_INT_RECV, DBG_WARNING,
|
||
("IpxFwd: FwdInternalReceive, filtered out"
|
||
" from %d(%lx)-%.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x,"
|
||
" type-%02x.\n",
|
||
srcIf->ICB_Index, srcIf,
|
||
LookAheadBuffer[IPXH_SRCNET],LookAheadBuffer[IPXH_SRCNET+1],
|
||
LookAheadBuffer[IPXH_SRCNET+2],LookAheadBuffer[IPXH_SRCNET+3],
|
||
LookAheadBuffer[IPXH_SRCNODE],LookAheadBuffer[IPXH_SRCNODE+1],
|
||
LookAheadBuffer[IPXH_SRCNODE+2],LookAheadBuffer[IPXH_SRCNODE+3],
|
||
LookAheadBuffer[IPXH_SRCNODE+4],LookAheadBuffer[IPXH_SRCNODE+5],
|
||
LookAheadBuffer[IPXH_PKTTYPE]));
|
||
}
|
||
}
|
||
else {// Internal interface is disabled
|
||
InterlockedIncrement (
|
||
&InternalInterface->ICB_Stats.OutDiscards);
|
||
status = STATUS_UNSUCCESSFUL;
|
||
IpxFwdDbgPrint (DBG_INT_RECV, DBG_WARNING,
|
||
("IpxFwd: FwdInternalReceive, internal if disabled"
|
||
" from %d(%lx)-%.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x,"
|
||
" type-%02x.\n",
|
||
srcIf->ICB_Index, srcIf,
|
||
LookAheadBuffer[IPXH_SRCNET],LookAheadBuffer[IPXH_SRCNET+1],
|
||
LookAheadBuffer[IPXH_SRCNET+2],LookAheadBuffer[IPXH_SRCNET+3],
|
||
LookAheadBuffer[IPXH_SRCNODE],LookAheadBuffer[IPXH_SRCNODE+1],
|
||
LookAheadBuffer[IPXH_SRCNODE+2],LookAheadBuffer[IPXH_SRCNODE+3],
|
||
LookAheadBuffer[IPXH_SRCNODE+4],LookAheadBuffer[IPXH_SRCNODE+5],
|
||
LookAheadBuffer[IPXH_PKTTYPE]));
|
||
}
|
||
}
|
||
else { // Disabled source interface
|
||
InterlockedIncrement (&srcIf->ICB_Stats.InDiscards);
|
||
IpxFwdDbgPrint (DBG_INT_RECV, DBG_ERROR,
|
||
("IpxFwd: FwdInternalReceive, source if disabled"
|
||
" from %d(%lx)-%.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x,"
|
||
" type-%02x.\n",
|
||
srcIf->ICB_Index, srcIf,
|
||
LookAheadBuffer[IPXH_SRCNET],LookAheadBuffer[IPXH_SRCNET+1],
|
||
LookAheadBuffer[IPXH_SRCNET+2],LookAheadBuffer[IPXH_SRCNET+3],
|
||
LookAheadBuffer[IPXH_SRCNODE],LookAheadBuffer[IPXH_SRCNODE+1],
|
||
LookAheadBuffer[IPXH_SRCNODE+2],LookAheadBuffer[IPXH_SRCNODE+3],
|
||
LookAheadBuffer[IPXH_SRCNODE+4],LookAheadBuffer[IPXH_SRCNODE+5],
|
||
LookAheadBuffer[IPXH_PKTTYPE]));
|
||
status = STATUS_UNSUCCESSFUL;
|
||
}
|
||
ReleaseInterfaceReference (srcIf);
|
||
}
|
||
else { // Invalid source interface context
|
||
IpxFwdDbgPrint (DBG_INT_RECV, DBG_ERROR,
|
||
("IpxFwd: FwdInternalReceive, source if context is invalid"
|
||
" from (%lx:%d)-%.2x%.2x%.2x%.2x:%.2x%.2x%.2x%.2x%.2x%.2x,"
|
||
" type-%02x.\n",
|
||
Context, RemoteAddress->NicId,
|
||
LookAheadBuffer[IPXH_SRCNET],LookAheadBuffer[IPXH_SRCNET+1],
|
||
LookAheadBuffer[IPXH_SRCNET+2],LookAheadBuffer[IPXH_SRCNET+3],
|
||
LookAheadBuffer[IPXH_SRCNODE],LookAheadBuffer[IPXH_SRCNODE+1],
|
||
LookAheadBuffer[IPXH_SRCNODE+2],LookAheadBuffer[IPXH_SRCNODE+3],
|
||
LookAheadBuffer[IPXH_SRCNODE+4],LookAheadBuffer[IPXH_SRCNODE+5],
|
||
LookAheadBuffer[IPXH_PKTTYPE]));
|
||
status = STATUS_UNSUCCESSFUL;
|
||
}
|
||
LeaveForwarder ();
|
||
return status;
|
||
}
|
||
|
||
/*++
|
||
*******************************************************************
|
||
D e l e t e R e c v Q u e u e
|
||
|
||
Routine Description:
|
||
Initializes the netbios bradcast queue
|
||
Arguments:
|
||
None
|
||
Return Value:
|
||
None
|
||
|
||
*******************************************************************
|
||
--*/
|
||
VOID
|
||
DeleteRecvQueue (
|
||
void
|
||
) {
|
||
// while (!IsListEmpty (&RecvQueue)) {
|
||
// PPACKET_TAG pktTag = CONTAINING_RECORD (RecvQueue.Flink,
|
||
// PACKET_TAG,
|
||
// PT_QueueLink);
|
||
// RemoveEntryList (&pktTag->PT_QueueLink);
|
||
// if (pktTag->PT_InterfaceReference!=NULL) {
|
||
// ReleaseInterfaceReference (pktTag->PT_InterfaceReference);
|
||
// }
|
||
// FreePacket (pktTag);
|
||
// }
|
||
}
|
||
#if DBG
|
||
|
||
ULONG DbgFilterTrap = 0; // 1 - on dst and src (net + node),
|
||
// 2 - on dst (net + node),
|
||
// 3 - on src (net + node),
|
||
// 4 - on dst (net + node + socket)
|
||
|
||
UCHAR DbgFilterDstNet[4];
|
||
UCHAR DbgFilterDstNode[6];
|
||
UCHAR DbgFilterDstSocket[2];
|
||
UCHAR DbgFilterSrcNet[4];
|
||
UCHAR DbgFilterSrcNode[6];
|
||
UCHAR DbgFilterSrcSocket[2];
|
||
PUCHAR DbgFilterFrame;
|
||
|
||
VOID
|
||
DbgFilterReceivedPacket(PUCHAR hdrp)
|
||
{
|
||
switch(DbgFilterTrap) {
|
||
|
||
case 1:
|
||
|
||
if(!memcmp(hdrp + IPXH_DESTNET, DbgFilterDstNet, 4) &&
|
||
!memcmp(hdrp + IPXH_DESTNODE, DbgFilterDstNode, 6) &&
|
||
!memcmp(hdrp + IPXH_SRCNET, DbgFilterSrcNet, 4) &&
|
||
!memcmp(hdrp + IPXH_SRCNODE, DbgFilterSrcNode, 6)) {
|
||
|
||
DbgBreakPoint();
|
||
}
|
||
|
||
break;
|
||
|
||
case 2:
|
||
|
||
if(!memcmp(hdrp + IPXH_DESTNET, DbgFilterDstNet, 4) &&
|
||
!memcmp(hdrp + IPXH_DESTNODE, DbgFilterDstNode, 6)) {
|
||
|
||
DbgBreakPoint();
|
||
}
|
||
|
||
break;
|
||
|
||
case 3:
|
||
|
||
if(!memcmp(hdrp + IPXH_SRCNET, DbgFilterSrcNet, 4) &&
|
||
!memcmp(hdrp + IPXH_SRCNODE, DbgFilterSrcNode, 6)) {
|
||
|
||
DbgBreakPoint();
|
||
}
|
||
|
||
break;
|
||
|
||
case 4:
|
||
|
||
if(!memcmp(hdrp + IPXH_DESTNET, DbgFilterDstNet, 4) &&
|
||
!memcmp(hdrp + IPXH_DESTNODE, DbgFilterDstNode, 6) &&
|
||
!memcmp(hdrp + IPXH_DESTSOCK, DbgFilterDstSocket, 2)) {
|
||
|
||
DbgBreakPoint();
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
break;
|
||
}
|
||
|
||
DbgFilterFrame = hdrp;
|
||
}
|
||
|
||
#endif
|
||
|
||
|