NTSTATUS PacketCancelReadIrps( IN PDEVICE_OBJECT DeviceObject ) { POPEN_INSTANCE open = DeviceObject->DeviceExtension; PLIST_ENTRY thisEntry; PIRP pendingIrp; PNDIS_PACKET myPacket = NULL; PPACKET_RESERVED reserved; PMDL mdl; // DebugPrint(("PacketCancelReadIrps\n")); // Walk through the RcvList and cancel all read IRPs. while( thisEntry = ExInterlockedRemoveHeadList( &open->RcvList, &open->RcvQSpinLock )) { reserved=CONTAINING_RECORD(thisEntry,PACKET_RESERVED,ListElement); myPacket=CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved); ASSERT(myPacket); pendingIrp = RESERVED(myPacket)->Irp; NdisFreePacket(myPacket); // DebugPrint(("Cancelled : 0%0x\n", pendingIrp)); IoSetCancelRoutine(pendingIrp, NULL); pendingIrp->IoStatus.Information = 0; pendingIrp->IoStatus.Status = STATUS_CANCELLED; IoCompleteRequest(pendingIrp, IO_NO_INCREMENT); IoDecrement(open); } return STATUS_SUCCESS; }
NTSTATUS PacketClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { // This is the dispatch routine for create/open and close requests. // These requests complete successfully. POPEN_INSTANCE open; NTSTATUS status = STATUS_SUCCESS; DebugPrint(("CloseAdapter \n")); #ifdef XNSDRW_LOG_PACKETS // reset the packet sniffing log LogReset(); #endif if (DeviceObject == Globals.ControlDeviceObject) { Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } open = DeviceObject->DeviceExtension; IoIncrement(open); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); IoDecrement(open); return status; }
NTSTATUS DispatchCleanup( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { POPEN_INSTANCE pOpen = (POPEN_INSTANCE)DeviceObject->DeviceExtension; NTSTATUS status = STATUS_SUCCESS; if(DeviceObject == g_data.pControlDevice) { Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } IoIncrement(pOpen); CancelReadIrp(DeviceObject); IoDecrement(pOpen); NdisWaitEvent(&pOpen->CleanupEvent, 0); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; }
VOID ProtocolResetComplete( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status ) { OPEN_INSTANCE *pOpen; pOpen = (OPEN_INSTANCE*)ProtocolBindingContext; // 取出IRP指针 PLIST_ENTRY pListEntry = ExInterlockedRemoveHeadList( &pOpen->ResetIrpList, &pOpen->ResetQueueLock ); PIRP pIrp = CONTAINING_RECORD(pListEntry,IRP,Tail.Overlay.ListEntry); // 完成此IRP if(Status == NDIS_STATUS_SUCCESS) { pIrp->IoStatus.Status = STATUS_SUCCESS; } else { pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; } pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT); IoDecrement(pOpen); }
// 处理IRP_MJ_CREATE、IRP_MJ_CLOSE功能代码 NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp) { DbgPrint(" ProtoDrv: DispatchCreate \n"); NTSTATUS status = STATUS_SUCCESS; if(pDevObj == g_data.pControlDevice) { pIrp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return status; } POPEN_INSTANCE pOpen = (POPEN_INSTANCE)pDevObj->DeviceExtension; IoIncrement(pOpen); if(!pOpen->bBound) { status = STATUS_DEVICE_NOT_READY; } pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = status; IoCompleteRequest(pIrp, IO_NO_INCREMENT); IoDecrement(pOpen); return status; }
VOID ProtocolSendComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET pPacket, IN NDIS_STATUS Status ) { OPEN_INSTANCE *pOpen = (OPEN_INSTANCE *)ProtocolBindingContext; PIRP pIrp = RESERVED(pPacket)->pIrp; PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp); // 释放封包 NdisFreePacket(pPacket); // 完成IRP请求 if(Status == NDIS_STATUS_SUCCESS) { pIrp->IoStatus.Information = pIrpSp->Parameters.Write.Length; pIrp->IoStatus.Status = STATUS_SUCCESS; DbgPrint(" ProtoDrv: Send data success \n"); } else { pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; } IoCompleteRequest(pIrp, IO_NO_INCREMENT); IoDecrement(pOpen); }
NTSTATUS PacketRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { POPEN_INSTANCE open; PNDIS_PACKET pPacket; NDIS_STATUS status; NTSTATUS ntStatus; PIO_STACK_LOCATION irpSp; // DebugPrint(("Read\n")); open = DeviceObject->DeviceExtension; IoIncrement(open); if(!open->Bound) { ntStatus = STATUS_DEVICE_NOT_READY; goto ERROR; } irpSp = IoGetCurrentIrpStackLocation(Irp); if (irpSp->Parameters.Read.Length < ETHERNET_HEADER_LENGTH) { ntStatus = STATUS_BUFFER_TOO_SMALL; goto ERROR; } NdisAllocatePacket( &status, &pPacket, open->PacketPool ); if (status != NDIS_STATUS_SUCCESS) { // DebugPrint(("Packet: Read- No free packets\n")); ntStatus = STATUS_INSUFFICIENT_RESOURCES; goto ERROR; } RESERVED(pPacket)->Irp=Irp; RESERVED(pPacket)->pMdl=NULL; IoMarkIrpPending(Irp); IoSetCancelRoutine(Irp, PacketCancelRoutine); ExInterlockedInsertTailList( &open->RcvList, &RESERVED(pPacket)->ListElement, &open->RcvQSpinLock); return STATUS_PENDING; ERROR: Irp->IoStatus.Status = ntStatus; IoCompleteRequest (Irp, IO_NO_INCREMENT); IoDecrement(open); return ntStatus; }
NTSTATUS DispatchWrite(PDEVICE_OBJECT pDevObj, PIRP pIrp) { NTSTATUS status; // 取得描述适配器的OPEN_INSTANCE结构的指针 OPEN_INSTANCE *pOpen = (OPEN_INSTANCE *)pDevObj->DeviceExtension; // 增加IO引用计数 IoIncrement(pOpen); do { if(!pOpen->bBound) { status = STATUS_DEVICE_NOT_READY; break; } // 从封包池中申请一个封包 PNDIS_PACKET pPacket; NdisAllocatePacket((NDIS_STATUS*)&status, &pPacket, pOpen->hPacketPool); if(status != NDIS_STATUS_SUCCESS) // 封包被申请完了! { status = STATUS_INSUFFICIENT_RESOURCES; break; } RESERVED(pPacket)->pIrp = pIrp; // 保存IRP指针,在完成例程中还要使用 // 附加写缓冲区到封包 NdisChainBufferAtFront(pPacket, pIrp->MdlAddress); // 注意,既然我们已经标识此IRP未决,我们必须返回STATUS_PENDING,即便是 // 我们恰巧同步完成了这个IRP IoMarkIrpPending(pIrp); // 发送封包到下层NIC设备 NdisSend((NDIS_STATUS*)&status, pOpen->hAdapter, pPacket); if(status != NDIS_STATUS_PENDING) { ProtocolSendComplete(pOpen, pPacket, status); } return STATUS_PENDING; }while(FALSE); if(status != STATUS_SUCCESS) { IoDecrement(pOpen); pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = status; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } return status; }
VOID PacketResetComplete(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status) { // This routine is called when a protocol-initiated reset operation, // begun with a call to NdisReset that returned NDIS_STATUS_PENDING, // is completed. POPEN_INSTANCE open; PIRP irp; PLIST_ENTRY resetListEntry; DebugPrint(("PacketResetComplte\n")); #ifdef XNSDRW_LOG_PACKETS // reset the packet sniff log LogReset(); #endif open = (POPEN_INSTANCE)ProtocolBindingContext; // remove the reset IRP from the list resetListEntry = ExInterlockedRemoveHeadList(&open->ResetIrpList, &open->ResetQueueLock); #if DBG if (resetListEntry == NULL) { DbgBreakPoint(); return; } #endif irp = CONTAINING_RECORD(resetListEntry, IRP, Tail.Overlay.ListEntry); if (Status == NDIS_STATUS_SUCCESS) irp->IoStatus.Status = STATUS_SUCCESS; else irp->IoStatus.Status = STATUS_UNSUCCESSFUL; irp->IoStatus.Information = 0; IoCompleteRequest(irp, IO_NO_INCREMENT); IoDecrement(open); DebugPrint(("PacketResetComplte exit\n")); }
NTSTATUS PacketOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { // This is the dispatch routine for create/open and close requests. // These requests complete successfully. POPEN_INSTANCE open; NTSTATUS status = STATUS_SUCCESS; DebugPrint(("OpenAdapter\n")); #ifdef XNSDRW_LOG_PACKETS // reset the packet sniffing log LogReset(); #endif if (DeviceObject == Globals.ControlDeviceObject) { Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } open = DeviceObject->DeviceExtension; DebugPrint(("AdapterName :%ws\n", open->AdapterName.Buffer)); IoIncrement(open); // Check to see whether you are still bound to the adapter if(! open->Bound) { status = STATUS_DEVICE_NOT_READY; } Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); IoDecrement(open); return status; }
VOID ProtocolRequestComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_REQUEST NdisRequest, IN NDIS_STATUS Status ) { POPEN_INSTANCE pOpen = (POPEN_INSTANCE)ProtocolBindingContext; PINTERNAL_REQUEST pInterRequest = CONTAINING_RECORD(NdisRequest, INTERNAL_REQUEST, Request); PIRP pIrp = pInterRequest->pIrp; if(Status == NDIS_STATUS_SUCCESS) { PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp); UINT nIoControlCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode; PPROTOCOL_OID_DATA pOidData = (PPROTOCOL_OID_DATA)pIrp->AssociatedIrp.SystemBuffer; // 将大小返回到用户缓冲区 if(nIoControlCode == IOCTL_PROTOCOL_SET_OID) { pOidData->Length = pInterRequest->Request.DATA.SET_INFORMATION.BytesRead; } else if(nIoControlCode == IOCTL_PROTOCOL_QUERY_OID) { pOidData->Length = pInterRequest->Request.DATA.QUERY_INFORMATION.BytesWritten; } // 设置返回给I/O管理器的信息 pIrp->IoStatus.Information = pIrpSp->Parameters.DeviceIoControl.InputBufferLength; pIrp->IoStatus.Status = STATUS_SUCCESS; } else { pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; } ExFreePool(pInterRequest); IoCompleteRequest(pIrp, IO_NO_INCREMENT); IoDecrement(pOpen); }
VOID PacketTransferDataComplete ( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET pPacket, IN NDIS_STATUS Status, IN UINT BytesTransfered ) { PIO_STACK_LOCATION irpSp; POPEN_INSTANCE open; PIRP irp; PMDL pMdl; // DebugPrint(("Packet: TransferDataComplete\n")); open = (POPEN_INSTANCE)ProtocolBindingContext; irp = RESERVED(pPacket)->Irp; irpSp = IoGetCurrentIrpStackLocation(irp); pMdl = RESERVED(pPacket)->pMdl; if(pMdl) IoFreeMdl(pMdl); NdisFreePacket(pPacket); if(Status == NDIS_STATUS_SUCCESS) { irp->IoStatus.Status = STATUS_SUCCESS; irp->IoStatus.Information = BytesTransfered+ETHERNET_HEADER_LENGTH; } else { irp->IoStatus.Status = STATUS_UNSUCCESSFUL; irp->IoStatus.Information = 0; } // DebugPrint(("BytesTransfered:%d\n", irp->IoStatus.Information)); IoCompleteRequest(irp, IO_NO_INCREMENT); IoDecrement(open); }
NTSTATUS PacketCleanup(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { // This is the dispatch routine for cleanup requests. // This routine is called whenever a handle to the device is closed. POPEN_INSTANCE open; NTSTATUS status = STATUS_SUCCESS; DebugPrint(("Packet: Cleanup\n")); if (DeviceObject == Globals.ControlDeviceObject) { Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } open = DeviceObject->DeviceExtension; IoIncrement(open); // Cancel all the pending reads. PacketCancelReadIrps(DeviceObject); // Since the current implementation of NDIS doesn't // allow us to cancel requests pending at the // miniport, we must wait here until they complete. IoDecrement(open); NdisWaitEvent(&open->CleanupEvent, 0); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; }
VOID PacketCancelRoutine ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { POPEN_INSTANCE open = DeviceObject->DeviceExtension; KIRQL oldIrql; PIRP irpToComplete = NULL; PLIST_ENTRY thisEntry, listHead; PIRP pendingIrp; PNDIS_PACKET myPacket = NULL; PPACKET_RESERVED reserved; PMDL mdl; // Don't assume that the IRP being cancelled is in the queue. // Only complete the IRP if it IS in the queue. // // Must acquire the local spinlock before releasing // the global cancel spinlock // // DebugPrint(("PacketCancelRoutine\n")); oldIrql = Irp->CancelIrql; // One should not intermix KeAcquireSpinLock(AtDpcLevel) // and ExInterlocked...List() functions on the same spinlock if the // routines that use the lock run at IRQL > DISPATCH_LEVEL. // After acquiring the lock using Ke function, if we got interrupted // and entered into an ISR and tried to manipulate the list using // ExInterlocked...List function with the same lock, we deadlock. // In this sample we can safely do that because none of our routines // will be called at IRQL > DISPATCH_LEVEL. KeAcquireSpinLockAtDpcLevel(&open->RcvQSpinLock); IoReleaseCancelSpinLock( KeGetCurrentIrql() ); listHead = &open->RcvList; for( thisEntry = listHead->Flink; thisEntry != listHead; thisEntry = thisEntry->Flink ) { reserved=CONTAINING_RECORD(thisEntry,PACKET_RESERVED,ListElement); myPacket=CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved); pendingIrp = RESERVED(myPacket)->Irp; if (pendingIrp == Irp) { RemoveEntryList(thisEntry); irpToComplete = pendingIrp; break; } } KeReleaseSpinLock(&open->RcvQSpinLock, oldIrql); if(irpToComplete) { // DebugPrint(("Cancelling IRP\n")); // ASSERT(myPacket); NdisFreePacket(myPacket); irpToComplete->IoStatus.Status = STATUS_CANCELLED; irpToComplete->IoStatus.Information = 0; IoCompleteRequest(irpToComplete, IO_NO_INCREMENT); IoDecrement(open); } }
INT PacketReceivePacket( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet ) { UINT bytesTransfered = 0; POPEN_INSTANCE open; PIRP irp; PNDIS_PACKET myPacket; PLIST_ENTRY packetListEntry; ULONG bufferLength; PPACKET_RESERVED reserved; PIO_STACK_LOCATION irpSp; PMDL mdl; PVOID startAddress; NTSTATUS status; // DebugPrint(("PacketReceivePacket\n")); open = (POPEN_INSTANCE)ProtocolBindingContext; packetListEntry = ExInterlockedRemoveHeadList( &open->RcvList, &open->RcvQSpinLock ); if (packetListEntry == NULL) { // DebugPrint(("No pending read, dropping packets\n")); return 0; } reserved = CONTAINING_RECORD(packetListEntry,PACKET_RESERVED,ListElement); myPacket = CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved); irp = RESERVED(myPacket)->Irp; irpSp = IoGetCurrentIrpStackLocation(irp); // We don't have to worry about the situation where the IRP is cancelled // after we remove it from the queue and before we reset the cancel // routine because the cancel routine has been coded to cancel an IRP // only if it's in the queue. IoSetCancelRoutine(irp, NULL); // Following block of code locks the destination packet // MDLs in a safe manner. This is a temporary workaround // for NdisCopyFromPacketToPacket that currently doesn't use // safe functions to lock pages of MDL. This is required to // prevent system from bugchecking under low memory resources. // { PVOID virtualAddress; PNDIS_BUFFER firstBuffer, nextBuffer; ULONG totalLength; NdisQueryPacket(Packet, NULL, NULL, &firstBuffer, &totalLength); while( firstBuffer ) { NdisQueryBufferSafe( firstBuffer, &virtualAddress, &totalLength, NormalPagePriority ); if(!virtualAddress) { status = STATUS_INSUFFICIENT_RESOURCES; goto CleanExit; } NdisGetNextBuffer(firstBuffer, &nextBuffer); firstBuffer = nextBuffer; } } NdisChainBufferAtFront( myPacket, irp->MdlAddress ); bufferLength=irpSp->Parameters.Read.Length; NdisCopyFromPacketToPacket( myPacket, 0, bufferLength, Packet, 0, &bytesTransfered ); CleanExit: NdisFreePacket(myPacket); irp->IoStatus.Status = status; irp->IoStatus.Information = bytesTransfered; IoCompleteRequest(irp, IO_NO_INCREMENT); // DebugPrint(("BytesTransfered:%d\n", bytesTransfered)); IoDecrement(open); return 0; }
// I/O控制派遣例程 NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp) { // 假设失败 NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; // 取得此IRP(pIrp)的I/O堆栈指针 PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp); // 取得I/O控制代码 ULONG uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode; // 取得I/O缓冲区指针和它的长度 PVOID pIoBuffer = pIrp->AssociatedIrp.SystemBuffer; ULONG uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength; ULONG uOutSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength; if(uIoControlCode == IOCTL_ENUM_ADAPTERS) { ULONG nDataLen = 0; if(pDevObj != g_data.pControlDevice) status = STATUS_INVALID_DEVICE_REQUEST; else { status = GetAdapterList(pIoBuffer, uOutSize, &nDataLen); if(status != STATUS_SUCCESS) DbgPrint("GetAdapterList error "); } pIrp->IoStatus.Information = nDataLen; pIrp->IoStatus.Status = status; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return status; } OPEN_INSTANCE *pOpen = (OPEN_INSTANCE *)pDevObj->DeviceExtension; if(pOpen == NULL || !pOpen->bBound) { pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return STATUS_UNSUCCESSFUL; } IoIncrement(pOpen); IoMarkIrpPending(pIrp); if(uIoControlCode == IOCTL_PROTOCOL_RESET) { // 插入此IRP到重置IRP列表 ExInterlockedInsertTailList( &pOpen->ResetIrpList, &pIrp->Tail.Overlay.ListEntry, &pOpen->ResetQueueLock); // 发出重置请求 NdisReset( &status, pOpen->hAdapter ); if(status != NDIS_STATUS_PENDING) { ProtocolResetComplete( pOpen, status); } } // 获取或者设置OID信息 else if(uIoControlCode == IOCTL_PROTOCOL_SET_OID || uIoControlCode == IOCTL_PROTOCOL_QUERY_OID) // 输入参数是一个自定义的PROTOCOL_OID_DATA结构 { PPROTOCOL_OID_DATA pOidData = (PPROTOCOL_OID_DATA)pIoBuffer; // 申请一个INTERNAL_REQUEST结构 PINTERNAL_REQUEST pInterRequest = (PINTERNAL_REQUEST)ExAllocatePool(NonPagedPool, sizeof(INTERNAL_REQUEST)); if(pInterRequest == NULL) { pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(pIrp, IO_NO_INCREMENT); IoDecrement(pOpen); return STATUS_PENDING; } pInterRequest->pIrp = pIrp; if(uOutSize == uInSize && uOutSize >= sizeof(PROTOCOL_OID_DATA) && uOutSize >= sizeof(PROTOCOL_OID_DATA) - 1 + pOidData->Length) // 缓冲区可用? { // 初始化NDIS_REQUEST结构 if(uIoControlCode == IOCTL_PROTOCOL_SET_OID) { pInterRequest->Request.RequestType = NdisRequestSetInformation; pInterRequest->Request.DATA.SET_INFORMATION.Oid = pOidData->Oid; pInterRequest->Request.DATA.SET_INFORMATION.InformationBuffer = pOidData->Data; pInterRequest->Request.DATA.SET_INFORMATION.InformationBufferLength = pOidData->Length; } else { pInterRequest->Request.RequestType = NdisRequestQueryInformation; pInterRequest->Request.DATA.QUERY_INFORMATION.Oid = pOidData->Oid; pInterRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer = pOidData->Data; pInterRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength = pOidData->Length; } // 提交这个请求 NdisRequest(&status, pOpen->hAdapter, &pInterRequest->Request); } else { status = NDIS_STATUS_FAILURE; pInterRequest->Request.DATA.SET_INFORMATION.BytesRead = 0; pInterRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0; } if(status != NDIS_STATUS_PENDING) { ProtocolRequestComplete(pOpen, &pInterRequest->Request, status); } } return STATUS_PENDING; }