精华内容
下载资源
问答
  • Windows 7 万能驱动下载 免费

    千次阅读 2018-11-06 13:48:41
    链接:https://pan.baidu.com/s/1MH2xDDscjavhKmlsMbvAxA  提取码:u2an  复制这段内容后打开百度网盘手机App,操作更方便哦

    链接:https://pan.baidu.com/s/1MH2xDDscjavhKmlsMbvAxA 
    提取码:u2an 
    复制这段内容后打开百度网盘手机App,操作更方便哦

    展开全文
  • Windows 万能网卡驱动

    热门讨论 2011-11-21 09:16:20
    Windows 2000、2003、2008、xp、win7、vista万能网卡驱动
  • Windows驱动开发如何入门

    万次阅读 多人点赞 2016-03-16 14:55:36
    有的人觉得Windows驱动开发就是把开发WDK下载下来,然后只要掌握了C/C++语言,接下来无非就是类库调来调去,像调用MFC、QT之类的库那样,看着书和MSDN上的文档来就行了。等真正接触以后才发现根本不是那么一回事,...
    搞Windows驱动开发是一件痛苦的事情,特别是初学Windows驱动开发。有的人觉得Windows驱动开发就是把开发包WDK下载下来,然后只要掌握了C/C++语言,接下来无非就是类库调来调去,像调用MFC、QT之类的库那样,看着书和MSDN上的文档来就行了。等真正接触以后才发现根本不是那么一回事,痛苦源于以下几点:
    

    痛苦一:中文资料太少
    讲Windows驱动开发的,无论是中文书籍还是网上的中文资料,都很少,手把手从零到精通的更是不用说了。仅有的少量中文资料,有的还比较旧,讲的是DDK、NT式驱动,新手拿着WDK8.1、WDK10面对Win8、Win10系统很难跟着学习,而且现在的WDK,在WDM上又出现了了WDF,而WDF又分KMDF(内核模式驱动)和UMDF(用户模式驱动),对于UMDF(用户模式驱动)中文资料就更少了。而且驱动开发不像应用开发,需要先对操作系统原理有一定了解,不然遇到“I/O管理器”、“输入输出请求包”、“软件中断”、“符号链接”、”派遣函数“等名词和概念都不知所云,是寸步难行的。

    解决方法:
    ①其实MSDN上已经提供了大量的文档和示例程序,对KMDF、UMDF等进行了详细的讲解,甚至还提供了手把手教你来的视频教程,可惜它们都是英文的,对于我等英语不好的程序员来说真是坐车不买票——白搭。最近越来越觉得英语不好是阻碍一个程序员进步最大的绊脚石,我们不谈什么算法,不谈什么数学功底了,首先要成为一个合格的码农,需要熟练使用各种编程语言和对应的各种工具库,而大部分的库都只有英文文档,不能流畅阅读这些文档的话,寸步难行。在成为了合格的码农,能熟练使用各种现成的工具库搭积木般的开发出应用程序后,才能去谈各种算法,各种数学知识的代入,才能去谈如何从一个码农升级为软件工程师。显然,当前摆在我面前最迫切的问题是如何成为一个合格的码农,先养活自己,再去考虑如何为社会主义做贡献,如何推动人类科技进步。学习英语确实应该赶快提上日程并立即执行、坚持执行了。英语好的人真的是把WDK拿来就像用MFC那样轻松,看着文档和示例程序,那些个API调来调去,一个完整的驱动程序就出来了。这不是吹牛,我之前在一家公司工作的时候,公司有个项目的一个模块需要在Ring0上实现,需要编写Windows内核驱动,然而公司里没有一个人会,于是老大将这个模块交给了他的一个朋友去做。他的这个朋友是中国人,在美国微软总部工作,英语水平怎么样就不用说了,总之人家以前从来没搞过驱动开发,看了文档和示例代码后,利用3天的业余时间就完成了这个模块,拿到了15K RMB的报酬,着实让人佩服,让人羡慕。真的,学好英语,不说“听说写”,只要能流畅阅读各种英文技术资料,完全是另一个世界,学什么、做什么都得心应手。
    MSDN上的驱动开发资料入口:https://msdn.microsoft.com/zh-cn/windows/hardware
    MSDN上手把手教你来的视频教程:https://msdn.microsoft.com/zh-cn/windows/hardware/gg454522

    ②抓住仅有的几本中文书籍,细细研读。关于Windows驱动开发的中文书籍大概有那么几本:
    Windows驱动开发技术详解》(强烈推荐先看这本)
    WindowsWDM设备驱动程序开发指南》(比较老了,2000年出版的,以win98、win2000为目标系统)
    Windows设备驱动程序WDF开发》(为数不多讲WDF的)
    《Windows 7设备驱动程序开发》(为数不多讲WDF的,且比较新,这本书的英文版是2010年出版的,中文译版是2012年出版的)
    《竹林蹊径:深入浅出windows驱动开发》
    《寒江独钓:Windows内核安全编程》
    《天书夜读:从汇编语言到Windows内核编程》
    《Windows内核安全与驱动开发》(是《天书夜读》和《寒江独钓》的合订本以及升级版)
    后面的这四本其实不太适合作为入门书籍,而适合作为进阶书籍,对一些基础的概念和原理的讲解没有《Windows驱动开发技术详解》那么多

    痛苦二:开发工具链不好用
    对于我等刚学编程时用的就是VisualStudio以及各种智能提示智能感知的插件,甚至还有代码生成器的辅助的程序员来说,习惯了VisualStudio傻瓜化的一切,代码可以自动生成,窗体应用程序可以拖控件,甚至连网页都能拖控件。很难接受只有文本编辑器和命令行工具的开发环境,很多时候连代码编辑器不能智能提示都无法忍受,更不说手动调用cl.exe link.exe,写起代码来就像有一万只蚂蚁在身上爬。
    在之前很长的一段时间里,VC6.0和VisualStudio里是没有创建驱动项目的选项的,更没有直接由IDE生成的HelloWorld,如果不想手动cl.exe link.exe,如果想在IDE中写代码,需要自己建一个空项目,然后手动配置编译器指令、链接器指令、包含目录、库目录等等,然后把书上的HelloWorld复制过来,然后可能还会遇到各种问题。生成好驱动程序文件后,还要手动拷贝到虚拟机中,借助工具或inf文件手动安装,然后要改系统配置,进入内核调试模式,然后要设置调试接口,比如使用COM串口调试的话要在虚拟机上设置,把COM串口映射到主机的命名管道,然后还不能在VC中调试,只能用Windbg来调试。总之每修改一下代码,需要手工进行很多步骤才能开始调试,非常麻烦。而且即便照着网上或书上的步骤来配置,在不同的环境下也会遇到各种奇怪的问题,搞起来颇为头疼。

    解决方法:
    ①有个名为VisualDDK的第三方软件,使得这个事情方便了很多。VisualDDK装好后会给VisualStudio安装一个插件,使得在VisualStudio中可以通过这个插件新建驱动项目,并且自带HelloWorld,然后把VisualDDK Monitor装到虚拟机中,两边配置一下,接下来只要在VisualStudio这边生成驱动文件,VisualDDK会自动传给虚拟机中的系统进行安装,并且可以直接在VisualStudio中下断点调试了。不过这个软件在安装和配置过程中,也需要不少步骤,有时候也会出现一些配置不对的问题,偶尔也略感头疼,且稳定性和兼容性不是非常好。此方式适用于VisualStudio2010及以下版本,WDK7.1及以下版本。对于更高的版本,不建议用VisualDDK,因为可以继续往下看,下面有更激动人心的办法。
    VS2010+VMWare8+VisualDDK1.5.6配置教程:http://techird.blog.163.com/blog/static/1215640362011112385241568/

    ②激动人心的就是,从VisualStudio2012开始,从WDK8.0开始,微软在里面整合了一套类似VisualDDK但比VisualDDK好用很多的工具。从那以后,开发Windows驱动程序就和开发Windows应用程序一样方便了,只需在虚拟机中安装一个EXE,然后在VisualStudio中输入它的IP、用户名、密码就OK了,接下来你只需新建一个WDK项目,点生成,VisualStudio会自动把驱动文件传给虚拟机中的系统并自动安装,然后点调试,就能在VisualStudio中单步调试了。是不是爽爆了,而且配置和设置都不复杂,MSDN上还有手把手教你配置的高清视频教程!
    具体可以看我写的另一篇文章:
    Win8.1+VS2013+WDK8.1+VirtualBox or VMware驱动开发环境配置》:http://blog.csdn.net/charlessimonyi/article/details/50904956

    痛苦三:没有库可用
    假如有一天老板叫你开发一个软件,允许你使用你擅长的任意一门语言,C/C++/C#/JAVA/Python等。但是附加了一个条件:不能使用任何第三方库,不能使用标准库!你有什么感想。What!标准库都不能用?那还写个毛。是的,没错,开发Windows驱动程序,几乎什么库都用不了,包括标准库。因为我们平时常用的第三方库或标准库,它的实现其实都是调用系统API,在Windows上调用的是Window API,即uer32.dll、kernel32.dll、gdi32.dll等等提供的API函数。但是这些API函数属于应用层API,无法在驱动程序中使用,因为驱动程序跑在内核层。所以只要一个库的实现上调用了系统API,就无法在驱动程序中使用。少数库还是可以使用的,比如math.h中的各种数值计算函数。不过仅剩的可用的库太少了,很多时候你都需要从新发明轮子。甚至连C语言中的malloc、free,C++中的new、delete,你都需要自己去实现。

    解决方法:
    ①自己发明轮子就自己发明轮子,虽然没有现成库可用,但有内核层下的系统API可用,很多和应用层的API很相似,你想要的功能基本都可以通过这些API实现。

    ②咬咬牙,把苦水往肚子里咽。搞驱动开发的人很少,苦尽甘(qian)来


    本文由CharlesSimonyi发表于CSDN博客:http://blog.csdn.net/charlessimonyi/article/details/50904854转载请注明出处

    展开全文
  • windows虚拟网卡驱动开发

    千次阅读 热门讨论 2017-04-06 19:05:24
    by fanxiushu 2017-04-06 转载或...很早前的文章介绍过windows和linux平台的虚拟网卡技术, 详见 http://blog.csdn.net/fanxiushu/article/details/8526708 http://blog.csdn.net/fanxiushu/article/details/8526
     
                                                                                                                              by fanxiushu   2017-04-06 转载或引用请注明原始作者。

    很早前的文章介绍过windows和linux平台的虚拟网卡技术,
    详见
         http://blog.csdn.net/fanxiushu/article/details/8526708
         http://blog.csdn.net/fanxiushu/article/details/8526719
         http://blog.csdn.net/fanxiushu/article/details/8525749
         http://blog.csdn.net/fanxiushu/article/details/8507638
    前两个是讲述如何组成一个虚拟局域网,后边的是如何在linux平台下开发一个虚拟网卡
    (当时提供的代码比较老,需要修改才能在新版本linux下使用,
    或者懒得自己开发,直接使用linux自带的tun驱动,linux底层这些驱动总比windows平台方便得多)。
    这些文章介绍过如何利用虚拟网卡组建局域网的原理:获取应用层程序发给虚拟网卡的数据包,
    然后通过真实的网络发给服务端, 服务端再转发给另外一台机器,这台机器再把从网络获取的数据包传递给虚拟网卡。
    通过这样的方式,就把处于不同真实网络环境中的机器连接到同一个虚拟局域网中。
    只是当时没介绍如何开发windows虚拟网卡驱动,这篇文章填补这个空白。

    win7系统有最新的NDIS6.2框架,win8 的NDIS提高到6.3以上,win10 达到ndis6.4 。
    最大变化是从NDIS5.x 到 NDIS6.x, 连最基本的包的定义等数据结构都发生了巨大变化。
    但是windows有个最大优点,就是兼容,在win7,win8,win10,等平台可以运行ndis5.x框架的驱动,
    (不过ndis5.x的中间驱动无法在win10上运行,这个估计是最大不方便了)
    就跟TDI驱动能在各种windows平台通吃一样,NDIS5.x也能通吃各种windows平台。
    这里采用 NDIS5.1框架,不是要抱着老的框架不放,而是许多用户抱着WinXP 不放,
    同时要兼容 WinXP和WIN7,而且也不用开发两套代码的最好选择就是NDIS5.1 了。
    如果你的程序只运行在WIN7系统以上,可以只使用NDIS6以上的版本的框架,
    NDIS6虽然基本结构尤其是包结构改变了,但是我们开发的总体方式差不多。

    首先在DriverEntry中声明 NDIS_MINIPORT_CHARACTERISTICS 变量,它是一个包含多个回调函数的数据结构,
    在此结构中填写好我们需要的各种回调函数之后,调用 NdisMRegisterMiniport 函数注册。

    NdisMRegisterMiniport虽然没开放源代码,但是基本工作流程应该能想到,因为虚拟网卡驱动也是即插即用驱动模型,
    因此在DriverEntry 函数中一样需要实现 AddDevice,以及各种派遣函数,
    只是 NdisMRegisterMiniport  使用它内部的某个函数 设置到AddDevice 回调中,同时设置各种IRP_MJ_XXX派遣函数,
    并且做一些其他初始化操作,当有设备(也就是网卡)插上来,DriverObject->DriverExtension->AddDevice 函数被调用,
    这时会进入到NdisMRegisterMiniport注册的 某个内部函数中,
    在这个函数中会调用 NDIS_MINIPORT_CHARACTERISTICS  导出的 InitializeHandler 函数,
    这样就进入到我们注册的网卡初始化函数。

    在虚拟网卡驱动中,主要实现以下几个回调函数,基本上就能完成一个虚拟网卡的功能:

      InitializeHandler , 初始化网卡。也就是当我们安装一块网卡实例驱动的时候,这个函数被调用,
                                      在这个函数中,初始化各种资源,这个函数等同于普通的即插即用驱动的AddDevice函数,
                                      只是被NDIS框架封装成 InitializeHandler 回调函数了。
     HaltHandler , 卸载网卡,当我们卸载某个网卡驱动时候,这个函数被调用,
                             相当于普通即插即用驱动程序收到 IRP_MN_REMOVE_DEVICE等消息之后触发的回调。

    QueryInformationHandler, 查询网卡 OID。其实就是查询网卡的各种信息,网卡包含的信息很多,基本上有几十个。
    SetInformationHandler,      设置网卡OID。 设置我们感兴趣的OID信息。
    ResetHandler, 是否重启网卡,虚拟网卡驱动中,基本用不上。
    CheckForHangHandler, 检测网卡是否处于hang状态,是的话,调用ResetHandler, 虚拟网卡基本上也用不着。

    SendPacketsHandler, 处理网络数据包的核心函数之一,这个回调函数表示网卡从应用层程序接收到以太网数据包,
                                          比如在应用层调用套接字函数send 或sendto发送数据,数据进入到内核的传输层,
                                          经过分析剥离,进入到NDIS协议驱动层,协议驱动层找到这个数据是朝哪个网卡发送的,
                                          于是找到这个网卡注册的  SendPacketsHandler 回调函数地址,
                                          最后调用这个回调函数实现数据包的真正发送。                             
                                          在SendPacketsHandler  函数中处理的数据包是准备发给底层的物理链路的,
                                          虚拟网卡没有物理链路,因此我们把这些数据包入队,
                                          然后直接在驱动层通过WSK(TDI)方式(或者其他各种方式,如USB, 串口等)发给远端设备或电脑,
                                          或者把数据包传递到应用层, 让我们的应用层程序做各种处理,为了开发的方便和简洁,
                                          我们采用的是传递到应用层来处理。

    ReturnPacketHandler, 这个函数与上边的刚好相反,当物理链路有数据包到达(或者通过其他方式有数据包,如USB等),
                                          调用NDIS函数NdisMIndicateReceivePacket,通知上层有个数据包达到,
                                          等上层(这个上层就是处理TCP/IP等各种协议的协议层)处理完这个数据包之后,
                                          ReturnPacketHandler 就被调用。
                                          接着这个数据被上传到传输层进一步分析处理,
                                          再进入到应用层,这时候调用 recv或者recvfrom等套接字函数的程序就接收到了数据。
                                          我们的虚拟网卡驱动在应用层程序通过某个IOCTL控制命令传递一个数据包到驱动,
                                          在驱动中直接调用NdisMIndicateReceivePacket通知上层有数据包到达。

    CancelSendPacketsHandler, 这个是NDIS5.1框架中,提供的取消某些数据包发送的回调函数,也就是上层调用SendPacketsHandler,
                                         发送数据包,但是我们的驱动还没来得及处理,只是入队等待处理,这个时候上层决定取消某些数据包的发送,
                                         于是调用 CancelSendPacketsHandler 让我们取消某些数据包的发送。
    PnPEventNotifyHandler, NDIS5.1框架的PnP通知事件,其实就是对应普通的即插即用驱动中的IRP_MJ_PNP请求的封装。
    AdapterShutdownHandler, NDIS5.1框架的网卡关闭事件。

    因为我们的虚拟网卡驱动是把数据包传递到应用层来处理,也就是应用层相当于是“物理连线”,
    必须创建一个控制设备才能跟应用层交换数据,NDIS5.1框架提供了NdisMRegisterDevice 函数来创建一个控制设备,
    在 InitializeHandler 网卡实例初始化函数中可以调用这个函数创建控制设备,
    在 HaltHandler 网卡卸载函数中可以调用NdisMDeregisterDevice删除这个设备。
    创建这个控制设备时候,传递一些参数,包括派遣函数,我们感兴趣的主要是IRP_MJ_DEVICE_CONTROL,以及CREATE /CLOSE 。
    可以定义两个IOCTL命令,一个用于数据包读取,一个用于向驱动写数据包,比如命名为 READ IOCTL 和WRITE IOCTL。
    网卡处理的数据包是非常多的,
    以100M以太网来计算,以太网数据包大小 1514,当全速传输时候, 100M*1024*1024/8/1514 =  大约 8千多个数据包, 
    全速传输,每秒传输8千多个数据包甚至更多, 这个量是很大的,千兆网达到8万多个包每秒,甚至更多。
    为了尽量提高IO吞吐率,在应用层可以采用完成端口方式接收数据包,下边会讲到。
    (开发虚拟网卡驱动相对而言不算太难,难得是如何调优,让他的IO性能提升到更好的效果)

    如此之多的数据包要在应用层和驱动层进行交换,驱动里边该采用什么结构来处理,才能尽可能的提高IO效率呢?
    这里顺带提一下我测试IO效率的方式,
    一个服务端程序,负责多个虚拟网卡数据包转发,它让多个虚拟网卡组成一个虚拟局域网,
    虚拟网卡的客户端程序采用TCP连接到服务端,转发的虚拟网卡数据包也是通过TCP方式转发。
    服务端程序放到一台性能还可以的WIN7的机器上(四代 i7 的 8核CPU,16G内存),
    它的千兆网卡接到千兆交换机上,完全保证它达到千兆网卡的速度。
    一台装有XP系统的古老机器,以前的ATOM的CPU,1G内存,它的网卡接到百兆交换机上。
    一台装WIN10系统的古老CPU是Core2的机器,2G内存,它的网卡接到百兆交换机上。
    测试以TCP传输为主,UDP基本不考虑,
    测试时候使用FTP,HTTP,windows文件夹共享三种方式上传或者下载一个超过1G大小的大文件。
    在100M网络环境下,以上的测试,XP和WIN10之间通过虚拟网络传输文件,
    基本达到5M-6MB的速度,也就是达到50-%60%的真实网卡利用率,
    也许使用更好的机器效果会更高,在装服务端程序的机器上也装上虚拟网卡,让他与WIN10传输文件,
    这个速度就比较高了,维持在7-11M的速度,基本上达到 70-95%的真实网卡利用率,峰值时候基本能达到饱和。
    这种测试还跟客户端服务端程序,机器配置等多种因素有关,因此不能保证换个环境就一定准确。
    整体来看,WIN7以上的系统性能的表现比WINXP系统好,这应该是WIN7上的内核,微软把整个网络层重构了一遍,跟WINXP完全不同。

    我是基于以上测试来评定开发的虚拟网卡的IO性能。
    为此想了许多办法,也做了多种尝试,往往写好了一种方式的代码发现效果不太理想,之后想到另外一种处理方式可能会更好,
    因此废弃先前的代码,重新再实现新想到的处理方式,来来回回的折腾了多种处理方式,采用了如下的处理结构:
    (不过任然是采用单帧接收和发送的方式)
    数据包传递以IRP 请求为主,一个IRP传递一个数据包。也就是上边所说的定义两个IOCTL命令,read ioctl和write ioctl,
    每次都发送和接收一个数据包,都会产生一个IOCTL调用。

    以read ioctl为例,
    应用层投递read ioctl请求到驱动,这个请求的 Irp 都被驱动挂载到某个 IRP队列 比如 tx_irps_head,
    上层数据包发到虚拟网卡驱动 ,也就是 SendPacketsHandler 函数被调用时候,
    把这些数据包挂载到 某个Packet队列,比如 tx_pkts_head 。
    两者每次处理完后,都调用 KeInsertQueueDpc触发DPC调用 ,在DPC执行函数中,检查两个队列是否都不为空,
    都不为空的话,分别取出一个IRP和一个Packet,把Packet数据copy到IRP,完成这个IRP和Packet,如此循环,直到某个队列为空。

    可能有人会问,这里为何要多次一举使用DPC调用,而不是直接执行这种检查处理!?
    一般是在硬件的中断函数中,为了尽快让出中断函数,让稍微耗时的处理交给次一级的函数处理,
    但是也是要求尽快处理完成而不被其他软中断打断,DPC就处于这种地位。
    对软件来说,是很高的运行级别,在DISPACH_LEVEL,运行的时候是不会被调度到其他CPU或者被软中断打断的运行级别。
    对于网络数据包的处理就是需要在这种DPC环境中运行,才能让他达到更好的IO效率。

     大致伪代码如下,
    在IRP_MJ_DEVICE_CONTROL请求中,响应 IOCTL_NCARD_READ_DATA(也就是read IOCTL宏)

    case IOCTL_NCARD_READ_DATA:
             // PENDING
             status = STATUS_PENDING;
             IoMarkIrpPending(Irp);

              InitializeListHead(&Irp->Tail.Overlay.ListEntry);
              Irp->Tail.Overlay.DriverContext[0] = a;
               IoSetCancelRoutine(Irp, ioctl_cacnel_routine); ///
             if (Irp->Cancel) {
                if (IoSetCancelRoutine(Irp, NULL) != NULL) { //取消例程还没被执行,自己取消
                   status = STATUS_CANCELLED;
                   complete_irp(Irp, status, 0);
                }
               
             }
            else {
                ///加入到队列 , 等待 上层有数据包发送 SendPacketsHandler 被调用,再从 tx_irps_head队列取出IRP进行处理。  
                NdisInterlockedInsertTailList(&a->tx_irps_head, &Irp->Tail.Overlay.ListEntry, &a->tx_spinlock);
            }
           
            // 触发DPC调用,这里采用DPC。
            KeInsertQueueDpc(&(a)->tx_dpc, NULL, NULL); /
           .......
         上边的DPC的初始化操作,
            KeInitializeDpc(&a->tx_dpc, adapter_complete_send_packets_dpc, a);
     
          在 adapter_complete_send_packets_dpc 这个DPC执行函数中完成类似如下的操作:
       
    ///--------------------------------------------------------------------------------------------------
        adapter_t* a = (adapter_t*)context;
        adapter_inc(a);
        PLIST_ENTRY entry;
       
        while (TRUE) {
           
            tx_lock(a);

            if (IsListEmpty(&a->tx_irps_head) || IsListEmpty(&a->tx_pkts_head)) {
                tx_unlock(a);
                break;
            }
            entry = RemoveHeadList(&a->tx_irps_head);
            PIRP Irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry );

            if (IoSetCancelRoutine(Irp, NULL) == NULL) { /// 应该检查返回值,若为空,说明取消例程已经被调用了
                NdisInitializeListHead(&Irp->Tail.Overlay.ListEntry); //初始化,防止在取消例程出问题
                tx_unlock(a);
                continue;
            }
           
            entry = RemoveHeadList(&a->tx_pkts_head);
            PNDIS_PACKET packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReserved);

            tx_unlock(a);
            /
            NTSTATUS status = adapter_send_packet_to_irp(a, packet, Irp); 复制 Packet 数据到 Irp

            ///
        }

        adapter_dec(a);
         /------------------------------------------------------------------------------------------------------------

        在网卡 SendPacketsHandler 函数中做类似如下处理:
         
            for (index = 0; index < NumberOfPackets; ++index) {
                  PNDIS_PACKET packet = PacketArray[index];  ///
                 
                  status = NDIS_STATUS_PENDING;
                  NDIS_SET_PACKET_STATUS(packet, status);

                   tx_inc(a);  //增加send包计数
                   NdisInterlockedInsertTailList(&a->tx_pkts_head, (PLIST_ENTRY)packet->MiniportReserved, &a->tx_spinlock); ///挂载到队列

                  ///
             }
             .........
            触发 DPC调用        
            KeInsertQueueDpc(&(a)->tx_dpc, NULL, NULL);
            -------.........................................................

         如上就完成一个数据包的交换。
         write ioctl也做类似的处理。

         回到应用层来,在应用层,一般做法都是阻塞调用 DeviceIoControl ,这样没什么问题。
         但是可以这样考虑,我们在调用DeviceIoControl返回后,处理数据包,然后再接着调用DeviceIoControl,
         在再次调用DeviceIocontrol之前这中间有空隙,如果一次多投递读请求,这样数据包一来就被接收,中间就不存在空隙了。
         最容易想到的就是多线程调用 DeviceIoControl ,但是这种密集型的IO,多线程反而会降低效率,
         而且多线程还容易造成接收到的数据包乱序,这对TCP这种君子协议来说不是好事。
         在一个线程里,同时投递多个请求,异步方式处理,这才是解决这个问题的办法。
         完成端口就可以完成这件事,
         大家所熟悉的完成端口,多用到网络编程上,其实网络套接字只是它的一个应用而已,
         凡是具备异步读写的OVERLAPPED重叠请求的,都可以关联到完成端口。
         这里也就不具体描述如何使用完成端口来异步投递read ioctl请求了,因为相信大家已经很熟悉。
        
         以上开发的虚拟网卡测试的都是在100M网络环境下进行的,但是在千兆网络环境下的测试是很糟糕的。
         我按照上边的环境测试,1000Mbps 的环境下,最快只能达到 20 MBytes 每秒的速度,也就是相当于 千兆网的 五分之一的速度。
         这个测试数据非常让人气馁。
        
         归根结底还是因为每个数据包长度不超过 1514,千兆网每秒需要处理 8多万甚至更多数据包,这么多数据包,
         按照每个包的取,而且取出来之后,再把每个包在应用层封装一下再发到服务端,再服务端再转发出去,
         达到对方虚拟网卡,再传递到网卡驱动层接收,再等待ACK回应,
         这中间的延时比真正的物理硬件环境要高得多了,
         解决这个问题也不是没办法,既然包太多了,那就减少包数量。如果在纯粹的虚拟网络中,可以设置虚拟网卡的MTU值,
         让他更大,比如设置4M这么大的MTU值,这样每个包就可以达到 4M,传递的包个数大大减少,这种情况下疯狂传输文件的话,
         立马就能把千兆网络跑满。
         但是如果把虚拟网卡和真实的网卡混合桥接,1514的包大小的限制是无法改变的,任然要面对大量的包造成的效率问题。
         
          在写这篇文章时候,想到另外一个把数据包传递到应用层的办法,不采用IRP传递。
          就是在应用层开辟一块很大的内存,比如2M的内存,这块内存映射到驱动,这个内存块按照 1514 拆分成起码1000多个小块。
          这些小块组成循环队列, 驱动不停的朝这个循环队列写数据包,应用层不停的从这个循环队列读数据包。
          这样就减少IRP调用的开销,应该能提高效率,但在千兆网环境中能否得到质的提升,因为没实现,所以不能下定论。
          不过即使提升了驱动和应用层的IO效率,但是应用层还得发数据包到网络去转发,这个无论如何也得不到实质的提升。
          总体下来估计不会有质的提升。
         
                                                                                                                                 范秀树 2017-04-06  晚
     

    展开全文
  • 但是windows操作系统不像Linux操作系统,它的代码不开源,导致这方面的资料很少,因此也找寻了很长时间,最终找到了两款开源项目的虚拟接口驱动: Wireguard项目的Wintun接口 openVPN的Tap接口 ...

    前一段时间,一直在找寻windows操作系统上的虚拟网卡接口,主要是为了搭建隧道使用。但是windows操作系统不像Linux操作系统,它的代码不开源,导致这方面的资料很少,因此花费了较长时间来寻找相关实现框架,最终找到了两款开源项目的虚拟接口驱动:

    这两个项目都是非常出名的搭建隧道的开源V.P.N项目。由于目前对openVPN项目不太了解,也没有适配Tap接口,因此这里重点介绍下WinTun接口。此接口实现我是非常非常的喜欢,喜欢到简直不要不要的。

    1.简介

    说到Wintun项目,就不得不说到它的父亲:WireGuard项目(以下简称WG)。Github传送门

    WG项目作为开源V.P.N项目,不同于OpenVPN, Openswan, Strongswan等,它的实现非常简介,Linux内核代码实现不到4000行。相对于上述的三个“按行收费”的项目(代码10万行起步),它简直是太简洁了。故而得到了众多好评,其中就包括Linux鼻祖:Linus Torvalds。他的评价如下:

    Btw, on an unrelated issue: I see that Jason actually made the pull request to have wireguard included in the kernel.

    Can I just once again state my love for it and hope it gets merged soon? Maybe the code isn’t perfect, but I’ve skimmed it, and compared to the horrors that are OpenVPN and IPSec, it’s a work of art.

    Linus

     简而言之就是:劳资稀罕你,要把你合入我的Linux项目中。因此Linux内核自5.6之后便自带WG隧道功能,配置非常的简单。通过几行代码便可以完成一个WG隧道:

    ip link add dev wg0 type wireguard
    ip address add dev wg0 10.0.0.1/24
    wg set wg0 listen-port 51820 private-key ./private.key peer NIk5TyDpRDoU9tfIckTTXCsz1eht2aEmdN7l0Q31ow0= allowed-ips 10.0.0.2/32 endpoint 192.168.1.5:51820
    ip link set dev wg0 up

    官网上的配置如下:

    配置非常简单。除此之外,还提供了Windows客户端,这也是此项目为何包含Wintun虚拟网络接口的原因。

    客户端页面也是非常简洁,没有多余的东西(客户端链接):

    客户端上隧道协商成功之后,会根据隧道名称建立一个虚拟网卡,隧道拆除后接口自动删除。由于我的隧道名称为Tun-1,因此在“控制版面”的“网络连接”中出现了一个Tun-1的网络接口:

    好了,下面开始介绍此虚拟网络接口。

     

    2.WinTun虚拟网络接口

    Github传送门

    wintun官网传送门

    常见的windwos的接口驱动开发、安装比较复杂。常见的驱动安装包有:.inf文件、.sys文件、.cat文件; 除此之外还涉及驱动程序签名,否则无法安装成功。尤其在开发调试阶段,每次都得签名,太磨叽了。

    但是WinTun接口用法非常简单高效非常简单高效非常简单高效

    1. 引入头文件:wintun.h

    2. 加载动态库,解析动态库中的函数指针

    它通过动态库中方式来提供接口,我们可以加载此动态库,然后调用动态库中的函数指针来完成虚拟接口的创建、销毁、收发数据包等工作。此外它提供了一个示例供大家学习,我便是通过参考开源代码中的示例(example.c),将Wintun接口移植到我的工程之中。非常简单,我太喜欢它了

    实例代码就400行,其中大部分为log信息,供大家查看程序运行状态和报文收发信息。

    2.1加载动态库中的函数指针

    此函数的作用:

    • 加载动态库,获取到动态库中的函数指针,后面通过函数指针来操作虚拟网卡接口。
    static HMODULE
    InitializeWintun(void)
    {
        HMODULE Wintun =
            LoadLibraryExW(L"wintun.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
        if (!Wintun)
            return NULL;
    #define X(Name, Type) ((Name = (Type)GetProcAddress(Wintun, #Name)) == NULL)
        if (X(WintunCreateAdapter, WINTUN_CREATE_ADAPTER_FUNC) || X(WintunDeleteAdapter, WINTUN_DELETE_ADAPTER_FUNC) ||
            X(WintunDeletePoolDriver, WINTUN_DELETE_POOL_DRIVER_FUNC) || X(WintunEnumAdapters, WINTUN_ENUM_ADAPTERS_FUNC) ||
            X(WintunFreeAdapter, WINTUN_FREE_ADAPTER_FUNC) || X(WintunOpenAdapter, WINTUN_OPEN_ADAPTER_FUNC) ||
            X(WintunGetAdapterLUID, WINTUN_GET_ADAPTER_LUID_FUNC) ||
            X(WintunGetAdapterName, WINTUN_GET_ADAPTER_NAME_FUNC) ||
            X(WintunSetAdapterName, WINTUN_SET_ADAPTER_NAME_FUNC) ||
            X(WintunGetRunningDriverVersion, WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC) ||
            X(WintunSetLogger, WINTUN_SET_LOGGER_FUNC) || X(WintunStartSession, WINTUN_START_SESSION_FUNC) ||
            X(WintunEndSession, WINTUN_END_SESSION_FUNC) || X(WintunGetReadWaitEvent, WINTUN_GET_READ_WAIT_EVENT_FUNC) ||
            X(WintunReceivePacket, WINTUN_RECEIVE_PACKET_FUNC) ||
            X(WintunReleaseReceivePacket, WINTUN_RELEASE_RECEIVE_PACKET_FUNC) ||
            X(WintunAllocateSendPacket, WINTUN_ALLOCATE_SEND_PACKET_FUNC) || X(WintunSendPacket, WINTUN_SEND_PACKET_FUNC))
    #undef X
        {
            DWORD LastError = GetLastError();
            FreeLibrary(Wintun);
            SetLastError(LastError);
            return NULL;
        }
        return Wintun;
    }

    2.2 main()函数

    作用:

    • 通过函数指针创建虚拟网卡
    • 创建虚拟网卡的收发线程
    int
    main(void)
    {
        HMODULE Wintun = InitializeWintun();
        if (!Wintun)
            return LogError(L"Failed to initialize Wintun", GetLastError());
        WintunSetLogger(ConsoleLogger);
        Log(WINTUN_LOG_INFO, L"Wintun library loaded");
        WintunEnumAdapters(L"Example", PrintAdapter, 0);
    
        DWORD LastError;
        HaveQuit = FALSE;
        QuitEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
        if (!QuitEvent)
        {
            LastError = LogError(L"Failed to create event", GetLastError());
            goto cleanupWintun;
        }
        if (!SetConsoleCtrlHandler(CtrlHandler, TRUE))
        {
            LastError = LogError(L"Failed to set console handler", GetLastError());
            goto cleanupQuit;
        }
    
        GUID ExampleGuid = { 0xdeadbabe, 0xcafe, 0xbeef, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
        WINTUN_ADAPTER_HANDLE Adapter = WintunOpenAdapter(L"Example", L"Demo");
        if (!Adapter)
        {
            Adapter = WintunCreateAdapter(L"Example", L"Demo", &ExampleGuid, NULL);
            if (!Adapter)
            {
                LastError = GetLastError();
                LogError(L"Failed to create adapter", LastError);
                goto cleanupQuit;
            }
        }
    
        DWORD Version = WintunGetRunningDriverVersion();
        Log(WINTUN_LOG_INFO, L"Wintun v%u.%u loaded", (Version >> 16) & 0xff, (Version >> 0) & 0xff);
    
        MIB_UNICASTIPADDRESS_ROW AddressRow;
        InitializeUnicastIpAddressEntry(&AddressRow);
        WintunGetAdapterLUID(Adapter, &AddressRow.InterfaceLuid);
        AddressRow.Address.Ipv4.sin_family = AF_INET;
        AddressRow.Address.Ipv4.sin_addr.S_un.S_addr = htonl((10 << 24) | (6 << 16) | (7 << 8) | (7 << 0)); /* 10.6.7.7 */
        AddressRow.OnLinkPrefixLength = 24; /* This is a /24 network */
        LastError = CreateUnicastIpAddressEntry(&AddressRow);
        if (LastError != ERROR_SUCCESS && LastError != ERROR_OBJECT_ALREADY_EXISTS)
        {
            LogError(L"Failed to set IP address", LastError);
            goto cleanupAdapter;
        }
    
        WINTUN_SESSION_HANDLE Session = WintunStartSession(Adapter, 0x400000);
        if (!Session)
        {
            LastError = LogLastError(L"Failed to create adapter");
            goto cleanupAdapter;
        }
    
        Log(WINTUN_LOG_INFO, L"Launching threads and mangling packets...");
    
        HANDLE Workers[] = { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReceivePackets, (LPVOID)Session, 0, NULL),
                             CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendPackets, (LPVOID)Session, 0, NULL) };
        if (!Workers[0] || !Workers[1])
        {
            LastError = LogError(L"Failed to create threads", GetLastError());
            goto cleanupWorkers;
        }
        WaitForMultipleObjectsEx(_countof(Workers), Workers, TRUE, INFINITE, TRUE);
        LastError = ERROR_SUCCESS;
    
    cleanupWorkers:
        HaveQuit = TRUE;
        SetEvent(QuitEvent);
        for (size_t i = 0; i < _countof(Workers); ++i)
        {
            if (Workers[i])
            {
                WaitForSingleObject(Workers[i], INFINITE);
                CloseHandle(Workers[i]);
            }
        }
        WintunEndSession(Session);
    cleanupAdapter:
        WintunDeleteAdapter(Adapter, FALSE, NULL);
        WintunFreeAdapter(Adapter);
    cleanupQuit:
        SetConsoleCtrlHandler(CtrlHandler, FALSE);
        CloseHandle(QuitEvent);
    cleanupWintun:
        FreeLibrary(Wintun);
        return LastError;
    }

    收发报文的接口操作也非常简单,但是与windows网络协议栈之间的关系仍需要继续摸索。

     

    2.3 特别说明

    Wintun接口是严格意义上的3层逻辑接口。原文如下:

    Wintun is a very simple and minimal TUN driver for the Windows kernel, which provides userspace programs with a simple network adapter for reading and writing packets. It is akin to Linux's /dev/net/tun and BSD's /dev/tun. Originally designed for use in WireGuard, Wintun is meant to be generally useful for a wide variety of layer 3 networking protocols and experiments. The driver is open source, so anybody can inspect and build it. Due to Microsoft's driver signing requirements, we provide precompiled and signed versions that may be distributed with your software. The goal of the project is to be as simple as possible, opting to do things in the most pure and straight-forward way provided by NDIS.

     

     

    这里出现了一个小小的问题:Wireshark上无法抓取此接口报文。如果想看封装后的报文信息,则需要单独记录日志而非抓包来完成。

    导致这个问题原因没有找到,我认为是:wireshark抓取的报文是二层报文(一个完整的以太网帧),而3层逻辑接口上的报文尚未封装以太网帧,故无法抓取此接口。这只是个人猜测,根本原因不得而知。


    好了,基本介绍完毕,重新表达下我对WireGuard和WinTun的态度: 劳资稀罕你,very喜欢

     
     
     
     
    展开全文
  • 分享最新版的 INTELWIFI 驱动包

    千次阅读 2020-06-28 11:26:16
    分别测速了3次先分享最新版的INTELWIFI 驱动包:采用Appleintelwifi1.2.5内核驱动包!本方案主要配合NVRAM中配置实现自动连接wifi 零:安装前确认是否已经加载itlwm/kext,如果加载请自自行屏蔽。查看是否加载...
  • windows server2012 安装网卡驱动

    万次阅读 2019-05-30 16:03:30
    WIN SERVER 安装网卡驱动 背景 为了搭域控创建了一台winserver2012镜像,并建了对应虚拟云。然而开机后发现没有网络设置,虚拟云勾选了网关随机分配ip然而并没有用。镜像和虚拟云都是 原因 安装系统时匆忙,没有...
  • Windows 7

    千次阅读 2010-03-31 19:00:00
    系统简介 系统名称:Windows 7 核心版本号:Windows NT 6.1 开发代号:Blackcomb及Windows Vienna 测试历史: 2007年12月20日 :windows 7 Milestone1(build 6519.1) 2008年12月12日 :windows 7 beta...
  • 但是windows操作系统不像Linux操作系统,它的代码不开源,导致这方面的资料很少,因此花费了较长时间来寻找相关实现框架,最终找到了两款开源项目的虚拟接口驱动: Wireguard项目的Wintun接口 OpenVPN的Tap接口 这...
  • Windows CE USB摄像头驱动编写

    千次阅读 2008-11-25 22:19:00
    2外 ,好友 1 人,关注者 1 人。 moonlord的文章 原创 1 篇 翻译 1 篇 转载 0 篇 评论 0 篇 最近评论 文章分类 收藏 相册 存档 2008年07月(1) ...
  • Windows 7真的来了

    千次阅读 热门讨论 2009-10-27 20:36:00
    10月25日在武昌宏博里举行了一场Windows7的社区发布活动,这是本人从山西太原回到湖北武汉后参加的第一次.NET俱乐部活动,这次活动的主要嘉宾是来自微软的俞晖。由于本人是在任的MVP,拥有从MSDN下载正版的微软软件...
  • 转载:windows驱动开发入门

    千次阅读 2018-08-03 17:46:30
    有的人觉得Windows驱动开发就是把开发WDK下载下来,然后只要掌握了C/C++语言,接下来无非就是类库调来调去,像调用MFC、QT之类的库那样,看着书和MSDN上的文档来就行了。等真正接触以后才发现根本不是那么一回事,...
  • Oracle数据库的驱动包有许多版本,你到底知不知道他们的差别呢?   原文链接:http://tiantian0521.blog.163.com/blog/static/4172088320117294265766/   classes12.jar,ojdbc14.jar,ojdbc5.jar和...
  • Windows驱动开发书籍简介

    千次阅读 2013-11-19 11:31:52
    3.2 WINDOWS NT与WINDOWS 2000设备驱动及开发 WINDOWS NT与WINDOWS 2000设备驱动及开发出版社: 电子工业出版社 译作者: [美]Peter G.Viscarola等著 新智工作室译 国标编号: ISBN 7-5053-5953-3/TP.3118 出版日期...
  • 这些网卡其实并没有本质上的差别,只是在驱动层面,利用不同的驱动签名使得显卡不通用。本文将详细说明如何在Windows Server系统上安装这些驱动。 1、驱动下载 首先,在Intel官网下载网卡...
  • Windows7开机加速全攻略

    千次阅读 2010-10-24 10:24:00
    -------《Windows7开机加速全攻略》全文导航-------- Windows7开机加速全攻略一:序章 Windows7开机加速全攻略二:系统开机原理篇 Windows7开机加速全攻略三:开机设置优化 Windows7开机...
  • 在使用Oracle JDBC驱动时,有些问题你是不是通过替换不同版本的Oracle JDBC驱动来解决的?最常使用的ojdbc14.jar有多个版本,classes12.jar有多个版本你了解吗?   连接类型: 1、JDBC OCI: oci是or
  • 目录 简介 安装 配置 测试 ...在使用华为无线上网卡E3276(Broadband Router)的时候,需要在设备开机的时候自动启动上网程序,并开机自动联网。...但购买的很多个模块都不支持开机...驱动名称:Cyfrowy Polsa...
  • CentOS7安装、网卡驱动的实践

    万次阅读 2016-04-28 14:16:13
    系统装的是CentOS7,装完系统发现没网卡驱动,Linux小白折腾了很久,最终顺利装好,并实现网络连接。期间各种碰壁,故作此记录。 正文 1、系统安装前准备 1.1系统准备 因为CentOS-7.0-1406-x86_64-DVD.iso是3.86G...
  • Intel x710兆 SR-IOV 网卡驱动升级

    千次阅读 2020-06-06 13:10:56
    CentOS7 Intel x710 获取最新驱动 官方地址:https://downloadcenter.intel.com/zh-cn/product/83967/Intel-Ethernet-Converged-Network-Adapter-XL710-QDA2 安装 依赖: yum install kernel-devel -y yum ...
  • RAMOS windows7 制作教程,有图有真相 ...8G的内存不用太浪费了,于是闲来蛋疼琢磨起了RAMOS Windows7 ,百度之。。。 到处都是转来的RAMOS XP教程,看到题目我都知道下文是什么了。。顺便 强烈
  • 北京时间11月23日消息,据国外媒体报道,...诺西同时宣布,作为此次重组的结果,到2013年年底,约有1.7万员工将被辞退。截至2011年11月1日,诺西在全球的员工总数约为7.4万人。 诺西在声明中称,裁员将涉及全球各个
  • 公告: 新版博客频道个人首页及发布功能介绍[意见反馈][官方博客] Windows 7 + Visual 2010 + WDK 7600.16385.1 配置方法 收藏 1. 新建一个空DLL项目2. 增加一个主程序文件,如 entry.c3. 找到配置管理器,添加一个...
  • CISCO技术(1.7万)

    万次阅读 2011-08-09 10:51:57
    acoustic transducer|声转换器\r\n acoustical holography|声全息摄影\r\n ACP|Adjacent Channel Power 邻道功率 |\r\n acquisition|采集\r\n ACR|Average Cell Rate 平均信元率;Allowed Cell Rate...
  • Windows XP Embedded 入门

    千次阅读 2007-09-19 16:11:00
    可以通过过滤的方法找到一个组件或一组相关的组件,Windows XP Embedded开发内包含的大量组件可以通过过滤器方便地进行查找。 点击在组件浏览器上面的Filter按钮,创建一个新的过滤器 在Filter Manager...
  • Windows CE

    千次阅读 2012-07-09 16:26:18
    WindowsCE是微软公司嵌入式、移动计算平台的基础,它是一个开放的、可升级的32位嵌入式操作系统,是基于掌上型电脑类的电子设备操作系统,它是精简的Windows 95,Windows CE的图形用户界面相当出色。 目录 ...
  • Linux USB 摄像头驱动

    万次阅读 热门讨论 2017-12-10 11:33:59
          在 cortex-a8 中,可接入摄像头的接口通常可以分为两种, CAMERA 接口和 USB 接口的摄像头。这一章主要是介绍 USB 摄像头...这一章我们讲 USB 摄像头设备驱动,那么是不是支持所有的 USB 摄像头驱动...
  • Windows XP源码泄露

    千次阅读 2020-09-29 09:15:00
    来源 | 开源中国(ID:oschina2013)4chan 论坛的一名用户发帖称 Windows XP 源码已被泄露,并在帖子里面附上了一张正在解压 Windows NT 内核源码的截...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 18,763
精华内容 7,505
关键字:

windows7万能驱动包