VirtualWiFi的驱动实现在物理层(Mac)以及协议层(Ip protocol)之间。如图:
图中就是VirtualWiFi的层次结构图了。VirtualWiFi加载了或者说虚拟了两种可用的无线网卡。而且这两张网卡在IP层看来,都是激活可用的。虽然在任意的某一个时刻只有一张是可用的,因为我们的实现方法是靠高速的切换。所以图中显示的此刻network2才是激活的。而VirtualWiFi driver又可以分为两层,Miniport driver(MD)绑定了上一层的网络协议 和protocol driver(PD)则绑定了下层的网卡的为端口驱动(miniport driever).这样做的好处就是每张网卡都有不同的IP地址,但是他们分享一张网卡的MAC地址。
现在简单介绍这两个层次的作用。MD负责监控所有虚拟网卡的状态,包括SSID,网络模式,同时负责对底层驱动的信息查询和设置。PD则管理这些网卡的状态,比如交换时间,停留时间,什么时候换成数据,什么时候发送缓冲区数据等等。VirtualWiFi Driver实现在kernel层,所以NDIS提供了主要的软件组件接口。而VWService实现在user层。主要考虑便于程序的开发。但是,如何在user层以及kernel层进行通讯呢?即VWService如何控制driver进行状态的改变呢?这个任务主要有DeviceIoControl()这个系统函数来完成,它传递了一种I/O控制码(IOCTLCODE)用来帮助鞋套VWService和底层驱动的通讯问题。关于DeviceIoContrl()可以参考
这里只做简单介绍哦。
DeviceIoControl函数向指定的设备驱动发送一个控制码,驱动程序通过这个控制码来完成特定的工作。该函数原型如下:
BOOL DeviceIoControl( HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped );
|
参数说明
hDevice
要进行操作的设备句柄。
dwIoControlCode
要进行操作的控制码。驱动程序可以通过CTL_CODE宏来组合定义一个控制码,并在IRP_MJ_DEVICE_CONTROL的实现中进行控制码的操作。在驱动层,irpStack->Parameters.DeviceIoControl.IoControlCode表示了这个控制码。
lpInBuffer
由用户层发送的缓冲区数据。在驱动层,依传输类型的不同,输入缓冲区的位置亦不同,见下表。
传输类型 |
位置 |
METHOD_IN_DIRECT |
irp->AssociatedIrp.SystemBuffer |
METHOD_OUT_DIRECT |
irp->AssociatedIrp.SystemBuffer |
METHOD_BUFFERED |
irp->AssociatedIrp.SystemBuffer |
METHOD_NEITHER |
irpStack->Parameters.DeviceIoControl.Type3InputBuffer |
nInBufferSize
由用户层发送的缓冲区大小。在驱动层,这个值是irpStack->Parameters.DeviceIoControl.InputBufferLength。
lpOutBuffer
由用户层指定,用于接收驱动层返回数据的缓冲区。在驱动层,依传输类型的不同,输出缓冲区的位置亦不同,见下表。
传输类型 |
位置 |
METHOD_IN_DIRECT |
irp->MdlAddress |
METHOD_OUT_DIRECT |
irp->MdlAddress |
METHOD_BUFFERED |
irp->AssociatedIrp.SystemBuffer |
METHOD_NEITHER |
irp->UserBuffer |
nOutBufferSize
由用户层指定,用于接收驱动层返回数据的缓冲区大小。在驱动层,这个值是irpStack->Parameters.DeviceIoControl.OutputBufferLength。
lpBytesReturned
由用户层指定,用于接收驱动层实际返回数据大小。在驱动层,这个值是irp->IoStatus->Information。
lpOverlapped
用于异步操作。
举个例子:VWService想通知driver发送缓冲区的数据。
一个简单的流程图:
![]()
首先,创建一个用户自定义的IOCTL:
// Send the buffered packets - used by both the Server and Service #define IOCTL_SEND_BUFFERED_PACKETS CTRL_CODE( 0x839, METHOD_BUFFERED, FILE_READ_ACCESS)
|
第二:由VWService调度执行IOCTL.
// Send the packets buffered on the current SSID
retVal = ioctlSet(IOCTL_SEND_BUFFERED_PACKETS, adapterNum, sizeof(adapterNum));
|
这里调用了自定义函数ioctlSet()传递了之前定义的IOCTL.
第三:由ioctlSet这个函数传递信息到底层驱动,当然主要还要靠DeviceIoCtrol()来完成。
VOID ioctlSet(DWORD dwIOControlCode, LPVOID lpInBuffer, DWORD lpInBufferSize) { (Omitted) b = DeviceIoControl( hDriver, // handle to a device, file, or directory
dwIOControlCode, // control code of operation to perform
lpInBuffer, //lpInBuffer, pointer to buffer to supply input data
lpInBufferSize, //nInBufferSize, in bytes, of input buffer
NULL, //lpOutBuffer, pointer to buffer to receive output data
0, //nOutBufferSize, in bytes, of output buffer
&bytesreturned, // pointer to variable to receive byte count
NULL // pointer to structure for asynchronous
); (Omitted) CloseHandle(hDriver); // Close the driver
} }
|
第四,底层驱动调度执行IOCTL对应的功能。I/O manager管理所有的IRP储存在IO_STACK_LOCATION堆栈里面。通过IoGetCurrentIrpStackLocation可以拿到需要的device control code.
1 NTSTATUS 2 PtDispatch() 3 { 4 (Omitted) 5 irpStack = IoGetCurrentIrpStackLocation(Irp); 6 DBGPRINT(MUX_LOUD, ("==>PtDispatch %d\n", irpStack->MajorFunction)); 7 8 switch (irpStack->MajorFunction) 9 { 10 case IRP_MJ_DEVICE_CONTROL: { 11 12 buffer = Irp->AssociatedIrp.SystemBuffer; 13 inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength; 14. outlen = irpStack->Parameters.DeviceIoControl.OutputBufferLength; 15. saveControlFlags = irpStack->Control; 16 17 switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { 18 case IOCTL_SEND_BUFFERED_PACKETS: 19 memcpy(tempBuffer, buffer, inlen); 20 // get adapter from ioctl buffer
21 adapterNum = atol(tempBuffer); 22 23 // get the corresponding pAdapt data structure
24 for(p = AdapterList.Flink; p != &AdapterList; p = p->Flink) 25 { 26 i++; 27 if(i<adapterNum) { 38. continue; 29 } 30 pAdapt = CONTAINING_RECORD(p, ADAPT, Link); 31 FoundAdapter = TRUE; 32 break; 33 } 34 // Send the packets for the corresponding adapter
35 if(FoundAdapter) 36 PtIoctlSendBufferedPackets(pAdapt); 37 FoundAdapter = FALSE; 38 i = 0; 39 DBGPRINT(MUX_LOUD, ("The card sent the buffered packets\n")); 40 Irp->IoStatus.Information = 0; 41 break; }
|
第五:调用PtIoctlSendBufferedPackets(pAdapt)执行具体的数据发送。
1 // Called by an Ioctl to Send the Buffered Packets
2 VOID PtIoctlSendBufferedPackets( IN PADAPT pAdapt ) 3{ 4 pAdapt->isSSIDActive[pAdapt->CurrentActiveConnection] = TRUE; 5 6 // Send all the buffered packets
7 while(!IsQueueEmpty(&pAdapt->SendWaitQueue[pAdapt->CurrentActiveConnection])) 8 { 9 PQUEUE_ENTRY pEntry = RemoveHeadQueue(&pAdapt->SendWaitQueue[pAdapt->CurrentActiveConnection]); 10 ASSERT(pEntry); 11 DBGPRINT(MUX_LOUD, ("Dequeueing packet for SSID %d\n", pAdapt->CurrentActiveConnection)); 12 13 // decrement the number of buffered packets
14 pAdapt->nWaitSend[pAdapt->CurrentActiveConnection]--; 15 MyPacket = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReserved); 16 17 pSendReserved = MUX_RSVD_FROM_SEND_PACKET(MyPacket); 18 pVElan = pSendReserved->pVElan; 19 20 MUX_INCR_PENDING_SENDS(pVElan); 21 22 NdisSend(&Status, pAdapt->BindingHandle, MyPacket); 23 if (Status != NDIS_STATUS_PENDING) 24 {
25 PtSendComplete((NDIS_HANDLE)pAdapt, MyPacket, Status); 26
|
这样就完成了发送缓冲区数据的全部过程。其他的I/O都类似这样的。不多讲了。
-----------------------------------
阅读(3208) | 评论(0) | 转发(0) |