Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3556 lines
99 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. ndis.c
  5. Abstract:
  6. NDIS wrapper functions
  7. Author:
  8. Adam Barr (adamba) 11-Jul-1990
  9. Environment:
  10. Kernel mode, FSD
  11. Revision History:
  12. 10-Jul-1995 JameelH Make NDIS.SYS a device-driver and add PnP support
  13. --*/
  14. #include <precomp.h>
  15. #pragma hdrstop
  16. //
  17. // Define the module number for debug code.
  18. //
  19. #define MODULE_NUMBER MODULE_NDIS
  20. #define NDIS_DEVICE_NAME L"\\Device\\Ndis"
  21. #define NDIS_SYMBOLIC_NAME L"\\Global??\\NDIS"
  22. NTSTATUS
  23. DriverEntry(
  24. IN PDRIVER_OBJECT DriverObject,
  25. IN PUNICODE_STRING RegistryPath
  26. )
  27. /*++
  28. Routine Description:
  29. NDIS wrapper driver entry point.
  30. Arguments:
  31. DriverObject - Pointer to the driver object created by the system.
  32. RegistryPath - Pointer to the registry section where the parameters reside.
  33. Return Value:
  34. Return value from IoCreateDevice
  35. --*/
  36. {
  37. NTSTATUS Status = STATUS_SUCCESS;
  38. UNICODE_STRING DeviceName;
  39. UINT i;
  40. OBJECT_ATTRIBUTES ObjectAttr;
  41. UNICODE_STRING CallbackObjectName;
  42. NTSTATUS NtStatus;
  43. SYSTEM_BATTERY_STATE ndisSystemBatteryState;
  44. HANDLE ThreadHandle;
  45. BOOLEAN fDerefCallbackObject = FALSE, fDeregisterCallback = FALSE;
  46. #define GET_TEXT_1(_T) #_T
  47. #define GET_TEXT(_T) GET_TEXT_1(_T)
  48. NdisInitializeString(&ndisBuildDate, __DATE__);
  49. NdisInitializeString(&ndisBuildTime, __TIME__);
  50. NdisInitializeString(&ndisBuiltBy, GET_TEXT(BUILT_BY));
  51. ndisDriverObject = DriverObject;
  52. //
  53. // Create the device object.
  54. //
  55. RtlInitUnicodeString(&DeviceName, NDIS_DEVICE_NAME);
  56. ndisNumberOfProcessors = KeNumberProcessors;
  57. Status = IoCreateDevice(DriverObject, // DriverObject
  58. 0, // DeviceExtension
  59. &DeviceName, // DeviceName
  60. FILE_DEVICE_NETWORK, // DeviceType
  61. FILE_DEVICE_SECURE_OPEN, // DeviceCharacteristics
  62. FALSE, // Exclusive
  63. &ndisDeviceObject); // DeviceObject
  64. if (NT_SUCCESS(Status))
  65. {
  66. UNICODE_STRING SymbolicLinkName;
  67. // Create a symbolic link to this device
  68. RtlInitUnicodeString(&SymbolicLinkName, NDIS_SYMBOLIC_NAME);
  69. Status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
  70. ndisDeviceObject->Flags |= DO_DIRECT_IO;
  71. // Initialize the driver object for this file system driver.
  72. for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
  73. {
  74. DriverObject->MajorFunction[i] = ndisDispatchRequest;
  75. }
  76. //
  77. // create a security descriptor for NDIS device object
  78. //
  79. Status = ndisCreateSecurityDescriptor(ndisDeviceObject,
  80. &ndisSecurityDescriptor,
  81. TRUE);
  82. Status = CreateDeviceDriverSecurityDescriptor(DriverObject);
  83. Status = CreateDeviceDriverSecurityDescriptor(DriverObject->DeviceObject);
  84. Status = CreateDeviceDriverSecurityDescriptor(ndisDeviceObject);
  85. //
  86. // disable for now
  87. //
  88. #if NDIS_UNLOAD
  89. DriverObject->DriverUnload = ndisUnload;
  90. #else
  91. DriverObject->DriverUnload = NULL;
  92. #endif
  93. INITIALIZE_SPIN_LOCK(&ndisGlobalLock);
  94. INITIALIZE_SPIN_LOCK(&ndisMiniDriverListLock);
  95. INITIALIZE_SPIN_LOCK(&ndisProtocolListLock);
  96. INITIALIZE_SPIN_LOCK(&ndisMiniportListLock);
  97. INITIALIZE_SPIN_LOCK(&ndisGlobalPacketPoolListLock);
  98. INITIALIZE_SPIN_LOCK(&ndisGlobalOpenListLock);
  99. ndisDmaAlignment = HalGetDmaAlignmentRequirement();
  100. if (sizeof(ULONG) > ndisDmaAlignment)
  101. {
  102. ndisDmaAlignment = sizeof(ULONG);
  103. }
  104. ndisTimeIncrement = KeQueryTimeIncrement();
  105. //
  106. // Get handles for all conditionally lockable sections
  107. //
  108. for (i = 0; i < MAX_PKG; i++)
  109. {
  110. ndisInitializePackage(&ndisPkgs[i]);
  111. }
  112. ExInitializeResourceLite(&SharedMemoryResource);
  113. ndisReadRegistry();
  114. //
  115. // don't let use set this bit through registry
  116. //
  117. ndisFlags &= ~NDIS_GFLAG_TRACK_MEM_ALLOCATION;
  118. Status = STATUS_SUCCESS;
  119. ndisSystemProcess = NtCurrentProcess();
  120. //
  121. // Now create a worker thread for use by NDIS
  122. // This is so that when we queue PnP events upto transports
  123. // and they need worker threads as well ...
  124. //
  125. KeInitializeQueue(&ndisWorkerQueue, 0);
  126. Status = PsCreateSystemThread(&ThreadHandle,
  127. THREAD_ALL_ACCESS,
  128. NULL,
  129. NtCurrentProcess(),
  130. NULL,
  131. ndisWorkerThread,
  132. NULL);
  133. if (!NT_SUCCESS(Status))
  134. {
  135. DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
  136. ("NDIS DriverEntry: Cannot create worker thread, Status %lx\n", Status));
  137. }
  138. else
  139. {
  140. NtClose(ThreadHandle);
  141. }
  142. }
  143. KeQuerySystemTime(&KeBootTime);
  144. ConvertSecondsToTicks(POOL_AGING_TIME, &PoolAgingTicks);
  145. //
  146. // verifir intialization. in case ndis tester wants to verify
  147. // the drivers by intercepting ndis entry points, ndis should
  148. // not verify the calls
  149. //
  150. if (!(ndisFlags & NDIS_GFLAG_DONT_VERIFY))
  151. ndisVerifierInitialization();
  152. #if DBG
  153. if (ndisDebugBreakPoint)
  154. {
  155. DbgPrint("Ndis: DriverEntry\n");
  156. DbgBreakPoint();
  157. }
  158. #endif
  159. #ifdef TRACK_MOPEN_REFCOUNTS
  160. NdisZeroMemory (&ndisLogfile, sizeof(UINT) * NDIS_LOGFILE_SIZE);
  161. #endif
  162. #ifdef TRACK_MINIPORT_REFCOUNTS
  163. NdisZeroMemory (&ndisMiniportLogfile, sizeof(UINT) * NDIS_MINIPORT_LOGFILE_SIZE);
  164. #endif
  165. //
  166. // create a callback options for those kernel mode components that like
  167. // to hear about Bind/Unbind events
  168. //
  169. RtlInitUnicodeString(&CallbackObjectName, NDIS_BIND_UNBIND_CALLBACK_NAME);
  170. InitializeObjectAttributes(&ObjectAttr,
  171. &CallbackObjectName,
  172. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  173. NULL,
  174. NULL);
  175. NtStatus = ExCreateCallback(&ndisBindUnbindCallbackObject,
  176. &ObjectAttr,
  177. TRUE, // create
  178. TRUE); // allow multiple callback registeration
  179. if (!NT_SUCCESS(NtStatus))
  180. {
  181. DbgPrint("Ndis: failed to create a Callback object. Status %lx\n", NtStatus);
  182. }
  183. #if 0
  184. else
  185. {
  186. //
  187. // for test purpose
  188. //
  189. ndisBindUnbindCallbackRegisterationHandle = ExRegisterCallback(ndisBindUnbindCallbackObject,
  190. ndisBindUnbindCallback,
  191. (PVOID)NULL);
  192. if (ndisBindUnbindCallbackRegisterationHandle == NULL)
  193. {
  194. DbgPrint("Ndis: failed to register a BindUnbind callback routine\n");
  195. }
  196. }
  197. #endif
  198. //
  199. // register a notification callback for power state changes
  200. //
  201. RtlInitUnicodeString(&CallbackObjectName, L"\\CallBack\\PowerState");
  202. InitializeObjectAttributes(&ObjectAttr,
  203. &CallbackObjectName,
  204. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  205. NULL,
  206. NULL);
  207. NtStatus = ExCreateCallback(&ndisPowerStateCallbackObject,
  208. &ObjectAttr,
  209. FALSE,
  210. TRUE);
  211. if (!NT_SUCCESS(Status))
  212. {
  213. DbgPrint("Ndis: failed to create a Callback object. Status %lx\n", NtStatus);
  214. }
  215. else
  216. {
  217. fDerefCallbackObject = TRUE;
  218. ndisPowerStateCallbackHandle = ExRegisterCallback(ndisPowerStateCallbackObject,
  219. (PCALLBACK_FUNCTION)&ndisPowerStateCallback,
  220. (PVOID)NULL);
  221. if (ndisPowerStateCallbackHandle == NULL)
  222. {
  223. DbgPrint("Ndis: failed to register a power state Callback routine\n");
  224. }
  225. else
  226. {
  227. fDeregisterCallback = TRUE;
  228. }
  229. RtlZeroMemory(&ndisSystemBatteryState, sizeof(SYSTEM_BATTERY_STATE));
  230. //
  231. // get the current power source
  232. //
  233. NtStatus = ZwPowerInformation(SystemBatteryState,
  234. NULL,
  235. 0,
  236. &ndisSystemBatteryState,
  237. sizeof(SYSTEM_BATTERY_STATE));
  238. if (NT_SUCCESS(NtStatus))
  239. {
  240. ndisAcOnLine = (ndisSystemBatteryState.AcOnLine == TRUE) ? 1 : 0;
  241. }
  242. fDerefCallbackObject = FALSE;
  243. fDeregisterCallback = FALSE;
  244. }
  245. InitializeListHead(&ndisGlobalPacketPoolList);
  246. if (fDeregisterCallback)
  247. {
  248. ExUnregisterCallback(ndisPowerStateCallbackHandle);
  249. }
  250. if (fDerefCallbackObject)
  251. {
  252. ObDereferenceObject(ndisPowerStateCallbackObject);
  253. }
  254. INITIALIZE_MUTEX(&ndisPnPMutex);
  255. return Status;
  256. }
  257. #if NDIS_UNLOAD
  258. VOID
  259. ndisUnload(
  260. IN PDRIVER_OBJECT DriverObject
  261. )
  262. /*++
  263. Routine Description:
  264. This is the unload routine for the Appletalk driver.
  265. NOTE: Unload will not be called until all the handles have been
  266. closed successfully. We just shutdown all the ports, and do
  267. misc. cleanup.
  268. Arguments:
  269. DriverObject - Pointer to driver object for this driver.
  270. Return Value:
  271. None.
  272. --*/
  273. {
  274. NTSTATUS Status;
  275. UNICODE_STRING SymbolicLinkName;
  276. UINT i;
  277. NdisFreeString(ndisBuildDate);
  278. NdisFreeString(ndisBuildTime);
  279. NdisFreeString(ndisBuiltBy);
  280. if (ndisPowerStateCallbackHandle)
  281. {
  282. ExUnregisterCallback(ndisPowerStateCallbackHandle);
  283. }
  284. if (ndisPowerStateCallbackObject)
  285. {
  286. ObDereferenceObject(ndisPowerStateCallbackObject);
  287. }
  288. ExDeleteResourceLite(&SharedMemoryResource);
  289. //
  290. // Tell the ndisWorkerThread to quit
  291. //
  292. INITIALIZE_WORK_ITEM(&ndisPoisonPill, NULL, &ndisPoisonPill);
  293. QUEUE_WORK_ITEM(&ndisPoisonPill, CriticalWorkQueue);
  294. WAIT_FOR_OBJECT(ndisThreadObject, 0);
  295. ObDereferenceObject(ndisThreadObject);
  296. RtlInitUnicodeString(&SymbolicLinkName, NDIS_SYMBOLIC_NAME);
  297. Status = IoDeleteSymbolicLink(&SymbolicLinkName);
  298. ASSERT(NT_SUCCESS(Status));
  299. IoDeleteDevice(ndisDeviceObject);
  300. //
  301. // ASSERT that all the packages are unlocked
  302. //
  303. for (i = 0; i < MAX_PKG; i++)
  304. {
  305. ASSERT(ndisPkgs[i].ReferenceCount == 0);
  306. }
  307. }
  308. #endif
  309. VOID
  310. ndisReadRegistry(
  311. VOID
  312. )
  313. {
  314. RTL_QUERY_REGISTRY_TABLE QueryTable[8];
  315. UCHAR c;
  316. ULONG DefaultZero = 0;
  317. //
  318. // First we need to initialize the processor information incase
  319. // the registry is empty.
  320. //
  321. for (c = 0; c < ndisNumberOfProcessors; c++)
  322. {
  323. ndisValidProcessors[c] = c;
  324. }
  325. ndisCurrentProcessor = ndisMaximumProcessor = c - 1;
  326. //
  327. // 1) Switch to the MediaTypes key below the service (NDIS) key
  328. //
  329. QueryTable[0].QueryRoutine = NULL;
  330. QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
  331. QueryTable[0].Name = L"MediaTypes";
  332. //
  333. // Setup to enumerate the values in the registry section (shown above).
  334. // For each such value, we'll add it to the ndisMediumArray
  335. //
  336. QueryTable[1].QueryRoutine = ndisAddMediaTypeToArray;
  337. QueryTable[1].DefaultType = REG_DWORD;
  338. QueryTable[1].DefaultData = (PVOID)&DefaultZero;
  339. QueryTable[1].DefaultLength = 0;
  340. QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
  341. QueryTable[1].Name = NULL;
  342. //
  343. // Query terminator
  344. //
  345. QueryTable[2].QueryRoutine = NULL;
  346. QueryTable[2].Flags = 0;
  347. QueryTable[2].Name = NULL;
  348. //
  349. // The rest of the work is done in the callback routine ndisAddMediaTypeToArray.
  350. //
  351. RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
  352. L"NDIS",
  353. QueryTable,
  354. (PVOID)NULL, // no context needed
  355. NULL);
  356. //
  357. // Switch to the parameters key below the service (NDIS) key and
  358. // read the parameters.
  359. //
  360. QueryTable[0].QueryRoutine = NULL;
  361. QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
  362. QueryTable[0].Name = L"Parameters";
  363. //
  364. // Read in the processor affinity mask.
  365. //
  366. QueryTable[1].QueryRoutine = ndisReadProcessorAffinityMask;
  367. QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
  368. QueryTable[1].DefaultData = (PVOID)&DefaultZero;
  369. QueryTable[1].DefaultLength = 0;
  370. QueryTable[1].DefaultType = REG_DWORD;
  371. QueryTable[1].Name = L"ProcessorAffinityMask";
  372. QueryTable[2].QueryRoutine = ndisReadRegParameters;
  373. QueryTable[2].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
  374. QueryTable[2].DefaultData = (PVOID)&ndisFlags;
  375. QueryTable[2].DefaultLength = 0;
  376. QueryTable[2].DefaultType = REG_DWORD;
  377. QueryTable[2].Name = L"Flags";
  378. QueryTable[2].EntryContext = (PVOID)&ndisFlags;
  379. QueryTable[3].QueryRoutine = ndisReadRegParameters;
  380. QueryTable[3].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
  381. QueryTable[3].DefaultData = (PVOID)&ndisPacketStackSize;
  382. QueryTable[3].DefaultLength = 0;
  383. QueryTable[3].DefaultType = REG_DWORD;
  384. QueryTable[3].Name = L"PacketStackSize";
  385. QueryTable[3].EntryContext = (PVOID)&ndisPacketStackSize;
  386. //
  387. // Query terminator
  388. //
  389. QueryTable[4].QueryRoutine = NULL;
  390. QueryTable[4].Flags = 0;
  391. QueryTable[4].Name = NULL;
  392. #if DBG
  393. #ifdef NDIS_TRACE
  394. ndisDebugBreakPoint = 1;
  395. ndisDebugLevel = 0;
  396. ndisDebugSystems = 0x3003;
  397. #else
  398. QueryTable[4].QueryRoutine = ndisReadRegParameters;
  399. QueryTable[4].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
  400. QueryTable[4].Name = L"DebugBreakPoint";
  401. QueryTable[4].DefaultData = (PVOID)&ndisDebugBreakPoint;
  402. QueryTable[4].DefaultLength = 0;
  403. QueryTable[4].EntryContext = (PVOID)&ndisDebugBreakPoint;
  404. QueryTable[4].DefaultType = REG_DWORD;
  405. QueryTable[5].QueryRoutine = ndisReadRegParameters;
  406. QueryTable[5].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
  407. QueryTable[5].Name = L"DebugLevel";
  408. QueryTable[5].DefaultData = (PVOID)&ndisDebugLevel;
  409. QueryTable[5].DefaultLength = 0;
  410. QueryTable[5].EntryContext = (PVOID)&ndisDebugLevel;
  411. QueryTable[5].DefaultType = REG_DWORD;
  412. QueryTable[6].QueryRoutine = ndisReadRegParameters;
  413. QueryTable[6].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
  414. QueryTable[6].Name = L"DebugSystems";
  415. QueryTable[6].DefaultData = (PVOID)&ndisDebugSystems;
  416. QueryTable[6].DefaultLength = 0;
  417. QueryTable[6].EntryContext = (PVOID)&ndisDebugSystems;
  418. QueryTable[6].DefaultType = REG_DWORD;
  419. //
  420. // Query terminator
  421. //
  422. QueryTable[7].QueryRoutine = NULL;
  423. QueryTable[7].Flags = 0;
  424. QueryTable[7].Name = NULL;
  425. #endif
  426. #endif
  427. //
  428. // The rest of the work is done in the callback routines
  429. //
  430. RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
  431. L"NDIS",
  432. QueryTable,
  433. (PVOID)NULL, // no context needed
  434. NULL);
  435. //
  436. // Make sure ndisPacketStackSize isn't zero
  437. //
  438. if (ndisPacketStackSize == 0)
  439. ndisPacketStackSize = 1;
  440. }
  441. NTSTATUS
  442. ndisReadRegParameters(
  443. IN PWSTR ValueName,
  444. IN ULONG ValueType,
  445. IN PVOID ValueData,
  446. IN ULONG ValueLength,
  447. IN PVOID Context,
  448. IN PVOID EntryContext
  449. )
  450. /*++
  451. Arguments:
  452. ValueName - The name of the value
  453. ValueType - The type of the value (REG_MULTI_SZ -- ignored).
  454. ValueData - The null-terminated data for the value.
  455. ValueLength - The length of ValueData.
  456. Context - Unused.
  457. EntryContext - A pointer to the pointer that holds the copied data.
  458. Return Value:
  459. STATUS_SUCCESS
  460. --*/
  461. {
  462. UNREFERENCED_PARAMETER(ValueName);
  463. UNREFERENCED_PARAMETER(ValueLength);
  464. UNREFERENCED_PARAMETER(Context);
  465. if ((ValueType != REG_DWORD) || (ValueData == NULL))
  466. return STATUS_UNSUCCESSFUL;
  467. *((PULONG)EntryContext) = *((PULONG)ValueData);
  468. return STATUS_SUCCESS;
  469. }
  470. NTSTATUS
  471. ndisReadProcessorAffinityMask(
  472. IN PWSTR ValueName,
  473. IN ULONG ValueType,
  474. IN PVOID ValueData,
  475. IN ULONG ValueLength,
  476. IN PVOID Context,
  477. IN PVOID EntryContext
  478. )
  479. /*++
  480. Routine Description:
  481. Arguments:
  482. Return Value:
  483. --*/
  484. {
  485. //
  486. // If we have valid data then build our array of valid processors
  487. // to use.... Treat the special case of 0 or default -1 to signify
  488. // that DPC affinity will follow interrupt affinity
  489. //
  490. if ((REG_DWORD == ValueType) && (ValueData != NULL))
  491. {
  492. if ((*(PULONG)ValueData == 0) ||
  493. (*(PULONG)ValueData == 0xFFFFFFFF))
  494. {
  495. ndisSkipProcessorAffinity = TRUE;
  496. }
  497. else
  498. {
  499. ULONG ProcessorAffinity;
  500. UCHAR c1, c2;
  501. //
  502. // Save the processor affinity.
  503. //
  504. ProcessorAffinity = *(PULONG)ValueData;
  505. //
  506. // Fill in the valid processor array.
  507. //
  508. for (c1 = c2 = 0;
  509. (c1 <= ndisMaximumProcessor) && (ProcessorAffinity != 0);
  510. c1++)
  511. {
  512. if (ProcessorAffinity & 1)
  513. {
  514. ndisValidProcessors[c2++] = c1;
  515. }
  516. ProcessorAffinity >>= 1;
  517. }
  518. ndisCurrentProcessor = ndisMaximumProcessor = c2 - 1;
  519. }
  520. }
  521. return STATUS_SUCCESS;
  522. }
  523. NTSTATUS
  524. ndisAddMediaTypeToArray(
  525. IN PWSTR ValueName,
  526. IN ULONG ValueType,
  527. IN PVOID ValueData,
  528. IN ULONG ValueLength,
  529. IN PVOID Context,
  530. IN PVOID EntryContext
  531. )
  532. {
  533. #if DBG
  534. NDIS_STRING Str;
  535. RtlInitUnicodeString(&Str, ValueName);
  536. #endif
  537. DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
  538. ("ExperimentalMediaType %Z - %x\n", &Str, *(PULONG)ValueData));
  539. //
  540. // Ignore all values that we already know about. These should not be in the
  541. // registry anyway, but just in case somebody is messing with it.
  542. //
  543. if ((ValueType == REG_DWORD) && (ValueData != NULL) && (*(PULONG)ValueData > NdisMediumIrda))
  544. {
  545. NDIS_MEDIUM *pTemp;
  546. ULONG size;
  547. //
  548. // See if we have enough space to add this value. If not allocate space for the
  549. // new array, copy the old one into this (and free the old if not static).
  550. //
  551. ASSERT (ndisMediumArraySize <= ndisMediumArrayMaxSize);
  552. //
  553. // Check for duplicates. If so drop it
  554. //
  555. for (pTemp = ndisMediumArray, size = ndisMediumArraySize;
  556. size > 0; pTemp ++, size -= sizeof(NDIS_MEDIUM))
  557. {
  558. if (*(NDIS_MEDIUM *)ValueData == *pTemp)
  559. {
  560. //
  561. // Duplicate.
  562. //
  563. return STATUS_SUCCESS;
  564. }
  565. }
  566. if (ndisMediumArraySize == ndisMediumArrayMaxSize)
  567. {
  568. //
  569. // We do not have any space in the array. Need to re-alloc. Be generous.
  570. //
  571. pTemp = (NDIS_MEDIUM *)ALLOC_FROM_POOL(ndisMediumArraySize + EXPERIMENTAL_SIZE*sizeof(NDIS_MEDIUM),
  572. NDIS_TAG_MEDIA_TYPE_ARRAY);
  573. if (pTemp != NULL)
  574. {
  575. CopyMemory(pTemp, ndisMediumArray, ndisMediumArraySize);
  576. if (ndisMediumArray != ndisMediumBuffer)
  577. {
  578. FREE_POOL(ndisMediumArray);
  579. }
  580. ndisMediumArray = pTemp;
  581. }
  582. }
  583. if (ndisMediumArraySize < ndisMediumArrayMaxSize)
  584. {
  585. ndisMediumArray[ndisMediumArraySize/sizeof(NDIS_MEDIUM)] = *(NDIS_MEDIUM *)ValueData;
  586. ndisMediumArraySize += sizeof(NDIS_MEDIUM);
  587. }
  588. }
  589. return STATUS_SUCCESS;
  590. }
  591. WORK_QUEUE_ITEM LastWorkerThreadWI = {0} ;
  592. VOID
  593. ndisWorkerThread(
  594. IN PVOID Context
  595. )
  596. /*++
  597. Routine Description:
  598. Arguments:
  599. Return Value:
  600. --*/
  601. {
  602. BOOLEAN FirstThread = (Context == NULL);
  603. PLIST_ENTRY pList;
  604. HANDLE ThreadHandle;
  605. PWORK_QUEUE_ITEM pWI;
  606. NTSTATUS Status;
  607. if (FirstThread)
  608. {
  609. ndisThreadObject = PsGetCurrentThread();
  610. ObReferenceObject(ndisThreadObject);
  611. do
  612. {
  613. //
  614. // Block here waiting for work-items to do
  615. //
  616. pList = KeRemoveQueue(&ndisWorkerQueue, KernelMode, NULL);
  617. DBGPRINT_RAW(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
  618. ("ndisWorkerThread: WorkItem %p\n", pList));
  619. pWI = CONTAINING_RECORD(pList, WORK_QUEUE_ITEM, List);
  620. #if NDIS_UNLOAD
  621. //
  622. // Unload asking us to quit, comply.
  623. //
  624. if (pWI == &ndisPoisonPill)
  625. {
  626. break;
  627. }
  628. #endif
  629. Status = PsCreateSystemThread(&ThreadHandle,
  630. THREAD_ALL_ACCESS,
  631. NULL,
  632. NtCurrentProcess(),
  633. NULL,
  634. ndisWorkerThread,
  635. pWI);
  636. if (NT_SUCCESS(Status))
  637. {
  638. NtClose(ThreadHandle);
  639. }
  640. else
  641. {
  642. DBGPRINT_RAW(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
  643. ("ndisWorkerThread: Failed to create a thread, using EX worker thread\n"));
  644. XQUEUE_WORK_ITEM(pWI, CriticalWorkQueue);
  645. ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
  646. }
  647. } while (TRUE);
  648. }
  649. else
  650. {
  651. //
  652. // Not the main thread, just do the thing and die.
  653. //
  654. LastWorkerThreadWI = *((PWORK_QUEUE_ITEM)Context);
  655. pWI = (PWORK_QUEUE_ITEM)Context;
  656. (*pWI->WorkerRoutine)(pWI->Parameter);
  657. ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
  658. }
  659. }
  660. NTSTATUS
  661. ndisDispatchRequest(
  662. IN PDEVICE_OBJECT pDeviceObject,
  663. IN PIRP pIrp
  664. )
  665. /*++
  666. Routine Description:
  667. Dispatcher for Irps intended for the NDIS Device.
  668. Arguments:
  669. Return Value:
  670. --*/
  671. {
  672. NTSTATUS Status = STATUS_SUCCESS;
  673. PIO_STACK_LOCATION pIrpSp;
  674. PNDIS_DEVICE_OBJECT_OPEN_CONTEXT OpenContext = NULL;
  675. NTSTATUS SecurityStatus;
  676. static LONG OpenCount = 0;
  677. pDeviceObject; // prevent compiler warnings
  678. PAGED_CODE( );
  679. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  680. pIrp->IoStatus.Status = STATUS_PENDING;
  681. pIrp->IoStatus.Information = 0;
  682. PnPReferencePackage();
  683. switch (pIrpSp->MajorFunction)
  684. {
  685. case IRP_MJ_CREATE:
  686. OpenContext = (PNDIS_DEVICE_OBJECT_OPEN_CONTEXT)ALLOC_FROM_POOL(sizeof(NDIS_DEVICE_OBJECT_OPEN_CONTEXT),
  687. NDIS_TAG_OPEN_CONTEXT);
  688. if (OpenContext == NULL)
  689. {
  690. Status = STATUS_INSUFFICIENT_RESOURCES;
  691. break;
  692. }
  693. ZeroMemory(OpenContext, sizeof(NDIS_DEVICE_OBJECT_OPEN_CONTEXT));
  694. OpenContext->AdminAccessAllowed = ndisCheckAccess(pIrp,
  695. pIrpSp,
  696. &SecurityStatus,
  697. ndisSecurityDescriptor);
  698. //
  699. // save the caller's access right
  700. //
  701. pIrpSp->FileObject->FsContext = OpenContext;
  702. Increment(&OpenCount, &Lock);
  703. break;
  704. case IRP_MJ_CLEANUP:
  705. OpenContext = pIrpSp->FileObject->FsContext;
  706. ASSERT(OpenContext != NULL);
  707. pIrpSp->FileObject->FsContext = NULL;
  708. FREE_POOL(OpenContext);
  709. Decrement(&OpenCount, &Lock);
  710. break;
  711. case IRP_MJ_CLOSE:
  712. break;
  713. case IRP_MJ_INTERNAL_DEVICE_CONTROL:
  714. break;
  715. case IRP_MJ_DEVICE_CONTROL:
  716. Status = ndisHandlePnPRequest(pIrp);
  717. break;
  718. default:
  719. Status = STATUS_NOT_IMPLEMENTED;
  720. break;
  721. }
  722. ASSERT (CURRENT_IRQL < DISPATCH_LEVEL);
  723. ASSERT (Status != STATUS_PENDING);
  724. pIrp->IoStatus.Status = Status;
  725. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  726. PnPDereferencePackage();
  727. return Status;
  728. }
  729. NTSTATUS
  730. ndispConvOffsetToPointer(
  731. IN PVOID MasterBuffer,
  732. IN ULONG MasterLength,
  733. IN OUT PULONG_PTR Offset,
  734. IN ULONG Length,
  735. IN ULONG Alignment
  736. )
  737. /*++
  738. Routine Description:
  739. This function validates a buffer within an IOCTL and converts a buffer
  740. offset to a pointer.
  741. Argumens:
  742. MasterBuffer - Pointer to the start of the IOCTL buffer
  743. MasterLength - Length of the IOCTL buffer
  744. Offset - Offset of the data buffer within the IOCTL buffer
  745. Length - Length of the data buffer within the IOCTL buffer
  746. Alignment - Required alignment of the type within the data buffer
  747. Return Value:
  748. The function status is the final status of the operation.
  749. --*/
  750. {
  751. ULONG_PTR masterStart;
  752. ULONG_PTR masterEnd;
  753. ULONG_PTR bufStart;
  754. ULONG_PTR bufEnd;
  755. if (Length == 0)
  756. {
  757. //
  758. // Nothing to do.
  759. //
  760. return STATUS_SUCCESS;
  761. }
  762. masterStart = (ULONG_PTR)MasterBuffer;
  763. masterEnd = masterStart + MasterLength;
  764. bufStart = masterStart + *Offset;
  765. bufEnd = bufStart + Length;
  766. //
  767. // Ensure that neither of the buffers wrap
  768. //
  769. if (masterEnd < masterStart || bufEnd < bufStart)
  770. {
  771. return STATUS_INVALID_PARAMETER;
  772. }
  773. //
  774. // Ensure that buf is wholly contained within master
  775. //
  776. if (bufStart < masterStart || bufEnd > masterEnd)
  777. {
  778. return STATUS_INVALID_PARAMETER;
  779. }
  780. //
  781. // Make sure that buf is properly aligned
  782. //
  783. if ((bufStart & (Alignment - 1)) != 0)
  784. {
  785. return STATUS_INVALID_PARAMETER;
  786. }
  787. //
  788. // Everything looks good, perform the conversion
  789. //
  790. *Offset += masterStart;
  791. return STATUS_SUCCESS;
  792. }
  793. NTSTATUS
  794. ndispConvVar(
  795. IN PVOID MasterBuffer,
  796. IN ULONG MasterLength,
  797. IN OUT PNDIS_VAR_DATA_DESC Var
  798. )
  799. /*++
  800. Routine Description:
  801. This function validates an NDIS_VAR_DATA_DESC buffer within an IOCTL
  802. and converts its data offset to a pointer.
  803. Argumens:
  804. MasterBuffer - Pointer to the start of the IOCTL buffer
  805. MasterLength - Length of the IOCTL buffer
  806. Var - Pointer to an NDIS_VAR_DATA_DESC structure.
  807. Return Value:
  808. The function status is the final status of the operation.
  809. --*/
  810. {
  811. return ndispConvOffsetToPointer( MasterBuffer,
  812. MasterLength,
  813. &Var->Offset,
  814. Var->Length,
  815. sizeof(WCHAR) );
  816. }
  817. NTSTATUS
  818. FASTCALL
  819. ndisHandlePnPRequest(
  820. IN PIRP pIrp
  821. )
  822. /*++
  823. Routine Description:
  824. Handler for PnP ioctls.
  825. Arguments:
  826. Return Value:
  827. --*/
  828. {
  829. NTSTATUS Status = STATUS_SUCCESS;
  830. PNDIS_PNP_OPERATION PnPOp;
  831. PNDIS_ENUM_INTF EnumIntf;
  832. PIO_STACK_LOCATION pIrpSp;
  833. UNICODE_STRING Device;
  834. ULONG Method;
  835. PVOID pBuf;
  836. UINT iBufLen, oBufLen;
  837. UINT AmtCopied;
  838. #if defined(_WIN64)
  839. PUCHAR pThunkBuf = NULL; // in case we thunk from 32-bit
  840. #endif
  841. PNDIS_DEVICE_OBJECT_OPEN_CONTEXT OpenContext;
  842. BOOLEAN AdminAccessAllowed = FALSE;
  843. PAGED_CODE( );
  844. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  845. OpenContext = pIrpSp->FileObject->FsContext;
  846. if (OpenContext == NULL)
  847. {
  848. return STATUS_NO_SUCH_FILE;
  849. }
  850. AdminAccessAllowed = OpenContext->AdminAccessAllowed;
  851. Method = pIrpSp->Parameters.DeviceIoControl.IoControlCode & 3;
  852. // Ensure that the method is buffered - we always use that.
  853. if (Method == METHOD_BUFFERED)
  854. {
  855. // Get the output buffer and its length. Input and Output buffers are
  856. // both pointed to by the SystemBuffer
  857. iBufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
  858. oBufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  859. pBuf = pIrp->AssociatedIrp.SystemBuffer;
  860. }
  861. else
  862. {
  863. return STATUS_INVALID_PARAMETER;
  864. }
  865. switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode)
  866. {
  867. case IOCTL_NDIS_ADD_TDI_DEVICE:
  868. if (!AdminAccessAllowed)
  869. {
  870. return STATUS_ACCESS_DENIED;
  871. }
  872. //
  873. // Validate the DeviceName
  874. //
  875. Status = STATUS_INVALID_PARAMETER;
  876. if ((iBufLen > 0) && ((iBufLen % sizeof(WCHAR)) == 0))
  877. {
  878. ((PWCHAR)pBuf)[iBufLen/sizeof(WCHAR) - 1] = 0;
  879. RtlInitUnicodeString(&Device, pBuf);
  880. Status = ndisHandleLegacyTransport(&Device);
  881. }
  882. break;
  883. case IOCTL_NDIS_DO_PNP_OPERATION:
  884. if (!AdminAccessAllowed)
  885. {
  886. return STATUS_ACCESS_DENIED;
  887. }
  888. Status = STATUS_BUFFER_TOO_SMALL;
  889. PnPOp = (PNDIS_PNP_OPERATION)pBuf;
  890. #if defined(_WIN64)
  891. if (IoIs32bitProcess(pIrp))
  892. {
  893. PNDIS_PNP_OPERATION32 PnPOp32;
  894. PUCHAR ThunkPtr;
  895. PnPOp32 = (PNDIS_PNP_OPERATION32)pBuf;
  896. //
  897. // Validate structure based on its 32-bit definition
  898. //
  899. if ((iBufLen < sizeof(NDIS_PNP_OPERATION32)) ||
  900. (iBufLen < sizeof(NDIS_PNP_OPERATION32) +
  901. PnPOp32->LowerComponent.MaximumLength +
  902. PnPOp32->UpperComponent.MaximumLength))
  903. {
  904. break;
  905. }
  906. pThunkBuf = ALLOC_FROM_POOL(sizeof(NDIS_PNP_OPERATION) +
  907. PnPOp32->LowerComponent.MaximumLength +
  908. PnPOp32->UpperComponent.MaximumLength, NDIS_TAG_DEFAULT);
  909. if (pThunkBuf == NULL)
  910. {
  911. Status = STATUS_INSUFFICIENT_RESOURCES;
  912. break;
  913. }
  914. PnPOp = (PNDIS_PNP_OPERATION)pThunkBuf;
  915. PnPOp->Layer = PnPOp32->Layer;
  916. PnPOp->Operation = PnPOp32->Operation;
  917. ThunkPtr = (PUCHAR)PnPOp + sizeof(NDIS_PNP_OPERATION);
  918. //
  919. // LowerComponent:
  920. //
  921. PnPOp->LowerComponent.MaximumLength = PnPOp32->LowerComponent.MaximumLength;
  922. PnPOp->LowerComponent.Length = PnPOp32->LowerComponent.Length;
  923. PnPOp->LowerComponent.Offset = ThunkPtr - (PUCHAR)&PnPOp->LowerComponent;
  924. NdisMoveMemory((PUCHAR)ThunkPtr, (PUCHAR)&PnPOp32->LowerComponent + PnPOp32->LowerComponent.Offset, PnPOp32->LowerComponent.MaximumLength);
  925. ThunkPtr += PnPOp->LowerComponent.MaximumLength;
  926. //
  927. // UpperComponent:
  928. //
  929. PnPOp->UpperComponent.MaximumLength = PnPOp32->UpperComponent.MaximumLength;
  930. PnPOp->UpperComponent.Length = PnPOp32->UpperComponent.Length;
  931. PnPOp->UpperComponent.Offset = ThunkPtr - (PUCHAR)&PnPOp->UpperComponent;
  932. NdisMoveMemory((PUCHAR)ThunkPtr, (PUCHAR)&PnPOp32->UpperComponent + PnPOp32->UpperComponent.Offset, PnPOp32->UpperComponent.MaximumLength);
  933. ThunkPtr += PnPOp->UpperComponent.MaximumLength;
  934. //
  935. // BindList:
  936. //
  937. PnPOp->BindList.MaximumLength = PnPOp32->BindList.MaximumLength;
  938. PnPOp->BindList.Length = PnPOp32->BindList.Length;
  939. PnPOp->BindList.Offset = ThunkPtr - (PUCHAR)&PnPOp->BindList;
  940. NdisMoveMemory((PUCHAR)ThunkPtr, (PUCHAR)&PnPOp32->BindList + PnPOp32->BindList.Offset, PnPOp32->BindList.MaximumLength);
  941. ThunkPtr += PnPOp->BindList.MaximumLength;
  942. }
  943. else
  944. {
  945. //
  946. // Not a 32-bit process on Win64
  947. //
  948. if ((iBufLen < sizeof(NDIS_PNP_OPERATION)) ||
  949. (iBufLen < (sizeof(NDIS_PNP_OPERATION) +
  950. PnPOp->LowerComponent.MaximumLength +
  951. PnPOp->UpperComponent.MaximumLength)))
  952. {
  953. break;
  954. }
  955. }
  956. #else
  957. if ((iBufLen < sizeof(NDIS_PNP_OPERATION)) ||
  958. (iBufLen < (sizeof(NDIS_PNP_OPERATION) +
  959. PnPOp->LowerComponent.MaximumLength +
  960. PnPOp->UpperComponent.MaximumLength)))
  961. {
  962. break;
  963. }
  964. #endif // _WIN64
  965. //
  966. // Convert the four buffer offsets within NDIS_PNP_OPERATION
  967. // to pointers.
  968. //
  969. Status = ndispConvVar( PnPOp, iBufLen, &PnPOp->LowerComponent );
  970. if (!NT_SUCCESS(Status))
  971. {
  972. break;
  973. }
  974. Status = ndispConvVar( PnPOp, iBufLen, &PnPOp->UpperComponent );
  975. if (!NT_SUCCESS(Status))
  976. {
  977. break;
  978. }
  979. Status = ndispConvVar( PnPOp, iBufLen, &PnPOp->BindList );
  980. if (!NT_SUCCESS(Status))
  981. {
  982. break;
  983. }
  984. Status = ndispConvOffsetToPointer( PnPOp,
  985. iBufLen,
  986. &PnPOp->ReConfigBufferOff,
  987. PnPOp->ReConfigBufferSize,
  988. sizeof(ULONG_PTR) );
  989. if (!NT_SUCCESS(Status))
  990. {
  991. break;
  992. }
  993. Status = ndisHandleUModePnPOp(PnPOp);
  994. break;
  995. case IOCTL_NDIS_ENUMERATE_INTERFACES:
  996. #if defined(_WIN64)
  997. if (IoIs32bitProcess(pIrp))
  998. {
  999. if (oBufLen >= sizeof(NDIS_ENUM_INTF32))
  1000. {
  1001. Status = ndisEnumerateInterfaces32(pBuf, oBufLen);
  1002. pIrp->IoStatus.Information = oBufLen;
  1003. }
  1004. else
  1005. {
  1006. Status = STATUS_BUFFER_TOO_SMALL;
  1007. }
  1008. break;
  1009. }
  1010. #endif
  1011. if (oBufLen >= sizeof(NDIS_ENUM_INTF))
  1012. {
  1013. EnumIntf = (PNDIS_ENUM_INTF)pBuf;
  1014. Status = ndisEnumerateInterfaces(pBuf, oBufLen);
  1015. pIrp->IoStatus.Information = oBufLen;
  1016. }
  1017. else Status = STATUS_BUFFER_TOO_SMALL;
  1018. break;
  1019. case IOCTL_NDIS_GET_VERSION:
  1020. if (oBufLen < sizeof(UINT))
  1021. {
  1022. Status = STATUS_BUFFER_TOO_SMALL;
  1023. }
  1024. else
  1025. {
  1026. *((PUINT)pBuf) = NdisGetVersion();
  1027. if (oBufLen >= 2 * sizeof(UINT))
  1028. {
  1029. *((PUINT)pBuf + 1) = (UINT)ndisChecked;
  1030. }
  1031. Status = STATUS_SUCCESS;
  1032. }
  1033. break;
  1034. default:
  1035. break;
  1036. }
  1037. ASSERT (CURRENT_IRQL < DISPATCH_LEVEL);
  1038. #if defined(_WIN64)
  1039. if (pThunkBuf)
  1040. {
  1041. FREE_POOL(pThunkBuf);
  1042. }
  1043. #endif
  1044. return Status;
  1045. }
  1046. NTSTATUS
  1047. FASTCALL
  1048. ndisHandleUModePnPOp(
  1049. IN PNDIS_PNP_OPERATION PnPOp
  1050. )
  1051. /*++
  1052. Routine Description:
  1053. Arguments:
  1054. Return Value:
  1055. --*/
  1056. {
  1057. NTSTATUS Status;
  1058. PUNICODE_STRING Protocol, Device, BindList;
  1059. WAIT_FOR_OBJECT(&ndisPnPMutex, NULL);
  1060. ndisPnPMutexOwner = MODULE_NUMBER + __LINE__;
  1061. //
  1062. // Upcase the protocol and device names
  1063. //
  1064. Protocol = (PUNICODE_STRING)&PnPOp->UpperComponent;
  1065. Device = (PUNICODE_STRING)&PnPOp->LowerComponent;
  1066. BindList = (PUNICODE_STRING)&PnPOp->BindList;
  1067. if (PnPOp->Operation == BIND)
  1068. {
  1069. DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
  1070. ("BIND (%s) %Z to %Z\n", (PnPOp->Layer == NDIS) ? "NDIS" : "TDI ", Protocol, Device));
  1071. }
  1072. else if (PnPOp->Operation == UNBIND)
  1073. {
  1074. DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
  1075. ("UNBIND(%s) %Z to %Z\n", (PnPOp->Layer == NDIS) ? "NDIS" : "TDI ", Protocol, Device));
  1076. }
  1077. switch (PnPOp->Layer)
  1078. {
  1079. case TDI:
  1080. //
  1081. // Call into the TDI handler to do this
  1082. //
  1083. if (ndisTdiPnPHandler != NULL)
  1084. {
  1085. Status = (*ndisTdiPnPHandler)(Protocol,
  1086. Device,
  1087. BindList,
  1088. PnPOp->ReConfigBufferPtr,
  1089. PnPOp->ReConfigBufferSize,
  1090. PnPOp->Operation);
  1091. }
  1092. else
  1093. {
  1094. Status = STATUS_UNSUCCESSFUL;
  1095. }
  1096. break;
  1097. case NDIS:
  1098. switch (PnPOp->Operation)
  1099. {
  1100. case BIND:
  1101. Status = ndisHandleProtocolBindNotification(Device, Protocol);
  1102. break;
  1103. case UNBIND:
  1104. Status = ndisHandleProtocolUnbindNotification(Device, Protocol);
  1105. break;
  1106. case RECONFIGURE:
  1107. case BIND_LIST:
  1108. Status = ndisHandleProtocolReconfigNotification(Device,
  1109. Protocol,
  1110. PnPOp->ReConfigBufferPtr,
  1111. PnPOp->ReConfigBufferSize,
  1112. PnPOp->Operation);
  1113. break;
  1114. case UNLOAD:
  1115. Status = ndisHandleProtocolUnloadNotification(Protocol);
  1116. break;
  1117. case REMOVE_DEVICE:
  1118. Status = ndisHandleOrphanDevice(Device);
  1119. break;
  1120. default:
  1121. Status = STATUS_INVALID_PARAMETER;
  1122. break;
  1123. }
  1124. break;
  1125. default:
  1126. Status = STATUS_INVALID_PARAMETER;
  1127. break;
  1128. }
  1129. ndisPnPMutexOwner = 0;
  1130. RELEASE_MUTEX(&ndisPnPMutex);
  1131. return Status;
  1132. }
  1133. NTSTATUS
  1134. FASTCALL
  1135. ndisHandleProtocolBindNotification(
  1136. IN PUNICODE_STRING DeviceName,
  1137. IN PUNICODE_STRING ProtocolName
  1138. )
  1139. /*++
  1140. Routine Description:
  1141. Given a erotocol's name and an adapter's name, this routine creates a binding between
  1142. a protocol and an adapter (assuming protocol has a BindAdapterHandler)
  1143. Arguments:
  1144. DeviceName: Adapter device name i.e. \Device\{GUID}
  1145. ProtocolName Protocols name i.e. TCPIP
  1146. Return Value:
  1147. STATUS_SUCCESS if we could call BindAdapterHandler
  1148. STATUS_UNSUCCESSFUL otherwise
  1149. Note
  1150. This routine does not return the status of attempted bind, rather if it -could- attempt to bind!
  1151. --*/
  1152. {
  1153. NTSTATUS Status = STATUS_SUCCESS;
  1154. PNDIS_PROTOCOL_BLOCK Protocol = NULL;
  1155. PNDIS_MINIPORT_BLOCK Miniport = NULL;
  1156. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  1157. ("==>ndisHandleProtocolBindNotification\n"));
  1158. do
  1159. {
  1160. ndisReferenceMiniportByName(DeviceName, &Miniport);
  1161. if (Miniport == NULL)
  1162. {
  1163. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  1164. break;
  1165. }
  1166. //
  1167. // Map ProtocolName to the Protocol block
  1168. //
  1169. Status = ndisReferenceProtocolByName(ProtocolName, &Protocol, FALSE);
  1170. if (!NT_SUCCESS(Status))
  1171. {
  1172. Protocol = NULL;
  1173. Status = STATUS_SUCCESS;
  1174. break;
  1175. }
  1176. //
  1177. // Bind this protocols
  1178. //
  1179. ndisCheckAdapterBindings(Miniport, Protocol);
  1180. } while (FALSE);
  1181. if (Protocol != NULL)
  1182. {
  1183. ndisDereferenceProtocol(Protocol);
  1184. }
  1185. if (Miniport != NULL)
  1186. {
  1187. MINIPORT_DECREMENT_REF(Miniport);
  1188. }
  1189. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  1190. ("<==ndisHandleProtocolBindNotification\n"));
  1191. return Status;
  1192. }
  1193. NTSTATUS
  1194. FASTCALL
  1195. ndisHandleProtocolUnbindNotification(
  1196. IN PUNICODE_STRING DeviceName,
  1197. IN PUNICODE_STRING ProtocolName
  1198. )
  1199. /*++
  1200. Routine Description:
  1201. Arguments:
  1202. Return Value:
  1203. --*/
  1204. {
  1205. NTSTATUS Status;
  1206. PNDIS_OPEN_BLOCK Open;
  1207. PNDIS_PROTOCOL_BLOCK Protocol = NULL;
  1208. PNDIS_MINIPORT_BLOCK Miniport = NULL;
  1209. BOOLEAN fPartial = FALSE;
  1210. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  1211. ("==>ndisHandleProtocolUnbindNotification\n"));
  1212. do
  1213. {
  1214. //
  1215. // Map ProtocolName to the Protocol block
  1216. //
  1217. Status = ndisReferenceProtocolByName(ProtocolName, &Protocol, FALSE);
  1218. if (!NT_SUCCESS(Status))
  1219. {
  1220. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  1221. ("ndisHandleProtocolUnbindNotification: ndisReferenceProtocolByName failed %lx\n", Status));
  1222. Status = STATUS_SUCCESS;
  1223. Protocol = NULL;
  1224. break;
  1225. }
  1226. do
  1227. {
  1228. Open = ndisMapOpenByName(DeviceName, Protocol, TRUE, TRUE);
  1229. if (Open == NULL)
  1230. {
  1231. //
  1232. // There is no -active- binding between this adapter and protocol.
  1233. // This would normally be an error but we need one special case for
  1234. // TCP/IP Arp modules. We can unbind notifications for TCP/IP which
  1235. // are actually destined for the ARP module.
  1236. // We also know that either TCP/IP or ONE and ONLY ONE arp module can be
  1237. // bound to an adapter. Make use of that knowledge.
  1238. //
  1239. ndisDereferenceProtocol(Protocol);
  1240. if (!fPartial)
  1241. {
  1242. fPartial = TRUE;
  1243. Protocol = NULL;
  1244. }
  1245. Status = ndisReferenceProtocolByName(ProtocolName, &Protocol, TRUE);
  1246. if (!NT_SUCCESS(Status))
  1247. {
  1248. break;
  1249. }
  1250. }
  1251. } while (Open == NULL);
  1252. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  1253. ("ndisHandleProtocolUnbindNotification: Open %p\n", Open));
  1254. if (Open != NULL)
  1255. {
  1256. Miniport = Open->MiniportHandle;
  1257. Status = ndisUnbindProtocol(Open, TRUE);
  1258. if (Status != NDIS_STATUS_SUCCESS)
  1259. {
  1260. KIRQL OldIrql;
  1261. PNDIS_OPEN_BLOCK tmpOpen;
  1262. //
  1263. // check to see if the open is still there and if it is
  1264. // clear the UNBIND flag. Note that we were the one
  1265. // setting the flag, so we can clear it ourselves
  1266. //
  1267. ACQUIRE_SPIN_LOCK(&Protocol->Ref.SpinLock, &OldIrql);
  1268. for (tmpOpen = Protocol->OpenQueue;
  1269. tmpOpen != NULL;
  1270. tmpOpen = tmpOpen->ProtocolNextOpen)
  1271. {
  1272. if(tmpOpen == Open)
  1273. {
  1274. ACQUIRE_SPIN_LOCK_DPC(&Open->SpinLock);
  1275. MINIPORT_CLEAR_FLAG(Open, fMINIPORT_OPEN_UNBINDING |
  1276. fMINIPORT_OPEN_DONT_FREE |
  1277. fMINIPORT_OPEN_PROCESSING);
  1278. RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
  1279. break;
  1280. }
  1281. }
  1282. RELEASE_SPIN_LOCK(&Protocol->Ref.SpinLock, OldIrql);
  1283. }
  1284. }
  1285. } while (FALSE);
  1286. if (Miniport != NULL)
  1287. {
  1288. MINIPORT_DECREMENT_REF(Miniport);
  1289. }
  1290. if (Protocol != NULL)
  1291. {
  1292. ndisDereferenceProtocol(Protocol);
  1293. }
  1294. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  1295. ("<==ndisHandleProtocolUnbindNotification: Protocol %p, Status %lx\n", Protocol, Status));
  1296. return Status;
  1297. }
  1298. NTSTATUS
  1299. ndisHandleProtocolReconfigNotification(
  1300. IN PUNICODE_STRING DeviceName,
  1301. IN PUNICODE_STRING ProtocolName,
  1302. IN PVOID ReConfigBuffer,
  1303. IN UINT ReConfigBufferSize,
  1304. IN UINT Operation
  1305. )
  1306. /*++
  1307. Routine Description:
  1308. This routine will notify protocols of a cahnge in their configuration -or-
  1309. their bind list
  1310. Arguments:
  1311. DeviceName: Adapter's name (if specified). if NULL, it means the change is global and not bind specific
  1312. ProtocolName: Protocol's name
  1313. ReConfigBuffer: information buffer
  1314. ReConfigBufferSize: Information buffer size
  1315. Operation: RECONFIGURE or BIND_LIST
  1316. Return Value:
  1317. --*/
  1318. {
  1319. NTSTATUS Status;
  1320. KIRQL OldIrql;
  1321. PNDIS_PROTOCOL_BLOCK Protocol = NULL;
  1322. PNDIS_OPEN_BLOCK Open = NULL;
  1323. NET_PNP_EVENT NetPnpEvent;
  1324. PNDIS_PNP_EVENT_RESERVED EventReserved;
  1325. KEVENT Event;
  1326. BOOLEAN fPartial = FALSE;
  1327. DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
  1328. ("==>ndisHandleProtocolReconfigNotification\n"));
  1329. do
  1330. {
  1331. //
  1332. // Map ProtocolName to the Protocol block
  1333. //
  1334. Status = ndisReferenceProtocolByName(ProtocolName, &Protocol, FALSE);
  1335. if (!NT_SUCCESS(Status))
  1336. {
  1337. Protocol = NULL;
  1338. break;
  1339. }
  1340. //
  1341. // We can be passed a NULL device-name which implies global reconfig and we call
  1342. // the protocol's event handler with a NULL BindingContext
  1343. //
  1344. if (DeviceName->Length != 0)
  1345. {
  1346. ASSERT(Operation == RECONFIGURE);
  1347. do
  1348. {
  1349. WAIT_FOR_PROTO_MUTEX(Protocol);
  1350. Open = ndisMapOpenByName(DeviceName, Protocol, FALSE, FALSE);
  1351. if (Open == NULL)
  1352. {
  1353. RELEASE_PROT_MUTEX(Protocol);
  1354. //
  1355. // There is no -active- binding between this adapter and protocol.
  1356. // This would normally be an error but we need one special case for
  1357. // TCP/IP Arp modules. We can unbind notifications for TCP/IP which
  1358. // are actually destined for the ARP module.
  1359. // We also know that either TCP/IP or ONE and ONLY ONE arp module can be
  1360. // bound to an adapter. Make use of that knowledge.
  1361. //
  1362. ndisDereferenceProtocol(Protocol);
  1363. if (!fPartial)
  1364. {
  1365. fPartial = TRUE;
  1366. Protocol = NULL;
  1367. }
  1368. Status = ndisReferenceProtocolByName(ProtocolName, &Protocol, TRUE);
  1369. if (!NT_SUCCESS(Status))
  1370. {
  1371. break;
  1372. }
  1373. }
  1374. } while (Open == NULL);
  1375. if (Open == NULL)
  1376. {
  1377. //
  1378. // if Open == NULL we are not holding the protocol mutex
  1379. //
  1380. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  1381. break;
  1382. }
  1383. else if (Protocol->ProtocolCharacteristics.PnPEventHandler == NULL)
  1384. {
  1385. //
  1386. // Open is not NULL, we -are- holding the protocol mutex. release
  1387. // it before breaking out
  1388. //
  1389. RELEASE_PROT_MUTEX(Protocol);
  1390. Status = STATUS_UNSUCCESSFUL;
  1391. break;
  1392. }
  1393. }
  1394. else
  1395. {
  1396. //
  1397. // the device is NULL, just grab the protocol mutex
  1398. //
  1399. if (Protocol->ProtocolCharacteristics.PnPEventHandler != NULL)
  1400. {
  1401. WAIT_FOR_PROTO_MUTEX(Protocol);
  1402. }
  1403. else
  1404. {
  1405. Status = STATUS_UNSUCCESSFUL;
  1406. break;
  1407. }
  1408. }
  1409. //
  1410. // Setup the PnPEvent buffer
  1411. //
  1412. NdisZeroMemory(&NetPnpEvent, sizeof(NetPnpEvent));
  1413. switch (Operation)
  1414. {
  1415. case RECONFIGURE:
  1416. NetPnpEvent.NetEvent = NetEventReconfigure;
  1417. break;
  1418. case BIND_LIST:
  1419. NetPnpEvent.NetEvent = NetEventBindList;
  1420. break;
  1421. default:
  1422. ASSERT(FALSE);
  1423. break;
  1424. }
  1425. NetPnpEvent.Buffer = ReConfigBuffer;
  1426. NetPnpEvent.BufferLength = ReConfigBufferSize;
  1427. //
  1428. // Get a pointer to the NDIS reserved are in the PnP event.
  1429. //
  1430. EventReserved = PNDIS_PNP_EVENT_RESERVED_FROM_NET_PNP_EVENT(&NetPnpEvent);
  1431. INITIALIZE_EVENT(&Event);
  1432. EventReserved->pEvent = &Event;
  1433. //
  1434. // Notify the protocol now
  1435. //
  1436. Status = (Protocol->ProtocolCharacteristics.PnPEventHandler)(
  1437. (Open != NULL) ? Open->ProtocolBindingContext : NULL,
  1438. &NetPnpEvent);
  1439. if (NDIS_STATUS_PENDING == Status)
  1440. {
  1441. //
  1442. // Wait for completion.
  1443. //
  1444. WAIT_FOR_PROTOCOL(Protocol, &Event);
  1445. //
  1446. // Get the completion status.
  1447. //
  1448. Status = EventReserved->Status;
  1449. }
  1450. if (Open)
  1451. {
  1452. ACQUIRE_SPIN_LOCK(&Open->SpinLock, &OldIrql);
  1453. MINIPORT_CLEAR_FLAG(Open, fMINIPORT_OPEN_PROCESSING);
  1454. RELEASE_SPIN_LOCK(&Open->SpinLock, OldIrql);
  1455. }
  1456. RELEASE_PROT_MUTEX(Protocol);
  1457. } while (FALSE);
  1458. if (Protocol != NULL)
  1459. {
  1460. ndisDereferenceProtocol(Protocol);
  1461. }
  1462. DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
  1463. ("<==ndisHandleProtocolReconfigNotification\n"));
  1464. return Status;
  1465. }
  1466. NTSTATUS
  1467. FASTCALL
  1468. ndisHandleProtocolUnloadNotification(
  1469. IN PUNICODE_STRING ProtocolName
  1470. )
  1471. /*++
  1472. Routine Description:
  1473. Arguments:
  1474. Return Value:
  1475. --*/
  1476. {
  1477. NTSTATUS Status;
  1478. PNDIS_PROTOCOL_BLOCK Protocol = NULL;
  1479. DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
  1480. ("==>ndisHandleProtocolUnloadNotification\n"));
  1481. //
  1482. // Map ProtocolName to the Protocol block
  1483. //
  1484. Status = ndisReferenceProtocolByName(ProtocolName, &Protocol, FALSE);
  1485. if (NT_SUCCESS(Status))
  1486. {
  1487. ndisDereferenceProtocol(Protocol);
  1488. if (Protocol->ProtocolCharacteristics.UnloadHandler != NULL)
  1489. {
  1490. (Protocol->ProtocolCharacteristics.UnloadHandler)();
  1491. }
  1492. else
  1493. {
  1494. Status = STATUS_UNSUCCESSFUL;
  1495. }
  1496. }
  1497. DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
  1498. ("<==ndisHandleProtocolUnloadNotification\n"));
  1499. return Status;
  1500. }
  1501. NTSTATUS
  1502. FASTCALL
  1503. ndisHandleOrphanDevice(
  1504. IN PUNICODE_STRING pDevice
  1505. )
  1506. /*++
  1507. Routine Description:
  1508. Arguments:
  1509. Return Value:
  1510. --*/
  1511. {
  1512. NTSTATUS Status;
  1513. KIRQL OldIrql;
  1514. BOOLEAN fFound = FALSE;
  1515. PNDIS_M_DRIVER_BLOCK MiniBlock;
  1516. PNDIS_MINIPORT_BLOCK Miniport = NULL;
  1517. UNICODE_STRING UpcaseDevice;
  1518. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1519. ("==>ndisHandleOrphanDevice\n"));
  1520. UpcaseDevice.Length = pDevice->Length;
  1521. UpcaseDevice.MaximumLength = pDevice->Length + sizeof(WCHAR);
  1522. UpcaseDevice.Buffer = ALLOC_FROM_POOL(UpcaseDevice.MaximumLength, NDIS_TAG_STRING);
  1523. if (UpcaseDevice.Buffer == NULL)
  1524. {
  1525. return STATUS_INSUFFICIENT_RESOURCES;
  1526. }
  1527. Status = RtlUpcaseUnicodeString(&UpcaseDevice, pDevice, FALSE);
  1528. ASSERT (NT_SUCCESS(Status));
  1529. ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
  1530. for (MiniBlock = ndisMiniDriverList;
  1531. (MiniBlock != NULL) && !fFound;
  1532. MiniBlock = MiniBlock->NextDriver)
  1533. {
  1534. ACQUIRE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
  1535. for (Miniport = MiniBlock->MiniportQueue;
  1536. Miniport != NULL;
  1537. Miniport = Miniport->NextMiniport)
  1538. {
  1539. if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &Miniport->MiniportName))
  1540. {
  1541. fFound = TRUE;
  1542. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  1543. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_ORPHANED);
  1544. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  1545. break;
  1546. }
  1547. }
  1548. RELEASE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
  1549. }
  1550. RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
  1551. FREE_POOL(UpcaseDevice.Buffer);
  1552. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1553. ("<==ndisHandleOrphanDevice\n"));
  1554. return STATUS_SUCCESS;
  1555. }
  1556. NTSTATUS
  1557. FASTCALL
  1558. ndisEnumerateInterfaces(
  1559. IN PNDIS_ENUM_INTF EnumIntf,
  1560. IN UINT BufferLength
  1561. )
  1562. {
  1563. PNDIS_MINIPORT_BLOCK Miniport;
  1564. PNDIS_M_DRIVER_BLOCK MiniBlock;
  1565. PNDIS_INTERFACE Interface;
  1566. UINT SpaceLeft = BufferLength - sizeof(NDIS_ENUM_INTF);
  1567. UINT SpaceNeeded;
  1568. PUCHAR pBuf;
  1569. KIRQL OldIrql;
  1570. NTSTATUS Status = STATUS_SUCCESS;
  1571. NdisZeroMemory(EnumIntf, BufferLength);
  1572. Interface = &EnumIntf->Interface[0];
  1573. pBuf = (PUCHAR)EnumIntf + BufferLength;
  1574. ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
  1575. for (MiniBlock = ndisMiniDriverList;
  1576. MiniBlock != NULL;
  1577. MiniBlock = MiniBlock->NextDriver)
  1578. {
  1579. ACQUIRE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
  1580. for (Miniport = MiniBlock->MiniportQueue;
  1581. Miniport != NULL;
  1582. Miniport = Miniport->NextMiniport)
  1583. {
  1584. if (Miniport->PnPDeviceState != NdisPnPDeviceStarted)
  1585. {
  1586. continue;
  1587. }
  1588. EnumIntf->AvailableInterfaces ++;
  1589. SpaceNeeded = sizeof(NDIS_INTERFACE) +
  1590. Miniport->MiniportName.Length +
  1591. Miniport->pAdapterInstanceName->Length;
  1592. EnumIntf->BytesNeeded += SpaceNeeded;
  1593. if (SpaceLeft >= SpaceNeeded)
  1594. {
  1595. EnumIntf->TotalInterfaces ++;
  1596. SpaceLeft -= SpaceNeeded;
  1597. pBuf -= Miniport->MiniportName.Length;
  1598. Interface->DeviceName.Buffer = (PWSTR)pBuf;
  1599. Interface->DeviceName.MaximumLength =
  1600. Interface->DeviceName.Length = Miniport->MiniportName.Length;
  1601. CopyMemory(pBuf, Miniport->MiniportName.Buffer, Interface->DeviceName.Length);
  1602. POINTER_TO_OFFSET(Interface->DeviceName.Buffer, EnumIntf);
  1603. pBuf -= Miniport->pAdapterInstanceName->Length;
  1604. Interface->DeviceDescription.Buffer = (PWSTR)pBuf;
  1605. Interface->DeviceDescription.MaximumLength =
  1606. Interface->DeviceDescription.Length = Miniport->pAdapterInstanceName->Length;
  1607. CopyMemory(pBuf, Miniport->pAdapterInstanceName->Buffer, Interface->DeviceDescription.Length);
  1608. POINTER_TO_OFFSET(Interface->DeviceDescription.Buffer, EnumIntf);
  1609. Interface ++;
  1610. }
  1611. }
  1612. RELEASE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
  1613. }
  1614. RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
  1615. return Status;
  1616. }
  1617. #if defined(_WIN64)
  1618. //
  1619. // Version of ndisEnumerateInterfaces that operates on 32-bit ioctl structures.
  1620. // This is to support 32-bit apps running on Win64.
  1621. //
  1622. NTSTATUS
  1623. FASTCALL
  1624. ndisEnumerateInterfaces32(
  1625. IN PNDIS_ENUM_INTF32 EnumIntf,
  1626. IN UINT BufferLength
  1627. )
  1628. {
  1629. PNDIS_MINIPORT_BLOCK Miniport;
  1630. PNDIS_M_DRIVER_BLOCK MiniBlock;
  1631. PNDIS_INTERFACE32 Interface;
  1632. UINT SpaceLeft = BufferLength - sizeof(NDIS_ENUM_INTF32);
  1633. UINT SpaceNeeded;
  1634. PUCHAR pBuf;
  1635. KIRQL OldIrql;
  1636. NTSTATUS Status = STATUS_SUCCESS;
  1637. NdisZeroMemory(EnumIntf, BufferLength);
  1638. Interface = &EnumIntf->Interface[0];
  1639. pBuf = (PUCHAR)EnumIntf + BufferLength;
  1640. ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
  1641. for (MiniBlock = ndisMiniDriverList;
  1642. MiniBlock != NULL;
  1643. MiniBlock = MiniBlock->NextDriver)
  1644. {
  1645. ACQUIRE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
  1646. for (Miniport = MiniBlock->MiniportQueue;
  1647. Miniport != NULL;
  1648. Miniport = Miniport->NextMiniport)
  1649. {
  1650. if (Miniport->PnPDeviceState != NdisPnPDeviceStarted)
  1651. {
  1652. continue;
  1653. }
  1654. EnumIntf->AvailableInterfaces ++;
  1655. SpaceNeeded = sizeof(NDIS_INTERFACE32) +
  1656. Miniport->MiniportName.Length +
  1657. Miniport->pAdapterInstanceName->Length;
  1658. if (SpaceLeft >= SpaceNeeded)
  1659. {
  1660. EnumIntf->TotalInterfaces ++;
  1661. SpaceLeft -= SpaceNeeded;
  1662. pBuf -= Miniport->MiniportName.Length;
  1663. Interface->DeviceName.MaximumLength =
  1664. Interface->DeviceName.Length = Miniport->MiniportName.Length;
  1665. CopyMemory(pBuf, Miniport->MiniportName.Buffer, Interface->DeviceName.Length);
  1666. Interface->DeviceName.Buffer = (ULONG)((ULONG_PTR)pBuf - (ULONG_PTR)EnumIntf);
  1667. pBuf -= Miniport->pAdapterInstanceName->Length;
  1668. Interface->DeviceDescription.MaximumLength =
  1669. Interface->DeviceDescription.Length = Miniport->pAdapterInstanceName->Length;
  1670. CopyMemory(pBuf, Miniport->pAdapterInstanceName->Buffer, Interface->DeviceDescription.Length);
  1671. Interface->DeviceDescription.Buffer = (ULONG)((ULONG_PTR)pBuf - (ULONG_PTR)EnumIntf);
  1672. Interface ++;
  1673. }
  1674. }
  1675. RELEASE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
  1676. }
  1677. RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
  1678. return Status;
  1679. }
  1680. #endif // _WIN64
  1681. NTSTATUS
  1682. ndisUnbindProtocol(
  1683. IN PNDIS_OPEN_BLOCK Open,
  1684. IN BOOLEAN Notify
  1685. )
  1686. /*+++
  1687. Routine Description:
  1688. Arguments:
  1689. Return Value:
  1690. None
  1691. ---*/
  1692. {
  1693. NDIS_STATUS Status = STATUS_SUCCESS;
  1694. NDIS_BIND_CONTEXT UnbindContext;
  1695. PKMUTEX pMutex;
  1696. PKEVENT CloseCompleteEvent = NULL;
  1697. PNDIS_PROTOCOL_BLOCK Protocol = Open->ProtocolHandle;
  1698. PNDIS_OPEN_BLOCK TmpOpen;
  1699. PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
  1700. KIRQL OldIrql;
  1701. BOOLEAN fDerefProtocol = FALSE;
  1702. BOOLEAN FreeOpen;
  1703. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  1704. ("==>ndisUnbindProtocol: Open %p, Notify %d\n", Open, Notify));
  1705. PnPReferencePackage();
  1706. //
  1707. // if this is called outside the context of the protocol deregistering, increment
  1708. // the ref count to make sure the protocol deregisteration does not go through
  1709. // otherwise make note of the fact that we could not increment the ref count and avoid
  1710. // deref at the end
  1711. //
  1712. if (ndisReferenceProtocol(Protocol))
  1713. {
  1714. fDerefProtocol = TRUE;
  1715. }
  1716. ASSERT(MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_UNBINDING));
  1717. CloseCompleteEvent = Open->CloseCompleteEvent;
  1718. do
  1719. {
  1720. NTSTATUS WaitStatus;
  1721. pMutex = &Protocol->Mutex;
  1722. WAIT_FOR_PROTO_MUTEX(Protocol);
  1723. //
  1724. // make sure the open didn't go away while we were waiting for
  1725. // protocol mutex.
  1726. //
  1727. ACQUIRE_SPIN_LOCK(&Protocol->Ref.SpinLock, &OldIrql);
  1728. for (TmpOpen = Protocol->OpenQueue;
  1729. TmpOpen != NULL;
  1730. TmpOpen = TmpOpen->ProtocolNextOpen)
  1731. {
  1732. if (TmpOpen == Open)
  1733. break;
  1734. }
  1735. RELEASE_SPIN_LOCK(&Protocol->Ref.SpinLock, OldIrql);
  1736. if (TmpOpen == NULL)
  1737. {
  1738. //
  1739. // open went away while we were trying to get the protocol mutex
  1740. // return right away
  1741. //
  1742. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  1743. ("ndisUnbindProtocol: Open %p, Flags %lx was closed while we were waiting for the protocol mutex.\n", Open, Open->Flags));
  1744. break;
  1745. }
  1746. //
  1747. // wait for all AF notifications to go through
  1748. //
  1749. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
  1750. {
  1751. KEVENT AfNotifyCompleteEvent;
  1752. INITIALIZE_EVENT(&AfNotifyCompleteEvent);
  1753. Open->AfNotifyCompleteEvent = &AfNotifyCompleteEvent;
  1754. if (Open->PendingAfNotifications != 0)
  1755. {
  1756. WAIT_FOR_OBJECT(Open->AfNotifyCompleteEvent , 0);
  1757. }
  1758. Open->AfNotifyCompleteEvent = NULL;
  1759. }
  1760. //
  1761. // Do a query-remove here first
  1762. //
  1763. if (Notify && (Protocol->ProtocolCharacteristics.PnPEventHandler != NULL))
  1764. {
  1765. NET_PNP_EVENT NetPnpEvent;
  1766. PNDIS_PNP_EVENT_RESERVED EventReserved;
  1767. KEVENT Event;
  1768. RtlZeroMemory(&NetPnpEvent, sizeof(NET_PNP_EVENT));
  1769. INITIALIZE_EVENT(&Event);
  1770. EventReserved = PNDIS_PNP_EVENT_RESERVED_FROM_NET_PNP_EVENT(&NetPnpEvent);
  1771. NetPnpEvent.NetEvent = NetEventQueryRemoveDevice;
  1772. NetPnpEvent.Buffer = NULL;
  1773. NetPnpEvent.BufferLength = 0;
  1774. EventReserved->pEvent = &Event;
  1775. //
  1776. // Indicate the event to the protocol.
  1777. //
  1778. Status = (Protocol->ProtocolCharacteristics.PnPEventHandler)(
  1779. Open->ProtocolBindingContext,
  1780. &NetPnpEvent);
  1781. if (NDIS_STATUS_PENDING == Status)
  1782. {
  1783. //
  1784. // Wait for completion.
  1785. //
  1786. WAIT_FOR_PROTOCOL(Protocol, &Event);
  1787. //
  1788. // Get the completion status.
  1789. //
  1790. Status = EventReserved->Status;
  1791. }
  1792. //
  1793. // Is the status OK?
  1794. //
  1795. if (Status != NDIS_STATUS_SUCCESS)
  1796. {
  1797. break;
  1798. }
  1799. }
  1800. if (CloseCompleteEvent != NULL)
  1801. {
  1802. INITIALIZE_EVENT(CloseCompleteEvent);
  1803. }
  1804. //
  1805. // Protocol ok with remove so now do it.
  1806. //
  1807. INITIALIZE_EVENT(&UnbindContext.Event);
  1808. Status = NDIS_STATUS_SUCCESS;
  1809. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  1810. (*Protocol->ProtocolCharacteristics.UnbindAdapterHandler)(
  1811. &Status,
  1812. Open->ProtocolBindingContext,
  1813. &UnbindContext);
  1814. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  1815. if (Status == NDIS_STATUS_PENDING)
  1816. {
  1817. WAIT_FOR_PROTOCOL(Protocol, &UnbindContext.Event);
  1818. Status = UnbindContext.BindStatus;
  1819. }
  1820. ASSERT(Status == NDIS_STATUS_SUCCESS);
  1821. ndisNotifyWmiBindUnbind(Miniport, Protocol, FALSE);
  1822. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  1823. if (CloseCompleteEvent != NULL)
  1824. {
  1825. //
  1826. // make sure the open is gone
  1827. //
  1828. WAIT_FOR_PROTOCOL(Protocol, CloseCompleteEvent);
  1829. }
  1830. } while (FALSE);
  1831. RELEASE_MUTEX(pMutex);
  1832. ACQUIRE_SPIN_LOCK(&Open->SpinLock, &OldIrql);
  1833. //
  1834. // did the close routine get our message not to free the open structure?
  1835. //
  1836. if (MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_CLOSE_COMPLETE))
  1837. {
  1838. //
  1839. // we have to get rid of open ourselves
  1840. //
  1841. FreeOpen = TRUE;
  1842. }
  1843. else
  1844. {
  1845. //
  1846. // for some reason, unbind did not go through or close is
  1847. // still in progress
  1848. //
  1849. MINIPORT_CLEAR_FLAG(Open, fMINIPORT_OPEN_UNBINDING |
  1850. fMINIPORT_OPEN_DONT_FREE |
  1851. fMINIPORT_OPEN_PROCESSING);
  1852. FreeOpen = FALSE;
  1853. }
  1854. RELEASE_SPIN_LOCK(&Open->SpinLock, OldIrql);
  1855. PnPDereferencePackage();
  1856. if (FreeOpen)
  1857. {
  1858. ndisRemoveOpenFromGlobalList(Open);
  1859. FREE_POOL(Open);
  1860. }
  1861. if (fDerefProtocol)
  1862. {
  1863. ndisDereferenceProtocol(Protocol);
  1864. }
  1865. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  1866. ("<==ndisUnbindProtocol: Open %p, Notify %d, Status %lx\n", Open, Notify, Status));
  1867. return(Status);
  1868. }
  1869. VOID
  1870. ndisReferenceMiniportByName(
  1871. IN PUNICODE_STRING DeviceName,
  1872. OUT PNDIS_MINIPORT_BLOCK * pMiniport
  1873. )
  1874. {
  1875. KIRQL OldIrql;
  1876. PNDIS_M_DRIVER_BLOCK MiniBlock;
  1877. PNDIS_MINIPORT_BLOCK Miniport = NULL;
  1878. UNICODE_STRING UpcaseDevice;
  1879. DBGPRINT_RAW(DBG_COMP_REF, DBG_LEVEL_INFO,
  1880. ("==>ndisReferenceMiniportByName\n"));
  1881. *pMiniport = NULL;
  1882. UpcaseDevice.Length = DeviceName->Length;
  1883. UpcaseDevice.MaximumLength = DeviceName->Length + sizeof(WCHAR);
  1884. UpcaseDevice.Buffer = ALLOC_FROM_POOL(UpcaseDevice.MaximumLength, NDIS_TAG_STRING);
  1885. if (UpcaseDevice.Buffer == NULL)
  1886. {
  1887. return;
  1888. }
  1889. RtlUpcaseUnicodeString(&UpcaseDevice, DeviceName, FALSE);
  1890. do
  1891. {
  1892. UINT Depth = 1;
  1893. ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
  1894. for (MiniBlock = ndisMiniDriverList;
  1895. MiniBlock != NULL;
  1896. MiniBlock = MiniBlock->NextDriver)
  1897. {
  1898. ACQUIRE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
  1899. for (Miniport = MiniBlock->MiniportQueue;
  1900. Miniport != NULL;
  1901. Miniport = Miniport->NextMiniport)
  1902. {
  1903. if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_ORPHANED) &&
  1904. (Miniport->BindPaths != NULL) &&
  1905. (Miniport->BindPaths->Number >= Depth) &&
  1906. NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &Miniport->BindPaths->Paths[0]))
  1907. {
  1908. if (*pMiniport != NULL)
  1909. {
  1910. MINIPORT_DECREMENT_REF(*pMiniport);
  1911. *pMiniport = NULL;
  1912. }
  1913. Depth = Miniport->BindPaths->Number;
  1914. if (MINIPORT_INCREMENT_REF(Miniport))
  1915. {
  1916. *pMiniport = Miniport;
  1917. }
  1918. break;
  1919. }
  1920. }
  1921. RELEASE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
  1922. }
  1923. } while (FALSE);
  1924. RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
  1925. FREE_POOL(UpcaseDevice.Buffer);
  1926. DBGPRINT_RAW(DBG_COMP_REF, DBG_LEVEL_INFO,
  1927. ("<==ndisReferenceMiniportByName\n"));
  1928. }
  1929. PNDIS_OPEN_BLOCK
  1930. FASTCALL
  1931. ndisMapOpenByName(
  1932. IN PUNICODE_STRING DeviceName,
  1933. IN PNDIS_PROTOCOL_BLOCK Protocol,
  1934. IN BOOLEAN Reference,
  1935. IN BOOLEAN fUnbinding
  1936. )
  1937. {
  1938. UNICODE_STRING UpcaseDevice;
  1939. PNDIS_OPEN_BLOCK Open, tmpOpen;
  1940. KIRQL OldIrql;
  1941. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  1942. ("==>ndisReferenceOpenByName, DeviceName %p, Protocol %p, fUnbinding %d\n",
  1943. DeviceName, Protocol, fUnbinding));
  1944. Open = NULL;
  1945. UpcaseDevice.Length = DeviceName->Length;
  1946. UpcaseDevice.MaximumLength = DeviceName->Length + sizeof(WCHAR);
  1947. UpcaseDevice.Buffer = ALLOC_FROM_POOL(UpcaseDevice.MaximumLength, NDIS_TAG_STRING);
  1948. if (UpcaseDevice.Buffer == NULL)
  1949. {
  1950. DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_ERR,
  1951. ("<==ndisReferenceOpenByName: failed to allocate memory.\n"));
  1952. return NULL;
  1953. }
  1954. RtlUpcaseUnicodeString(&UpcaseDevice, DeviceName, FALSE);
  1955. ACQUIRE_SPIN_LOCK(&Protocol->Ref.SpinLock, &OldIrql);
  1956. //
  1957. // Now walk the open list and get to the open representing the DeviceName
  1958. //
  1959. for (Open = Protocol->OpenQueue;
  1960. Open != NULL;
  1961. Open = Open->ProtocolNextOpen)
  1962. {
  1963. if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, Open->RootDeviceName))
  1964. {
  1965. tmpOpen = Open;
  1966. ACQUIRE_SPIN_LOCK_DPC(&tmpOpen->SpinLock);
  1967. if (fUnbinding)
  1968. {
  1969. if (MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_UNBINDING |
  1970. fMINIPORT_OPEN_CLOSING |
  1971. fMINIPORT_OPEN_PROCESSING))
  1972. {
  1973. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  1974. ("ndisReferenceOpenByName: Open %p is already getting unbind\n", Open));
  1975. Open = NULL;
  1976. }
  1977. else
  1978. {
  1979. MINIPORT_SET_FLAG(Open, fMINIPORT_OPEN_UNBINDING |
  1980. fMINIPORT_OPEN_DONT_FREE |
  1981. fMINIPORT_OPEN_PROCESSING);
  1982. }
  1983. }
  1984. else
  1985. {
  1986. if (MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_PROCESSING))
  1987. {
  1988. Open = NULL;
  1989. }
  1990. else
  1991. {
  1992. MINIPORT_SET_FLAG(Open, fMINIPORT_OPEN_PROCESSING);
  1993. }
  1994. }
  1995. RELEASE_SPIN_LOCK_DPC(&tmpOpen->SpinLock);
  1996. break;
  1997. }
  1998. }
  1999. RELEASE_SPIN_LOCK(&Protocol->Ref.SpinLock, OldIrql);
  2000. if ((Open != NULL) && Reference)
  2001. {
  2002. PNDIS_MINIPORT_BLOCK Miniport;
  2003. Miniport = Open->MiniportHandle;
  2004. if (!MINIPORT_INCREMENT_REF(Miniport))
  2005. {
  2006. if (fUnbinding)
  2007. {
  2008. MINIPORT_CLEAR_FLAG(Open, fMINIPORT_OPEN_UNBINDING |
  2009. fMINIPORT_OPEN_PROCESSING |
  2010. fMINIPORT_OPEN_DONT_FREE);
  2011. }
  2012. else
  2013. {
  2014. MINIPORT_CLEAR_FLAG(Open, fMINIPORT_OPEN_PROCESSING);
  2015. }
  2016. Open = NULL;
  2017. }
  2018. }
  2019. FREE_POOL(UpcaseDevice.Buffer);
  2020. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  2021. ("<==ndisReferenceOpenByName: Open %p\n", Open ));
  2022. return(Open);
  2023. }
  2024. NTSTATUS
  2025. FASTCALL
  2026. ndisHandleLegacyTransport(
  2027. IN PUNICODE_STRING pDevice
  2028. )
  2029. {
  2030. NTSTATUS Status = STATUS_SUCCESS;
  2031. RTL_QUERY_REGISTRY_TABLE LinkQueryTable[3];
  2032. PWSTR Export = NULL;
  2033. HANDLE TdiHandle;
  2034. DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
  2035. ("==>ndisHandleLegacyTransport\n"));
  2036. if (ndisTdiRegisterCallback == NULL)
  2037. {
  2038. DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
  2039. ("<==ndisHandleLegacyTransport\n"));
  2040. return STATUS_UNSUCCESSFUL;
  2041. }
  2042. //
  2043. // Set up LinkQueryTable to do the following:
  2044. //
  2045. //
  2046. // 1) Switch to the Linkage key below the xports registry key
  2047. //
  2048. LinkQueryTable[0].QueryRoutine = NULL;
  2049. LinkQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
  2050. LinkQueryTable[0].Name = L"Linkage";
  2051. //
  2052. // 2) Call ndisReadParameter for "Export" (as a single multi-string),
  2053. // which will allocate storage and save the data in Export.
  2054. //
  2055. LinkQueryTable[1].QueryRoutine = ndisReadParameter;
  2056. LinkQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
  2057. LinkQueryTable[1].Name = L"Export";
  2058. LinkQueryTable[1].EntryContext = (PVOID)&Export;
  2059. LinkQueryTable[1].DefaultType = REG_NONE;
  2060. //
  2061. // 3) Stop
  2062. //
  2063. LinkQueryTable[2].QueryRoutine = NULL;
  2064. LinkQueryTable[2].Flags = 0;
  2065. LinkQueryTable[2].Name = NULL;
  2066. do
  2067. {
  2068. UNICODE_STRING Us;
  2069. PWSTR CurExport;
  2070. Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
  2071. pDevice->Buffer,
  2072. LinkQueryTable,
  2073. (PVOID)NULL, // no context needed
  2074. NULL);
  2075. if (!NT_SUCCESS(Status))
  2076. {
  2077. //
  2078. // Do not complain about TDI drivers which do not
  2079. // have any linkages
  2080. //
  2081. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  2082. {
  2083. Status = STATUS_SUCCESS;
  2084. }
  2085. break;
  2086. }
  2087. //
  2088. // Walk the list of exports and call TdiRegisterDevice for each
  2089. //
  2090. for (CurExport = Export;
  2091. *CurExport != 0;
  2092. CurExport = (PWCHAR)((PUCHAR)CurExport + Us.MaximumLength))
  2093. {
  2094. RtlInitUnicodeString (&Us, CurExport);
  2095. Status = (*ndisTdiRegisterCallback)(&Us, &TdiHandle);
  2096. if (!NT_SUCCESS(Status))
  2097. {
  2098. break;
  2099. }
  2100. }
  2101. } while (FALSE);
  2102. if (Export != NULL)
  2103. FREE_POOL(Export);
  2104. DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
  2105. ("<==ndisHandleLegacyTransport\n"));
  2106. return(Status);
  2107. }
  2108. VOID
  2109. FASTCALL
  2110. ndisInitializeBinding(
  2111. IN PNDIS_MINIPORT_BLOCK Miniport,
  2112. IN PNDIS_PROTOCOL_BLOCK Protocol
  2113. )
  2114. {
  2115. PUNICODE_STRING ExportName;
  2116. NDIS_BIND_CONTEXT BindContext;
  2117. PDEVICE_OBJECT PhysicalDeviceObject;
  2118. NDIS_STATUS BindStatus;
  2119. UNICODE_STRING ProtocolSection;
  2120. UNICODE_STRING DerivedBaseName, Parms;
  2121. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  2122. ("==>ndisInitializeBinding\n"));
  2123. //
  2124. // Call the protocol to bind to the Miniport
  2125. //
  2126. WAIT_FOR_PROTO_MUTEX(Protocol);
  2127. do
  2128. {
  2129. //
  2130. // once we grabbed the protocol mutex, check again to see if
  2131. // the adapter is still there
  2132. //
  2133. if (!ndisIsMiniportStarted(Miniport) ||
  2134. ((Miniport->PnPDeviceState != NdisPnPDeviceStarted) &&
  2135. (Miniport->PnPDeviceState != NdisPnPDeviceQueryStopped) &&
  2136. (Miniport->PnPDeviceState != NdisPnPDeviceQueryRemoved)))
  2137. {
  2138. break;
  2139. }
  2140. if (TRUE == ndisProtocolAlreadyBound(Protocol, Miniport))
  2141. {
  2142. //
  2143. // these two are already bound. just return
  2144. //
  2145. break;
  2146. }
  2147. ExportName = &Miniport->BindPaths->Paths[0];
  2148. Protocol->BindDeviceName = &Miniport->MiniportName;
  2149. Protocol->RootDeviceName = ExportName;
  2150. PhysicalDeviceObject = Miniport->PhysicalDeviceObject;
  2151. if (ndisReferenceProtocol(Protocol) == FALSE)
  2152. {
  2153. break;
  2154. }
  2155. RtlInitUnicodeString(&Parms, L"\\Parameters\\Adapters\\");
  2156. DerivedBaseName = *ExportName;
  2157. DerivedBaseName.Length -= ndisDeviceStr.Length;
  2158. DerivedBaseName.MaximumLength -= ndisDeviceStr.Length;
  2159. (PUCHAR)(DerivedBaseName.Buffer) += ndisDeviceStr.Length;
  2160. ProtocolSection.MaximumLength = Protocol->ProtocolCharacteristics.Name.Length + // "tcpip"
  2161. Parms.Length + // "\Parameters\Adapters\"
  2162. ExportName->Length - ndisDeviceStr.Length + // "{GUID}"
  2163. sizeof(WCHAR);
  2164. ProtocolSection.Length = 0;
  2165. ProtocolSection.Buffer = (PWSTR)ALLOC_FROM_POOL(ProtocolSection.MaximumLength,
  2166. NDIS_TAG_DEFAULT);
  2167. if (ProtocolSection.Buffer != NULL)
  2168. {
  2169. ZeroMemory(ProtocolSection.Buffer, ProtocolSection.MaximumLength);
  2170. RtlCopyUnicodeString(&ProtocolSection,
  2171. &Protocol->ProtocolCharacteristics.Name);
  2172. RtlAppendUnicodeStringToString(&ProtocolSection,
  2173. &Parms);
  2174. RtlAppendUnicodeStringToString(&ProtocolSection,
  2175. &DerivedBaseName);
  2176. }
  2177. else
  2178. {
  2179. ndisDereferenceProtocol(Protocol);
  2180. break;
  2181. }
  2182. BindContext.Next = NULL;
  2183. BindContext.Protocol = Protocol;
  2184. BindContext.Miniport = Miniport;
  2185. BindContext.ProtocolSection = ProtocolSection;
  2186. BindContext.DeviceName = ExportName;
  2187. INITIALIZE_EVENT(&BindContext.Event);
  2188. if (!Protocol->Ref.Closing)
  2189. {
  2190. BindStatus = NDIS_STATUS_SUCCESS;
  2191. Protocol->BindingAdapter = Miniport;
  2192. (*Protocol->ProtocolCharacteristics.BindAdapterHandler)(&BindStatus,
  2193. &BindContext,
  2194. ExportName,
  2195. &ProtocolSection,
  2196. (PVOID)PhysicalDeviceObject);
  2197. if (BindStatus == NDIS_STATUS_PENDING)
  2198. {
  2199. WAIT_FOR_PROTOCOL(Protocol, &BindContext.Event);
  2200. BindStatus = BindContext.BindStatus;
  2201. }
  2202. Protocol->BindingAdapter = NULL;
  2203. if (BindStatus == NDIS_STATUS_SUCCESS)
  2204. {
  2205. ndisNotifyWmiBindUnbind(Miniport, Protocol, TRUE);
  2206. }
  2207. #if DBG
  2208. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  2209. (" ndisInitializeBinding\n"));
  2210. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  2211. (" Protocol: "));
  2212. DBGPRINT_UNICODE(DBG_COMP_BIND, DBG_LEVEL_INFO,
  2213. &Protocol->ProtocolCharacteristics.Name);
  2214. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  2215. ("\n Adapter: "));
  2216. if (Miniport->pAdapterInstanceName)
  2217. {
  2218. DBGPRINT_UNICODE(DBG_COMP_BIND, DBG_LEVEL_INFO,
  2219. Miniport->pAdapterInstanceName);
  2220. }
  2221. else
  2222. {
  2223. DBGPRINT_UNICODE(DBG_COMP_INIT, DBG_LEVEL_INFO,
  2224. &Miniport->BaseName);
  2225. }
  2226. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  2227. ("\n Result: %lx\n", BindStatus));
  2228. #endif
  2229. }
  2230. FREE_POOL(ProtocolSection.Buffer);
  2231. Protocol->BindDeviceName = NULL;
  2232. ndisDereferenceProtocol(Protocol);
  2233. } while (FALSE);
  2234. RELEASE_PROT_MUTEX(Protocol);
  2235. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  2236. ("<==ndisInitializeBinding\n"));
  2237. }
  2238. VOID
  2239. NdisCompleteBindAdapter(
  2240. IN NDIS_HANDLE BindAdapterContext,
  2241. IN NDIS_STATUS Status,
  2242. IN NDIS_STATUS OpenStatus
  2243. )
  2244. /*++
  2245. Routine Description:
  2246. Arguments:
  2247. Return Value:
  2248. --*/
  2249. {
  2250. PNDIS_BIND_CONTEXT pContext = (PNDIS_BIND_CONTEXT)BindAdapterContext;
  2251. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  2252. ("==>NdisCompleteBindAdapter\n"));
  2253. pContext->BindStatus = Status;
  2254. SET_EVENT(&pContext->Event);
  2255. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  2256. ("<==NdisCompleteBindAdapter\n"));
  2257. }
  2258. VOID
  2259. NdisCompleteUnbindAdapter(
  2260. IN NDIS_HANDLE UnbindAdapterContext,
  2261. IN NDIS_STATUS Status
  2262. )
  2263. /*++
  2264. Routine Description:
  2265. Arguments:
  2266. Return Value:
  2267. --*/
  2268. {
  2269. PNDIS_BIND_CONTEXT pContext = (PNDIS_BIND_CONTEXT)UnbindAdapterContext;
  2270. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  2271. ("==>NdisCompleteUnbindAdapter\n"));
  2272. pContext->BindStatus = Status;
  2273. SET_EVENT(&pContext->Event);
  2274. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  2275. ("<==NdisCompleteUnbindAdapter\n"));
  2276. }
  2277. VOID
  2278. NdisRegisterTdiCallBack(
  2279. IN TDI_REGISTER_CALLBACK RegisterCallback,
  2280. IN TDI_PNP_HANDLER PnPHandler
  2281. )
  2282. /*++
  2283. Routine Description:
  2284. Arguments:
  2285. Return Value:
  2286. --*/
  2287. {
  2288. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2289. ("==>NdisRegisterTdiCallBack\n"));
  2290. if (ndisTdiRegisterCallback == NULL)
  2291. {
  2292. ndisTdiRegisterCallback = RegisterCallback;
  2293. }
  2294. if (ndisTdiPnPHandler == NULL)
  2295. {
  2296. ndisTdiPnPHandler = PnPHandler;
  2297. }
  2298. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2299. ("<==NdisRegisterTdiCallBack\n"));
  2300. }
  2301. VOID
  2302. ndisFindRootDevice(
  2303. IN PNDIS_STRING DeviceName,
  2304. IN BOOLEAN fTester,
  2305. OUT PNDIS_STRING * pBindDevice,
  2306. OUT PNDIS_STRING * pRootDevice,
  2307. OUT PNDIS_MINIPORT_BLOCK * pAdapter
  2308. )
  2309. /*++
  2310. Routine Description:
  2311. Find the Miniport which is the highest level filter given the target root name.
  2312. Arguments:
  2313. Return Value:
  2314. --*/
  2315. {
  2316. KIRQL OldIrql;
  2317. PNDIS_M_DRIVER_BLOCK MiniBlock;
  2318. PNDIS_MINIPORT_BLOCK Miniport;
  2319. PNDIS_STRING RootDevice, BindDevice;
  2320. NDIS_STRING UpcaseDevice;
  2321. PWSTR pwch;
  2322. UINT Depth = 1;
  2323. BOOLEAN Found = FALSE;
  2324. DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2325. ("==>ndisFindRootDevice\n"));
  2326. *pBindDevice = NULL;
  2327. *pRootDevice = NULL;
  2328. *pAdapter = NULL;
  2329. //
  2330. // First we need to upcase the device-name before checking
  2331. //
  2332. UpcaseDevice.Length = DeviceName->Length;
  2333. UpcaseDevice.MaximumLength = DeviceName->Length + sizeof(WCHAR);
  2334. UpcaseDevice.Buffer = ALLOC_FROM_POOL(UpcaseDevice.MaximumLength, NDIS_TAG_STRING);
  2335. if ((pwch = UpcaseDevice.Buffer) == NULL)
  2336. {
  2337. return;
  2338. }
  2339. RtlUpcaseUnicodeString(&UpcaseDevice, DeviceName, FALSE);
  2340. BindDevice = &UpcaseDevice;
  2341. ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0);
  2342. PnPReferencePackage();
  2343. ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
  2344. for (MiniBlock = ndisMiniDriverList;
  2345. MiniBlock != NULL;
  2346. MiniBlock = MiniBlock->NextDriver)
  2347. {
  2348. ACQUIRE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
  2349. for (Miniport = MiniBlock->MiniportQueue;
  2350. Miniport != NULL;
  2351. Miniport = Miniport->NextMiniport)
  2352. {
  2353. if (fTester)
  2354. {
  2355. if (NDIS_EQUAL_UNICODE_STRING(BindDevice, &Miniport->MiniportName))
  2356. {
  2357. BindDevice = &Miniport->MiniportName;
  2358. RootDevice = &Miniport->MiniportName;
  2359. *pAdapter = Miniport;
  2360. Found = TRUE;
  2361. break;
  2362. }
  2363. }
  2364. else if ((Miniport->BindPaths->Number >= Depth) &&
  2365. NDIS_EQUAL_UNICODE_STRING(BindDevice, &Miniport->BindPaths->Paths[0]))
  2366. {
  2367. RootDevice = &Miniport->BindPaths->Paths[0];
  2368. BindDevice = &Miniport->MiniportName;
  2369. *pAdapter = Miniport;
  2370. Depth = Miniport->BindPaths->Number;
  2371. Found = TRUE;
  2372. }
  2373. }
  2374. RELEASE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
  2375. if (fTester && Found)
  2376. {
  2377. break;
  2378. }
  2379. }
  2380. RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
  2381. PnPDereferencePackage();
  2382. FREE_POOL(pwch);
  2383. if (Found)
  2384. {
  2385. *pBindDevice = BindDevice;
  2386. *pRootDevice = RootDevice;
  2387. }
  2388. DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2389. ("<==ndisFindRootDevice\n"));
  2390. }
  2391. VOID
  2392. ndisNotifyWmiBindUnbind(
  2393. PNDIS_MINIPORT_BLOCK Miniport,
  2394. PNDIS_PROTOCOL_BLOCK Protocol,
  2395. BOOLEAN fBind
  2396. )
  2397. /*++
  2398. Routine Description:
  2399. Notify WMI that either a bind or an unbind has occured.
  2400. Arguments:
  2401. Return Value:
  2402. --*/
  2403. {
  2404. PWNODE_SINGLE_INSTANCE wnode;
  2405. PUCHAR ptmp;
  2406. NTSTATUS NtStatus;
  2407. DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2408. ("==>ndisNotifyWmiBindUnbind: Miniport %p, Protocol %p, fBind %lx\n", Miniport, Protocol, fBind));
  2409. ndisSetupWmiNode(Miniport,
  2410. Miniport->pAdapterInstanceName,
  2411. Miniport->BindPaths->Paths[0].Length + sizeof(WCHAR) +
  2412. Protocol->ProtocolCharacteristics.Name.Length + sizeof(WCHAR),
  2413. fBind ? (PVOID)&GUID_NDIS_NOTIFY_BIND : (PVOID)&GUID_NDIS_NOTIFY_UNBIND,
  2414. &wnode);
  2415. if (wnode != NULL)
  2416. {
  2417. //
  2418. // Save the number of elements in the first ULONG.
  2419. //
  2420. ptmp = (PUCHAR)wnode + wnode->DataBlockOffset;
  2421. //
  2422. // Copy the data which is the protocol name + the miniport name in the data field
  2423. // Protocol<NULL>MiniportName<NULL>
  2424. //
  2425. RtlCopyMemory(ptmp,
  2426. Protocol->ProtocolCharacteristics.Name.Buffer,
  2427. Protocol->ProtocolCharacteristics.Name.Length);
  2428. RtlCopyMemory(ptmp + Protocol->ProtocolCharacteristics.Name.Length + sizeof(WCHAR),
  2429. Miniport->BindPaths->Paths[0].Buffer,
  2430. Miniport->BindPaths->Paths[0].Length);
  2431. //
  2432. // notify kernel mode components who have registered for Ndis BindUnbind event
  2433. //
  2434. if (ndisBindUnbindCallbackObject != NULL)
  2435. {
  2436. ExNotifyCallback(ndisBindUnbindCallbackObject,
  2437. (PVOID)wnode,
  2438. NULL);
  2439. }
  2440. //
  2441. // Indicate the event to WMI. WMI will take care of freeing
  2442. // the WMI struct back to pool.
  2443. //
  2444. NtStatus = IoWMIWriteEvent(wnode);
  2445. if (!NT_SUCCESS(NtStatus))
  2446. {
  2447. DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
  2448. ("IoWMIWriteEvent failed %lx\n", NtStatus));
  2449. FREE_POOL(wnode);
  2450. }
  2451. }
  2452. DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2453. ("<==ndisNotifyWmiBindUnbind: Miniport %p, Protocol %p, fBind %lx\n", Miniport, Protocol, fBind));
  2454. return;
  2455. }
  2456. VOID
  2457. ndisNotifyDevicePowerStateChange(
  2458. PNDIS_MINIPORT_BLOCK Miniport,
  2459. NDIS_DEVICE_POWER_STATE PowerState
  2460. )
  2461. /*++
  2462. Routine Description:
  2463. Notify WMI that that the power state of a NIC is changed.
  2464. Arguments:
  2465. Return Value:
  2466. --*/
  2467. {
  2468. PWNODE_SINGLE_INSTANCE wnode;
  2469. PUCHAR ptmp;
  2470. NTSTATUS NtStatus;
  2471. DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2472. ("==>ndisNotifyDevicePowerStateChange: Miniport %p, PowerState %lx\n", Miniport, PowerState));
  2473. ndisSetupWmiNode(Miniport,
  2474. Miniport->pAdapterInstanceName,
  2475. Miniport->MiniportName.Length + sizeof(WCHAR),
  2476. (PowerState == NdisDeviceStateD0) ? (PVOID)&GUID_NDIS_NOTIFY_DEVICE_POWER_ON : (PVOID)&GUID_NDIS_NOTIFY_DEVICE_POWER_OFF,
  2477. &wnode);
  2478. if (wnode != NULL)
  2479. {
  2480. //
  2481. // Save the number of elements in the first ULONG.
  2482. //
  2483. ptmp = (PUCHAR)wnode + wnode->DataBlockOffset;
  2484. RtlCopyMemory(ptmp,
  2485. Miniport->MiniportName.Buffer,
  2486. Miniport->MiniportName.Length);
  2487. //
  2488. // Indicate the event to WMI. WMI will take care of freeing
  2489. // the WMI struct back to pool.
  2490. //
  2491. NtStatus = IoWMIWriteEvent(wnode);
  2492. if (!NT_SUCCESS(NtStatus))
  2493. {
  2494. DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
  2495. ("IoWMIWriteEvent failed %lx\n", NtStatus));
  2496. FREE_POOL(wnode);
  2497. }
  2498. }
  2499. DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2500. ("<==ndisNotifyDevicePowerStateChange: Miniport %p, PowerState %lx\n", Miniport, PowerState));
  2501. return;
  2502. }
  2503. BOOLEAN
  2504. NdisMatchPdoWithPacket(
  2505. IN PNDIS_PACKET Packet,
  2506. IN PVOID Pdo
  2507. )
  2508. {
  2509. PNDIS_STACK_RESERVED NSR;
  2510. PNDIS_MINIPORT_BLOCK Miniport;
  2511. NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR);
  2512. Miniport = NSR->Miniport;
  2513. return (Pdo == Miniport->PhysicalDeviceObject);
  2514. }
  2515. VOID
  2516. ndisPowerStateCallback(
  2517. PVOID CallBackContext,
  2518. PVOID Argument1,
  2519. PVOID Argument2
  2520. )
  2521. {
  2522. ULONG Action = (ULONG)((ULONG_PTR)Argument1);
  2523. ULONG State = (ULONG)((ULONG_PTR)Argument2);
  2524. NDIS_POWER_PROFILE PowerProfile;
  2525. DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2526. ("==>ndisPowerStateCallback: Action %lx, State %lx\n", Action, State));
  2527. if (Action == PO_CB_AC_STATUS)
  2528. {
  2529. ndisAcOnLine = State;
  2530. PowerProfile = ((BOOLEAN)ndisAcOnLine == TRUE) ? NdisPowerProfileAcOnLine : NdisPowerProfileBattery;
  2531. ndisNotifyMiniports((PNDIS_MINIPORT_BLOCK)NULL,
  2532. NdisDevicePnPEventPowerProfileChanged,
  2533. &PowerProfile,
  2534. sizeof(NDIS_POWER_PROFILE));
  2535. }
  2536. DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2537. ("<==ndisPowerStateCallback: Action %lx, State %lx\n", Action, State));
  2538. }
  2539. VOID
  2540. ndisNotifyMiniports(
  2541. IN PNDIS_MINIPORT_BLOCK Miniport OPTIONAL,
  2542. IN NDIS_DEVICE_PNP_EVENT DevicePnPEvent,
  2543. IN PVOID Buffer,
  2544. IN ULONG Length
  2545. )
  2546. {
  2547. PNDIS_M_DRIVER_BLOCK MiniBlock, NextMiniBlock;
  2548. PNDIS_MINIPORT_BLOCK CurMiniport, NM;
  2549. KIRQL OldIrql;
  2550. DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2551. ("==>ndisNotifyMiniportsPowerProfileChange: Miniport %p, Event %lx, Buffer %p\n",
  2552. Miniport,
  2553. DevicePnPEvent,
  2554. Buffer));
  2555. PnPReferencePackage();
  2556. do
  2557. {
  2558. if (Miniport)
  2559. {
  2560. if(Miniport->DriverHandle->MiniportCharacteristics.PnPEventNotifyHandler != NULL)
  2561. {
  2562. //
  2563. // if Miniport has been specified, the caller is responsible to make sure it is valid and appropriate
  2564. // to call the miniport
  2565. //
  2566. Miniport->DriverHandle->MiniportCharacteristics.PnPEventNotifyHandler(Miniport->MiniportAdapterContext,
  2567. DevicePnPEvent,
  2568. Buffer,
  2569. Length);
  2570. }
  2571. break;
  2572. }
  2573. //
  2574. // notification is for all the miniports
  2575. //
  2576. ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
  2577. for (MiniBlock = ndisMiniDriverList;
  2578. MiniBlock != NULL;
  2579. MiniBlock = NextMiniBlock)
  2580. {
  2581. if (ndisReferenceDriver(MiniBlock))
  2582. {
  2583. RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
  2584. while ((CurMiniport = ndisReferenceNextUnprocessedMiniport(MiniBlock)) != NULL)
  2585. {
  2586. if (CurMiniport->DriverHandle->MiniportCharacteristics.PnPEventNotifyHandler != NULL)
  2587. {
  2588. CurMiniport->DriverHandle->MiniportCharacteristics.PnPEventNotifyHandler(CurMiniport->MiniportAdapterContext,
  2589. NdisDevicePnPEventPowerProfileChanged,
  2590. Buffer,
  2591. Length);
  2592. }
  2593. }
  2594. ndisUnprocessAllMiniports(MiniBlock);
  2595. ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
  2596. NextMiniBlock = MiniBlock->NextDriver;
  2597. ndisDereferenceDriver(MiniBlock, TRUE);
  2598. }
  2599. }
  2600. RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
  2601. } while (FALSE);
  2602. PnPDereferencePackage();
  2603. DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2604. ("<==>ndisNotifyMiniportsPowerProfileChange: Miniport %p\n", Miniport));
  2605. return;
  2606. }
  2607. PNDIS_MINIPORT_BLOCK
  2608. ndisReferenceNextUnprocessedMiniport(
  2609. IN PNDIS_M_DRIVER_BLOCK MiniBlock
  2610. )
  2611. {
  2612. PNDIS_MINIPORT_BLOCK Miniport;
  2613. KIRQL OldIrql;
  2614. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2615. ("==>ndisReferenceNextUnprocessedMiniport: MiniBlock %p\n", MiniBlock));
  2616. ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
  2617. for (Miniport = MiniBlock->MiniportQueue;
  2618. Miniport != NULL;
  2619. Miniport = Miniport->NextMiniport)
  2620. {
  2621. if (!MINIPORT_TEST_FLAG(Miniport, (fMINIPORT_DEREGISTERED_INTERRUPT |
  2622. fMINIPORT_RESET_IN_PROGRESS |
  2623. fMINIPORT_PM_HALTING)) &&
  2624. !MINIPORT_PNP_TEST_FLAG(Miniport, (fMINIPORT_REMOVE_IN_PROGRESS |
  2625. fMINIPORT_DEVICE_FAILED |
  2626. fMINIPORT_PM_HALTED |
  2627. fMINIPORT_HALTING |
  2628. fMINIPORT_SHUTTING_DOWN |
  2629. fMINIPORT_PROCESSING)) &&
  2630. (Miniport->PnPDeviceState == NdisPnPDeviceStarted) &&
  2631. (Miniport->CurrentDevicePowerState == PowerDeviceD0) &&
  2632. MINIPORT_INCREMENT_REF(Miniport))
  2633. {
  2634. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_PROCESSING);
  2635. break;
  2636. }
  2637. }
  2638. RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
  2639. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2640. ("<==ndisReferenceNextUnprocessedMiniport: MiniBlock %p\n", MiniBlock));
  2641. return(Miniport);
  2642. }
  2643. VOID
  2644. ndisUnprocessAllMiniports(
  2645. IN PNDIS_M_DRIVER_BLOCK MiniBlock
  2646. )
  2647. {
  2648. PNDIS_MINIPORT_BLOCK Miniport;
  2649. KIRQL OldIrql;
  2650. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2651. ("==>ndisUnprocessAllMiniports: MiniBlock %p\n", MiniBlock));
  2652. while (TRUE)
  2653. {
  2654. ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
  2655. //
  2656. // find the first miniport that is being proccessed. clear the flag, dereference the
  2657. // miniport and go through the whole process again.
  2658. //
  2659. for (Miniport = MiniBlock->MiniportQueue;
  2660. Miniport != NULL;
  2661. Miniport = Miniport->NextMiniport)
  2662. {
  2663. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PROCESSING))
  2664. {
  2665. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_PROCESSING);
  2666. break;
  2667. }
  2668. }
  2669. RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
  2670. if (Miniport == NULL)
  2671. break;
  2672. //
  2673. // dereferencing the miniport could make it to go away
  2674. //
  2675. MINIPORT_DECREMENT_REF(Miniport);
  2676. }
  2677. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2678. ("<==ndisUnprocessAllMiniports: MiniBlock %p\n", MiniBlock));
  2679. }
  2680. PVOID
  2681. NdisGetRoutineAddress(
  2682. IN PUNICODE_STRING NdisRoutineName
  2683. )
  2684. {
  2685. PVOID Address;
  2686. ANSI_STRING AnsiString;
  2687. NTSTATUS Status;
  2688. Status = RtlUnicodeStringToAnsiString(&AnsiString,
  2689. NdisRoutineName,
  2690. TRUE);
  2691. if (!NT_SUCCESS(Status))
  2692. {
  2693. return NULL;
  2694. }
  2695. Address = FindExportedRoutineByName(ndisDriverObject->DriverStart, &AnsiString);
  2696. RtlFreeAnsiString (&AnsiString);
  2697. return Address;
  2698. }
  2699. PVOID
  2700. FindExportedRoutineByName (
  2701. IN PVOID DllBase,
  2702. IN PANSI_STRING AnsiImageRoutineName
  2703. )
  2704. /*++
  2705. Routine Description:
  2706. This function searches the argument module looking for the requested
  2707. exported function name.
  2708. Arguments:
  2709. DllBase - Supplies the base address of the requested module.
  2710. AnsiImageRoutineName - Supplies the ANSI routine name being searched for.
  2711. Return Value:
  2712. The virtual address of the requested routine or NULL if not found.
  2713. --*/
  2714. {
  2715. USHORT OrdinalNumber;
  2716. PULONG NameTableBase;
  2717. PUSHORT NameOrdinalTableBase;
  2718. PULONG Addr;
  2719. ULONG High;
  2720. ULONG Low;
  2721. ULONG Middle;
  2722. LONG Result;
  2723. ULONG ExportSize;
  2724. PVOID FunctionAddress;
  2725. PIMAGE_EXPORT_DIRECTORY ExportDirectory;
  2726. PAGED_CODE();
  2727. FunctionAddress = NULL;
  2728. ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(
  2729. DllBase,
  2730. TRUE,
  2731. IMAGE_DIRECTORY_ENTRY_EXPORT,
  2732. &ExportSize
  2733. );
  2734. if (ExportDirectory == NULL) {
  2735. return NULL;
  2736. }
  2737. //
  2738. // Initialize the pointer to the array of RVA-based ansi export strings.
  2739. //
  2740. NameTableBase = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNames);
  2741. //
  2742. // Initialize the pointer to the array of USHORT ordinal numbers.
  2743. //
  2744. NameOrdinalTableBase = (PUSHORT)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals);
  2745. //
  2746. // Lookup the desired name in the name table using a binary search.
  2747. //
  2748. Low = 0;
  2749. High = ExportDirectory->NumberOfNames - 1;
  2750. //
  2751. // Initializing Middle is not needed for correctness, but without it
  2752. // the compiler cannot compile this code W4 to check for use of
  2753. // uninitialized variables.
  2754. //
  2755. Middle = 0;
  2756. while (High >= Low && (LONG)High >= 0) {
  2757. //
  2758. // Compute the next probe index and compare the import name
  2759. // with the export name entry.
  2760. //
  2761. Middle = (Low + High) >> 1;
  2762. Result = strcmp (AnsiImageRoutineName->Buffer,
  2763. (PCHAR)DllBase + NameTableBase[Middle]);
  2764. if (Result < 0) {
  2765. High = Middle - 1;
  2766. }
  2767. else if (Result > 0) {
  2768. Low = Middle + 1;
  2769. }
  2770. else {
  2771. break;
  2772. }
  2773. }
  2774. //
  2775. // If the high index is less than the low index, then a matching
  2776. // table entry was not found. Otherwise, get the ordinal number
  2777. // from the ordinal table.
  2778. //
  2779. if ((LONG)High < (LONG)Low) {
  2780. return NULL;
  2781. }
  2782. OrdinalNumber = NameOrdinalTableBase[Middle];
  2783. //
  2784. // If the OrdinalNumber is not within the Export Address Table,
  2785. // then this image does not implement the function. Return not found.
  2786. //
  2787. if ((ULONG)OrdinalNumber >= ExportDirectory->NumberOfFunctions) {
  2788. return NULL;
  2789. }
  2790. //
  2791. // Index into the array of RVA export addresses by ordinal number.
  2792. //
  2793. Addr = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions);
  2794. FunctionAddress = (PVOID)((PCHAR)DllBase + Addr[OrdinalNumber]);
  2795. //
  2796. // Forwarders are not used by the kernel and HAL to each other.
  2797. //
  2798. if ((ULONG_PTR)FunctionAddress > (ULONG_PTR)ExportDirectory &&
  2799. (ULONG_PTR)FunctionAddress < ((ULONG_PTR)ExportDirectory + ExportSize)) {
  2800. FunctionAddress = NULL;
  2801. }
  2802. return FunctionAddress;
  2803. }
  2804. UINT
  2805. NdisGetVersion(
  2806. VOID
  2807. )
  2808. {
  2809. return ((NDIS_MAJOR_VERSION << 16) | NDIS_MINOR_VERSION);
  2810. }
  2811. #if 0
  2812. VOID
  2813. ndisBindUnbindCallback(
  2814. PVOID CallBackContext,
  2815. PVOID Argument1,
  2816. PVOID Argument2
  2817. )
  2818. {
  2819. PWNODE_SINGLE_INSTANCE wnode = (PWNODE_SINGLE_INSTANCE)Argument1;
  2820. PUCHAR ptmp;
  2821. UNICODE_STRING ProtocolName, MiniportName;
  2822. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2823. ("==>ndisBindUnbindCallback\n"));
  2824. if (wnode != NULL)
  2825. {
  2826. ptmp = (PUCHAR)wnode + wnode->DataBlockOffset;
  2827. RtlInitUnicodeString(&ProtocolName, (PWCHAR)ptmp);
  2828. ptmp += ProtocolName.Length + sizeof(WCHAR);
  2829. RtlInitUnicodeString(&MiniportName, (PWCHAR)ptmp);
  2830. ndisDbgPrintUnicodeString(&ProtocolName);
  2831. DbgPrint("\n");
  2832. ndisDbgPrintUnicodeString(&MiniportName);
  2833. DbgPrint("\n");
  2834. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  2835. ("<==ndisBindUnbindCallback\n"));
  2836. }
  2837. }
  2838. #endif