从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里这个函数 EXPORT NdisInitializeWrapper( 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或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做了什么 NDIS_STATUS EXPORT NdisMRegisterMiniport( 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例程,当有网卡插入设备时创建设备,让我们看看NdisIAddDevice NTSTATUS NTAPI NdisIAddDevice( 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函数 VOID EXPORT NdisRegisterProtocol( 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 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例程了,还有接包发包,和注册的各种例程,但现在就到这吧,要说下去不知什么时候能说完,这仅仅是一个开始,下面复杂的东西还很多,我这个小菜鸟就不现丑了。 哈哈 有什么问题可以讨论 qq:498793761