You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2718 lines
102 KiB
2718 lines
102 KiB
|
|
/*++
|
|
|
|
Copyright (c) 1989-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
send.c
|
|
|
|
Abstract:
|
|
|
|
This module contains code that implements the send engine for the
|
|
IPX transport provider.
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
Sanjay Anand (SanjayAn) - August-25-1995
|
|
Bug Fixes - tagged [SA]
|
|
Sanjay Anand (SanjayAn) - 22-Sept-1995
|
|
BackFill optimization changes added under #if BACK_FILL
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// Using the macro for performance reasons. Should be taken out
|
|
// when NdisQueryPacket is optimized. In the near future (after PPC release)
|
|
// move this to a header file and use it at other places.
|
|
//
|
|
#define IPX_PACKET_HEAD(Pkt) (Pkt)->Private.Head
|
|
|
|
#if 0
|
|
#define IpxGetMdlChainLength(Mdl, Length) { \
|
|
PMDL _Mdl = (Mdl); \
|
|
*(Length) = 0; \
|
|
while (_Mdl) { \
|
|
*(Length) += MmGetMdlByteCount(_Mdl); \
|
|
_Mdl = _Mdl->Next; \
|
|
} \
|
|
}
|
|
#endif
|
|
|
|
|
|
VOID
|
|
IpxSendComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_PACKET NdisPacket,
|
|
IN NDIS_STATUS NdisStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the I/O system to indicate that a connection-
|
|
oriented packet has been shipped and is no longer needed by the Physical
|
|
Provider.
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext - The ADAPTER structure for this binding.
|
|
|
|
NdisPacket/RequestHandle - A pointer to the NDIS_PACKET that we sent.
|
|
|
|
NdisStatus - the completion status of the send.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(NdisPacket->ProtocolReserved);
|
|
PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
|
|
PREQUEST Request;
|
|
PADDRESS_FILE AddressFile;
|
|
PDEVICE Device = IpxDevice;
|
|
PBINDING Binding, pBinding= NULL;
|
|
USHORT NewId, OldId;
|
|
ULONG NewOffset, OldOffset;
|
|
PIPX_HEADER IpxHeader, pIpxHeader;
|
|
IPX_LOCAL_TARGET LocalTarget;
|
|
PIO_STACK_LOCATION irpSp;
|
|
BOOLEAN IsLoopback= FALSE;
|
|
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
|
|
|
|
#if DBG
|
|
if (Adapter != NULL) {
|
|
ASSERT_ADAPTER(Adapter);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// See if this send was padded.
|
|
//
|
|
RealFunctionStart:;
|
|
if (Reserved->PaddingBuffer) {
|
|
|
|
UINT Offset;
|
|
//
|
|
// Check if we simply need to re-adjust the buffer length. This will
|
|
// happen if we incremented the buffer length in MAC.C.
|
|
//
|
|
|
|
if (Reserved->PreviousTail) {
|
|
CTEAssert (NDIS_BUFFER_LINKAGE(Reserved->PaddingBuffer->NdisBuffer) == NULL);
|
|
NDIS_BUFFER_LINKAGE (Reserved->PreviousTail) = (PNDIS_BUFFER)NULL;
|
|
} else {
|
|
PNDIS_BUFFER LastBuffer = (PNDIS_BUFFER)Reserved->PaddingBuffer;
|
|
UINT BufferLength;
|
|
|
|
NdisQueryBufferOffset( LastBuffer, &Offset, &BufferLength );
|
|
NdisAdjustBufferLength( LastBuffer, (BufferLength - 1) );
|
|
}
|
|
|
|
Reserved->PaddingBuffer = NULL;
|
|
|
|
if (Reserved->Identifier < IDENTIFIER_IPX) {
|
|
NdisRecalculatePacketCounts (NdisPacket);
|
|
}
|
|
}
|
|
|
|
FunctionStart:;
|
|
|
|
switch (Reserved->Identifier) {
|
|
|
|
case IDENTIFIER_IPX:
|
|
|
|
// #if DBG
|
|
CTEAssert (Reserved->SendInProgress);
|
|
Reserved->SendInProgress = FALSE;
|
|
// #endif
|
|
|
|
//
|
|
// Check if this packet should be sent to all
|
|
// networks.
|
|
//
|
|
|
|
if (Reserved->u.SR_DG.CurrentNicId) {
|
|
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS) {
|
|
Reserved->u.SR_DG.Net0SendSucceeded = TRUE;
|
|
}
|
|
|
|
OldId = Reserved->u.SR_DG.CurrentNicId;
|
|
|
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|
{
|
|
ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
|
|
|
|
Binding = NULL;
|
|
|
|
for (NewId = OldId+1; NewId <= Index; NewId++) {
|
|
if ((Binding = NIC_ID_TO_BINDING(Device, NewId))
|
|
&&
|
|
((!Device->SingleNetworkActive) ||
|
|
(Device->ActiveNetworkWan == Binding->Adapter->MacInfo.MediumAsync))
|
|
&&
|
|
(Device->ForwarderBound ||
|
|
(!Device->DisableDialoutSap) ||
|
|
(!Binding->DialOutAsync) ||
|
|
(!Reserved->u.SR_DG.OutgoingSap))) {
|
|
|
|
//
|
|
// The binding exists, and we either are not configured
|
|
// for "SingleNetworkActive", or we are and this binding
|
|
// is the right type (i.e. the active network is wan and
|
|
// this is a wan binding, or the active network is not
|
|
// wan and this is not a wan binding), and if the FWD is
|
|
// not bound; and this is not an outgoing sap that we are
|
|
// trying to send with "DisableDialoutSap" set.
|
|
//
|
|
|
|
//
|
|
// 179436 - If forwarder is bound then ensure that we are picking a Binding that
|
|
// the forwarder has an open context on. Otherwise, go to the next good binding
|
|
//
|
|
if (Device->ForwarderBound) {
|
|
|
|
if (GET_LONG_VALUE(Binding->ReferenceCount) == 2) {
|
|
|
|
break;
|
|
}
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Binding != NULL && NewId <= MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
|
|
IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|
|
|
//
|
|
// Yes, we found another net to send it on, so
|
|
// move the header around if needed and do so.
|
|
//
|
|
|
|
Reserved->u.SR_DG.CurrentNicId = NewId;
|
|
CTEAssert ((Reserved->DestinationType == DESTINATION_BCAST) ||
|
|
(Reserved->DestinationType == DESTINATION_MCAST));
|
|
|
|
#if 0
|
|
NewOffset = Binding->BcMcHeaderSize;
|
|
OldOffset = Device->Bindings[OldId]->BcMcHeaderSize;
|
|
|
|
if (OldOffset != NewOffset) {
|
|
|
|
RtlMoveMemory(
|
|
&Reserved->Header[NewOffset],
|
|
&Reserved->Header[OldOffset],
|
|
sizeof(IPX_HEADER));
|
|
|
|
}
|
|
|
|
IpxHeader = (PIPX_HEADER)(&Reserved->Header[NewOffset]);
|
|
#endif
|
|
|
|
|
|
|
|
#if BACK_FILL
|
|
// This should be a normal packet. Backfill packet is never used for
|
|
// reserved other than IPX type
|
|
|
|
CTEAssert(!Reserved->BackFill);
|
|
|
|
// Check if this is backfilled. If so restore users Mdl back to its original shape
|
|
// Also, push the packet on to backfillpacket queue if the packet is not owned by the address
|
|
|
|
if (Reserved->BackFill) {
|
|
|
|
IPX_DEBUG(SEND, ("MSVa:%lx, UL:%d\n", Reserved->MappedSystemVa, Reserved->UserLength));
|
|
|
|
Reserved->HeaderBuffer->MappedSystemVa = Reserved->MappedSystemVa;
|
|
Reserved->HeaderBuffer->ByteCount = Reserved->UserLength;
|
|
#ifdef SUNDOWN
|
|
Reserved->HeaderBuffer->StartVa = (PCHAR)((ULONG_PTR)Reserved->HeaderBuffer->MappedSystemVa & ~(PAGE_SIZE-1));
|
|
// ByteOffset is & with 0xfff. PAGE_SIZE is unlikely to > 0x100000000, so we are save to convert to ulong.
|
|
Reserved->HeaderBuffer->ByteOffset = (ULONG) ((ULONG_PTR)Reserved->HeaderBuffer->MappedSystemVa & (PAGE_SIZE-1));
|
|
#else
|
|
Reserved->HeaderBuffer->StartVa = (PCHAR)((ULONG)Reserved->HeaderBuffer->MappedSystemVa & ~(PAGE_SIZE-1));
|
|
Reserved->HeaderBuffer->ByteOffset = (ULONG)Reserved->HeaderBuffer->MappedSystemVa & (PAGE_SIZE-1);
|
|
#endif
|
|
|
|
IPX_DEBUG(SEND, ("completeing back filled userMdl %x\n",Reserved->HeaderBuffer));
|
|
|
|
Reserved->HeaderBuffer->ByteOffset -= sizeof(IPX_HEADER);
|
|
#ifdef SUNDOWN
|
|
(ULONG_PTR)Reserved->HeaderBuffer->MappedSystemVa-= sizeof(IPX_HEADER);
|
|
#else
|
|
(ULONG)Reserved->HeaderBuffer->MappedSystemVa-= sizeof(IPX_HEADER);
|
|
#endif
|
|
|
|
ASSERT((LONG)Reserved->HeaderBuffer->ByteOffset >= 0);
|
|
|
|
NdisAdjustBufferLength(Reserved->HeaderBuffer, (Reserved->HeaderBuffer->ByteCount+sizeof(IPX_HEADER)));
|
|
|
|
IPX_DEBUG(SEND, ("Adjusting backfill userMdl Ipxheader %x RESD : %x\n",Reserved->HeaderBuffer, Reserved));
|
|
|
|
}
|
|
#endif
|
|
|
|
IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
|
|
|
|
FILL_LOCAL_TARGET(&LocalTarget, NewId);
|
|
RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
|
|
|
|
if (Device->MultiCardZeroVirtual ||
|
|
(IpxHeader->DestinationSocket == SAP_SOCKET)) {
|
|
|
|
//
|
|
// SAP frames need to look like they come from the
|
|
// local network, not the virtual one. The same is
|
|
// true if we are running multiple nets without
|
|
// a virtual net.
|
|
//
|
|
|
|
*(UNALIGNED ULONG *)IpxHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
|
|
RtlCopyMemory (IpxHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
|
|
}
|
|
|
|
//
|
|
// Fill in the MAC header and submit the frame to NDIS.
|
|
//
|
|
|
|
// #if DBG
|
|
CTEAssert (!Reserved->SendInProgress);
|
|
Reserved->SendInProgress = TRUE;
|
|
// #endif
|
|
|
|
//
|
|
// [FW] Call the InternalSendHandler of the Forwarder
|
|
//
|
|
|
|
if (Device->ForwarderBound) {
|
|
|
|
//
|
|
// Call the InternalSend to filter the packet and get to know
|
|
// the correct adapter context
|
|
//
|
|
|
|
NTSTATUS ret;
|
|
PUCHAR IpxHeader;
|
|
PUCHAR Data;
|
|
PNDIS_BUFFER HeaderBuffer;
|
|
UINT TempHeaderBufferLength;
|
|
UINT DataLength;
|
|
#ifdef SUNDOWN
|
|
ULONG_PTR FwdAdapterCtx = INVALID_CONTEXT_VALUE;
|
|
#else
|
|
ULONG FwdAdapterCtx = INVALID_CONTEXT_VALUE;
|
|
#endif
|
|
|
|
|
|
|
|
if (GET_LONG_VALUE(Binding->ReferenceCount) == 2) {
|
|
FwdAdapterCtx = Binding->FwdAdapterContext;
|
|
}
|
|
|
|
//
|
|
// Figure out the IpxHeader - it is always at the top of the second MDL.
|
|
//
|
|
NdisQueryPacket (NdisPacket, NULL, NULL, &HeaderBuffer, NULL);
|
|
NdisQueryBufferSafe (NDIS_BUFFER_LINKAGE(HeaderBuffer), &IpxHeader, &TempHeaderBufferLength, HighPagePriority);
|
|
|
|
//
|
|
// Data is always at the top of the third MDL.
|
|
//
|
|
NdisQueryBufferSafe (NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(HeaderBuffer)), &Data, &DataLength, HighPagePriority);
|
|
|
|
if (IpxHeader != NULL && Data != NULL) {
|
|
#ifdef SUNDOWN
|
|
// upper driver interface needs ULONG
|
|
ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)(
|
|
&LocalTarget,
|
|
FwdAdapterCtx,
|
|
NdisPacket,
|
|
IpxHeader,
|
|
Data,
|
|
(ULONG) (REQUEST_INFORMATION(Reserved->u.SR_DG.Request)) + sizeof(IPX_HEADER),
|
|
FALSE);
|
|
#else
|
|
ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)(
|
|
&LocalTarget,
|
|
FwdAdapterCtx,
|
|
NdisPacket,
|
|
IpxHeader,
|
|
Data,
|
|
REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
|
|
FALSE);
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
// The return shd not be a silent drop - we dont broadcast keepalives.
|
|
//
|
|
CTEAssert(ret != STATUS_DROP_SILENTLY);
|
|
|
|
if (ret == STATUS_SUCCESS) {
|
|
//
|
|
// The adapter could have gone away and we have indicated to the Forwarder
|
|
// but the Forwarder has not yet closed the adapter.
|
|
// [ZZ] adapters do not go away now.
|
|
//
|
|
// what if the binding is NULL here? Can we trust the Forwarder to
|
|
// give us a non-NULL binding?
|
|
//
|
|
Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&LocalTarget));
|
|
|
|
NewId = NIC_FROM_LOCAL_TARGET(&LocalTarget);
|
|
if (Binding == NULL || GET_LONG_VALUE(Binding->ReferenceCount) == 1) {
|
|
Adapter = Binding->Adapter;
|
|
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
FILL_LOCAL_TARGET(&Reserved->LocalTarget, NewId);
|
|
goto FunctionStart;
|
|
} else {
|
|
goto send_packet;
|
|
}
|
|
|
|
} else if (ret == STATUS_PENDING) {
|
|
//
|
|
// LocalTarget will get filled up in InternalSendComplete
|
|
//
|
|
return;
|
|
}
|
|
}
|
|
//
|
|
// else DISCARD
|
|
//
|
|
Adapter = Binding->Adapter;
|
|
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
goto FunctionStart;
|
|
|
|
} else {
|
|
send_packet:
|
|
//
|
|
// [FW] Use the frametype specific send handler
|
|
//
|
|
|
|
// if ((NdisStatus = IpxSendFrame(
|
|
// &LocalTarget,
|
|
// NdisPacket,
|
|
// REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
|
|
// sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
|
|
//
|
|
// Adapter = Binding->Adapter;
|
|
// goto FunctionStart;
|
|
// }
|
|
//
|
|
// return;
|
|
|
|
|
|
if ((IPX_NODE_EQUAL(IpxHeader->SourceNode, IpxHeader->DestinationNode)) &&
|
|
(*(UNALIGNED ULONG *)IpxHeader->SourceNetwork == *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork)) {
|
|
|
|
IPX_DEBUG(TEMP, ("It is self-directed. Loop it back ourselves (tdisenddatagram)\n"));
|
|
IsLoopback = TRUE;
|
|
|
|
}
|
|
|
|
pBinding = NIC_ID_TO_BINDING(Device, Reserved->LocalTarget.NicId);
|
|
|
|
if (pBinding) {
|
|
|
|
if ((IPX_NODE_EQUAL(Reserved->LocalTarget.MacAddress, pBinding->LocalAddress.NodeAddress)) ||
|
|
(IPX_NODE_EQUAL(pBinding->LocalAddress.NodeAddress, IpxHeader->DestinationNode))) {
|
|
|
|
IPX_DEBUG(TEMP, ("Source Net:%lx, Source Address: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
|
|
*(UNALIGNED ULONG *)IpxHeader->SourceNetwork,
|
|
IpxHeader->SourceNode[0],
|
|
IpxHeader->SourceNode[1],
|
|
IpxHeader->SourceNode[2],
|
|
IpxHeader->SourceNode[3],
|
|
IpxHeader->SourceNode[4],
|
|
IpxHeader->SourceNode[5]));
|
|
|
|
IPX_DEBUG(TEMP, ("Dest Net:%lx, DestAddress: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x \n",
|
|
*(UNALIGNED ULONG *)IpxHeader->DestinationNetwork,
|
|
IpxHeader->DestinationNode[0],
|
|
IpxHeader->DestinationNode[1],
|
|
IpxHeader->DestinationNode[2],
|
|
IpxHeader->DestinationNode[3],
|
|
IpxHeader->DestinationNode[4],
|
|
IpxHeader->DestinationNode[5]
|
|
));
|
|
|
|
IPX_DEBUG(TEMP, ("Well, It is self-directed. Loop it back ourselves (TDISENDDATAGRAM - NIC_HANDLE is the same!)\n"));
|
|
IsLoopback = TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
IPX_DEBUG(TEMP, ("Sending a packet now Loopback - %x\n", IsLoopback));
|
|
|
|
if (IsLoopback) {
|
|
//
|
|
// Enque this packet to the LoopbackQueue on the binding.
|
|
// If the LoopbackRtn is not already scheduled, schedule it.
|
|
//
|
|
|
|
IPX_DEBUG(LOOPB, ("Packet: %lx\n", NdisPacket));
|
|
|
|
//
|
|
// Recalculate packet counts here.
|
|
//
|
|
// NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
|
|
#if BACK_FILL
|
|
|
|
if (Reserved->BackFill) {
|
|
//
|
|
// Set the Header pointer and chain the first MDL
|
|
//
|
|
Reserved->Header = (PCHAR)Reserved->HeaderBuffer->MappedSystemVa;
|
|
NdisChainBufferAtFront(NdisPacket,(PNDIS_BUFFER)Reserved->HeaderBuffer);
|
|
}
|
|
#endif
|
|
NdisRecalculatePacketCounts (NdisPacket);
|
|
IpxLoopbackEnque(NdisPacket, NIC_ID_TO_BINDING(Device, 1)->Adapter);
|
|
|
|
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
return;
|
|
|
|
} else {
|
|
#ifdef SUNDOWN
|
|
|
|
if ((NdisStatus = (*Binding->SendFrameHandler)(
|
|
Binding->Adapter,
|
|
&LocalTarget,
|
|
NdisPacket,
|
|
(ULONG) (REQUEST_INFORMATION(Reserved->u.SR_DG.Request)) + sizeof(IPX_HEADER),
|
|
sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING)
|
|
#else
|
|
|
|
if ((NdisStatus = (*Binding->SendFrameHandler)(
|
|
Binding->Adapter,
|
|
&LocalTarget,
|
|
NdisPacket,
|
|
REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
|
|
sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING)
|
|
#endif
|
|
|
|
{
|
|
Adapter = Binding->Adapter;
|
|
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
goto RealFunctionStart;
|
|
}
|
|
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
|
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|
//
|
|
// If any of the sends succeeded then return
|
|
// success on the datagram send, otherwise
|
|
// use the most recent failure status.
|
|
//
|
|
|
|
if (Reserved->u.SR_DG.Net0SendSucceeded) {
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// NOTE: We don't NULL out the linkage field of the
|
|
// HeaderBuffer, which will leave the old buffer chain
|
|
// hanging off it; but that is OK because if we reuse
|
|
// this packet we will replace that chain with the new
|
|
// one, and before we free it we NULL it out.
|
|
//
|
|
// I.e. we don't do this:
|
|
//
|
|
|
|
NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer) = NULL;
|
|
NdisRecalculatePacketCounts (NdisPacket);
|
|
#endif
|
|
|
|
#if 0
|
|
{
|
|
ULONG ActualLength;
|
|
IpxGetMdlChainLength(NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer), &ActualLength);
|
|
if (ActualLength != REQUEST_INFORMATION(Reserved->u.SR_DG.Request)) {
|
|
DbgPrint ("IPX: At completion, IRP %lx has parameter length %d, buffer chain length %d\n",
|
|
Reserved->u.SR_DG.Request, REQUEST_INFORMATION(Reserved->u.SR_DG.Request), ActualLength);
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Save these so we can free the packet.
|
|
//
|
|
|
|
Request = Reserved->u.SR_DG.Request;
|
|
AddressFile = Reserved->u.SR_DG.AddressFile;
|
|
|
|
|
|
#if BACK_FILL
|
|
// Check if this is backfilled. If so restore users Mdl back to its original shape
|
|
// Also, push the packet on to backfillpacket queue if the packet is not owned by the address
|
|
|
|
|
|
if (Reserved->BackFill) {
|
|
|
|
|
|
IPX_DEBUG(SEND, ("MSVa:%lx, UL:%d\n", Reserved->MappedSystemVa, Reserved->UserLength));
|
|
|
|
Reserved->HeaderBuffer->MappedSystemVa = Reserved->MappedSystemVa;
|
|
Reserved->HeaderBuffer->ByteCount = Reserved->UserLength;
|
|
#ifdef SUNDOWN
|
|
Reserved->HeaderBuffer->StartVa = (PCHAR)((ULONG_PTR)Reserved->HeaderBuffer->MappedSystemVa & ~(PAGE_SIZE-1));
|
|
Reserved->HeaderBuffer->ByteOffset = (ULONG) ((ULONG_PTR)Reserved->HeaderBuffer->MappedSystemVa & (PAGE_SIZE-1));
|
|
#else
|
|
Reserved->HeaderBuffer->StartVa = (PCHAR)((ULONG)Reserved->HeaderBuffer->MappedSystemVa & ~(PAGE_SIZE-1));
|
|
Reserved->HeaderBuffer->ByteOffset = (ULONG)Reserved->HeaderBuffer->MappedSystemVa & (PAGE_SIZE-1);
|
|
#endif
|
|
|
|
ASSERT((LONG)Reserved->HeaderBuffer->ByteOffset >= 0);
|
|
|
|
IPX_DEBUG(SEND, ("completeing back filled userMdl %x\n",Reserved->HeaderBuffer));
|
|
|
|
|
|
|
|
NdisPacket->Private.ValidCounts = FALSE;
|
|
|
|
NdisPacket->Private.Head = NULL;
|
|
NdisPacket->Private.Tail = NULL;
|
|
Reserved->HeaderBuffer = NULL;
|
|
|
|
if (Reserved->OwnedByAddress) {
|
|
|
|
// Reserved->Address->BackFillPacketInUse = FALSE;
|
|
InterlockedDecrement(&Reserved->Address->BackFillPacketInUse);
|
|
|
|
IPX_DEBUG(SEND, ("Freeing owned backfill %x\n", Reserved));
|
|
|
|
} else {
|
|
|
|
IPX_PUSH_ENTRY_LIST(
|
|
&Device->BackFillPacketList,
|
|
&Reserved->PoolLinkage,
|
|
&Device->SListsLock);
|
|
}
|
|
}
|
|
// not a back fill packet. Push it on sendpacket pool
|
|
else {
|
|
|
|
if (Reserved->OwnedByAddress) {
|
|
|
|
// Reserved->Address->SendPacketInUse = FALSE;
|
|
InterlockedDecrement(&Reserved->Address->SendPacketInUse);
|
|
|
|
} else {
|
|
|
|
IPX_PUSH_ENTRY_LIST(
|
|
&Device->SendPacketList,
|
|
&Reserved->PoolLinkage,
|
|
&Device->SListsLock);
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (Reserved->OwnedByAddress) {
|
|
|
|
|
|
Reserved->Address->SendPacketInUse = FALSE;
|
|
|
|
} else {
|
|
|
|
IPX_PUSH_ENTRY_LIST(
|
|
&Device->SendPacketList,
|
|
&Reserved->PoolLinkage,
|
|
&Device->SListsLock);
|
|
|
|
}
|
|
#endif
|
|
|
|
++Device->Statistics.PacketsSent;
|
|
|
|
//
|
|
// If this is a fast send irp, we bypass the file system and
|
|
// call the completion routine directly.
|
|
//
|
|
|
|
REQUEST_STATUS(Request) = NdisStatus;
|
|
irpSp = IoGetCurrentIrpStackLocation( Request );
|
|
|
|
if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
|
|
|
|
Request->CurrentLocation++,
|
|
Request->Tail.Overlay.CurrentStackLocation++;
|
|
|
|
(VOID) irpSp->CompletionRoutine(
|
|
NULL,
|
|
Request,
|
|
irpSp->Context
|
|
);
|
|
|
|
} else {
|
|
IpxCompleteRequest (Request);
|
|
}
|
|
|
|
IpxFreeRequest(Device, Request);
|
|
|
|
IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
|
|
|
|
break;
|
|
|
|
case IDENTIFIER_RIP_INTERNAL:
|
|
|
|
CTEAssert (Reserved->SendInProgress);
|
|
Reserved->SendInProgress = FALSE;
|
|
break;
|
|
|
|
case IDENTIFIER_RIP_RESPONSE:
|
|
|
|
CTEAssert (Reserved->SendInProgress);
|
|
Reserved->SendInProgress = FALSE;
|
|
|
|
Reserved->Identifier = IDENTIFIER_IPX;
|
|
IPX_PUSH_ENTRY_LIST(
|
|
&Device->SendPacketList,
|
|
&Reserved->PoolLinkage,
|
|
&Device->SListsLock);
|
|
|
|
IpxDereferenceDevice (Device, DREF_RIP_PACKET);
|
|
break;
|
|
|
|
case IDENTIFIER_NB:
|
|
case IDENTIFIER_SPX:
|
|
|
|
//
|
|
// See if this is an iterative send
|
|
//
|
|
if (OldId = Reserved->CurrentNicId) {
|
|
|
|
PNDIS_BUFFER HeaderBuffer;
|
|
UINT TempHeaderBufferLength;
|
|
PUCHAR Header;
|
|
PIPX_HEADER IpxHeader;
|
|
BOOLEAN fFwdDecides=FALSE;
|
|
|
|
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS) {
|
|
Reserved->Net0SendSucceeded = TRUE;
|
|
}
|
|
|
|
//
|
|
// Figure out the IpxHeader - it is always at the top of the second MDL.
|
|
//
|
|
NdisQueryPacket (NdisPacket, NULL, NULL, &HeaderBuffer, NULL);
|
|
NdisQueryBufferSafe (NDIS_BUFFER_LINKAGE(HeaderBuffer), &IpxHeader, &TempHeaderBufferLength, HighPagePriority);
|
|
|
|
if (IpxHeader == NULL) {
|
|
DbgPrint("IpxSendComplete: NdisQuerryBufferSafe failed. Stop iterative send\n");
|
|
goto NoMoreSends;
|
|
}
|
|
//
|
|
// For Type 20 pkts, we let the Fwd decide the next Nic to send on, so we pass
|
|
// the old Nic itself and let the Fwd change it for us.
|
|
//
|
|
if ((Device->ForwarderBound) &&
|
|
(IpxHeader->PacketType == 0x14)) {
|
|
NewId = NIC_FROM_LOCAL_TARGET(&Reserved->LocalTarget);
|
|
fFwdDecides=TRUE;
|
|
|
|
Binding = NIC_ID_TO_BINDING(Device, NewId);
|
|
|
|
//
|
|
// 206647: It is likely that after we sent the previous packet, the binding on which we
|
|
// sent it is gone (due to an unbindadapter or whatever). if it is Null, get the previous
|
|
// good NICID and pass it to the forwarder to get the next one. We should be in sync
|
|
// with the forwarder and so it will tell us the next logical one it thinks is right.
|
|
//
|
|
//
|
|
if (!Binding) {
|
|
USHORT Index = NewId;
|
|
|
|
while (Index-- > 0) { //using 0, since we should atleast have Loopback - nicid 1
|
|
if( Binding = NIC_ID_TO_BINDING(Device, Index)) {
|
|
//
|
|
// So we found something good. Let's set newid to this Index and we should
|
|
// be all set.
|
|
//
|
|
NewId = Index;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
IPX_DEBUG(SEND, ("SendComplete: IpxHeader has Type20: %lx\n", IpxHeader));
|
|
|
|
} else {
|
|
|
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|
{
|
|
ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
|
|
|
|
Binding = NULL;
|
|
|
|
for (NewId = OldId+1; NewId <= Index; NewId++) {
|
|
if (Binding = NIC_ID_TO_BINDING(Device, NewId)) {
|
|
//
|
|
// Found next NIC to send on
|
|
//
|
|
//
|
|
// 179436 - If forwarder is bound then ensure that we are picking a Binding that
|
|
// the forwarder has an open context on. Otherwise, go to the next good binding
|
|
//
|
|
if (Device->ForwarderBound) {
|
|
if (GET_LONG_VALUE(Binding->ReferenceCount) == 2) {
|
|
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Binding != NULL && NewId <= MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
|
|
|
|
IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|
|
|
//
|
|
// Yes, we found another net to send it on, so
|
|
// move the header around if needed and do so.
|
|
//
|
|
IPX_DEBUG(SEND, ("ISN iteration: OldId: %lx, NewId: %lx\n", OldId, NewId));
|
|
Reserved->CurrentNicId = NewId;
|
|
|
|
FILL_LOCAL_TARGET(&LocalTarget, NewId);
|
|
RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
|
|
|
|
//
|
|
// [FW] Call the InternalSendHandler of the Forwarder
|
|
//
|
|
|
|
if (Device->ForwarderBound) {
|
|
|
|
//
|
|
// Call the InternalSend to filter the packet and get to know
|
|
// the correct adapter context
|
|
//
|
|
|
|
NTSTATUS ret;
|
|
PUCHAR Data;
|
|
UINT DataLength;
|
|
#ifdef SUNDOWN
|
|
ULONG_PTR FwdAdapterCtx = INVALID_CONTEXT_VALUE;
|
|
#else
|
|
ULONG FwdAdapterCtx = INVALID_CONTEXT_VALUE;
|
|
#endif
|
|
|
|
|
|
|
|
if (GET_LONG_VALUE(Binding->ReferenceCount) == 2) {
|
|
FwdAdapterCtx = Binding->FwdAdapterContext;
|
|
}
|
|
|
|
ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)(
|
|
&LocalTarget,
|
|
FwdAdapterCtx,
|
|
NdisPacket,
|
|
(PUCHAR)IpxHeader,
|
|
((PUCHAR)IpxHeader)+sizeof(IPX_HEADER), // the data starts after the IPX Header.
|
|
Reserved->PacketLength,
|
|
TRUE); // iterate is true
|
|
|
|
//
|
|
// The return shd not be a silent drop - we dont broadcast keepalives.
|
|
//
|
|
CTEAssert(ret != STATUS_DROP_SILENTLY);
|
|
|
|
if (ret == STATUS_SUCCESS) {
|
|
//
|
|
// The adapter could have gone away and we have indicated to the Forwarder
|
|
// but the Forwarder has not yet closed the adapter.
|
|
// [ZZ] adapters do not go away now.
|
|
//
|
|
// what if the binding is NULL here? Can we trust the Forwarder to
|
|
// give us a non-NULL binding?
|
|
//
|
|
Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&LocalTarget));
|
|
|
|
NewId = NIC_FROM_LOCAL_TARGET(&LocalTarget);
|
|
if (Binding == NULL || GET_LONG_VALUE(Binding->ReferenceCount) == 1) {
|
|
if (Binding != NULL) {
|
|
Adapter = Binding->Adapter;
|
|
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
}
|
|
FILL_LOCAL_TARGET(&Reserved->LocalTarget, NewId);
|
|
DbgPrint("IPX: FWD returns an invalid nic id %d, no more sends\n", NewId);
|
|
goto NoMoreSends;
|
|
} else {
|
|
goto send_packet1;
|
|
}
|
|
|
|
} else if (ret == STATUS_PENDING) {
|
|
//
|
|
// LocalTarget will get filled up in InternalSendComplete
|
|
//
|
|
return;
|
|
}
|
|
//
|
|
// else DISCARD
|
|
//
|
|
Adapter = Binding->Adapter;
|
|
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
|
|
//
|
|
// If Fwd decides, then this is end of Nic list - complete the send.
|
|
//
|
|
if (fFwdDecides) {
|
|
goto NoMoreSends;
|
|
} else {
|
|
goto FunctionStart;
|
|
}
|
|
|
|
} else {
|
|
#if DBG
|
|
NdisQueryPacket (NdisPacket, NULL, NULL, &HeaderBuffer, NULL);
|
|
NdisQueryBufferSafe(HeaderBuffer, &Header, &TempHeaderBufferLength, LowPagePriority);
|
|
|
|
if (Header != NULL) {
|
|
IpxHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
|
|
|
|
IPX_DEBUG(SEND, ("SendComplete: IpxHeader: %lx\n", IpxHeader));
|
|
}
|
|
#endif
|
|
|
|
send_packet1:
|
|
|
|
FILL_LOCAL_TARGET(&Reserved->LocalTarget, NewId);
|
|
|
|
if ((IPX_NODE_EQUAL(IpxHeader->SourceNode, IpxHeader->DestinationNode)) &&
|
|
(*(UNALIGNED ULONG *)IpxHeader->SourceNetwork == *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork)) {
|
|
|
|
IPX_DEBUG(TEMP, ("It is self-directed. Loop it back ourselves (tdisenddatagram)\n"));
|
|
IsLoopback = TRUE;
|
|
|
|
}
|
|
|
|
pBinding = NIC_ID_TO_BINDING(Device, Reserved->LocalTarget.NicId);
|
|
|
|
if (pBinding) {
|
|
|
|
if ((IPX_NODE_EQUAL(Reserved->LocalTarget.MacAddress, pBinding->LocalAddress.NodeAddress)) ||
|
|
(IPX_NODE_EQUAL(pBinding->LocalAddress.NodeAddress, IpxHeader->DestinationNode))) {
|
|
|
|
IPX_DEBUG(TEMP, ("Source Net:%lx, Source Address: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
|
|
*(UNALIGNED ULONG *)IpxHeader->SourceNetwork,
|
|
IpxHeader->SourceNode[0],
|
|
IpxHeader->SourceNode[1],
|
|
IpxHeader->SourceNode[2],
|
|
IpxHeader->SourceNode[3],
|
|
IpxHeader->SourceNode[4],
|
|
IpxHeader->SourceNode[5]));
|
|
|
|
IPX_DEBUG(TEMP, ("Dest Net:%lx, DestAddress: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x \n",
|
|
*(UNALIGNED ULONG *)IpxHeader->DestinationNetwork,
|
|
IpxHeader->DestinationNode[0],
|
|
IpxHeader->DestinationNode[1],
|
|
IpxHeader->DestinationNode[2],
|
|
IpxHeader->DestinationNode[3],
|
|
IpxHeader->DestinationNode[4],
|
|
IpxHeader->DestinationNode[5]
|
|
));
|
|
|
|
IPX_DEBUG(TEMP, ("Well, It is self-directed. Loop it back ourselves (TDISENDDATAGRAM - NIC_HANDLE is the same!)\n"));
|
|
IsLoopback = TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
IPX_DEBUG(TEMP, ("Sending a packet now. Loopback?:%x\n", IsLoopback));
|
|
|
|
if (IsLoopback) {
|
|
//
|
|
// Enque this packet to the LoopbackQueue on the binding.
|
|
// If the LoopbackRtn is not already scheduled, schedule it.
|
|
//
|
|
|
|
IPX_DEBUG(LOOPB, ("Packet: %lx\n", NdisPacket));
|
|
|
|
//
|
|
// Recalculate packet counts here.
|
|
//
|
|
// NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
|
|
NdisRecalculatePacketCounts (NdisPacket);
|
|
IpxLoopbackEnque(NdisPacket, NIC_ID_TO_BINDING(Device, 1)->Adapter);
|
|
|
|
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
return;
|
|
|
|
} else {
|
|
|
|
|
|
//
|
|
// We don't need to so this since the macaddress is replaced in
|
|
// IpxSendFrame anyway. The LocalTarget is the same as the one on
|
|
// the original send - this is passed down for further sends.
|
|
//
|
|
// RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
|
|
|
|
//
|
|
// Fill in the MAC header and submit the frame to NDIS.
|
|
//
|
|
|
|
if ((NdisStatus = IpxSendFrame(
|
|
&Reserved->LocalTarget,
|
|
NdisPacket,
|
|
Reserved->PacketLength,
|
|
sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
|
|
|
|
Adapter = Binding->Adapter;
|
|
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
goto FunctionStart;
|
|
}
|
|
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|
NoMoreSends:
|
|
//
|
|
// If any of the sends succeeded then return
|
|
// success on the datagram send, otherwise
|
|
// use the most recent failure status.
|
|
//
|
|
if (Reserved->Net0SendSucceeded) {
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// fall thru'
|
|
//
|
|
default:
|
|
ASSERT((*Device->UpperDrivers[Reserved->Identifier].SendCompleteHandler) != NULL);
|
|
(*Device->UpperDrivers[Reserved->Identifier].SendCompleteHandler)(
|
|
NdisPacket,
|
|
NdisStatus);
|
|
break;
|
|
}
|
|
|
|
} /* IpxSendComplete */
|
|
|
|
|
|
NTSTATUS
|
|
IpxTdiSendDatagram(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PREQUEST Request
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the TdiSendDatagram request for the transport
|
|
provider.
|
|
|
|
Arguments:
|
|
|
|
Request - Pointer to the request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PADDRESS_FILE AddressFile;
|
|
PADDRESS Address;
|
|
PNDIS_PACKET Packet;
|
|
PIPX_SEND_RESERVED Reserved;
|
|
PSLIST_ENTRY s;
|
|
TDI_ADDRESS_IPX UNALIGNED * RemoteAddress;
|
|
TDI_ADDRESS_IPX TempAddress;
|
|
TA_ADDRESS * AddressName;
|
|
PTDI_CONNECTION_INFORMATION Information;
|
|
PTDI_REQUEST_KERNEL_SENDDG Parameters;
|
|
PBINDING Binding, pBinding = NULL;
|
|
IPX_LOCAL_TARGET TempLocalTarget;
|
|
PIPX_LOCAL_TARGET LocalTarget;
|
|
PDEVICE Device = IpxDevice;
|
|
UCHAR PacketType;
|
|
NTSTATUS Status;
|
|
PIPX_HEADER IpxHeader, pIpxHeader;
|
|
NDIS_STATUS NdisStatus;
|
|
USHORT LengthIncludingHeader;
|
|
IPX_DEFINE_SYNC_CONTEXT (SyncContext)
|
|
IPX_DEFINE_LOCK_HANDLE (LockHandle)
|
|
PIO_STACK_LOCATION irpSp; \
|
|
BOOLEAN IsLoopback = FALSE;
|
|
IPX_FIND_ROUTE_REQUEST routeEntry;
|
|
PIPX_DATAGRAM_OPTIONS2 Options;
|
|
KPROCESSOR_MODE PreviousMode;
|
|
|
|
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
|
|
|
|
#ifdef SNMP
|
|
++IPX_MIB_ENTRY(Device, SysOutRequests);
|
|
#endif SNMP
|
|
|
|
|
|
|
|
//
|
|
// Do a quick check of the validity of the address.
|
|
//
|
|
|
|
AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
|
|
|
|
IPX_BEGIN_SYNC (&SyncContext);
|
|
|
|
if ((AddressFile->Size == sizeof (ADDRESS_FILE)) &&
|
|
(AddressFile->Type == IPX_ADDRESSFILE_SIGNATURE) &&
|
|
((Address = AddressFile->Address) != NULL)) {
|
|
|
|
IPX_GET_LOCK (&Address->Lock, &LockHandle);
|
|
|
|
if (AddressFile->State != ADDRESSFILE_STATE_CLOSING) {
|
|
|
|
Parameters = (PTDI_REQUEST_KERNEL_SENDDG)REQUEST_PARAMETERS(Request);
|
|
|
|
//
|
|
// Previously it was kmode, so things are trusted.
|
|
//
|
|
Information = Parameters->SendDatagramInformation;
|
|
|
|
if (!REQUEST_SPECIAL_SEND(Request)) {
|
|
AddressName = &((TRANSPORT_ADDRESS UNALIGNED *)(Information->RemoteAddress))->Address[0];
|
|
|
|
if ((AddressName->AddressType == TDI_ADDRESS_TYPE_IPX) &&
|
|
(AddressName->AddressLength >= sizeof(TDI_ADDRESS_IPX))) {
|
|
|
|
RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)(AddressName->Address);
|
|
|
|
} else if ((RemoteAddress = IpxParseTdiAddress (Information->RemoteAddress)) == NULL) {
|
|
|
|
IPX_FREE_LOCK (&Address->Lock, LockHandle);
|
|
Status = STATUS_INVALID_ADDRESS;
|
|
#ifdef SNMP
|
|
++IPX_MIB_ENTRY(Device, SysOutDiscards);
|
|
#endif SNMP
|
|
goto error_send_no_packet;
|
|
}
|
|
} else {
|
|
ASSERT(OPEN_REQUEST_EA_LENGTH(Request) == sizeof(IPX_DATAGRAM_OPTIONS2));
|
|
Options = ((PIPX_DATAGRAM_OPTIONS2)(OPEN_REQUEST_EA_INFORMATION(Request)));
|
|
RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)(&Options->RemoteAddress);
|
|
IPX_DEBUG(SEND, ("IpxTdiSendDatagram: Options buffer supplied as input buffer\n"));
|
|
}
|
|
|
|
IPX_DEBUG (SEND, ("Send on %lx, network %lx socket %lx\n",
|
|
Address, RemoteAddress->NetworkAddress, RemoteAddress->Socket));
|
|
|
|
#if 0
|
|
if (Parameters->SendLength > IpxDevice->RealMaxDatagramSize) {
|
|
|
|
IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
|
|
Parameters->SendLength,
|
|
IpxDevice->RealMaxDatagramSize));
|
|
|
|
REQUEST_INFORMATION(Request) = 0;
|
|
IPX_FREE_LOCK (&Address->Lock, LockHandle);
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
goto error_send_no_packet;
|
|
}
|
|
#endif
|
|
//
|
|
// Every address has one packet committed to it, use that
|
|
// if possible, otherwise take one out of the pool.
|
|
//
|
|
|
|
|
|
#if BACK_FILL
|
|
|
|
// If the request is coming from the server, which resrves transport header space
|
|
// build the header in its space. Allocate a special packet to which does not contain
|
|
// mac and ipx headers in its reserved space.
|
|
|
|
if ((PMDL)REQUEST_NDIS_BUFFER(Request) &&
|
|
(((PMDL)REQUEST_NDIS_BUFFER(Request))->MdlFlags & MDL_NETWORK_HEADER) &&
|
|
(!(Information->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS))) &&
|
|
(RemoteAddress->NodeAddress[0] != 0xff)) {
|
|
|
|
//if (!Address->BackFillPacketInUse) {
|
|
if (InterlockedExchangeAdd(&Address->BackFillPacketInUse, 0) == 0) {
|
|
//Address->BackFillPacketInUse = TRUE;
|
|
InterlockedIncrement(&Address->BackFillPacketInUse);
|
|
|
|
Packet = PACKET(&Address->BackFillPacket);
|
|
Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
|
|
IPX_DEBUG(SEND, ("Getting owned backfill %x %x \n", Packet,Reserved));
|
|
|
|
}else {
|
|
|
|
s = IPX_POP_ENTRY_LIST(
|
|
&Device->BackFillPacketList,
|
|
&Device->SListsLock);
|
|
|
|
if (s != NULL) {
|
|
goto GotBackFillPacket;
|
|
}
|
|
|
|
//
|
|
// This function tries to allocate another packet pool.
|
|
//
|
|
|
|
s = IpxPopBackFillPacket(Device);
|
|
|
|
//
|
|
// Possibly we should queue the packet up to wait
|
|
// for one to become free.
|
|
//
|
|
|
|
if (s == NULL) {
|
|
IPX_FREE_LOCK (&Address->Lock, LockHandle);
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
#ifdef SNMP
|
|
++IPX_MIB_ENTRY(Device, SysOutDiscards);
|
|
#endif SNMP
|
|
goto error_send_no_packet;
|
|
}
|
|
|
|
GotBackFillPacket:
|
|
|
|
Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
|
|
Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
|
|
IPX_DEBUG(SEND, ("getting backfill packet %x %x %x\n", s, Reserved, RemoteAddress->NodeAddress));
|
|
if(!Reserved->BackFill)DbgBreakPoint();
|
|
|
|
}
|
|
|
|
}else {
|
|
|
|
// if (!Address->SendPacketInUse) {
|
|
if (InterlockedExchangeAdd(&Address->SendPacketInUse, 0) == 0) {
|
|
// Address->SendPacketInUse = TRUE;
|
|
InterlockedIncrement(&Address->SendPacketInUse);
|
|
|
|
Packet = PACKET(&Address->SendPacket);
|
|
Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
|
|
|
|
} else {
|
|
|
|
s = IPX_POP_ENTRY_LIST(
|
|
&Device->SendPacketList,
|
|
&Device->SListsLock);
|
|
|
|
if (s != NULL) {
|
|
goto GotPacket;
|
|
}
|
|
|
|
//
|
|
// This function tries to allocate another packet pool.
|
|
//
|
|
|
|
s = IpxPopSendPacket(Device);
|
|
|
|
//
|
|
// Possibly we should queue the packet up to wait
|
|
// for one to become free.
|
|
//
|
|
|
|
if (s == NULL) {
|
|
IPX_FREE_LOCK (&Address->Lock, LockHandle);
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
#ifdef SNMP
|
|
++IPX_MIB_ENTRY(Device, SysOutDiscards);
|
|
#endif SNMP
|
|
goto error_send_no_packet;
|
|
}
|
|
|
|
GotPacket:
|
|
|
|
Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
|
|
Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
|
|
Reserved->BackFill = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
#else
|
|
|
|
if (!Address->SendPacketInUse) {
|
|
|
|
Address->SendPacketInUse = TRUE;
|
|
Packet = PACKET(&Address->SendPacket);
|
|
Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
|
|
|
|
} else {
|
|
|
|
s = IPX_POP_ENTRY_LIST(
|
|
&Device->SendPacketList,
|
|
&Device->SListsLock);
|
|
|
|
if (s != NULL) {
|
|
goto GotPacket;
|
|
}
|
|
|
|
//
|
|
// This function tries to allocate another packet pool.
|
|
//
|
|
|
|
s = IpxPopSendPacket(Device);
|
|
|
|
//
|
|
// Possibly we should queue the packet up to wait
|
|
// for one to become free.
|
|
//
|
|
|
|
if (s == NULL) {
|
|
IPX_FREE_LOCK (&Address->Lock, LockHandle);
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto error_send_no_packet;
|
|
}
|
|
|
|
GotPacket:
|
|
|
|
Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
|
|
Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
IpxReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
|
|
|
|
IPX_FREE_LOCK (&Address->Lock, LockHandle);
|
|
|
|
//
|
|
// Save this now while we have Parameters available.
|
|
//
|
|
|
|
REQUEST_INFORMATION(Request) = Parameters->SendLength;
|
|
LengthIncludingHeader = (USHORT)(Parameters->SendLength + sizeof(IPX_HEADER));
|
|
|
|
#if 0
|
|
{
|
|
ULONG ActualLength;
|
|
IpxGetMdlChainLength(REQUEST_NDIS_BUFFER(Request), &ActualLength);
|
|
if (ActualLength != Parameters->SendLength) {
|
|
DbgPrint ("IPX: IRP %lx has parameter length %d, buffer chain length %d\n",
|
|
Request, Parameters->SendLength, ActualLength);
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
Reserved->u.SR_DG.AddressFile = AddressFile;
|
|
Reserved->u.SR_DG.Request = Request;
|
|
CTEAssert (Reserved->Identifier == IDENTIFIER_IPX);
|
|
|
|
|
|
//
|
|
// Set this to 0; this means the packet is not one that
|
|
// should be broadcast on all nets. We will change it
|
|
// later if it turns out this is the case.
|
|
//
|
|
|
|
Reserved->u.SR_DG.CurrentNicId = 0;
|
|
|
|
//
|
|
// We need this to track these packets specially.
|
|
//
|
|
|
|
Reserved->u.SR_DG.OutgoingSap = AddressFile->IsSapSocket;
|
|
|
|
//
|
|
// Add the MDL chain after the pre-allocated header buffer.
|
|
// NOTE: THIS WILL ONLY WORK IF WE EVENTUALLY CALL
|
|
// NDISRECALCULATEPACKETCOUNTS (which we do in IpxSendFrame).
|
|
//
|
|
//
|
|
#if BACK_FILL
|
|
|
|
if (Reserved->BackFill) {
|
|
Reserved->HeaderBuffer = REQUEST_NDIS_BUFFER(Request);
|
|
|
|
//remove the ipx mdl from the packet.
|
|
Reserved->UserLength = Reserved->HeaderBuffer->ByteCount;
|
|
|
|
IPX_DEBUG(SEND, ("back filling userMdl Reserved %x %x\n", Reserved->HeaderBuffer, Reserved));
|
|
} else {
|
|
NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = REQUEST_NDIS_BUFFER(Request);
|
|
}
|
|
#else
|
|
NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = REQUEST_NDIS_BUFFER(Request);
|
|
#endif
|
|
|
|
|
|
//
|
|
// If IrpSp does not have a buffer for the right size for
|
|
// datagram options and there is no input buffer
|
|
//
|
|
if (!REQUEST_SPECIAL_SEND(Request) &&
|
|
(Information->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS))) {
|
|
|
|
//
|
|
// The caller did not supply the local target for this
|
|
// send, so we look it up ourselves.
|
|
//
|
|
|
|
UINT Segment;
|
|
|
|
//
|
|
// We calculate this now since we need to know
|
|
// if it is directed below.
|
|
//
|
|
if (RemoteAddress->NodeAddress[0] == 0xff) {
|
|
// What about multicast?
|
|
if ((*(UNALIGNED ULONG *)(RemoteAddress->NodeAddress) != 0xffffffff) ||
|
|
(*(UNALIGNED USHORT *)(RemoteAddress->NodeAddress+4) != 0xffff)) {
|
|
Reserved->DestinationType = DESTINATION_MCAST;
|
|
} else {
|
|
Reserved->DestinationType = DESTINATION_BCAST;
|
|
}
|
|
} else {
|
|
Reserved->DestinationType = DESTINATION_DEF; // directed send
|
|
}
|
|
|
|
//
|
|
// If there are no options, then check if the
|
|
// caller is passing the packet type as a final byte
|
|
// in the remote address; if not use the default.
|
|
//
|
|
|
|
if (Information->OptionsLength == 0) {
|
|
if (AddressFile->ExtendedAddressing) {
|
|
PacketType = ((PUCHAR)(RemoteAddress+1))[0];
|
|
} else {
|
|
PacketType = AddressFile->DefaultPacketType;
|
|
}
|
|
} else {
|
|
PacketType = ((PUCHAR)(Information->Options))[0];
|
|
}
|
|
|
|
if ((Reserved->DestinationType != DESTINATION_DEF) &&
|
|
((RemoteAddress->NetworkAddress == 0) ||
|
|
(Device->VirtualNetwork &&
|
|
(RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)))) {
|
|
|
|
|
|
//
|
|
// Do we have any REAL adapters? If not, just get out now.
|
|
//
|
|
if (!Device->RealAdapters) {
|
|
|
|
IPX_END_SYNC (&SyncContext);
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation( Request );
|
|
|
|
if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
|
|
|
|
REQUEST_STATUS(Request) = STATUS_SUCCESS;
|
|
Request->CurrentLocation++,
|
|
Request->Tail.Overlay.CurrentStackLocation++;
|
|
|
|
(VOID) irpSp->CompletionRoutine(
|
|
NULL,
|
|
Request,
|
|
irpSp->Context
|
|
);
|
|
|
|
IpxFreeRequest (DeviceObject, Request);
|
|
}
|
|
|
|
IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// This packet needs to be broadcast to all networks.
|
|
// Make sure it is not too big for any of them.
|
|
//
|
|
|
|
if (Parameters->SendLength > Device->RealMaxDatagramSize) {
|
|
IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
|
|
Parameters->SendLength, Device->RealMaxDatagramSize));
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
#ifdef SNMP
|
|
++IPX_MIB_ENTRY(Device, SysOutMalformedRequests);
|
|
#endif SNMP
|
|
goto error_send_with_packet;
|
|
}
|
|
|
|
//
|
|
// If this is a broadcast to the virtual net, we
|
|
// need to construct a fake remote address which
|
|
// has network 0 in there instead.
|
|
//
|
|
|
|
if (Device->VirtualNetwork &&
|
|
(RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)) {
|
|
|
|
RtlCopyMemory (&TempAddress, (PVOID)RemoteAddress, sizeof(TDI_ADDRESS_IPX));
|
|
TempAddress.NetworkAddress = 0;
|
|
RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)&TempAddress;
|
|
|
|
}
|
|
|
|
//
|
|
// If someone is sending to the SAP socket and
|
|
// we are running with multiple cards without a
|
|
// virtual network, AND this packet is a SAP response,
|
|
// then we log an error to warn them that the
|
|
// system may not work as they like (since there
|
|
// is no virtual network to advertise, we use
|
|
// the first card's net/node as our local address).
|
|
// We only do this once per boot, using the
|
|
// SapWarningLogged variable to control that.
|
|
//
|
|
|
|
if ((RemoteAddress->Socket == SAP_SOCKET) &&
|
|
(!Device->SapWarningLogged) &&
|
|
(Device->MultiCardZeroVirtual)) {
|
|
|
|
PNDIS_BUFFER FirstBuffer;
|
|
UINT FirstBufferLength;
|
|
USHORT UNALIGNED * FirstBufferData;
|
|
|
|
if ((FirstBuffer = REQUEST_NDIS_BUFFER(Request)) != NULL) {
|
|
|
|
NdisQueryBufferSafe (
|
|
FirstBuffer,
|
|
(PVOID *)&FirstBufferData,
|
|
&FirstBufferLength, NormalPagePriority);
|
|
|
|
if (FirstBufferData != NULL) {
|
|
|
|
//
|
|
// The first two bytes of a SAP packet are the
|
|
// operation, 0x2 (in network order) is response.
|
|
//
|
|
|
|
if ((FirstBufferLength >= sizeof(USHORT)) &&
|
|
(*FirstBufferData == 0x0200)) {
|
|
|
|
Device->SapWarningLogged = TRUE;
|
|
|
|
IpxWriteGeneralErrorLog(
|
|
Device->DeviceObject,
|
|
EVENT_IPX_SAP_ANNOUNCE,
|
|
777,
|
|
STATUS_NOT_SUPPORTED,
|
|
NULL,
|
|
0,
|
|
NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// In this case we do not RIP but instead set the
|
|
// packet up so it is sent to each network in turn.
|
|
//
|
|
// Special case: If this packet is from the SAP
|
|
// socket and we are running with multiple cards
|
|
// without a virtual network, we only send this
|
|
// on the card with NIC ID 1, so we leave
|
|
// CurrentNicId set to 0.
|
|
//
|
|
|
|
//
|
|
// What if NicId 1 is invalid? Should scan
|
|
// for first valid one, fail send if none.
|
|
//
|
|
|
|
if ((Address->Socket != SAP_SOCKET) ||
|
|
(!Device->MultiCardZeroVirtual)) {
|
|
|
|
if (Device->SingleNetworkActive) {
|
|
|
|
if (Device->ActiveNetworkWan) {
|
|
Reserved->u.SR_DG.CurrentNicId = Device->FirstWanNicId;
|
|
} else {
|
|
Reserved->u.SR_DG.CurrentNicId = Device->FirstLanNicId;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Is this the change I need to make?
|
|
//
|
|
|
|
Reserved->u.SR_DG.CurrentNicId = FIRST_REAL_BINDING;
|
|
|
|
}
|
|
|
|
Reserved->u.SR_DG.Net0SendSucceeded = FALSE;
|
|
|
|
//
|
|
// In this case, we need to scan for the first
|
|
// non-dialout wan socket.
|
|
//
|
|
|
|
if ((Device->DisableDialoutSap) &&
|
|
(Address->Socket == SAP_SOCKET)) {
|
|
|
|
PBINDING TempBinding;
|
|
|
|
CTEAssert (Reserved->u.SR_DG.CurrentNicId <= Device->ValidBindings);
|
|
while (Reserved->u.SR_DG.CurrentNicId <= MIN (Device->MaxBindings, Device->ValidBindings)) {
|
|
// No need to lock the access path since he just looks at it
|
|
//
|
|
TempBinding = NIC_ID_TO_BINDING(Device, Reserved->u.SR_DG.CurrentNicId);
|
|
if ((TempBinding != NULL) &&
|
|
(!TempBinding->DialOutAsync)) {
|
|
|
|
break;
|
|
|
|
}
|
|
++Reserved->u.SR_DG.CurrentNicId;
|
|
}
|
|
if (Reserved->u.SR_DG.CurrentNicId > MIN (Device->MaxBindings, Device->ValidBindings)) {
|
|
//
|
|
// [SA] Bug #17273 return proper error mesg.
|
|
//
|
|
|
|
// Status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
Status = STATUS_NETWORK_UNREACHABLE;
|
|
|
|
goto error_send_with_packet;
|
|
}
|
|
}
|
|
|
|
FILL_LOCAL_TARGET(&TempLocalTarget, Reserved->u.SR_DG.CurrentNicId);
|
|
|
|
} else {
|
|
FILL_LOCAL_TARGET(&TempLocalTarget, FIRST_REAL_BINDING);
|
|
}
|
|
|
|
RtlCopyMemory(TempLocalTarget.MacAddress, RemoteAddress->NodeAddress, 6);
|
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|
Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&TempLocalTarget));
|
|
IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|
|
|
//
|
|
// [FW] the localtarget shd be in the packet's reserved section
|
|
//
|
|
LocalTarget = &Reserved->LocalTarget;
|
|
Reserved->LocalTarget = TempLocalTarget;
|
|
} else {
|
|
|
|
//
|
|
// [FW] If router installed, call the Forwarder's FindRouteHandler.
|
|
// This returns a STATUS_SUCCESS if a route is available
|
|
//
|
|
if (Device->ForwarderBound) {
|
|
|
|
Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) (
|
|
(PUCHAR)&RemoteAddress->NetworkAddress,
|
|
RemoteAddress->NodeAddress,
|
|
&routeEntry);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
|
|
IPX_DEBUG (SEND, ("RouteHandler failed, network: %lx\n",
|
|
REORDER_ULONG(RemoteAddress->NetworkAddress)));
|
|
goto error_send_with_packet;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Fill in the LocalTarget from the RouteEntry
|
|
//
|
|
|
|
LocalTarget = &Reserved->LocalTarget;
|
|
|
|
Reserved->LocalTarget = routeEntry.LocalTarget;
|
|
|
|
IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: LocalTarget is: %lx\n", Reserved->LocalTarget));
|
|
|
|
if (NIC_ID_TO_BINDING(Device, LocalTarget->NicId) == NULL || GET_LONG_VALUE(NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->ReferenceCount) == 1) {
|
|
IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned SUCCESS, Ref count is 1\n"));
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
goto error_send_with_packet;
|
|
}
|
|
|
|
if (Parameters->SendLength >
|
|
NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->RealMaxDatagramSize) {
|
|
|
|
IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
|
|
Parameters->SendLength,
|
|
NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->RealMaxDatagramSize));
|
|
|
|
REQUEST_INFORMATION(Request) = 0;
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
|
|
goto error_send_with_packet;
|
|
}
|
|
|
|
//
|
|
// [FW] we dont need to check this since the FWD does it for us.
|
|
//
|
|
|
|
/*
|
|
if ((Device->DisableDialoutSap) &&
|
|
(Address->Socket == SAP_SOCKET) &&
|
|
(NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->DialOutAsync)) {
|
|
|
|
REQUEST_INFORMATION(Request) = 0;
|
|
Status = STATUS_NETWORK_UNREACHABLE;
|
|
goto error_send_with_packet;
|
|
}
|
|
*/
|
|
|
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|
Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
|
|
IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|
IPX_DEBUG(SEND, ("FindRoute for %02x-%02x-%02x-%02x-%02x-%02x returned %lx\n",
|
|
LocalTarget->MacAddress[0],
|
|
LocalTarget->MacAddress[1],
|
|
LocalTarget->MacAddress[2],
|
|
LocalTarget->MacAddress[3],
|
|
LocalTarget->MacAddress[4],
|
|
LocalTarget->MacAddress[5],
|
|
Status));
|
|
|
|
}
|
|
|
|
} else {
|
|
Segment = RipGetSegment((PUCHAR)&RemoteAddress->NetworkAddress);
|
|
|
|
|
|
IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
|
|
|
|
//
|
|
// This call will return STATUS_PENDING if we need to
|
|
// RIP for the packet.
|
|
//
|
|
|
|
Status = RipGetLocalTarget(
|
|
Segment,
|
|
RemoteAddress,
|
|
IPX_FIND_ROUTE_RIP_IF_NEEDED,
|
|
&TempLocalTarget,
|
|
NULL);
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
|
|
//
|
|
// We found the route, TempLocalTarget is filled in.
|
|
//
|
|
|
|
IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
|
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|
if (NIC_FROM_LOCAL_TARGET(&TempLocalTarget) == (USHORT)LOOPBACK_NIC_ID) {
|
|
IPX_DEBUG(LOOPB, ("Loopback TDI packet: remoteaddr: %lx\n", RemoteAddress));
|
|
IsLoopback = TRUE;
|
|
//FILL_LOCAL_TARGET(&TempLocalTarget, FIRST_REAL_BINDING);
|
|
//DbgPrint("Real Adapters?:%lx\n", Device->RealAdapters);
|
|
}
|
|
Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&TempLocalTarget));
|
|
IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|
|
|
|
|
if (Binding == NULL || Parameters->SendLength >
|
|
Binding->RealMaxDatagramSize) {
|
|
IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
|
|
Parameters->SendLength,
|
|
Binding->RealMaxDatagramSize));
|
|
|
|
REQUEST_INFORMATION(Request) = 0;
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
#ifdef SNMP
|
|
++IPX_MIB_ENTRY(Device, SysOutMalformedRequests);
|
|
#endif SNMP
|
|
goto error_send_with_packet;
|
|
}
|
|
|
|
if (!Device->ForwarderBound &&
|
|
(Device->DisableDialoutSap) &&
|
|
(Address->Socket == SAP_SOCKET) &&
|
|
(Binding->DialOutAsync)) {
|
|
|
|
REQUEST_INFORMATION(Request) = 0;
|
|
//
|
|
// [SA] Bug #17273 return proper error mesg.
|
|
//
|
|
|
|
// Status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
Status = STATUS_NETWORK_UNREACHABLE;
|
|
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
#ifdef SNMP
|
|
++IPX_MIB_ENTRY(Device, SysOutDiscards);
|
|
#endif SNMP
|
|
goto error_send_with_packet;
|
|
}
|
|
|
|
} else if (Status == STATUS_PENDING) {
|
|
|
|
//
|
|
// A RIP request went out on the network; we queue
|
|
// this packet for transmission when the RIP
|
|
// response arrives. First we fill in the IPX
|
|
// header; the only thing we don't know is where
|
|
// exactly to fill it in, so we choose
|
|
// the most common location.
|
|
//
|
|
|
|
IpxConstructHeader(
|
|
&Reserved->Header[Device->IncludedHeaderOffset],
|
|
LengthIncludingHeader,
|
|
PacketType,
|
|
RemoteAddress,
|
|
&Address->LocalAddress);
|
|
|
|
//
|
|
// Adjust the 2nd mdl's size
|
|
//
|
|
NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
|
|
|
|
IPX_DEBUG (RIP, ("Queueing packet %lx\n", Reserved));
|
|
|
|
InsertTailList(
|
|
&Device->Segments[Segment].WaitingForRoute,
|
|
&Reserved->WaitLinkage);
|
|
|
|
IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
|
|
IPX_END_SYNC (&SyncContext);
|
|
|
|
return STATUS_PENDING;
|
|
|
|
} else {
|
|
|
|
IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
|
|
#ifdef SNMP
|
|
++IPX_MIB_ENTRY(Device, SysOutDiscards);
|
|
#endif SNMP
|
|
goto error_send_with_packet;
|
|
|
|
}
|
|
|
|
//
|
|
// [FW] The localtarget shd be in the reserved section.
|
|
//
|
|
LocalTarget = &Reserved->LocalTarget;
|
|
Reserved->LocalTarget = TempLocalTarget;
|
|
}
|
|
}
|
|
|
|
//
|
|
// [FW] moved to the conditions above so we save a copy in the RIP case
|
|
//
|
|
|
|
// LocalTarget = &TempLocalTarget;
|
|
|
|
//
|
|
// Now we know the local target, we can figure out
|
|
// the offset for the IPX header.
|
|
//
|
|
|
|
|
|
// Remember that we have got the binding with ref above....
|
|
|
|
IpxHeader = (PIPX_HEADER)&Reserved->Header[MAC_HEADER_SIZE];
|
|
#if 0
|
|
if (Reserved->DestinationType == DESTINATION_DEF) {
|
|
IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->DefHeaderSize];
|
|
} else {
|
|
IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->BcMcHeaderSize];
|
|
}
|
|
#endif
|
|
|
|
} else {
|
|
|
|
if (!REQUEST_SPECIAL_SEND(Request)) {
|
|
PacketType = ((PUCHAR)(Information->Options))[0];
|
|
LocalTarget = &((PIPX_DATAGRAM_OPTIONS)(Information->Options))->LocalTarget;
|
|
} else {
|
|
ASSERT(OPEN_REQUEST_EA_LENGTH(Request) == sizeof(IPX_DATAGRAM_OPTIONS2));
|
|
if (OPEN_REQUEST_EA_LENGTH(Request) == sizeof(IPX_DATAGRAM_OPTIONS2)) {
|
|
//IpxPrint0("IpxTdiSendDatagram: We have an input buffer of the right size\n");
|
|
} else {
|
|
//IpxPrint1("IpxTdiSendDatagram: Wrong sized buffer. Buff size is =(%d)\n", OPEN_REQUEST_EA_LENGTH(Request));
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
goto error_send_with_packet;
|
|
}
|
|
|
|
PacketType = Options->DgrmOptions.PacketType;
|
|
LocalTarget = &Options->DgrmOptions.LocalTarget;
|
|
}
|
|
|
|
//
|
|
// Calculate the binding and the correct location
|
|
// for the IPX header. We can do this at the same
|
|
// time as we calculate the DestinationType which
|
|
// saves an if like the one 15 lines up.
|
|
//
|
|
|
|
// Get lock to ref.
|
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|
//
|
|
// If a loopback packet, use the first binding as place holder
|
|
//
|
|
if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID) {
|
|
IsLoopback = TRUE;
|
|
}
|
|
|
|
Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
|
|
|
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|
|
|
if (Binding == NULL) {
|
|
DbgPrint("Binding %d does not exist.\n",NIC_FROM_LOCAL_TARGET(LocalTarget));
|
|
Status = STATUS_NOT_FOUND;
|
|
goto error_send_with_packet;
|
|
}
|
|
|
|
IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
|
|
if (Parameters->SendLength > Binding->RealMaxDatagramSize) {
|
|
|
|
IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
|
|
Parameters->SendLength,
|
|
Binding->RealMaxDatagramSize));
|
|
|
|
REQUEST_INFORMATION(Request) = 0;
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
#ifdef SNMP
|
|
++IPX_MIB_ENTRY(Device, SysOutMalformedRequests);
|
|
#endif SNMP
|
|
goto error_send_with_packet;
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// This shouldn't be needed because even WAN bindings
|
|
// don't go away once they are added.
|
|
//
|
|
|
|
if (Binding == NULL) {
|
|
Status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
goto error_send_with_packet;
|
|
}
|
|
#endif
|
|
|
|
if (RemoteAddress->NodeAddress[0] == 0xff) {
|
|
// What about multicast?
|
|
if ((*(UNALIGNED ULONG *)(RemoteAddress->NodeAddress) != 0xffffffff) ||
|
|
(*(UNALIGNED USHORT *)(RemoteAddress->NodeAddress+4) != 0xffff)) {
|
|
Reserved->DestinationType = DESTINATION_MCAST;
|
|
} else {
|
|
Reserved->DestinationType = DESTINATION_BCAST;
|
|
}
|
|
// IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->BcMcHeaderSize];
|
|
} else {
|
|
Reserved->DestinationType = DESTINATION_DEF; // directed send
|
|
// IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->DefHeaderSize];
|
|
}
|
|
IpxHeader = (PIPX_HEADER)&Reserved->Header[MAC_HEADER_SIZE];
|
|
|
|
}
|
|
|
|
|
|
// ++Device->TempDatagramsSent;
|
|
// Device->TempDatagramBytesSent += Parameters->SendLength;
|
|
ADD_TO_LARGE_INTEGER(&Device->Statistics.DatagramBytesSent,
|
|
Parameters->SendLength);
|
|
Device->Statistics.DatagramsSent++;
|
|
|
|
|
|
#if BACK_FILL
|
|
|
|
if (Reserved->BackFill) {
|
|
Reserved->MappedSystemVa = Reserved->HeaderBuffer->MappedSystemVa;
|
|
IpxHeader = (PIPX_HEADER)((PCHAR)Reserved->HeaderBuffer->MappedSystemVa - sizeof(IPX_HEADER));
|
|
Reserved->HeaderBuffer->ByteOffset -= sizeof(IPX_HEADER);
|
|
|
|
ASSERT((LONG)Reserved->HeaderBuffer->ByteOffset >= 0);
|
|
#ifdef SUNDOWN
|
|
(ULONG_PTR)Reserved->HeaderBuffer->MappedSystemVa-= sizeof(IPX_HEADER);
|
|
#else
|
|
(ULONG)Reserved->HeaderBuffer->MappedSystemVa-= sizeof(IPX_HEADER);
|
|
#endif
|
|
|
|
|
|
IPX_DEBUG(SEND, ("Adjusting backfill userMdl Ipxheader %x %x \n",Reserved->HeaderBuffer,IpxHeader));
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// In case the packet is being sent to a SAP socket or
|
|
// we have multiple cards and a zero virtual net or
|
|
// it is a special send (on a nic), we need to use
|
|
// the binding's address instead of the virtual address.
|
|
//
|
|
if (Device->MultiCardZeroVirtual ||
|
|
(Address->LocalAddress.Socket == SAP_SOCKET) ||
|
|
(RemoteAddress->Socket == SAP_SOCKET) ||
|
|
(REQUEST_SPECIAL_SEND(Request))) {
|
|
|
|
//
|
|
// SAP frames need to look like they come from the
|
|
// local network, not the virtual one. The same is
|
|
// true if we are running multiple nets without
|
|
// a virtual network number.
|
|
//
|
|
// If this is a binding set member and a local target
|
|
// was provided we will send using the real node of
|
|
// the binding, even if it was a slave. This is
|
|
// intentional. If no local target was provided then
|
|
// this will not be a binding slave.
|
|
//
|
|
|
|
IpxConstructHeader(
|
|
(PUCHAR)IpxHeader,
|
|
LengthIncludingHeader,
|
|
PacketType,
|
|
RemoteAddress,
|
|
&Binding->LocalAddress);
|
|
|
|
IpxHeader->SourceSocket = Address->SendSourceSocket;
|
|
|
|
} else {
|
|
|
|
IpxConstructHeader(
|
|
(PUCHAR)IpxHeader,
|
|
LengthIncludingHeader,
|
|
PacketType,
|
|
RemoteAddress,
|
|
&Address->LocalAddress);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Fill in the MAC header and submit the frame to NDIS.
|
|
//
|
|
|
|
// #if DBG
|
|
CTEAssert (!Reserved->SendInProgress);
|
|
Reserved->SendInProgress = TRUE;
|
|
// #endif
|
|
|
|
//
|
|
// Adjust the 2nd mdl's size
|
|
//
|
|
#if BACK_FILL
|
|
if (Reserved->BackFill) {
|
|
NdisAdjustBufferLength(Reserved->HeaderBuffer, (Reserved->HeaderBuffer->ByteCount+sizeof(IPX_HEADER)));
|
|
} else {
|
|
NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
|
|
}
|
|
#else
|
|
NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
|
|
#endif
|
|
|
|
IPX_DEBUG(SEND, ("Packet Head %x\n",IPX_PACKET_HEAD(Packet)));
|
|
|
|
/*
|
|
if (Address->RtAdd)
|
|
{
|
|
REQUEST_OPEN_CONTEXT(Request) = (PVOID)(pRtInfo);
|
|
}
|
|
*/
|
|
|
|
//
|
|
// [FW] If Forwarder installed, send the packet out for filtering
|
|
//
|
|
// STEFAN: 3/28/96:
|
|
// Dont filter IPXWAN config packets since the FWD does not have this adapter opened yet.
|
|
//
|
|
|
|
IPX_DEBUG(SEND, ("LocalAddress.Socket %x, IPXWAN_SOCKET\n", Address->LocalAddress.Socket, IPXWAN_SOCKET));
|
|
if (Address->LocalAddress.Socket != IPXWAN_SOCKET &&
|
|
Device->ForwarderBound) {
|
|
|
|
//
|
|
// Call the InternalSend to filter the packet and get to know
|
|
// the correct adapter context
|
|
//
|
|
|
|
NTSTATUS ret;
|
|
|
|
#ifdef SUNDOWN
|
|
ULONG_PTR FwdAdapterCtx = INVALID_CONTEXT_VALUE;
|
|
#else
|
|
ULONG FwdAdapterCtx = INVALID_CONTEXT_VALUE;
|
|
#endif
|
|
|
|
|
|
PUCHAR Data;
|
|
UINT DataLength;
|
|
|
|
if (GET_LONG_VALUE(Binding->ReferenceCount) == 2) {
|
|
FwdAdapterCtx = Binding->FwdAdapterContext;
|
|
}
|
|
|
|
//
|
|
// Figure out the location of the data in the packet
|
|
// For BackFill packets, the data is in the first (and only) MDL.
|
|
// For others, it is in the third MDL.
|
|
//
|
|
|
|
if (Reserved->BackFill) {
|
|
Data = (PUCHAR)(IpxHeader+sizeof(IPX_HEADER));
|
|
} else {
|
|
NdisQueryBufferSafe(NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)), &Data, &DataLength, HighPagePriority);
|
|
}
|
|
|
|
if (Data != NULL) {
|
|
|
|
ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)(
|
|
LocalTarget,
|
|
FwdAdapterCtx,
|
|
Packet,
|
|
(PUCHAR)IpxHeader,
|
|
Data,
|
|
LengthIncludingHeader,
|
|
FALSE);
|
|
|
|
|
|
if (ret == STATUS_SUCCESS) {
|
|
//
|
|
// The adapter could have gone away and we have indicated to the Forwarder
|
|
// but the Forwarder has not yet closed the adapter.
|
|
//
|
|
// what if the binding is NULL here? Can we trust the Forwarder to
|
|
// give us a non-NULL binding?
|
|
//
|
|
|
|
Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
|
|
|
|
// 302384
|
|
|
|
if (Binding == NULL) {
|
|
DbgPrint("IPX:nwlnkfwd has returned invalid nic id (%d) in LocalTarget (%p).\n",NIC_FROM_LOCAL_TARGET(LocalTarget), LocalTarget);
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
CTEAssert (Reserved->SendInProgress);
|
|
Reserved->SendInProgress = FALSE;
|
|
goto error_send_with_packet;
|
|
}
|
|
|
|
if (GET_LONG_VALUE(Binding->ReferenceCount) == 1) {
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
// #if DBG
|
|
CTEAssert (Reserved->SendInProgress);
|
|
Reserved->SendInProgress = FALSE;
|
|
// #endif
|
|
goto error_send_with_packet;
|
|
} else {
|
|
IsLoopback = (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID);
|
|
goto send_packet;
|
|
}
|
|
} else if (ret == STATUS_PENDING) {
|
|
//
|
|
// LocalTarget will get filled up in InternalSendComplete
|
|
//
|
|
|
|
//
|
|
// this is a NULL macro - include this?
|
|
//
|
|
IPX_END_SYNC (&SyncContext);
|
|
|
|
return STATUS_PENDING;
|
|
} else if (ret == STATUS_DROP_SILENTLY) {
|
|
IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned STATUS_DROP_SILENTLY - dropping pkt.\n"));
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
// #if DBG
|
|
CTEAssert (Reserved->SendInProgress);
|
|
Reserved->SendInProgress = FALSE;
|
|
// #endif
|
|
goto error_send_with_packet;
|
|
}
|
|
|
|
}
|
|
//
|
|
// else DISCARD
|
|
//
|
|
|
|
//
|
|
// 179436 - If forwarder is bound then its likely that we still wanna send.
|
|
//
|
|
if (Device->ForwarderBound && (GET_LONG_VALUE(NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget))->ReferenceCount) == 1)) {
|
|
|
|
goto send_packet;
|
|
|
|
}
|
|
|
|
// #if DBG
|
|
CTEAssert (Reserved->SendInProgress);
|
|
Reserved->SendInProgress = FALSE;
|
|
// #endif
|
|
Status = STATUS_NETWORK_UNREACHABLE;
|
|
goto error_send_with_packet;
|
|
|
|
} else {
|
|
|
|
//
|
|
// [FW] Jump here if the Forwarder gave us the go ahead on this send.
|
|
// We also come here to send if the Forwarder is not installed.
|
|
//
|
|
|
|
send_packet:
|
|
|
|
//
|
|
// The workaround what is a NdisMSendX bug -
|
|
// IPX checks if it is the same network.
|
|
//
|
|
if (Reserved->BackFill) {
|
|
|
|
pIpxHeader = (PIPX_HEADER)((PCHAR)Reserved->HeaderBuffer->MappedSystemVa);
|
|
|
|
} else {
|
|
|
|
pIpxHeader = IpxHeader;
|
|
|
|
}
|
|
|
|
if ((IPX_NODE_EQUAL(pIpxHeader->SourceNode, pIpxHeader->DestinationNode)) &&
|
|
(*(UNALIGNED ULONG *)pIpxHeader->SourceNetwork == *(UNALIGNED ULONG *)pIpxHeader->DestinationNetwork)) {
|
|
|
|
IPX_DEBUG(TEMP, ("It is self-directed. Loop it back ourselves (tdisenddatagram)\n"));
|
|
IsLoopback = TRUE;
|
|
|
|
}
|
|
|
|
pBinding = NIC_ID_TO_BINDING(Device, Reserved->LocalTarget.NicId);
|
|
|
|
if (pBinding) {
|
|
|
|
if ((IPX_NODE_EQUAL(Reserved->LocalTarget.MacAddress, pBinding->LocalAddress.NodeAddress)) ||
|
|
(IPX_NODE_EQUAL(pBinding->LocalAddress.NodeAddress, pIpxHeader->DestinationNode))) {
|
|
|
|
IPX_DEBUG(TEMP, ("Source Net:%lx, Source Address: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
|
|
*(UNALIGNED ULONG *)pIpxHeader->SourceNetwork,
|
|
pIpxHeader->SourceNode[0],
|
|
pIpxHeader->SourceNode[1],
|
|
pIpxHeader->SourceNode[2],
|
|
pIpxHeader->SourceNode[3],
|
|
pIpxHeader->SourceNode[4],
|
|
pIpxHeader->SourceNode[5]));
|
|
|
|
IPX_DEBUG(TEMP, ("Dest Net:%lx, DestAddress: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x \n",
|
|
*(UNALIGNED ULONG *)pIpxHeader->DestinationNetwork,
|
|
pIpxHeader->DestinationNode[0],
|
|
pIpxHeader->DestinationNode[1],
|
|
pIpxHeader->DestinationNode[2],
|
|
pIpxHeader->DestinationNode[3],
|
|
pIpxHeader->DestinationNode[4],
|
|
pIpxHeader->DestinationNode[5]
|
|
));
|
|
|
|
IPX_DEBUG(TEMP, ("Well, It is self-directed. Loop it back ourselves (TDISENDDATAGRAM - NIC_HANDLE is the same!)\n"));
|
|
IsLoopback = TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
IPX_DEBUG(TEMP, ("Sending a packet now\n"));
|
|
IPX_DEBUG(TEMP, ("**** RemoteAddress: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x LocalAddress: %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x \n",
|
|
RemoteAddress->NodeAddress[0],
|
|
RemoteAddress->NodeAddress[1],
|
|
RemoteAddress->NodeAddress[2],
|
|
RemoteAddress->NodeAddress[3],
|
|
RemoteAddress->NodeAddress[4],
|
|
RemoteAddress->NodeAddress[5],
|
|
Reserved->LocalTarget.MacAddress[0],
|
|
Reserved->LocalTarget.MacAddress[1],
|
|
Reserved->LocalTarget.MacAddress[2],
|
|
Reserved->LocalTarget.MacAddress[3],
|
|
Reserved->LocalTarget.MacAddress[4],
|
|
Reserved->LocalTarget.MacAddress[5]
|
|
));
|
|
|
|
if (IsLoopback) {
|
|
//
|
|
// Enque this packet to the LoopbackQueue on the binding.
|
|
// If the LoopbackRtn is not already scheduled, schedule it.
|
|
//
|
|
|
|
IPX_DEBUG(LOOPB, ("Packet: %lx, Addr: %lx, Addr->SendPacket: %lx\n", Packet, Address, Address->SendPacket));
|
|
|
|
//
|
|
// Recalculate packet counts here.
|
|
//
|
|
// NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
|
|
#if BACK_FILL
|
|
|
|
if (Reserved->BackFill) {
|
|
//
|
|
// Set the Header pointer and chain the first MDL
|
|
//
|
|
Reserved->Header = (PCHAR)Reserved->HeaderBuffer->MappedSystemVa;
|
|
NdisChainBufferAtFront(Packet,(PNDIS_BUFFER)Reserved->HeaderBuffer);
|
|
}
|
|
#endif
|
|
NdisRecalculatePacketCounts (Packet);
|
|
IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
|
|
|
|
} else {
|
|
|
|
|
|
if ((NdisStatus = (*Binding->SendFrameHandler)(
|
|
Binding->Adapter,
|
|
LocalTarget,
|
|
Packet,
|
|
Parameters->SendLength + sizeof(IPX_HEADER),
|
|
sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
|
|
|
|
IpxSendComplete(
|
|
(NDIS_HANDLE)Binding->Adapter,
|
|
Packet,
|
|
NdisStatus);
|
|
}
|
|
}
|
|
|
|
IPX_END_SYNC (&SyncContext);
|
|
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
return STATUS_PENDING;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// The address file state was closing.
|
|
//
|
|
|
|
IPX_FREE_LOCK (&Address->Lock, LockHandle);
|
|
Status = STATUS_INVALID_HANDLE;
|
|
#ifdef SNMP
|
|
++IPX_MIB_ENTRY(Device, SysOutDiscards);
|
|
#endif SNMP
|
|
goto error_send_no_packet;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// The address file didn't look like one.
|
|
//
|
|
|
|
Status = STATUS_INVALID_HANDLE;
|
|
#ifdef SNMP
|
|
++IPX_MIB_ENTRY(Device, SysOutDiscards);
|
|
#endif SNMP
|
|
goto error_send_no_packet;
|
|
}
|
|
|
|
//
|
|
// Jump here if we want to fail the send and we have already
|
|
// allocated the packet and ref'ed the address file.
|
|
//
|
|
|
|
error_send_with_packet:
|
|
|
|
#if BACK_FILL
|
|
//
|
|
// Check if this is backfilled. If so, set the headerbuffer to NULL. Note that we dont need
|
|
// restore to restore the user's MDL since it was never touched when this error occurred.
|
|
// Also, push the packet on to backfillpacket queue if the packet is not owned by the address
|
|
//
|
|
if (Reserved->BackFill) {
|
|
|
|
Reserved->HeaderBuffer = NULL;
|
|
|
|
if (Reserved->OwnedByAddress) {
|
|
// Reserved->Address->BackFillPacketInUse = FALSE;
|
|
InterlockedDecrement(&Reserved->Address->BackFillPacketInUse);
|
|
|
|
IPX_DEBUG(SEND, ("Freeing owned backfill %x\n", Reserved));
|
|
} else {
|
|
IPX_PUSH_ENTRY_LIST(
|
|
&Device->BackFillPacketList,
|
|
&Reserved->PoolLinkage,
|
|
&Device->SListsLock);
|
|
}
|
|
} else {
|
|
// not a back fill packet. Push it on sendpacket pool
|
|
if (Reserved->OwnedByAddress) {
|
|
// Reserved->Address->SendPacketInUse = FALSE;
|
|
InterlockedDecrement(&Reserved->Address->SendPacketInUse);
|
|
|
|
} else {
|
|
IPX_PUSH_ENTRY_LIST(
|
|
&Device->SendPacketList,
|
|
&Reserved->PoolLinkage,
|
|
&Device->SListsLock);
|
|
|
|
}
|
|
}
|
|
#else
|
|
if (Reserved->OwnedByAddress) {
|
|
Reserved->Address->SendPacketInUse = FALSE;
|
|
} else {
|
|
IPX_PUSH_ENTRY_LIST(
|
|
&Device->SendPacketList,
|
|
&Reserved->PoolLinkage,
|
|
&Device->SListsLock);
|
|
}
|
|
#endif
|
|
|
|
IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
|
|
|
|
error_send_no_packet:
|
|
|
|
//
|
|
// Jump here if we fail before doing any of that.
|
|
//
|
|
|
|
IPX_END_SYNC (&SyncContext);
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation( Request );
|
|
if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
|
|
|
|
REQUEST_STATUS(Request) = Status;
|
|
Request->CurrentLocation++,
|
|
Request->Tail.Overlay.CurrentStackLocation++;
|
|
|
|
(VOID) irpSp->CompletionRoutine(
|
|
NULL,
|
|
Request,
|
|
irpSp->Context
|
|
);
|
|
|
|
IpxFreeRequest (DeviceObject, Request);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} /* IpxTdiSendDatagram */
|
|
|
|
|
|
#if DBG
|
|
VOID
|
|
IpxConstructHeader(
|
|
IN PUCHAR Header,
|
|
IN USHORT PacketLength,
|
|
IN UCHAR PacketType,
|
|
IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
|
|
IN PTDI_ADDRESS_IPX LocalAddress
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine constructs an IPX header in a packet.
|
|
|
|
Arguments:
|
|
|
|
Header - The location at which the header should be built.
|
|
|
|
PacketLength - The length of the packet, including the IPX header.
|
|
|
|
PacketType - The packet type of the frame.
|
|
|
|
RemoteAddress - The remote IPX address.
|
|
|
|
LocalAddress - The local IPX address.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PIPX_HEADER IpxHeader = (PIPX_HEADER)Header;
|
|
|
|
IpxHeader->CheckSum = 0xffff;
|
|
IpxHeader->PacketLength[0] = (UCHAR)(PacketLength / 256);
|
|
IpxHeader->PacketLength[1] = (UCHAR)(PacketLength % 256);
|
|
IpxHeader->TransportControl = 0;
|
|
IpxHeader->PacketType = PacketType;
|
|
|
|
//
|
|
// These copies depend on the fact that the destination
|
|
// network is the first field in the 12-byte address.
|
|
//
|
|
|
|
RtlCopyMemory(IpxHeader->DestinationNetwork, (PVOID)RemoteAddress, 12);
|
|
RtlCopyMemory(IpxHeader->SourceNetwork, LocalAddress, 12);
|
|
|
|
} /* IpxConstructHeader */
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
// [FW]
|
|
//
|
|
|
|
VOID
|
|
IpxInternalSendComplete(
|
|
IN PIPX_LOCAL_TARGET LocalTarget,
|
|
IN PNDIS_PACKET Packet,
|
|
IN ULONG PacketLength,
|
|
IN NTSTATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the Kernel Forwarder to indicate that a pending
|
|
internal send to it has completed.
|
|
|
|
Arguments:
|
|
|
|
LocalTarget - if Status is OK, this has the local target for the send.
|
|
|
|
Packet - A pointer to the NDIS_PACKET that we sent.
|
|
|
|
PacketLength - length of the packet (including the IPX header)
|
|
|
|
Can IpxSendFrame use the local var. PktLength instead? What about IpxSendFrameXXX (frame specific)
|
|
|
|
Status - the completion status of the send - STATUS_SUCCESS or STATUS_NETWORK_UNREACHABLE
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE Device=IpxDevice;
|
|
PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
|
|
PBINDING Binding;
|
|
NDIS_STATUS NdisStatus;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PREQUEST Request;
|
|
PADDRESS_FILE AddressFile;
|
|
|
|
switch (Reserved->Identifier)
|
|
{
|
|
case IDENTIFIER_IPX:
|
|
|
|
//
|
|
// datagrams can be sent to the frame-specific handlers directly
|
|
//
|
|
// Make this change in SendComplete too
|
|
//
|
|
|
|
if ((Status == STATUS_SUCCESS) &&
|
|
(Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget))) &&
|
|
(GET_LONG_VALUE(Binding->ReferenceCount) == 2)) {
|
|
|
|
if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID) {
|
|
|
|
//
|
|
// Enque this packet to the LoopbackQueue on the binding.
|
|
// If the LoopbackRtn is not already scheduled, schedule it.
|
|
//
|
|
|
|
IPX_DEBUG(LOOPB, ("Packet: %lx \n", Packet));
|
|
|
|
//
|
|
// Recalculate packet counts here.
|
|
//
|
|
// NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
|
|
#if BACK_FILL
|
|
|
|
if (Reserved->BackFill) {
|
|
//
|
|
// Set the Header pointer and chain the first MDL
|
|
//
|
|
Reserved->Header = (PCHAR)Reserved->HeaderBuffer->MappedSystemVa;
|
|
NdisChainBufferAtFront(Packet,(PNDIS_BUFFER)Reserved->HeaderBuffer);
|
|
}
|
|
#endif
|
|
NdisRecalculatePacketCounts (Packet);
|
|
IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
|
|
|
|
} else {
|
|
if ((NdisStatus = (*Binding->SendFrameHandler)(
|
|
Binding->Adapter,
|
|
LocalTarget,
|
|
Packet,
|
|
PacketLength,
|
|
sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
|
|
//
|
|
// Call SendComplete here so it can send broadcasts over other
|
|
// Nic's and remove any padding if used.
|
|
//
|
|
|
|
IpxSendComplete((NDIS_HANDLE)Binding->Adapter,
|
|
Packet,
|
|
NdisStatus);
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// DISCARD was returned - complete the IRP
|
|
//
|
|
NdisStatus = STATUS_NETWORK_UNREACHABLE;
|
|
|
|
|
|
//
|
|
// We need to free the packet and deref the addressfile...
|
|
//
|
|
|
|
// #if DBG
|
|
CTEAssert (Reserved->SendInProgress);
|
|
Reserved->SendInProgress = FALSE;
|
|
// #endif
|
|
|
|
if (Reserved->OwnedByAddress) {
|
|
Reserved->Address->SendPacketInUse = FALSE;
|
|
} else {
|
|
IPX_PUSH_ENTRY_LIST(
|
|
&Device->SendPacketList,
|
|
&Reserved->PoolLinkage,
|
|
&Device->Lock);
|
|
}
|
|
|
|
AddressFile = Reserved->u.SR_DG.AddressFile;
|
|
IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
|
|
|
|
Request = Reserved->u.SR_DG.Request;
|
|
REQUEST_STATUS(Request) = NdisStatus;
|
|
irpSp = IoGetCurrentIrpStackLocation( Request );
|
|
|
|
//
|
|
// If this is a fast send irp, we bypass the file system and
|
|
// call the completion routine directly.
|
|
//
|
|
|
|
if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
|
|
Request->CurrentLocation++,
|
|
Request->Tail.Overlay.CurrentStackLocation++;
|
|
|
|
(VOID) irpSp->CompletionRoutine(
|
|
NULL,
|
|
Request,
|
|
irpSp->Context
|
|
);
|
|
|
|
} else {
|
|
IpxCompleteRequest (Request);
|
|
}
|
|
IpxFreeRequest(Device, Request);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// for all other packet types
|
|
//
|
|
|
|
if ((Status == STATUS_SUCCESS) &&
|
|
(Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget))) &&
|
|
(GET_LONG_VALUE(Binding->ReferenceCount) == 2)) {
|
|
//
|
|
// IncludedHeaderLength is only used to check for RIP packets (==0)
|
|
// so IPX_HEADER size is OK. Should finally remove this parameter.
|
|
//
|
|
|
|
if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID) {
|
|
|
|
//
|
|
// Enque this packet to the LoopbackQueue on the binding.
|
|
// If the LoopbackRtn is not already scheduled, schedule it.
|
|
//
|
|
|
|
IPX_DEBUG(LOOPB, ("Packet: %lx\n", Packet));
|
|
|
|
//
|
|
// Recalculate packet counts here.
|
|
//
|
|
// NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
|
|
#if BACK_FILL
|
|
|
|
if (Reserved->BackFill) {
|
|
//
|
|
// Set the Header pointer and chain the first MDL
|
|
//
|
|
Reserved->Header = (PCHAR)Reserved->HeaderBuffer->MappedSystemVa;
|
|
NdisChainBufferAtFront(Packet,(PNDIS_BUFFER)Reserved->HeaderBuffer);
|
|
}
|
|
#endif
|
|
NdisRecalculatePacketCounts (Packet);
|
|
IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
|
|
|
|
} else {
|
|
NdisStatus = IpxSendFrame(LocalTarget, Packet, PacketLength, sizeof(IPX_HEADER));
|
|
|
|
if (NdisStatus != NDIS_STATUS_PENDING) {
|
|
IPX_DEBUG (SEND, ("IpxSendFrame status %lx on NICid %lx, packet %lx \n",
|
|
NdisStatus, LocalTarget->NicId, Packet));
|
|
goto error_complete;
|
|
}
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// DISCARD was returned - call the upper driver's sendcomplete with error
|
|
//
|
|
|
|
//
|
|
// Else return STATUS_NETWORK_UNREACHABLE
|
|
//
|
|
|
|
NdisStatus = STATUS_NETWORK_UNREACHABLE;
|
|
|
|
error_complete:
|
|
|
|
IPX_DEBUG (SEND, ("Calling the SendCompleteHandler of tightly bound driver with status: %lx\n", NdisStatus));
|
|
(*Device->UpperDrivers[Reserved->Identifier].SendCompleteHandler)(
|
|
Packet,
|
|
NdisStatus);
|
|
}
|
|
}
|
|
}
|
|
|
|
|