对一个虚拟网卡驱动程序的剖析(三):网卡的初始化函数MiniportInitialize

来源:互联网 发布:胎教音乐 知乎 编辑:程序博客网 时间:2024/05/08 22:33

 前面的驱动程序入口函数DriverEntry的作用是向系统说明这个驱动程序的结构。初始化函数则是为了使我们的网卡能够正常工作而进行各种准备工作。

    系统在调用网卡的初始化函数的时候,会传进来一个输入参数MediumArray,这是一个包含一系列介质类型的数组,初始化函数要在这个数组中间选一种类型返回给系统,告诉系统该驱动支持的类型。做法就是将系统传进来的一个输出参数SelectedMediumIndex指向的地方赋上选择的类型在数组中的索引值。我们的虚拟网卡选择的是NdisMedium802_3,也就是告诉系统,我们的网卡是一块标准的以太网网卡。

    接下来要做的也是最重要的准备工作就是想办法使一些公共信息能够在驱动程序的各个部分进行传递。通常使用的方法是定义一个结构,把驱动程序各个部分要用的信息都包含进去,驱动程序的各个部分根据这个结构的指针获取自己需要的信息。我们的这个虚拟网卡的驱动也定义了一个这样一个结构,D100_ADAPTER。

    NdisAllocateMemoryWithTag(&Adapter,sizeof(D100_ADAPTER),'0000');

    上面的系统的Ndis库函数,它负责分配内存,注意要检查它返回的状态,如果不成功的话,整个初始化函数也应该向系统返回对应的失败状态。然后将MiniportAdapterHandle,这是另外一个输入参数保存起来。日后调用很多Ndis库函数的时候都要提供这个Handle,以便让系统了解是哪个网卡要调用这些库函数。

    接下来可以调用NdisOpenConfiguration函数打开注册表读取一些配置。系统允许每块网卡在注册表中的指定位置保留一些配置信息,每次初始化的时候可以去读取,也可以在需要的时候进行改变。当然,目前我们的虚拟网卡并没有什么信息需要保存在注册表。

    下面应该对这个结构中的其它成员进行初始化,例如,如果用到同步互斥锁NDIS_SPIN_LOCK的话,要调用NdisAllocateSpinLock进行初始化,用到同步事件KEVENT也要调用KeInitializeEvent对其进行初始化。在我们的网卡中,为了使接收和发送的数据包的申请更加方便,预先申请了一个发送数据包的PacketPool和BufferPool,以及接收数据包的相应类型缓冲池。这样以后要申请一个数据包描述对象(NDIS_PACKET)或者缓存区描述对象(NDIS_BUFFER)的时候就可以在上面这个缓存池中申请了。

    最后,我们使用了NdisMRegisterDevice向系统注册了一个支持各种Dispatch函数的设备对象,这样是为了使虚拟网卡能和用户态的代理(Agent)程序进行直接地通讯。例如,用户态的程序可以将我们注册的符号链接名放到CreateFile函数中去直接打开设备句柄,可以用ReadFile或者WriteFile这样的接口对设备进行读写,可以用DeviceIoControl对设备进行一些操纵。这些都是要以驱动程序中实现相应的Dispatch函数为基础的。

    如果一切顺利的话,下面这条语句一定是出现在这个函数的最后的:

    return NDIS_STATUS_SUCCESS;