summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/isn/ipx/send.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/tdi/isn/ipx/send.c')
-rw-r--r--private/ntos/tdi/isn/ipx/send.c2364
1 files changed, 2364 insertions, 0 deletions
diff --git a/private/ntos/tdi/isn/ipx/send.c b/private/ntos/tdi/isn/ipx/send.c
new file mode 100644
index 000000000..b4e885c48
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/send.c
@@ -0,0 +1,2364 @@
+
+/*++
+
+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
+
+//
+// BUGBUG 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;
+ USHORT NewId, OldId;
+ ULONG NewOffset, OldOffset;
+ PIPX_HEADER IpxHeader;
+ IPX_LOCAL_TARGET LocalTarget;
+ PIO_STACK_LOCATION irpSp;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+#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;
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (NewId = OldId+1; NewId <= Index; NewId++) {
+ if ((Binding = NIC_ID_TO_BINDING(Device, NewId))
+#else
+ for (NewId = OldId+1; NewId <= Device->HighestExternalNicId; NewId++) {
+ if ((Binding = Device->Bindings[NewId])
+#endif _PNP_POWER
+ &&
+ ((!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.
+ //
+
+ break;
+ }
+ }
+ }
+
+ if (NewId <= MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif _PNP_POWER
+
+ //
+ // 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);
+#endif
+
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
+
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&LocalTarget, NewId);
+#else
+ LocalTarget.NicId = NewId;
+#endif
+ 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;
+ ULONG FwdAdapterCtx = INVALID_CONTEXT_VALUE;
+
+ if (GET_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);
+ NdisQueryBuffer (NDIS_BUFFER_LINKAGE(HeaderBuffer), &IpxHeader, &TempHeaderBufferLength);
+
+ //
+ // Data is always at the top of the third MDL.
+ //
+ NdisQueryBuffer (NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(HeaderBuffer)), &Data, &DataLength);
+
+ ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)(
+ &LocalTarget,
+ FwdAdapterCtx,
+ NdisPacket,
+ IpxHeader,
+ Data,
+ REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
+ FALSE);
+
+ //
+ // 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.
+ //
+ // BUGBUG: 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));
+
+ if (GET_VALUE(Binding->ReferenceCount) == 1) {
+ Adapter = Binding->Adapter;
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif _PNP_POWER
+ goto FunctionStart;
+ } else {
+ goto send_packet;
+ }
+
+ } else if (ret == STATUS_PENDING) {
+ //
+ // LocalTarget will get filled up in InternalSendComplete
+ //
+ return;
+ }
+ //
+ // else DISCARD
+ //
+ Adapter = Binding->Adapter;
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif _PNP_POWER
+ 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 ((NdisStatus = (*Binding->SendFrameHandler)(
+ Binding->Adapter,
+ &LocalTarget,
+ NdisPacket,
+ REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ Adapter = Binding->Adapter;
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif _PNP_POWER
+ goto RealFunctionStart;
+ }
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif _PNP_POWER
+ return;
+ }
+ } else {
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif _PNP_POWER
+ //
+ // 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) {
+
+ Reserved->HeaderBuffer->MappedSystemVa = Reserved->MappedSystemVa;
+ Reserved->HeaderBuffer->ByteCount = Reserved->UserLength;
+ Reserved->HeaderBuffer->StartVa = (PCHAR)((ULONG)Reserved->HeaderBuffer->MappedSystemVa & ~(PAGE_SIZE-1));
+ Reserved->HeaderBuffer->ByteOffset = (ULONG)Reserved->HeaderBuffer->MappedSystemVa & (PAGE_SIZE-1);
+
+ 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;
+
+#ifdef _PNP_POWER
+ 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);
+ NdisQueryBuffer (NDIS_BUFFER_LINKAGE(HeaderBuffer), &IpxHeader, &TempHeaderBufferLength);
+
+ //
+ // 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);
+ IPX_DEBUG(SEND, ("SendComplete: IpxHeader has Type20: %lx\n", IpxHeader));
+ } else {
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (NewId = OldId+1; NewId <= Index; NewId++) {
+ if (Binding = NIC_ID_TO_BINDING(Device, NewId)) {
+ //
+ // Found next NIC to send on
+ //
+ break;
+ }
+ }
+ }
+ }
+
+ if (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;
+
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&LocalTarget, NewId);
+#else
+ LocalTarget.NicId = NewId;
+#endif
+ 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;
+ ULONG FwdAdapterCtx = INVALID_CONTEXT_VALUE;
+
+ if (GET_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.
+ //
+ // BUGBUG: 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));
+
+ if (GET_VALUE(Binding->ReferenceCount) == 1) {
+ Adapter = Binding->Adapter;
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ goto FunctionStart;
+ } else {
+ NewId = NIC_FROM_LOCAL_TARGET(&LocalTarget);
+ 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);
+ NdisQueryBuffer(HeaderBuffer, &Header, &TempHeaderBufferLength);
+
+ IpxHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+
+ IPX_DEBUG(SEND, ("SendComplete: IpxHeader: %lx\n", IpxHeader));
+#endif
+
+send_packet1:
+
+ FILL_LOCAL_TARGET(&Reserved->LocalTarget, NewId);
+
+ //
+ // 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'
+ //
+#endif
+ default:
+
+ (*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;
+ PSINGLE_LIST_ENTRY s;
+ TDI_ADDRESS_IPX UNALIGNED * RemoteAddress;
+ TDI_ADDRESS_IPX TempAddress;
+ TA_ADDRESS UNALIGNED * AddressName;
+ PTDI_CONNECTION_INFORMATION Information;
+ PTDI_REQUEST_KERNEL_SENDDG Parameters;
+ PBINDING Binding;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PIPX_LOCAL_TARGET LocalTarget;
+ PDEVICE Device = IpxDevice;
+ UCHAR PacketType;
+ NTSTATUS Status;
+ PIPX_HEADER IpxHeader;
+ 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;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+#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);
+ Information = Parameters->SendDatagramInformation;
+
+ //
+ // Do a quick check if this address has only one entry.
+ //
+
+ 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) {
+ // BUGBUG: 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)))) {
+
+ //
+ // 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) {
+
+ NdisQueryBuffer(
+ FirstBuffer,
+ (PVOID *)&FirstBufferData,
+ &FirstBufferLength);
+
+ //
+ // 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.
+ //
+
+ //
+ // BUGBUG: 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 {
+
+ Reserved->u.SR_DG.CurrentNicId = 1;
+
+ }
+
+ 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)) {
+#ifdef _PNP_POWER
+// No need to lock the access path since he just looks at it
+//
+ TempBinding = NIC_ID_TO_BINDING(Device, Reserved->u.SR_DG.CurrentNicId);
+#else
+ TempBinding = Device->Bindings[Reserved->u.SR_DG.CurrentNicId];
+#endif _PNP_POWER
+ 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;
+ }
+ }
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&TempLocalTarget, Reserved->u.SR_DG.CurrentNicId);
+#else
+ TempLocalTarget.NicId = Reserved->u.SR_DG.CurrentNicId;
+#endif
+
+ } else {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&TempLocalTarget, 1);
+#else
+ TempLocalTarget.NicId = 1;
+#endif
+ }
+
+ RtlCopyMemory(TempLocalTarget.MacAddress, RemoteAddress->NodeAddress, 6);
+#ifdef _PNP_POWER
+ 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);
+#endif
+
+ //
+ // [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(*(UNALIGNED 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 (GET_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;
+ }
+ */
+
+#ifdef _PNP_POWER
+ 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);
+#endif
+ 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);
+ #ifdef _PNP_POWER
+ 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, 1);
+ }
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&TempLocalTarget));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ 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 (!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 (TempLocalTarget.NicId == 0) {
+ IPX_DEBUG(LOOPB, ("Loopback TDI packet: remoteaddr: %lx\n", RemoteAddress));
+ IsLoopback = TRUE;
+ TempLocalTarget.NicId = 1;
+ }
+
+ if (Parameters->SendLength >
+ Device->Bindings[TempLocalTarget.NicId]->RealMaxDatagramSize) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ Device->Bindings[TempLocalTarget.NicId]->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_with_packet;
+ }
+
+ if ((Device->DisableDialoutSap) &&
+ (Address->Socket == SAP_SOCKET) &&
+ (Device->Bindings[TempLocalTarget.NicId]->DialOutAsync)) {
+
+ REQUEST_INFORMATION(Request) = 0;
+ //
+ // [SA] Bug #17273 return proper error mesg.
+ //
+
+ // Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ Status = STATUS_NETWORK_UNREACHABLE;
+ goto error_send_with_packet;
+ }
+ #endif _PNP_POWER
+
+ } 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.
+ //
+#ifdef _PNP_POWER
+// Remember that we have got the binding with ref above....
+
+#else
+ Binding = Device->Bindings[LocalTarget->NicId];
+#endif
+ 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;
+ if (NIC_ID_TO_BINDING(Device, LocalTarget->NicId) == NULL) {
+ Status = STATUS_NOT_FOUND;
+ goto error_send_with_packet;
+ }
+ }
+
+ //
+ // 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.
+ //
+
+#ifdef _PNP_POWER
+// 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) {
+ Binding = NIC_ID_TO_BINDING(Device, 1);
+ IsLoopback = TRUE;
+ } else {
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
+ }
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (LocalTarget->NicId == 0) {
+ Binding = Device->Bindings[1];
+ IsLoopback = TRUE;
+ } else {
+ Binding = Device->Bindings[LocalTarget->NicId];
+ }
+#endif _PNP_POWER
+ 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) {
+ // BUGBUG: 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;
+
+
+#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);
+ (ULONG)Reserved->HeaderBuffer->MappedSystemVa-= sizeof(IPX_HEADER);
+ 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;
+ ULONG FwdAdapterCtx = INVALID_CONTEXT_VALUE;
+ PUCHAR Data;
+ UINT DataLength;
+
+ if (GET_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 BACK_FILL
+ if (Reserved->BackFill) {
+ Data = (PUCHAR)(IpxHeader+sizeof(IPX_HEADER));
+ } else {
+ NdisQueryBuffer(NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)), &Data, &DataLength);
+ }
+#else
+ NdisQueryBuffer(NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)), &Data, &DataLength);
+#endif
+
+ 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.
+ //
+ // BUGBUG: 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));
+
+ if (GET_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
+ //
+
+ //
+ // BUGBUG: 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
+ //
+
+// #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:
+ 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);
+#ifdef _PNP_POWER
+ IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
+#else
+ IpxLoopbackEnque(Packet, Device->Bindings[1]->Adapter);
+#endif
+
+ } 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);
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ 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)
+
+ BUGBUG: 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
+ //
+ // BUGBUG: Make this change in SendComplete too
+ //
+
+ if ((Status == STATUS_SUCCESS) &&
+ (Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget))) &&
+ (GET_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);
+#ifdef _PNP_POWER
+ IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
+#else
+ IpxLoopbackEnque(Packet, Device->Bindings[1]->Adapter);
+#endif
+
+ } 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_VALUE(Binding->ReferenceCount) == 2)) {
+ //
+ // BUGBUG: 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);
+#ifdef _PNP_POWER
+ IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
+#else
+ IpxLoopbackEnque(Packet, Device->Bindings[1]->Adapter);
+#endif
+
+ } 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);
+ }
+ }
+}
+
+