阅读:1898回复:1
我这个驱动到底怎么了--高手指点啊
一个虚拟网卡的驱动
请高手看看我的发包和收包部分是否有问题 发包: 通知跟驱动通信的应用程序来取数据 收包: 应用程序把数据写到驱动中,触发一个收包信号 下面是源代码: ////////////////////////////////////////////////////////////////////// // VNICAdap.cpp: implementation of the VNICAdapter class. // // Generated by Network Driver Wizard on 星期一, 五月 09, 2005 // #include <stdlib.h> #include "VNICAdap.h" #include "Global.h" #include <kexception.h> //////////////////////////////////////////////////////////////////// // CmpMac // 比较两个MAC地址是否相等 // Parameters: // lmac - MAC地址1 // rmac - MAC地址2 // Return: // true - 如果两个MAC地址相等 // false - 如果不相等 // Note: // 静态全局方法 static bool CmpMac(UCHAR * lmac, UCHAR *rmac, int len = 6) { for (int i = 0; i < len ; i++) { if (lmac != rmac) { return false; } } return true; } ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// VNICAdapter::VNICAdapter() : KNdisMiniAdapter(), m_DeviceHandle(NULL),m_pDeviceObject(NULL) { // TODO: initialize your private sndData members // Do NOT call any NDIS functions in here. Defer to Initialize() pFile = NULL; pEvent = NULL; } VNICAdapter::~VNICAdapter() { // TODO: deallocate all the resources allocated in constructor/Initialize() pAdapter = NULL; } //////////////////////////////////////////////////////////////////// // NDIS callback handlers //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// // VNICAdapter::Initialize // // MiniportInitialize is a required function that sets up a NIC (or // virtual NIC) for network I/O operations, claims all hardware resources // necessary to the NIC in the registry, and allocates resources the driver // needs to carry out network I/O operations // // Parameters: // Medium // Reference to KNdisMedium object that we have to set the medium // type our NIC supports // Config // Reference to KNdisConfig object that we use to query various // configuration parameters // IRQL: // PASSIVE_LEVEL // Return Mode: // Synchronous // // TODO: // 1) Select supported medium in Medium object // 2) Read config parameters if any using Config object // 3) Allocate h/w resources, pools, etc. // 4) Register with NDIS using SetAttributes() // 5) Register Shutdown Handler // 6) Initialize and enable the NIC. // NOTE: Be ready to process INTs even before the function exits // NDIS_STATUS VNICAdapter::Initialize (IN OUT KNdisMedium& Medium, IN KNdisConfig& Config) { TRACE("VNICAdapter::Initialize() Entered\n"); //保存执针 pAdapter = this; // Select our the Medium: if (! Medium.Select(VNIC_MEDIUM_TYPE) ) KNDIS_RETURN_ERROR (NDIS_STATUS_UNSUPPORTED_MEDIA); // Get network address (if any) from the Registry. If specified // it will be used instead of burned permanent address: if (Config.ReadNetworkAddress(m_CurrentAddress) != NDIS_STATUS_SUCCESS) { m_CurrentAddress.Invalidate(); //生成一个随机的mac地址,以减少冲突的可能性 CHAR temp[12]; //指定随机数生成的种子 srand( KeQueryTimeIncrement() ); for(int i = 0; i <= 5; i++) { m_CurrentAddress.m_bytes = rand() % 256; } //转化mac地址 TranslateAddr(temp, m_CurrentAddress.m_bytes); //将生成的mac地址写入注册表 KNdisString valueStr((PSTR)&temp); Config.Write(KNDIS_STRING_CONST("NetworkAddress"), PNDIS_STRING(valueStr)); } //保存mac地址到一个全局变量 for(int i = 0; i <= 5; i++) { mac = m_CurrentAddress.m_bytes; } // TODO: Read some other config stuff from the Registry, e.g. // Now let NDIS know about the BUS the NIC is on. Here's where the NDIS/Adapter-instance // handshake takes place. This should happen *before* allocating the h/w resources: ULONG AttributeFlags = 0 #if NDIS51_MINIPORT | NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK // meaning can support surprise removal. See PnpEventNotify() #endif ; SetAttributesEx( NdisInterfaceInternal, AttributeFlags ); // TODO: Configure the bus device further // TODO: Read perm address from the card instead m_PermanentAddress = m_CurrentAddress; // Set default filter and MAC options. In principle, we should also // relay that to our card... m_uPacketFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST | NDIS_PACKET_TYPE_BROADCAST; m_uMacOptions = NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | NDIS_MAC_OPTION_RECEIVE_SERIALIZED | NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | NDIS_MAC_OPTION_NO_LOOPBACK; // TODO: Start the card up. //创建一个虚拟设备 NDIS_STATUS Status = CreateMyDevice(); //显示调试信息 TRACE("VNICAdapter Create Device: %s\n", ((Status)?"FAILED":"OK")); return NDIS_STATUS_SUCCESS; } //////////////////////////////////////////////////////////////////// // VNICAdapter::Halt // // MiniportHalt is a required function that deallocates resources when // the NIC is removed and halts the NIC. // // Parameters: // None // IRQL: // PASSIVE_LEVEL // Return Mode: // Synchronous // // NOTE: Miniports has no "unload" for the driver. The Halt() is the last // function called into a miniport, so everything should be stopped // and freed right here. The KNDIS framework takes care of destroying // the adapter object itself, so this member function is merery required // to undo things done by the Initialize() above - in the inversed order. // // Alternatevely, the driver writer can move all the deallocations to the // destructor: the destructor will be called immediatelly after Halt() // returns. Our sample follows this practice. // VOID VNICAdapter::Halt(VOID) { TRACE("VNICAdapter::Halt() Entered\n"); // TODO: Stop the card. Theoretically, however, // our Isr() still can be called, so we should be prepared. //删除虚拟出来的设备 #if VNIC_WIN2K // win2k,xp系统 if (m_DeviceHandle) { NdisMDeregisterDevice(m_DeviceHandle); m_DeviceHandle = NULL; } #else // win98系统 if (m_pDeviceObject) IoDeleteDevice(m_pDeviceObject); #endif m_pDeviceObject=NULL; } //////////////////////////////////////////////////////////////////// // VNICAdapter::Reset // // MiniportReset is a required function that issues a hardware reset // to the NIC and/or resets the driver's software state. // // Parameters: // AddressingReset // Points to a variable that MiniportReset sets to TRUE if the // NDIS library should call MiniportSetInformation to restore // addressing information to the current values. // IRQL: // DISPATCH_LEVEL // Return Mode: // Synchronous // NDIS_STATUS VNICAdapter::Reset (OUT PBOOLEAN AddressingReset) { TRACE("VNICAdapter::Reset() Entered\n"); // TODO: Reset the card return NDIS_STATUS_SUCCESS; } //////////////////////////////////////////////////////////////////// // VNICAdapter::Shutdown // // MiniportShutdown does nothing more than restore the NIC to its // initial state (before the miniport's DriverEntry function runs) // // Parameters: // None // IRQL: // If MiniportShutdown is called due to a user-initiated system shutdown, // it runs at IRQL PASSIVE_LEVEL in a system-thread context. If it is called // due to an unrecoverable error, MiniportShutdown runs at an arbitrary IRQL // and in the context of whatever component raised the error. // Return Mode: // Synchronous // VOID VNICAdapter::Shutdown(VOID) { TRACE("VNICAdapter::Shutdown() Entered\n"); // TODO: Reset the card for good } //////////////////////////////////////////////////////////////////// // VNICAdapter::Send // // Transfers a protocol-supplied packet over the network // // Parameters: // Packet // Points to a packet descriptor specifying the sndData to be transmitted. // Flags // Specifies the packet flags, if any, set by the protocol. // IRQL: // DISPATCH_LEVEL // Return Mode: // Asynchronous // NOTE: // The return code determines the ownership of the packet and further // interaction between NDIS and our driver. Specifically, // // NDIS_STATUS_SUCCESS - Done with. // NDIS_STATUS_PENDING - We keep it until further notice. // NDIS_STATUS_RESOURCES - We didn't have the resouces *now*, so tell NDIS // please hold it on until further notice. // NOTE: Deserialized Miniports should never return NDIS_STATUS_RESOURCES to NDIS, // and must instead queue it internally. // NDIS_STATUS VNICAdapter::Send( IN PNDIS_PACKET Packet, IN UINT Flags ) { TRACE("VNICAdapter::Send() Entered\n"); // declare for convenience KNdisPacket pkt(Packet); //保存包的执针 pPacket = Packet; // TODO: Manage the packet into the hardware. // Return NDIS_STATUS_SUCCESS if the packet got submitted to the h/w and // NDIS_STATUS_PENDING if it's been queued into m_TxQueue. // if(notify) { //把包的内容填充到数据数组中 KNdisBuffer buf = pkt.QueryFirstBuffer(); UINT nBufCnt = pkt.QueryBufferCount(); UINT start = 0; for(UINT i = 0; i < nBufCnt; i++) { if(buf.IsValid()) { PUCHAR src = (PUCHAR)buf.Address(); UINT len = buf.Length(); for(UINT j=0; j<len;j++) { sndData[start + j] = src[j]; } start = start + len; buf = buf.GetNext(); } } //更新包的长度 packetSize = start; //设置事件通知应用程序来取数据 notify = false; pEvent->Set(); } else { return NDIS_STATUS_FAILURE; } if ( 0/* have to postpone the packet */) { m_TxQueue.InsertTail(pkt); return NDIS_STATUS_PENDING; } //更新发送包的数量 m_GenStats->xmit_ok++; return NDIS_STATUS_SUCCESS; } //////////////////////////////////////////////////////////////////// // VNICAdapter::ReturnPacket // // This method is called when NDIS returns a packet previuosly // indicated by IndicateReceive() back to the miniport // // Parameters: // Packet // Points to a packet descriptor specifying the packet // IRQL: // DISPATCH_LEVEL // Return Mode: // n/a // NOTE: // The packet returns to the "free list" in the Rx area. // Reclaim() does the necessary reset of the chained buffer // and OOB sndData if any. VOID VNICAdapter::ReturnPacket(IN PNDIS_PACKET Packet) { TRACE("VNICAdapter::ReturnPacket() Entered Packet=%p\n, Packet"); // declare for convenience KNdisPacket pkt(Packet); // TODO: Reclaim the packet back to an internal list } //////////////////////////////////////////////////////////////////// // VNICAdapter::CheckForHang // Optional function that reports the state of the NIC or monitors // the responsiveness of an underlying device driver. // Parameters: // none // IRQL: // IRQL DISPATCH_LEVEL // Return Mode: // Synchronous // NOTE: // By default, the NDIS library calls MiniportCheckForHang // approximately every two seconds. If MiniportCheckForHang returns // TRUE, NDIS then calls the driver's MiniportReset function. BOOLEAN VNICAdapter::CheckForHang() { // TODO: Check the h/w for hang return FALSE; } #if defined(NDIS51_MINIPORT) /////////////////////////////////////////////////////////////////////// // Notify on PNP or Power Event (5.1) // // Parameters: // PnPEvent - PNP Event Type // InformationBuffer - Buffer With Extra info // InformationBufferLength - Size of the buffer // Returns: // none // Comments: // See DDK MiniportPnPEventNotify VOID VNICAdapter::PnPEventNotify( IN NDIS_DEVICE_PNP_EVENT PnPEvent, IN PVOID InformationBuffer, IN ULONG InformationBufferLength ) { switch(PnPEvent) { case NdisDevicePnPEventSurpriseRemoved: // Surprise Removal // "When a miniport driver receives notification of a surprise removal, it should note internally // that the device has been removed and cancel any pending IRPs that it sent down to the underlying // bus driver. After calling the MiniportPnPEventNotify function to indicate the surprise removal, // NDIS calls the miniport's MiniportHalt function. If the miniport driver receives any requests to send // packets or query or set OIDs before its MiniportHalt function is called, it should immediately complete // such requests with a status value of NDIS_STATUS_NOT_ACCEPTED" // // @@TODO: Figure what exactly we must do here. // The Halt() method takes care of cancelling the IRPs. // So, should we do that here now? Or it is OK no still do it on Halt()? // What's the point of this notification except we know WHY // the adapter is being Halted... // TRACE("VNICAdapter::PnPEventNotify: Surprised Removal!\n"); break; case NdisDevicePnPEventPowerProfileChanged: // // Power change notification. // The "AC" notification also triggers when the computer exits the standby mode. // TODO: Apply some operational mode adjustments if needed. // E.g., reduce power consumption when switching to battery. // { bool bOnBattery = (*PULONG(InformationBuffer))==NdisPowerProfileBattery; TRACE("VNICAdapter::PnPEventNotify: Running on %s\n", (bOnBattery)?"Batterry":"AC"); } break; default: // // Everything else is non-documented in XP DDK // TRACE("VNICAdapter::PnPEventNotify: Event %u\n", PnPEvent); break; } } /////////////////////////////////////////////////////////////////////// // Cancel Packets Being Sent (5.1) // // Parameters: // CancelId - An identifier specifying the packet or group // of packets whose transmission is being canceled. // Returns: // none // Comments: // Walk the list of not-yet-transmitted packets and cancel them // VOID VNICAdapter::CancelSendPackets( IN PVOID CancelId ) { TRACE("VNICAdapter::CancelSendPackets ID=%p\n", CancelId); // m_TxQueue contains the list of packets waiting for resources (IRPs, buffers) // to become available. Search for packets with the specified ID. KNdisPacketList CancelList; m_TxQueue.Lock(); // protect the loop PNDIS_PACKET p = m_TxQueue.HeadNoLock(); while (p) { PNDIS_PACKET thepacket = p; p = m_TxQueue.NextNoLock(p); if (NDIS_GET_PACKET_CANCEL_ID(thepacket)==CancelId) { m_TxQueue.RemoveNoLock(thepacket); CancelList.InsertTailNoLock(thepacket); } } m_TxQueue.Unlock(); // protect the loop // CancelList contains the packets (if any) with given ID. Abort them. while (!CancelList.IsEmpty()) { KNdisPacket p = CancelList.RemoveHead(); SendComplete(p, NDIS_STATUS_REQUEST_ABORTED); } }; #endif // NDIS51_MINIPORT //////////////////////////////////////////////////////////////////// // VNICAdapter::TranslateAddr // 将mac地址转化为对应的字符串 // Parameters: // char des[] -存储mac地址转化后对应的字符串 // UCHAR addr[] -待转化的mac地址 // Return Mode: // NULL // NOTE: // 通过队mac地址的每一字节移位实现转化 // void VNICAdapter::TranslateAddr(char des[], UCHAR addr[]) { USHORT a[12]; int i,j; for( i = j = 0; i < 6; i++) { a[j] = (addr >> 4) & 0xf; j++; a[j] = addr & 0xf; j++; } for( i = 0; i < 12; i++) { if(a >= 0 && a <= 9) { des = 48 + a; } else { des = 65 + a - 0xa; } } } //////////////////////////////////////////////////////////////////// // VNICAdapter::CreateMyDevice // 创建一个可以从 user mode 访问的I/O设备对象 // Parameters: // none // IRQL: // PASSIVE_LEVEL // Return: // STATUS_SUCCESS 如果设备创建成功 // Note: // 该方法调用的NdisMRegisterDevice()不适用于win98 NDIS_STATUS VNICAdapter::CreateMyDevice() { NDIS_STATUS Status; #if VNIC_WIN2K //WIN2K, XP系统下 static PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1]; //初始化MajorFuction NdisZeroMemory(MajorFunction, sizeof(MajorFunction)); //指定irp处理例程 MajorFunction[IRP_MJ_CREATE] = MajorFunction[IRP_MJ_CLOSE] = MajorFunction[IRP_MJ_CLEANUP] = MajorFunction[IRP_MJ_READ] = MajorFunction[IRP_MJ_WRITE] = MajorFunction[IRP_MJ_DEVICE_CONTROL] = IoDispatch; //注册设备 Status = NdisMRegisterDevice( *KNdisMiniDriver::DriverInstance(), KNDIS_STRING_CONST("\\Device\\VNICDevice"), KNDIS_STRING_CONST("\\DosDevices\\VNICDevice"), MajorFunction, &m_pDeviceObject, &m_DeviceHandle); #else //win98环境 static PDRIVER_OBJECT pDriverObject = KNdisMiniDriver::DriverInstance()->DriverObject(); //指定irp处理例程 pDriverObject->MajorFunction[IRP_MJ_CREATE] = pDriverObject->MajorFunction[IRP_MJ_CLOSE] = pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = pDriverObject->MajorFunction[IRP_MJ_READ] = pDriverObject->MajorFunction[IRP_MJ_WRITE] = pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IoDispatch; //注册设备 Status = IOCreatDevice( pDriverObject, 0, KNDIS_STRING_CONST("\\Device\\VNICDevice"), FILE_DEVICE_NETWORK, 0, FALSE, &m_pDeviceObject); if(STATUS_SUCCESS == Status) m_pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; #endif return Status; } //////////////////////////////////////////////////////////////////// // VNICAdapter::IoDispatch // 处理对该驱动的IRP请求. // 静态方法. // Parameters: // DeviceObject - 一个指向设备对象的指针 // Irp - 一个指向IRP请求的指针 // IRQL: // PASSIVE_LEVEL // Return: // STATUS NTSTATUS VNICAdapter::IoDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS Status = STATUS_SUCCESS; //将IRP指针转化为KIrp类 KIrp I(Irp); //显示调试信息 TRACE("VNICAdapter::IoDispatch func 0x%02x \n", I.MajorFunction()); switch (I.MajorFunction()) { case IRP_MJ_CREATE: // TODO:获取应用程序文件指针 if(pFile == 0) { //没有应用程序打开设备的情况 pFile = I.FileObject(); } else { Status = STATUS_UNSUCCESSFUL; } I.Information() = 0; break; case IRP_MJ_CLOSE: // TODO: 删除应用程序文件指针 I.Information() = 0; if(pFile == I.FileObject()) { pFile = 0; } else { Status = STATUS_UNSUCCESSFUL; } //清楚notify标记 notify = false; //if(pEvent != NULL) //{ // delete pEvent; //} break; case IRP_MJ_CLEANUP: // TODO: break; case IRP_MJ_READ: // TODO break; case IRP_MJ_WRITE: // TODO break; case IRP_MJ_DEVICE_CONTROL: // TODO: 处理用户自定义的I/O控制命令 try { switch(I.IoctlCode()) { I.Information() = 0; case VNIC_IOCTL_SETEVENT: //TODO: 设置事件 { //获取应用程序设置的句柄 HANDLE hEvent = *(HANDLE*)I.IoctlBuffer(); if(pEvent) { delete pEvent; } //构造系统事件函数 pEvent = new (NonPagedPool)KEvent(hEvent, OBJECT_TYPE_ALL_ACCESS); notify = true; break; } case VNIC_IOCTL_ENABLE_NOTIY: //TODO: 将notify设为true notify = true; break; case VNIC_IOCTL_GETMAC: //TODO: 获取网卡的mac地址 { PUCHAR out = (PUCHAR)I.IoctlBuffer(); for(UINT i = 0; i <= 5; i++) { out = mac; } I.Information() = 6; break; } case VNIC_IOCTL_READFRAME: //TODO: 读取帧 { PUCHAR out = (PUCHAR)I.IoctlBuffer(); //向服务程序输出发送的帧 for(UINT i = 0; i < packetSize; i++) { out = sndData; } I.Information() = packetSize; // //if(pAdapter != NULL) //{ // pAdapter->SendComplete(pPacket); //} notify = true; break; } case VNIC_IOCTL_WRITEFRAME: //TODO: 写帧 { PUCHAR in = (PUCHAR)I.IoctlBuffer(); //指定堆栈为当前堆栈 EStackLocation s = CURRENT; //获取输入缓冲区的长度 UINT size = I.IoctlInputBufferSize(s); for(UINT i = 0; i< size; i++) { recData = in; } //产生一个收包信号 if(pAdapter != NULL) { //pAdapter是指向当前Adapter的指针 NdisMEthIndicateReceive(*pAdapter, *pAdapter, (PCHAR)recData, ETHE_HEADER_LEN, (PCHAR)recData + ETHE_HEADER_LEN, size - ETHE_HEADER_LEN, size - ETHE_HEADER_LEN); NdisMEthIndicateReceiveComplete(*pAdapter); } else { TRACE("receive packet failed!"); } } break; default: Status = STATUS_INVALID_PARAMETER; break; } } catch(...) { TRACE("Caught Default Exception"); //释放Event指针 if(pEvent) { delete pEvent; } } break; default: Status = STATUS_UNSUCCESSFUL; }; return I.Complete(Status); } // end of file |
|
最新喜欢:wingma... |
沙发#
发布于:2005-07-23 22:13
主要是在send 和 IoDispatch两个函数里
这几天问了好多问题都还没解决,还不如直接把代码贴出来 大家多帮忙看看有什么问题啊! 很奇怪啊 为什么“[ i ]” 之类的贴上来候都没了呢 大家看到怪怪的地方可能变量名后面还有个"[ i ]" |
|