NDIS驱动学习笔记

    技术2022-05-20  40

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

    NDIS驱动学习笔记by ufphpc小弟看了大牛们众多文章,而自己还没写过什么东西,并不是不想写,实在是和大牛们差距太大,今天小弟把学习NDIS驱动贴出来,希望大牛们给指正。从Ndis Intermediate Miniport driver说吧,参考passthruNTSTATUSDriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)程序入口没什么好说的 而NDIS不符合WDM往下到了NdisMInitializeWrapper(&NdisWrapperHandle, DriverObject, RegistryPath, NULL);在DriverEntry里调用NdisMInitializeWrapper函数初始包裹来使得微端口驱动和NDIS相联系。它返回一个NdisWrapperHandle句柄,它是代表这个微端口驱动程序结构的句柄。然而NdisMInitializeWrapper到底作了什么呢?我们看REACTOS里这个函数EXPORTNdisInitializeWrapper(OUT PNDIS_HANDLE NdisWrapperHandle,IN   PVOID           SystemSpecific1,IN   PVOID           SystemSpecific2,IN   PVOID           SystemSpecific3)/** FUNCTION: Notifies the NDIS library that a new miniport is initializing* ARGUMENTS:*     NdisWrapperHandle = Address of buffer to place NDIS wrapper handle*     SystemSpecific1 = Pointer to the driver's driver object*     SystemSpecific2 = Pointer to the driver's registry path*     SystemSpecific3 = Always NULL* NOTES:*     - SystemSpecific2 goes invalid so we copy it*/{   PNDIS_M_DRIVER_BLOCK Miniport;   PUNICODE_STRING RegistryPath;   WCHAR *RegistryBuffer;   NDIS_DbgPrint(MAX_TRACE, ("Called./n"));   ASSERT(NdisWrapperHandle);   *NdisWrapperHandle = NULL;#if BREAK_ON_MINIPORT_INIT   __asm__ ("int $3/n");#endif   Miniport = ExAllocatePool(NonPagedPool, sizeof(NDIS_M_DRIVER_BLOCK));   if (!Miniport){   NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources./n"));   return;}   RtlZeroMemory(Miniport, sizeof(NDIS_M_DRIVER_BLOCK));   KeInitializeSpinLock(&Miniport->Lock);   Miniport->DriverObject = (PDRIVER_OBJECT)SystemSpecific1;   /* set the miniport's driver registry path */   RegistryPath = ExAllocatePool(PagedPool, sizeof(UNICODE_STRING));   if(!RegistryPath){   NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources./n"));   return;}   RegistryPath->Length = ((PUNICODE_STRING)SystemSpecific2)->Length;   RegistryPath->MaximumLength = RegistryPath->Length + sizeof(WCHAR); /* room for 0-term */   RegistryBuffer = ExAllocatePool(PagedPool, RegistryPath->MaximumLength);   if(!RegistryBuffer){   NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources./n"));   return;}   RtlCopyMemory(RegistryBuffer, ((PUNICODE_STRING)SystemSpecific2)->Buffer, RegistryPath->Length);   RegistryBuffer[RegistryPath->Length/sizeof(WCHAR)] = 0;   RegistryPath->Buffer = RegistryBuffer;   Miniport->RegistryPath = RegistryPath;   InitializeListHead(&Miniport->DeviceList);   /* Put miniport in global miniport list */   ExInterlockedInsertTailList(&MiniportListHead, &Miniport->ListEntry, &MiniportListLock);   *NdisWrapperHandle = Miniport;}它仅初始化了一个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或NdisMRegisterMiniportNdisZeroMemory(&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_MINIPORTMChars.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做了什么NDIS_STATUSEXPORTNdisMRegisterMiniport(IN   NDIS_HANDLE                   NdisWrapperHandle,IN   PNDIS_MINIPORT_CHARACTERISTICS   MiniportCharacteristics,IN   UINT                         CharacteristicsLength)/** FUNCTION: Registers a miniport's MiniportXxx entry points with the NDIS library* ARGUMENTS:*     NdisWrapperHandle    = Pointer to handle returned by NdisMInitializeWrapper*     MiniportCharacteristics = Pointer to a buffer with miniport characteristics*     CharacteristicsLength = Number of bytes in characteristics buffer* RETURNS:*     Status of operation*/{   UINT MinSize;   PNDIS_M_DRIVER_BLOCK Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);   PNDIS_M_DRIVER_BLOCK *MiniportPtr;   NTSTATUS Status;   NDIS_DbgPrint(MAX_TRACE, ("Called./n"));   switch (MiniportCharacteristics->MajorNdisVersion){   case 0x03:       MinSize = sizeof(NDIS30_MINIPORT_CHARACTERISTICS);       break;   case 0x04:       MinSize = sizeof(NDIS40_MINIPORT_CHARACTERISTICS);       break;   case 0x05:       MinSize = sizeof(NDIS50_MINIPORT_CHARACTERISTICS);       break;   default:       NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics version./n"));       return NDIS_STATUS_BAD_VERSION;}   if (CharacteristicsLength < MinSize){       NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics./n"));       return NDIS_STATUS_BAD_CHARACTERISTICS;}   /* Check if mandatory MiniportXxx functions are specified */   if ((!MiniportCharacteristics->HaltHandler) ||   (!MiniportCharacteristics->InitializeHandler)||   (!MiniportCharacteristics->QueryInformationHandler) ||   (!MiniportCharacteristics->ResetHandler) ||   (!MiniportCharacteristics->SetInformationHandler)){   NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics./n"));   return NDIS_STATUS_BAD_CHARACTERISTICS;}   if (MiniportCharacteristics->MajorNdisVersion == 0x03){   if (!MiniportCharacteristics->SendHandler)       {      NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics./n"));      return NDIS_STATUS_BAD_CHARACTERISTICS;       }}   else if (MiniportCharacteristics->MajorNdisVersion >= 0x04){   /* NDIS 4.0+ */   if ((!MiniportCharacteristics->SendHandler) &&      (!MiniportCharacteristics->SendPacketsHandler))       {      NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics./n"));      return NDIS_STATUS_BAD_CHARACTERISTICS;       }}   /* TODO: verify NDIS5 and NDIS5.1 */   RtlCopyMemory(&Miniport->MiniportCharacteristics, MiniportCharacteristics, MinSize);   /** NOTE: This is VERY unoptimal! Should we store the NDIS_M_DRIVER_BLOCK* structure in the driver extension or what?*/   Status = IoAllocateDriverObjectExtension(Miniport->DriverObject, (PVOID)TAG('D','I','M','N'),                                       sizeof(PNDIS_M_DRIVER_BLOCK), (PVOID*)&MiniportPtr);   if (!NT_SUCCESS(Status)){   NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate driver object extension./n"));   return NDIS_STATUS_RESOURCES;}   *MiniportPtr = Miniport;   Miniport->DriverObject->MajorFunction[IRP_MJ_PNP] = NdisIDispatchPnp;   Miniport->DriverObject->DriverExtension->AddDevice = NdisIAddDevice;   return NDIS_STATUS_SUCCESS;}首先检查NDIS_MINIPORT_CHARACTERISTICS结构的有效性,然后调用了IoAllocateDriverObjectExtension分配了DriverObjectExtension然后就是设置PNP例程和AddDevice例程,当有网卡插入设备时创建设备,让我们看看NdisIAddDeviceNTSTATUSNTAPINdisIAddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PhysicalDeviceObject)/** FUNCTION: Create a device for an adapter found using PnP* ARGUMENTS:*     DriverObject       = Pointer to the miniport driver object*     PhysicalDeviceObject = Pointer to the PDO for our adapter*/{   static const WCHAR ClassKeyName[] = {'C','l','a','s','s','//'};   static const WCHAR LinkageKeyName[] = {'//','L','i','n','k','a','g','e',0};   PNDIS_M_DRIVER_BLOCK Miniport;   PNDIS_M_DRIVER_BLOCK *MiniportPtr;   WCHAR *LinkageKeyBuffer;   ULONG DriverKeyLength;   RTL_QUERY_REGISTRY_TABLE QueryTable[2];   UNICODE_STRING ExportName;   PDEVICE_OBJECT DeviceObject;   PLOGICAL_ADAPTER Adapter;   NTSTATUS Status;   /** Gain the access to the miniport data structure first.*/   MiniportPtr = IoGetDriverObjectExtension(DriverObject, (PVOID)TAG('D','I','M','N'));   if (MiniportPtr == NULL){   NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get driver object extension./n"));   return STATUS_UNSUCCESSFUL;}   Miniport = *MiniportPtr;   /** Get name of the Linkage registry key for our adapter. It's located under* the driver key for our driver and so we have basicly two ways to do it.* Either we can use IoOpenDriverRegistryKey or compose it using information* gathered by IoGetDeviceProperty. I choosed the second because* IoOpenDriverRegistryKey wasn't implemented at the time of writing.*/   Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,                           0, NULL, &DriverKeyLength);   if (Status != STATUS_BUFFER_TOO_SMALL){   NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key length./n"));   return Status;}   LinkageKeyBuffer = ExAllocatePool(PagedPool, DriverKeyLength +                                 sizeof(ClassKeyName) + sizeof(LinkageKeyName));   if (LinkageKeyBuffer == NULL){   NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate memory for driver key name./n"));   return STATUS_INSUFFICIENT_RESOURCES;}   Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,                           DriverKeyLength, LinkageKeyBuffer +                           (sizeof(ClassKeyName) / sizeof(WCHAR)),                           &DriverKeyLength);   if (!NT_SUCCESS(Status)){   NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key./n"));   ExFreePool(LinkageKeyBuffer);   return Status;}   /* Compose the linkage key name. */   RtlCopyMemory(LinkageKeyBuffer, ClassKeyName, sizeof(ClassKeyName));   RtlCopyMemory(LinkageKeyBuffer + ((sizeof(ClassKeyName) + DriverKeyLength) /            sizeof(WCHAR)) - 1, LinkageKeyName, sizeof(LinkageKeyName));   NDIS_DbgPrint(DEBUG_MINIPORT, ("LinkageKey: %S./n", LinkageKeyBuffer));   /** Now open the linkage key and read the "Export" and "RootDevice" values* which contains device name and root service respectively.*/   RtlZeroMemory(QueryTable, sizeof(QueryTable));   RtlInitUnicodeString(&ExportName, NULL);   QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;   QueryTable[0].Name = L"Export";   QueryTable[0].EntryContext = &ExportName;   Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, LinkageKeyBuffer,                              QueryTable, NULL, NULL);   ExFreePool(LinkageKeyBuffer);   if (!NT_SUCCESS(Status)){   NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport device name. (%x)/n", Status));   return Status;}   /** Create the device object.*/   NDIS_DbgPrint(MAX_TRACE, ("creating device %wZ/n", &ExportName));   Status = IoCreateDevice(Miniport->DriverObject, sizeof(LOGICAL_ADAPTER),&ExportName, FILE_DEVICE_PHYSICAL_NETCARD,0, FALSE, &DeviceObject);   if (!NT_SUCCESS(Status)){   NDIS_DbgPrint(MIN_TRACE, ("Could not create device object./n"));   RtlFreeUnicodeString(&ExportName);   return Status;}   /** Initialize the adapter structure.*/   Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;   KeInitializeSpinLock(&Adapter->NdisMiniportBlock.Lock);   InitializeListHead(&Adapter->ProtocolListHead);   Adapter->NdisMiniportBlock.DriverHandle = Miniport;   Adapter->NdisMiniportBlock.MiniportName = ExportName;   Adapter->NdisMiniportBlock.DeviceObject = DeviceObject;   Adapter->NdisMiniportBlock.PhysicalDeviceObject = PhysicalDeviceObject;   Adapter->NdisMiniportBlock.NextDeviceObject =IoAttachDeviceToDeviceStack(Adapter->NdisMiniportBlock.DeviceObject,                               PhysicalDeviceObject);   Adapter->NdisMiniportBlock.OldPnPDeviceState = 0;   Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceAdded;   KeInitializeDpc(&Adapter->NdisMiniportBlock.DeferredDpc, MiniportDpc, (PVOID)Adapter);   DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;   return STATUS_SUCCESS;}

     

    可以看到首先通过注册表得到设备名,然后创建设备对象,然后初始化了一个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函数VOIDEXPORTNdisRegisterProtocol(    OUT PNDIS_STATUS                    Status,    OUT PNDIS_HANDLE                    NdisProtocolHandle,    IN  PNDIS_PROTOCOL_CHARACTERISTICS  ProtocolCharacteristics,    IN  UINT                            CharacteristicsLength)/* * FUNCTION: Registers an NDIS driver's ProtocolXxx entry points * ARGUMENTS: *     Status                  = Address of buffer for status information *     NdisProtocolHandle      = Address of buffer for handle used to identify the driver *     ProtocolCharacteristics = Pointer to NDIS_PROTOCOL_CHARACTERISTICS structure *     CharacteristicsLength   = Size of structure which ProtocolCharacteristics targets * NOTES: *     - you *must* set NdisProtocolHandle before doing anything that could wind up *       getting BindAdapterHandler, as it will probably call OpenAdapter with this handle *     - the above implies that the initialization of the protocol block must be complete *       by then * TODO: *     - break this function up - probably do a 'ndisRefreshProtocolBindings' function *     - make this thing able to handle >1 protocol */{  PPROTOCOL_BINDING Protocol;  NTSTATUS NtStatus;  UINT MinSize;  HANDLE DriverKeyHandle = NULL;  PKEY_VALUE_PARTIAL_INFORMATION KeyInformation = NULL;  WCHAR *DataPtr;  NDIS_DbgPrint(MAX_TRACE, ("Called./n"));  /* first validate the PROTOCOL_CHARACTERISTICS */  switch (ProtocolCharacteristics->MajorNdisVersion)    {    case 0x03:      /* we don't really want to support ndis3 drivers - so we complain for now */      NDIS_DbgPrint(MID_TRACE, ("NDIS 3 protocol attempting to register/n"));      MinSize = sizeof(NDIS30_PROTOCOL_CHARACTERISTICS);      break;    case 0x04:      MinSize = sizeof(NDIS40_PROTOCOL_CHARACTERISTICS);      break;    case 0x05:      MinSize = sizeof(NDIS50_PROTOCOL_CHARACTERISTICS);      break;    default:      *Status = NDIS_STATUS_BAD_VERSION;      NDIS_DbgPrint(MIN_TRACE, ("Incorrect characteristics size/n"));      return;    }  if (CharacteristicsLength < MinSize)    {      NDIS_DbgPrint(DEBUG_PROTOCOL, ("Bad protocol characteristics./n"));      *Status = NDIS_STATUS_BAD_CHARACTERISTICS;      return;    }  /* set up the protocol block */  Protocol = ExAllocatePool(NonPagedPool, sizeof(PROTOCOL_BINDING));  if (!Protocol)    {      NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources./n"));      *Status = NDIS_STATUS_RESOURCES;      return;    }  RtlZeroMemory(Protocol, sizeof(PROTOCOL_BINDING));  RtlCopyMemory(&Protocol->Chars, ProtocolCharacteristics, MinSize);  NtStatus = RtlUpcaseUnicodeString(&Protocol->Chars.Name, &ProtocolCharacteristics->Name, TRUE);  if (!NT_SUCCESS(NtStatus))    {      NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources./n"));      ExFreePool(Protocol);      *Status = NDIS_STATUS_RESOURCES;      return;    }  KeInitializeSpinLock(&Protocol->Lock);  InitializeListHead(&Protocol->AdapterListHead);  /*   * bind the protocol to all of its miniports   *   * open registry path   * get list of devices from Bind key   * call BindAdapterHandler for each   */  {    OBJECT_ATTRIBUTES ObjectAttributes;    UNICODE_STRING RegistryPath;    WCHAR *RegistryPathStr;    RegistryPathStr = ExAllocatePoolWithTag(PagedPool, sizeof(SERVICES_KEY) + ProtocolCharacteristics->Name.Length + sizeof(LINKAGE_KEY), NDIS_TAG + __LINE__);    if(!RegistryPathStr)      {        NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources./n"));        ExFreePool(Protocol);        *Status = NDIS_STATUS_RESOURCES;        return;      }    wcscpy(RegistryPathStr, SERVICES_KEY);    wcsncat(RegistryPathStr, ((WCHAR *)ProtocolCharacteristics->Name.Buffer), ProtocolCharacteristics->Name.Length / sizeof(WCHAR));    RegistryPathStr[wcslen(SERVICES_KEY)+ProtocolCharacteristics->Name.Length/sizeof(WCHAR)] = 0;    wcscat(RegistryPathStr, LINKAGE_KEY);    RtlInitUnicodeString(&RegistryPath, RegistryPathStr);    NDIS_DbgPrint(MAX_TRACE, ("Opening configuration key: %wZ/n", &RegistryPath));    InitializeObjectAttributes(&ObjectAttributes, &RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL);    NtStatus = ZwOpenKey(&DriverKeyHandle, KEY_READ, &ObjectAttributes);    ExFreePool(RegistryPathStr);    if(!NT_SUCCESS(NtStatus))      {        NDIS_DbgPrint(MID_TRACE, ("Unable to open protocol configuration/n"));        ExFreePool(Protocol);        *Status = NDIS_STATUS_FAILURE;        return;      }  }  NDIS_DbgPrint(MAX_TRACE, ("Successfully opened the registry configuration/n"));  {    UNICODE_STRING ValueName;    ULONG ResultLength;    RtlInitUnicodeString(&ValueName, L"Bind");    NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, NULL, 0, &ResultLength);    if(NtStatus != STATUS_BUFFER_OVERFLOW && NtStatus != STATUS_BUFFER_TOO_SMALL)      {        NDIS_DbgPrint(MID_TRACE, ("Unable to query the Bind value for size/n"));        ZwClose(DriverKeyHandle);        ExFreePool(Protocol);        *Status = NDIS_STATUS_FAILURE;        return;      }    KeyInformation = ExAllocatePoolWithTag(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength, NDIS_TAG + __LINE__);    if(!KeyInformation)      {        NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources./n"));        ZwClose(DriverKeyHandle);        ExFreePool(Protocol);        *Status = NDIS_STATUS_FAILURE;        return;      }    NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, KeyInformation,        sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength, &ResultLength);    if(!NT_SUCCESS(NtStatus))      {        NDIS_DbgPrint(MIN_TRACE, ("Unable to query the Bind value/n"));        ZwClose(DriverKeyHandle);        ExFreePool(KeyInformation);        ExFreePool(Protocol);        *Status = NDIS_STATUS_FAILURE;        return;      }  }  for (DataPtr = (WCHAR *)KeyInformation->Data;       *DataPtr != 0;       DataPtr += wcslen(DataPtr) + 1)    {      /* BindContext is for tracking pending binding operations */      VOID *BindContext = 0;      NDIS_STRING DeviceName;      NDIS_STRING RegistryPath;      WCHAR *RegistryPathStr = NULL;      ULONG PathLength = 0;      RtlInitUnicodeString(&DeviceName, DataPtr);  /* we know this is 0-term */      /*       * RegistryPath should be:       *     /Registry/Machine/System/CurrentControlSet/Services/Nic1/Parameters/Tcpip       *       *  This is constructed as follows:       *      SERVICES_KEY + extracted device name + Protocol name from characteristics       */      PathLength = sizeof(SERVICES_KEY) +                               /* /Registry/Machine/System/CurrentControlSet/Services/ */          wcslen( DataPtr + 8 ) * sizeof(WCHAR) + /* Adapter1  (extracted from /Device/Adapter1)          */          sizeof(PARAMETERS_KEY) +                                      /* /Parameters/                                         */          ProtocolCharacteristics->Name.Length + sizeof(WCHAR);                         /* Tcpip                                                */      RegistryPathStr = ExAllocatePool(PagedPool, PathLength);      if(!RegistryPathStr)        {          NDIS_DbgPrint(MIN_TRACE, ("insufficient resources./n"));          ExFreePool(KeyInformation);          ExFreePool(Protocol);          *Status = NDIS_STATUS_RESOURCES;          return;        }      wcscpy(RegistryPathStr, SERVICES_KEY);      wcscat(RegistryPathStr, DataPtr + 8 );      wcscat(RegistryPathStr, PARAMETERS_KEY);      wcsncat(RegistryPathStr, ProtocolCharacteristics->Name.Buffer, ProtocolCharacteristics->Name.Length / sizeof(WCHAR) );      RegistryPathStr[PathLength/sizeof(WCHAR) - 1] = 0;      RtlInitUnicodeString(&RegistryPath, RegistryPathStr);      NDIS_DbgPrint(MAX_TRACE, ("Calling protocol's BindAdapter handler with DeviceName %wZ and RegistryPath %wZ/n",          &DeviceName, &RegistryPath));      /* XXX SD must do something with bind context */      *NdisProtocolHandle = Protocol;        {          BIND_HANDLER BindHandler = ProtocolCharacteristics->BindAdapterHandler;          if(BindHandler)            BindHandler(Status, BindContext, &DeviceName, &RegistryPath, 0);          else            NDIS_DbgPrint(MID_TRACE, ("No protocol bind handler specified/n"));        }      /*      (*(Protocol->Chars.BindAdapterHandler))(Status, BindContext, &DeviceName, &RegistryPath, 0);      */      if(*Status == NDIS_STATUS_SUCCESS)        {          /* Put protocol binding struct on global list */          ExInterlockedInsertTailList(&ProtocolListHead, &Protocol->ListEntry, &ProtocolListLock);        }      /*      else if(*Status != NDIS_STATUS_PENDING)        {          // what to do here?        }       */    }  *Status             = NDIS_STATUS_SUCCESS;}它首先判断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 bindingtypedef 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例程了,还有接包发包,和注册的各种例程,但现在就到这吧,要说下去不知什么时候能说完,这仅仅是一个开始,下面复杂的东西还很多,我这个小菜鸟就不现丑了。


    最新回复(0)