|
|
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
send.c
Abstract:
utility routines to handle sending data.
Environment:
Kernel mode only.
Revision History:
alid 10/22/2001 modified for tunmp arvindm 4/10/2000 Created
--*/
#include "precomp.h"
#define __FILENUMBER 'DNES'
NTSTATUS TunWrite( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) /*++
Routine Description:
Dispatch routine to handle IRP_MJ_WRITE.
Arguments:
pDeviceObject - pointer to our device object pIrp - Pointer to request packet
Return Value:
NT status code.
--*/ { PIO_STACK_LOCATION pIrpSp; ULONG DataLength; NTSTATUS NtStatus; NDIS_STATUS Status; PTUN_ADAPTER pAdapter; PNDIS_PACKET pNdisPacket; PNDIS_BUFFER pNdisBuffer; PVOID Address;
pIrpSp = IoGetCurrentIrpStackLocation(pIrp); pIrp->IoStatus.Information = 0; pAdapter = (PTUN_ADAPTER)pIrpSp->FileObject->FsContext;
DEBUGP(DL_LOUD, ("==>TunWrite: Adapter %p/%x\n", pAdapter, pAdapter->Flags));
pNdisPacket = NULL;
do { if (pAdapter == NULL) { DEBUGP(DL_WARN, ("Write: FileObject %p not yet associated with a device\n", pIrpSp->FileObject)); NtStatus = STATUS_INVALID_HANDLE; break; } TUN_STRUCT_ASSERT(pAdapter, mc);
if(pIrp->MdlAddress == NULL) { NtStatus = STATUS_INVALID_PARAMETER; break; }
//
// Sanity-check the length.
//
DataLength = MmGetMdlByteCount(pIrp->MdlAddress); if (DataLength < sizeof(TUN_ETH_HEADER)) { DEBUGP(DL_WARN, ("Write: too small to be a valid packet (%d bytes)\n", DataLength)); NtStatus = STATUS_BUFFER_TOO_SMALL; break; }
Address = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); if (Address == NULL) { DEBUGP(DL_WARN, ("Write: Adapter %p: Mdl %p" " couldn't get the system address for MDL\n", pAdapter, pIrp->MdlAddress));
NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; }
if (DataLength > (pAdapter->MediumMaxFrameLen + sizeof(TUN_ETH_HEADER))) { DEBUGP(DL_WARN, ("Write: Adapter %p: data length (%d)" " larger than max frame size (%d)\n", pAdapter, DataLength, pAdapter->MediumMaxFrameLen));
NtStatus = STATUS_INVALID_BUFFER_SIZE; break; }
TUN_ACQUIRE_LOCK(&pAdapter->Lock);
if ((!TUN_TEST_FLAGS(pAdapter, TUN_ADAPTER_ACTIVE)) || TUN_TEST_FLAG(pAdapter, TUN_ADAPTER_OFF)) { TUN_RELEASE_LOCK(&pAdapter->Lock);
DEBUGP(DL_FATAL, ("Write: Adapter %p is not bound" " or in low power state\n", pAdapter));
NtStatus = STATUS_INVALID_DEVICE_REQUEST; break; }
//
// Allocate a send packet.
//
TUN_ASSERT(pAdapter->SendPacketPool != NULL); NdisAllocatePacket( &Status, &pNdisPacket, pAdapter->SendPacketPool); if (Status != NDIS_STATUS_SUCCESS) { TUN_RELEASE_LOCK(&pAdapter->Lock);
DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send pkt\n", pAdapter)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; }
//1 we should do a copy here
pNdisBuffer = pIrp->MdlAddress; pAdapter->PendedSendCount++; pAdapter->RcvBytes += MmGetMdlByteCount(pIrp->MdlAddress);
TUN_REF_ADAPTER(pAdapter); // pended send
IoMarkIrpPending(pIrp);
//
// Initialize the packet ref count. This packet will be freed
// when this count goes to zero.
//
TUN_SEND_PKT_RSVD(pNdisPacket)->RefCount = 1;
TUN_RELEASE_LOCK(&pAdapter->Lock);
//
// Set a back pointer from the packet to the IRP.
//
TUN_IRP_FROM_SEND_PKT(pNdisPacket) = pIrp;
NtStatus = STATUS_PENDING;
pNdisBuffer->Next = NULL; NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
#if SEND_DBG
{ PUCHAR pData;
pData = MmGetSystemAddressForMdlSafe(pNdisBuffer, NormalPagePriority); TUN_ASSERT(pEthHeader == pData);
DEBUGP(DL_VERY_LOUD, ("Write: MDL %p, MdlFlags %x, SystemAddr %p, %d bytes\n", pIrp->MdlAddress, pIrp->MdlAddress->MdlFlags, pData, DataLength));
DEBUGPDUMP(DL_VERY_LOUD, pData, MIN(DataLength, 48)); } #endif // SEND_DBG
NDIS_SET_PACKET_STATUS(pNdisPacket, NDIS_STATUS_SUCCESS); NDIS_SET_PACKET_HEADER_SIZE(pNdisPacket, sizeof(TUN_ETH_HEADER));
NdisMIndicateReceivePacket(pAdapter->MiniportHandle, &pNdisPacket, 1);
} while (FALSE);
if (NtStatus != STATUS_PENDING) { pIrp->IoStatus.Status = NtStatus; IoCompleteRequest(pIrp, IO_NO_INCREMENT); }
DEBUGP(DL_LOUD, ("<==TunWrite: Adapter %p/%x\n", pAdapter, pAdapter->Flags));
return (NtStatus); }
|