NTSTATUS NdisProtWrite( 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; PNDISPROT_OPEN_CONTEXT pOpenContext; PNDIS_PACKET pNdisPacket; PNDIS_BUFFER pNdisBuffer; NDISPROT_ETH_HEADER UNALIGNED *pEthHeader; #ifdef NDIS51 PVOID CancelId; #endif UNREFERENCED_PARAMETER(pDeviceObject); pIrpSp = IoGetCurrentIrpStackLocation(pIrp); pOpenContext = pIrpSp->FileObject->FsContext; pNdisPacket = NULL; do { if (pOpenContext == NULL) { DEBUGP(DL_WARN, ("Write: FileObject %p not yet associated with a device\n", pIrpSp->FileObject)); NtStatus = STATUS_INVALID_HANDLE; break; } NPROT_STRUCT_ASSERT(pOpenContext, oc); if (pIrp->MdlAddress == NULL) { DEBUGP(DL_FATAL, ("Write: NULL MDL address on IRP %p\n", pIrp)); NtStatus = STATUS_INVALID_PARAMETER; break; } // // Try to get a virtual address for the MDL. // pEthHeader = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); if (pEthHeader == NULL) { DEBUGP(DL_FATAL, ("Write: MmGetSystemAddr failed for" " IRP %p, MDL %p\n", pIrp, pIrp->MdlAddress)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } // // Sanity-check the length. // DataLength = MmGetMdlByteCount(pIrp->MdlAddress); if (DataLength < sizeof(NDISPROT_ETH_HEADER)) { DEBUGP(DL_WARN, ("Write: too small to be a valid packet (%d bytes)\n", DataLength)); NtStatus = STATUS_BUFFER_TOO_SMALL; break; } if (DataLength > (pOpenContext->MaxFrameSize + sizeof(NDISPROT_ETH_HEADER))) { DEBUGP(DL_WARN, ("Write: Open %p: data length (%d)" " larger than max frame size (%d)\n", pOpenContext, DataLength, pOpenContext->MaxFrameSize)); NtStatus = STATUS_INVALID_BUFFER_SIZE; break; } // // To prevent applications from sending packets with spoofed // mac address, we will do the following check to make sure the source // address in the packet is same as the current MAC address of the NIC. // if ((pIrp->RequestorMode == UserMode) && !NPROT_MEM_CMP(pEthHeader->SrcAddr, pOpenContext->CurrentAddress, NPROT_MAC_ADDR_LEN)) { DEBUGP(DL_WARN, ("Write: Failing with invalid Source address")); NtStatus = STATUS_INVALID_PARAMETER; break; } NPROT_ACQUIRE_LOCK(&pOpenContext->Lock); if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE)) { NPROT_RELEASE_LOCK(&pOpenContext->Lock); DEBUGP(DL_FATAL, ("Write: Open %p is not bound" " or in low power state\n", pOpenContext)); NtStatus = STATUS_INVALID_HANDLE; break; } // // Allocate a send packet. // NPROT_ASSERT(pOpenContext->SendPacketPool != NULL); NdisAllocatePacket( &Status, &pNdisPacket, pOpenContext->SendPacketPool); if (Status != NDIS_STATUS_SUCCESS) { NPROT_RELEASE_LOCK(&pOpenContext->Lock); DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send pkt\n", pOpenContext)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } // // Allocate a send buffer if necessary. // if (pOpenContext->bRunningOnWin9x) { NdisAllocateBuffer( &Status, &pNdisBuffer, pOpenContext->SendBufferPool, pEthHeader, DataLength); if (Status != NDIS_STATUS_SUCCESS) { NPROT_RELEASE_LOCK(&pOpenContext->Lock); NdisFreePacket(pNdisPacket); DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send buf\n", pOpenContext)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } } else { pNdisBuffer = pIrp->MdlAddress; } NdisInterlockedIncrement((PLONG)&pOpenContext->PendedSendCount); NPROT_REF_OPEN(pOpenContext); // pended send IoMarkIrpPending(pIrp); // // Initialize the packet ref count. This packet will be freed // when this count goes to zero. // NPROT_SEND_PKT_RSVD(pNdisPacket)->RefCount = 1; #ifdef NDIS51 // // NDIS 5.1 supports cancelling sends. We set up a cancel ID on // each send packet (which maps to a Write IRP), and save the // packet pointer in the IRP. If the IRP gets cancelled, we use // NdisCancelSendPackets() to cancel the packet. // CancelId = NPROT_GET_NEXT_CANCEL_ID(); NDIS_SET_PACKET_CANCEL_ID(pNdisPacket, CancelId); pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext; pIrp->Tail.Overlay.DriverContext[1] = (PVOID)pNdisPacket; NPROT_INSERT_TAIL_LIST(&pOpenContext->PendedWrites, &pIrp->Tail.Overlay.ListEntry); IoSetCancelRoutine(pIrp, NdisProtCancelWrite); #endif // NDIS51 NPROT_RELEASE_LOCK(&pOpenContext->Lock); // // Set a back pointer from the packet to the IRP. // NPROT_IRP_FROM_SEND_PKT(pNdisPacket) = pIrp; NtStatus = STATUS_PENDING; pNdisBuffer->Next = NULL; NdisChainBufferAtFront(pNdisPacket, pNdisBuffer); #if SEND_DBG { PUCHAR pData; pData = MmGetSystemAddressForMdlSafe(pNdisBuffer, NormalPagePriority); NPROT_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 NdisSendPackets(pOpenContext->BindingHandle, &pNdisPacket, 1); } while (FALSE); if (NtStatus != STATUS_PENDING) { pIrp->IoStatus.Status = NtStatus; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } return (NtStatus); }
// //发送相关函数的实现、 // NTSTATUS SecLabSendPacket( PADAPT pAdapt, IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp ) { PIO_STACK_LOCATION pIrpSp; ULONG FunctionCode; ULONG DataLength; NTSTATUS NtStatus=STATUS_INVALID_HANDLE; NDIS_STATUS Status; PNDIS_PACKET pNdisPacket; PNDIS_BUFFER pNdisBuffer; // SECLAB_ETH_HEADER UNALIGNED *pEthHeader; PUCHAR pData; ULONG i; #ifdef NDIS51 PVOID CancelId; #endif pIrpSp = IoGetCurrentIrpStackLocation(pIrp); pNdisPacket = NULL; pNdisBuffer = NULL; do { if (pAdapt == NULL) { DbgPrint("Write: FileObject not yet associated with a device\n"); NtStatus = STATUS_INVALID_HANDLE; break; } // // 检查发送数据包的长度 // DataLength=pIrpSp->Parameters.DeviceIoControl.InputBufferLength; if (DataLength > MAX_SEND_PACKETLEN ) { DbgPrint("Write: Open data length larger than max frame size\n"); NtStatus = STATUS_UNSUCCESSFUL; break; } // // 构造一个发送封包 // if(pAdapt->SendPacketPoolHandle==NULL) { DbgPrint("The Packet Pool should not be NULL"); DbgBreakPoint(); break; } do { //其实怎么样分配内存是无关紧要的,忘记资源的释放也不是很严重的 //最多导致内存支出过多。关键是不能让程序引用不存在的内存,这样会 //造成崩溃,比如重复释放内存。崩溃的另一大可能是在Dispatch>=passive //级别上调用非分页内存。 //pData=(PUCHAR)ExAllocatePool(NonPagedPool,DataLength); NdisAllocateMemoryWithTag((PVOID *)(&pData), DataLength,'lceS'); if(pData==NULL) { DbgPrint("Can not allocate pool for send"); break; } //RtlCopyMemory(pData,pIrp->AssociatedIrp.SystemBuffer,DataLength); NdisMoveMemory(pData,pIrp->AssociatedIrp.SystemBuffer,DataLength); // // 将其转化为NDIS_BUFFER. // NdisAllocateBuffer( &Status, &pNdisBuffer, SendBufferPool, pData, DataLength); if (Status != NDIS_STATUS_SUCCESS) { DbgPrint("failed to allocate Ndis Buffer"); break; } NdisAllocatePacket(&Status, &pNdisPacket, pAdapt->SendPacketPoolHandle); if (Status != NDIS_STATUS_SUCCESS) { DbgPrint("failed to alloc NDIS packet"); break; } NDIS_SET_PACKET_STATUS(pNdisPacket, 0); pNdisBuffer->Next = NULL; NdisChainBufferAtFront(pNdisPacket, pNdisBuffer); pNdisPacket->Private.Head->Next=NULL; pNdisPacket->Private.Tail=NULL; break; } while (FALSE); if (pNdisPacket == NULL || pNdisBuffer==NULL) { // // Clean up // if (pNdisBuffer != NULL) { NdisFreeBuffer(pNdisBuffer); } if (pData != NULL) { NdisFreeMemory(pData, 0, 0); } } IoMarkIrpPending(pIrp); NtStatus = STATUS_PENDING; pIrp->IoStatus.Status = STATUS_PENDING; // // 初始化封包中的标志符。当标志符值为0时此包被释放 // SECLAB_SEND_PKT_RSVD(pNdisPacket)->RefCount = 1; #ifdef NDIS51 // // NDIS 5.1 supports cancelling sends. We set up a cancel ID on // each send packet (which maps to a Write IRP), and save the // packet pointer in the IRP. If the IRP gets cancelled, we use // NdisCancelSendPackets() to cancel the packet. // CancelId = SECLAB_GET_NEXT_CANCEL_ID(); NDIS_SET_PACKET_CANCEL_ID(pNdisPacket, CancelId); pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pAdapt; pIrp->Tail.Overlay.DriverContext[1] = (PVOID)pNdisPacket; NdisInterlockedIncrement(&PendedSendCount); NdisAcquireSpinLock(&WriteIrpLock); InsertTailList(&PendedWritesList, &pIrp->Tail.Overlay.ListEntry); IoSetCancelRoutine(pIrp, SecLabCancelWrite); NdisReleaseSpinLock(&WriteIrpLock); #endif // NDIS51 // // 创建一个指针从packet回指向IRP // SECLAB_IRP_FROM_SEND_PKT(pNdisPacket) = pIrp; // //创建三个信号,以便在发送完成例程中指示此包 // SECLAB_SIGNAL1_FROM_SEND_PKT(pNdisPacket)=SIGNAL1; SECLAB_SIGNAL2_FROM_SEND_PKT(pNdisPacket)=SIGNAL2; SECLAB_SIGNAL3_FROM_SEND_PKT(pNdisPacket)=SIGNAL3; // //发包 // NdisSendPackets(pAdapt->BindingHandle, &pNdisPacket, 1); } while (FALSE); if (NtStatus != STATUS_PENDING) { pIrp->IoStatus.Status = NtStatus; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } return (NtStatus); }