windows-nt/Source/XPSP1/NT/net/rras/ndis/asyncmac/send.c
2020-09-26 16:20:57 +08:00

310 lines
7.1 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
send.c
Abstract:
NOTE: ZZZ There is a potential priority inversion problem when
allocating the packet. For nt it looks like we need to raise
the irql to dpc when we start the allocation.
Author:
Thomas J. Dimitri 8-May-1992
Environment:
Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
Revision History:
Ray Patch (raypa) 04/13/94 Modified for new WAN wrapper.
--*/
#include "asyncall.h"
#include "globals.h"
//
// Forward references.
//
extern
NTSTATUS
AsyncWriteCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PNDIS_WAN_PACKET WanPacket);
//=============================================================================
// Function:
//
// AsyncSend()
//
// Description:
//
// This function is the main entry point for transmitting data to the serial
// driver. When entered, we get the MAC binding handle (a pointer to our
// private data structure) and the WAN packet which we are going to send.
// We don't bother queuing the frame, we simple allocate an IRP and ship
// it to the serial driver and let him worry about it.
//
// In Parameters:
//
// NdisLinkContext - Pointer to the ASYNC_INFO structure.
//
// Packet - WAN packet containing the data to be framed and shipped.
//
// Out Parameters:
//
// None.
//
// Return status:
//
// NDIS_STATUS_SUCCESS.
//=============================================================================
NDIS_STATUS
MpSend(
IN NDIS_HANDLE MacBindingHandle,
IN NDIS_HANDLE NdisLinkHandle,
IN PNDIS_WAN_PACKET Packet)
{
PASYNC_INFO AsyncInfo;
NDIS_STATUS Status;
DbgTracef(1,("AS\n"));
//
// Get the open handle for this MAC binding.
//
AsyncInfo = (PASYNC_INFO) NdisLinkHandle;
//
// First make sure this link is still up.
//
if (AsyncInfo->PortState == PORT_FRAMING &&
(AsyncInfo->GetLinkInfo.SendFramingBits &
(PPP_FRAMING | SLIP_FRAMING)) != 0)
{
//
// Now we can send this frame.
//
Status = AsyncSendPacket(
NdisLinkHandle,
Packet);
// For all Status values (PENDING, SUCCESS, and ERROR) the callback from Write will
// do a sendcomplete indication so we always return PENDING.
//
Status = STATUS_PENDING ;
}
else
{
DbgTracef(-2,("AsyncSend: Link not found, dropping packet!\n"));
Status = NDIS_STATUS_SUCCESS;
}
return Status;
}
//=============================================================================
// Function:
//
// AsyncSendPacket()
//
// Description:
// This function is called from AsyncSend() to send an IRP to the serial
// driver. If this IRP pends, the the I/O complete routine will be called
// later to complete the request.
//
// In Parameters:
//
// Packet - WAN packet containing the data to be framed and shipped.
//
// Out Parameters:
//
// None.
//
// Return status:
//
// NDIS_STATUS_SUCCESS.
//=============================================================================
NTSTATUS
AsyncSendPacket(
IN PASYNC_INFO AsyncInfo,
IN PNDIS_WAN_PACKET WanPacket)
{
NTSTATUS Status;
PIRP irp;
PIO_STACK_LOCATION irpSp;
PFILE_OBJECT FileObject;
PDEVICE_OBJECT DeviceObject;
PASYNC_ADAPTER Adapter;
UCHAR irpStackSize;
//
// Initialize locals.
//
FileObject = AsyncInfo->FileObject;
DeviceObject = AsyncInfo->DeviceObject;
Adapter = AsyncInfo->Adapter;
irpStackSize = (UCHAR) Adapter->IrpStackSize;
//
// Get irp from irp pool.
//
irp = IoAllocateIrp(DeviceObject->StackSize, (BOOLEAN)FALSE);
//
// The IO subsystem may be out of irps.
//
if (irp == NULL) {
return(NDIS_STATUS_RESOURCES);
}
//
// Tuck pointer to AsyncInfo for completion use
//
WanPacket->MacReserved1 = AsyncInfo;
irp->Tail.Overlay.OriginalFileObject = FileObject;
irp->RequestorMode = KernelMode;
irp->PendingReturned = FALSE;
//
// Fill in the service independent parameters in the IRP.
//
irp->UserEvent = NULL;
//
// 8 byte align (also use end of packet for IOSB).
//
irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
irp->Overlay.AsynchronousParameters.UserApcContext = NULL;
//
// Get a pointer to the stack location for the first driver. This will be
// used to pass the original function codes and parameters.
//
irpSp = IoGetNextIrpStackLocation(irp);
irpSp->MajorFunction = IRP_MJ_WRITE;
irpSp->FileObject = FileObject;
if (FileObject->Flags & FO_WRITE_THROUGH) {
irpSp->Flags = SL_WRITE_THROUGH;
}
//
// If this write operation is to be performed without any caching, set the
// appropriate flag in the IRP so no caching is performed.
//
if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
irp->Flags |= (IRP_NOCACHE | IRP_WRITE_OPERATION);
} else {
irp->Flags |= IRP_WRITE_OPERATION;
}
//
// Assemble a RAS, PPP, SLIP frame type.
//
if (AsyncInfo->GetLinkInfo.SendFramingBits & PPP_FRAMING) {
AssemblePPPFrame(WanPacket);
} else
if (AsyncInfo->GetLinkInfo.SendFramingBits & SLIP_FRAMING) {
AssembleSLIPFrame(WanPacket);
}
irp->AssociatedIrp.SystemBuffer =
WanPacket->CurrentBuffer;
DbgTracef(0, ("Writing out %.2x %.2x %.2x %.2x %.2x\n",
WanPacket->CurrentBuffer[0],
WanPacket->CurrentBuffer[1],
WanPacket->CurrentBuffer[2],
WanPacket->CurrentBuffer[3],
WanPacket->CurrentBuffer[4]));
//
// Copy the caller's parameters to the service-specific portion of the IRP.
//
irpSp->Parameters.Write.Length = WanPacket->CurrentLength;
irpSp->Parameters.Write.Key = 0;
irpSp->Parameters.Write.ByteOffset = FileObject->CurrentByteOffset;
//
// Setup IRP for callback.
//
IoSetCompletionRoutine(
irp, // irp to use
AsyncWriteCompletionRoutine, // routine to call when irp is done
WanPacket, // context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE); // call on cancel
//
// We DO NOT insert the packet at the head of the IRP list for the thread.
// because we do NOT really have an IoCompletionRoutine that does
// anything with the thread or needs to be in that thread's context.
//
GlobalXmitWentOut++;
AsyncInfo->In++;
//
// Now simply invoke the driver at its dispatch entry with the IRP.
//
Status = IoCallDriver(DeviceObject, irp);
// According to TonyE, the status for the serial driver should
// always be STATUS_PENDING. DigiBoard usually STATUS_SUCCESS.
return Status;
}