NDIS驱动分析


链 接: http://bbs.pediy.com/showthread.php?t=65053


从Ndis Intermediate Miniport driver说吧,参考passthru

NTSTATUS
DriverEntry(
  IN  PDRIVER_OBJECT    DriverObject,
  IN  PUNICODE_STRING    RegistryPath
  )
程序入口没什么好说的 而NDIS不符合WDM往下到了

NdisMInitializeWrapper(&NdisWrapperHandle, DriverObject, RegistryPath, NULL);
在DriverEntry里调用NdisMInitializeWrapper函数初始包裹来使得微端口驱动和NDIS相联系。它返回一个NdisWrapperHandle句柄,它是代表这个微端口驱动程序结构的句柄。

然而NdisMInitializeWrapper到底作了什么呢?我们看REACTOS里这个函数

Code



它仅初始化了一个NDIS_M_DRIVER_BLOCK结构Miniport,并把他插入链表并返回这个结构
让我们看看它的结构
typedef struct _NDIS_M_DRIVER_BLOCK {
    LIST_ENTRY                      ListEntry;                /* Entry on global list */
    KSPIN_LOCK                      Lock;                     /* Protecting spin lock */
    NDIS_MINIPORT_CHARACTERISTICS   MiniportCharacteristics;  /* Miniport characteristics */
    WORK_QUEUE_ITEM                 WorkItem;                 /* Work item */
    PDRIVER_OBJECT                  DriverObject;             /* Driver object of miniport */
    LIST_ENTRY                      DeviceList;               /* Adapters created by miniport */
    PUNICODE_STRING                 RegistryPath;             /* SCM Registry key */
} NDIS_M_DRIVER_BLOCK, *PNDIS_M_DRIVER_BLOCK;

注意有一个 NDIS_MINIPORT_CHARACTERISTICS结构,我们下面必须初始化这一结构, NDIS_MINIPORT_CHARACTERISTICS结构指定了与微端口兼容的NDIS版本以及由微端口提供的可选上层函数(MINIPORTXXX)。然后DriverEntry通过一个指向NDIS_MINIPORT_CHARACTERISTICS的指针调用NdisIMRegisterLayeredMiniport或NdisMRegisterMiniport


    NdisZeroMemory(&MChars, sizeof(NDIS_MINIPORT_CHARACTERISTICS));

    MChars.MajorNdisVersion = PASSTHRU_MAJOR_NDIS_VERSION;
    MChars.MinorNdisVersion = PASSTHRU_MINOR_NDIS_VERSION;

    MChars.InitializeHandler = MPInitialize;
    MChars.QueryInformationHandler = MPQueryInformation;
    MChars.SetInformationHandler = MPSetInformation;
    MChars.ResetHandler = MPReset;
    MChars.TransferDataHandler = MPTransferData;
    MChars.HaltHandler = MPHalt;
#ifdef NDIS51_MINIPORT
    MChars.CancelSendPacketsHandler = MPCancelSendPackets;
    MChars.PnPEventNotifyHandler = MPDevicePnPEvent;
    MChars.AdapterShutdownHandler = MPAdapterShutdown;
#endif // NDIS51_MINIPORT

    //
    // We will disable the check for hang timeout so we do not
    // need a check for hang handler!
    //
    MChars.CheckForHangHandler = NULL;
    MChars.ReturnPacketHandler = MPReturnPacket;

    //
    // Either the Send or the SendPackets handler should be specified.
    // If SendPackets handler is specified, SendHandler is ignored
    //
    MChars.SendHandler = NULL;  // MPSend;
    MChars.SendPacketsHandler = MPSendPackets;

    Status = NdisIMRegisterLayeredMiniport(NdisWrapperHandle,
                            &MChars,
                            sizeof(MChars),
                            &DriverHandle);

我们来看看NdisMRegisterMiniport做了什么

Code



首先检查NDIS_MINIPORT_CHARACTERISTICS结构的有效性,然后调用了IoAllocateDriverObjectExtension分配了DriverObjectExtension然后就是设置PNP例程和AddDevice例程,当有网卡插入设备时创建设备,让我们看看NdisIAddDevice

Code



可以看到首先通过注册表得到设备名,然后创建设备对象,然后初始化了一个adapter structure,让我们看看这个结构
typedef struct _LOGICAL_ADAPTER
{
    NDIS_MINIPORT_BLOCK         NdisMiniportBlock;      /* NDIS defined fields */
    BOOLEAN                     MiniportBusy;           /* A MiniportXxx routine is executing */
    PNDIS_MINIPORT_WORK_ITEM    WorkQueueHead;          /* Head of work queue */
    PNDIS_MINIPORT_WORK_ITEM    WorkQueueTail;          /* Tail of work queue */
    LIST_ENTRY                  ListEntry;              /* Entry on global list */
    LIST_ENTRY                  MiniportListEntry;      /* Entry on miniport driver list */
    LIST_ENTRY                  ProtocolListHead;       /* List of bound protocols */
    ULONG                       MediumHeaderSize;       /* Size of medium header */
    HARDWARE_ADDRESS            Address;                /* Hardware address of adapter */
    ULONG                       AddressLength;          /* Length of hardware address */
    PUCHAR                      LookaheadBuffer;        /* Pointer to lookahead buffer */
    ULONG                       LookaheadLength;        /* Length of lookahead buffer */
    PMINIPORT_BUGCHECK_CONTEXT  BugcheckContext;        /* Adapter's shutdown handler */
} LOGICAL_ADAPTER, *PLOGICAL_ADAPTER


第一个是 NDIS_MINIPORT_BLOCK 结构,它包括的东西很多很全这里就不贴了,可以到DDK去看 哈哈。

好了按照passthru下面它应该调用NdisRegisterProtocol注册协议了,它有一个NDIS_PROTOCOL_CHARACTERISTICS结构必须先初始化,和上面那个差不多吧 哈哈

    // Now register the protocol.
    //
    NdisZeroMemory(&PChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
    PChars.MajorNdisVersion = PASSTHRU_PROT_MAJOR_NDIS_VERSION;
    PChars.MinorNdisVersion = PASSTHRU_PROT_MINOR_NDIS_VERSION;

    //
    // Make sure the protocol-name matches the service-name
    // (from the INF) under which this protocol is installed.
    // This is needed to ensure that NDIS can correctly determine
    // the binding and call us to bind to miniports below.
    //
    NdisInitUnicodeString(&Name, L"Passthru");  // Protocol name
    PChars.Name = Name;
    PChars.OpenAdapterCompleteHandler = PtOpenAdapterComplete;
    PChars.CloseAdapterCompleteHandler = PtCloseAdapterComplete;
    PChars.SendCompleteHandler = PtSendComplete;
    PChars.TransferDataCompleteHandler = PtTransferDataComplete;
  
    PChars.ResetCompleteHandler = PtResetComplete;
    PChars.RequestCompleteHandler = PtRequestComplete;
    PChars.ReceiveHandler = PtReceive;
    PChars.ReceiveCompleteHandler = PtReceiveComplete;
    PChars.StatusHandler = PtStatus;
    PChars.StatusCompleteHandler = PtStatusComplete;
    PChars.BindAdapterHandler = PtBindAdapter;
    PChars.UnbindAdapterHandler = PtUnbindAdapter;
    PChars.UnloadHandler = PtUnloadProtocol;

    PChars.ReceivePacketHandler = PtReceivePacket;
    PChars.PnPEventHandler= PtPNPHandler;

    NdisRegisterProtocol(&Status,
               &ProtHandle,
               &PChars,
               sizeof(NDIS_PROTOCOL_CHARACTERISTICS));

可以看到在NDIS_PROTOCOL_CHARACTERISTICS中除了指定兼容版本以外还保存了强制的和非强制的ProtocolXxx函数地址。下面我们看一看NdisRegisterProtocol函数

Code



它首先判断NDIS_PROTOCOL_CHARACTERISTICS的有效性,然后初始化了一个PPROTOCOL_BINDING Protocol结构,然后从Bind key获得设备链表,获得设备名,并创建了这样       *     \Registry\Machine\System\CurrentControlSet\Services\Nic1\Parameters\Tcpip
       *的注册表键,然后调用我们传进去的BindAdapterHandler进行绑定设备。并把Protocol加如链表。从*NdisProtocolHandle = Protocol我们知道NdisProtocolHandle 指向Protocol那让我们看看这个Protocol是什么,
typedef struct _PROTOCOL_BINDING {
    LIST_ENTRY                    ListEntry;        /* Entry on global list */
    KSPIN_LOCK                    Lock;             /* Protecting spin lock */
    NDIS_PROTOCOL_CHARACTERISTICS Chars;            /* Characteristics */
    WORK_QUEUE_ITEM               WorkItem;         /* Work item */
    LIST_ENTRY                    AdapterListHead;  /* List of adapter bindings */
} PROTOCOL_BINDING, *PPROTOCOL_BINDING;
这里面有个指向adapter bindings的链表,来让我们看看adapter binding

typedef struct _ADAPTER_BINDING {
    NDIS_OPEN_BLOCK NdisOpenBlock;                            /* NDIS defined fields */

    LIST_ENTRY        ListEntry;                /* Entry on global list */
    LIST_ENTRY        ProtocolListEntry;        /* Entry on protocol binding adapter list */
    LIST_ENTRY        AdapterListEntry;         /* Entry on logical adapter list */
    KSPIN_LOCK        Lock;                     /* Protecting spin lock */
    PPROTOCOL_BINDING ProtocolBinding;          /* Protocol that opened adapter */
    PLOGICAL_ADAPTER  Adapter;                  /* Adapter opened by protocol */
} ADAPTER_BINDING, *PADAPTER_BINDING;
我们看到第一项是一个NdisOpenBlock结构,现在很多的NDIS放火墙就是通过注册协议根据返回的NdisProtocolHandle来找到NdisOpenBlock结构的,因为NdisOpenBlock结构是用来描述和该ndis protocol有联系的所有ndis miniport和该ndisprotocol绑定的状态每个绑定的send(packets)handler和receive(packet)handler都在这个ndis open block里面。

struct _NDIS_OPEN_BLOCK
{
#ifdef __cplusplus
  NDIS_COMMON_OPEN_BLOCK NdisCommonOpenBlock;
#else
  NDIS_COMMON_OPEN_BLOCK;
#endif

#if defined(NDIS_WRAPPER)
  
  //
  // The stuff below is for CO drivers/protocols. This part is not allocated for CL drivers.
  //
  struct _NDIS_OPEN_CO
  {
  ....
  };
#endif
};

typedef struct _NDIS_COMMON_OPEN_BLOCK
{
  PVOID            MacHandle;     // needed for backward compatibility
  NDIS_HANDLE         BindingHandle;   // Miniport's open context
  PNDIS_MINIPORT_BLOCK    MiniportHandle;   // pointer to the miniport
  PNDIS_PROTOCOL_BLOCK    ProtocolHandle;   // pointer to our protocol
  NDIS_HANDLE         ProtocolBindingContext;// context when calling ProtXX funcs
  PNDIS_OPEN_BLOCK      MiniportNextOpen;  // used by adapter's OpenQueue
  PNDIS_OPEN_BLOCK      ProtocolNextOpen;  // used by protocol's OpenQueue
  NDIS_HANDLE         MiniportAdapterContext; // context for miniport
  BOOLEAN           Reserved1;
  BOOLEAN           Reserved2;
  BOOLEAN           Reserved3;
  BOOLEAN           Reserved4;
  PNDIS_STRING        BindDeviceName;
  KSPIN_LOCK         Reserved5;
  PNDIS_STRING        RootDeviceName;

  //
  // These are referenced by the macros used by protocols to call.
  // All of the ones referenced by the macros are internal NDIS handlers for the miniports
  //
  union
  {
    SEND_HANDLER      SendHandler;
    WAN_SEND_HANDLER    WanSendHandler;
  };
  TRANSFER_DATA_HANDLER    TransferDataHandler;

  //
  // These are referenced internally by NDIS
  //
  SEND_COMPLETE_HANDLER    SendCompleteHandler;
  TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;
  RECEIVE_HANDLER       ReceiveHandler;
  RECEIVE_COMPLETE_HANDLER  ReceiveCompleteHandler;
  WAN_RECEIVE_HANDLER     WanReceiveHandler;
  REQUEST_COMPLETE_HANDLER  RequestCompleteHandler;

  //
  // NDIS 4.0 extensions
  //
  RECEIVE_PACKET_HANDLER   ReceivePacketHandler;
  SEND_PACKETS_HANDLER    SendPacketsHandler;

  //
  // More Cached Handlers
  //
  RESET_HANDLER        ResetHandler;
  REQUEST_HANDLER       RequestHandler;
  RESET_COMPLETE_HANDLER   ResetCompleteHandler;
  STATUS_HANDLER       StatusHandler;
  STATUS_COMPLETE_HANDLER   StatusCompleteHandler;
  
#if defined(NDIS_WRAPPER)
  ....
#endif

} NDIS_COMMON_OPEN_BLOCK;

  需要处理的,是ndis open block里面的SendHandler,ReceiveHandler,WanReceiveHandler,ReceivePacketHandler和SendPacketsHandler。

好了在passthru里注册好协议以后  调用NdisIMAssociateMiniport(DriverHandle, ProtHandle)就可以了,因为passthru是中间层驱动程序,下面就应该分开说miniport和PROTOCOL,象MPInitialize,还有上面我们调用了BindAdapterHandler,我们应该说我们的BindAdapterHandler例程了,还有接包发包,和注册的各种例程,但现在就到这吧,要说下去不知什么时候能说完,这仅仅是一个开始,下面复杂的东西还很多


posted @ 2009-11-21 16:01  辛勤耕耘  阅读(1621)  评论(0编辑  收藏  举报