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.

3004 lines
77 KiB

  1. /*++ BUILD Version: 0000 // Increment this if a change has global effects
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. ndistapi.c
  5. Abstract:
  6. This module contains the NdisTapi.sys implementation
  7. Author:
  8. Dan Knudson (DanKn) 20-Feb-1994
  9. Notes:
  10. (Future/outstanding issues)
  11. - stuff marked with "PnP" needs to be rev'd for plug 'n play support
  12. Revision History:
  13. --*/
  14. #include "ndis.h"
  15. #include "stdarg.h"
  16. #include "stdio.h"
  17. #include "ntddndis.h"
  18. #include "ndistapi.h"
  19. #include "private.h"
  20. #include "intrface.h"
  21. NTSTATUS
  22. DriverEntry(
  23. IN PDRIVER_OBJECT DriverObject,
  24. IN PUNICODE_STRING RegistryPath
  25. );
  26. VOID
  27. NdisTapiCancel(
  28. IN PDEVICE_OBJECT DeviceObject,
  29. IN PIRP Irp
  30. );
  31. NTSTATUS
  32. NdisTapiCleanup(
  33. IN PDEVICE_OBJECT DeviceObject,
  34. IN PIRP Irp
  35. );
  36. NTSTATUS
  37. NdisTapiDispatch(
  38. IN PDEVICE_OBJECT DeviceObject,
  39. IN PIRP Irp
  40. );
  41. VOID
  42. NdisTapiUnload(
  43. IN PDRIVER_OBJECT DriverObject
  44. );
  45. #if DBG
  46. VOID
  47. DbgPrt(
  48. IN LONG DbgLevel,
  49. IN PUCHAR DbgMessage,
  50. IN ...
  51. );
  52. #endif
  53. VOID
  54. DoProviderInitComplete(
  55. PPROVIDER_REQUEST ProviderRequest,
  56. NDIS_STATUS Status
  57. );
  58. ULONG
  59. GetLineEvents(
  60. PVOID EventBuffer,
  61. ULONG BufferSize
  62. );
  63. BOOLEAN
  64. SyncInitAllProviders(
  65. void
  66. );
  67. VOID
  68. DoIrpMjCloseWork(
  69. PIRP Irp
  70. );
  71. NDIS_STATUS
  72. SendProviderInitRequest(
  73. PPROVIDER_INFO Provider
  74. );
  75. NDIS_STATUS
  76. SendProviderShutdown(
  77. PPROVIDER_INFO Provider,
  78. PKIRQL oldIrql
  79. );
  80. VOID
  81. NdisTapiIndicateStatus(
  82. IN ULONG_PTR DriverHandle,
  83. IN PVOID StatusBuffer,
  84. IN UINT StatusBufferSize
  85. );
  86. VOID
  87. DoLineOpenCompleteWork(
  88. PNDISTAPI_REQUEST ndisTapiRequest,
  89. PPROVIDER_INFO provider
  90. );
  91. VOID
  92. DoLineOpenWork(
  93. PNDISTAPI_REQUEST ndisTapiRequest,
  94. PPROVIDER_INFO provider
  95. );
  96. NDIS_STATUS
  97. VerifyProvider(
  98. PNDISTAPI_REQUEST ndisTapiRequest,
  99. PPROVIDER_INFO *provider
  100. );
  101. NDIS_STATUS
  102. VerifyLineClose(
  103. PNDISTAPI_REQUEST ndisTapiRequest,
  104. PPROVIDER_INFO provider
  105. );
  106. NTSTATUS
  107. DoIoctlConnectWork(
  108. PIRP Irp,
  109. PVOID ioBuffer,
  110. ULONG inputBufferLength,
  111. ULONG outputBufferLength
  112. );
  113. NTSTATUS
  114. DoIoctlQuerySetWork(
  115. PIRP Irp,
  116. PVOID ioBuffer,
  117. ULONG inputBufferLength,
  118. ULONG outputBufferLength
  119. );
  120. NTSTATUS
  121. DoGetProviderEventsWork(
  122. PIRP Irp,
  123. PVOID ioBuffer,
  124. ULONG inputBufferLength,
  125. ULONG outputBufferLength
  126. );
  127. NTSTATUS
  128. DoLineCreateWork(
  129. PIRP Irp,
  130. PVOID ioBuffer,
  131. ULONG inputBufferLength,
  132. ULONG outputBufferLength
  133. );
  134. //
  135. // Use the alloc_text pragma to specify the driver initialization routines
  136. // (they can be paged out).
  137. //
  138. #ifdef ALLOC_PRAGMA
  139. #pragma alloc_text(INIT,DriverEntry)
  140. #endif
  141. NPAGED_LOOKASIDE_LIST ProviderEventLookaside;
  142. NTSTATUS
  143. DriverEntry(
  144. IN PDRIVER_OBJECT DriverObject,
  145. IN PUNICODE_STRING RegistryPath
  146. )
  147. /*++
  148. Routine Description:
  149. Installable driver initialization entry point.
  150. This entry point is called directly by the I/O system.
  151. Arguments:
  152. DriverObject - pointer to the driver object
  153. RegistryPath - pointer to a unicode string representing the path
  154. to driver-specific key in the registry
  155. Return Value:
  156. STATUS_SUCCESS if successful,
  157. STATUS_UNSUCCESSFUL otherwise
  158. --*/
  159. {
  160. PDEVICE_OBJECT deviceObject = NULL;
  161. NTSTATUS ntStatus;
  162. WCHAR deviceNameBuffer[] = L"\\Device\\NdisTapi";
  163. UNICODE_STRING deviceNameUnicodeString;
  164. UNICODE_STRING registryPath;
  165. DBGOUT ((2, "DriverEntry: enter"));
  166. //
  167. // Create a NON-EXCLUSIVE device, i.e. multiple threads at a time
  168. // can send i/o requests.
  169. //
  170. RtlInitUnicodeString (&deviceNameUnicodeString, deviceNameBuffer);
  171. ntStatus = IoCreateDevice(
  172. DriverObject,
  173. sizeof (KMDD_DEVICE_EXTENSION),
  174. &deviceNameUnicodeString,
  175. FILE_DEVICE_NDISTAPI,
  176. 0,
  177. FALSE,
  178. &deviceObject
  179. );
  180. if (NT_SUCCESS(ntStatus))
  181. {
  182. //
  183. // Init the global & sero the extension
  184. //
  185. DeviceExtension =
  186. (PKMDD_DEVICE_EXTENSION) deviceObject->DeviceExtension;
  187. RtlZeroMemory(
  188. DeviceExtension,
  189. sizeof (KMDD_DEVICE_EXTENSION)
  190. );
  191. //
  192. // Create a NULL-terminated registry path & retrieve the registry
  193. // params (EventDataQueueLength)
  194. //
  195. registryPath.Buffer = ExAllocatePoolWithTag(
  196. PagedPool,
  197. RegistryPath->Length + sizeof(UNICODE_NULL),
  198. 'IPAT'
  199. );
  200. if (!registryPath.Buffer)
  201. {
  202. DBGOUT((1, "DriverEntry: ExAllocPool for szRegistryPath failed"));
  203. ntStatus = STATUS_UNSUCCESSFUL;
  204. goto DriverEntry_err;
  205. }
  206. else
  207. {
  208. registryPath.Length = RegistryPath->Length;
  209. registryPath.MaximumLength =
  210. registryPath.Length + sizeof(UNICODE_NULL);
  211. RtlZeroMemory(
  212. registryPath.Buffer,
  213. registryPath.MaximumLength
  214. );
  215. RtlMoveMemory(
  216. registryPath.Buffer,
  217. RegistryPath->Buffer,
  218. RegistryPath->Length
  219. );
  220. }
  221. ExFreePool (registryPath.Buffer);
  222. InitializeListHead(&DeviceExtension->ProviderEventList);
  223. ExInitializeNPagedLookasideList(&ProviderEventLookaside,
  224. NULL,
  225. NULL,
  226. 0,
  227. sizeof(PROVIDER_EVENT),
  228. 'IPAT',
  229. 0);
  230. DeviceExtension->DeviceObject = deviceObject;
  231. DeviceExtension->Status = NDISTAPI_STATUS_DISCONNECTED;
  232. DeviceExtension->NdisTapiNumDevices = 0;
  233. DeviceExtension->htCall = 0x80000001;
  234. KeInitializeSpinLock (&DeviceExtension->SpinLock);
  235. InitializeListHead(&DeviceExtension->ProviderRequestList);
  236. //
  237. // Create dispatch points for device control, create, close.
  238. //
  239. DriverObject->MajorFunction[IRP_MJ_CREATE] =
  240. DriverObject->MajorFunction[IRP_MJ_CLOSE] =
  241. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisTapiDispatch;
  242. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = NdisTapiCleanup;
  243. DriverObject->DriverUnload = NdisTapiUnload;
  244. }
  245. if (!NT_SUCCESS(ntStatus)) {
  246. DriverEntry_err:
  247. //
  248. // Something went wrong, so clean up
  249. //
  250. DBGOUT((0, "init failed"));
  251. if (deviceObject)
  252. {
  253. while (!(IsListEmpty(&DeviceExtension->ProviderEventList))) {
  254. PPROVIDER_EVENT ProviderEvent;
  255. ProviderEvent = (PPROVIDER_EVENT)
  256. RemoveHeadList(&DeviceExtension->ProviderEventList);
  257. ExFreeToNPagedLookasideList(&ProviderEventLookaside, ProviderEvent);
  258. }
  259. IoDeleteDevice (deviceObject);
  260. }
  261. }
  262. DBGOUT ((2, "DriverEntry: exit"));
  263. return ntStatus;
  264. }
  265. VOID
  266. NdisTapiCancel(
  267. IN PDEVICE_OBJECT DeviceObject,
  268. IN PIRP Irp
  269. )
  270. {
  271. KIRQL oldIrql;
  272. DBGOUT((2,"NdisTapiCancel: enter"));
  273. //
  274. // Release the cancel spinlock
  275. //
  276. IoReleaseCancelSpinLock (Irp->CancelIrql);
  277. //
  278. // Acquire the SpinLock & check to see if we're canceling a
  279. // pending get-events Irp
  280. //
  281. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  282. do {
  283. DeviceExtension->IrpsCanceledCount++;
  284. if (Irp == DeviceExtension->EventsRequestIrp) {
  285. DeviceExtension->EventsRequestIrp = NULL;
  286. DeviceExtension->Flags |= EVENTIRP_CANCELED;
  287. break;
  288. }
  289. //
  290. // Try to remove request from our special
  291. // user-mode requests dev queue
  292. //
  293. if (!IsListEmpty(&DeviceExtension->ProviderRequestList)) {
  294. PLIST_ENTRY Entry;
  295. Entry = DeviceExtension->ProviderRequestList.Flink;
  296. while (Entry != &DeviceExtension->ProviderRequestList) {
  297. PPROVIDER_REQUEST pReq;
  298. pReq = (PPROVIDER_REQUEST)Entry;
  299. if (pReq->Irp == Irp) {
  300. RemoveEntryList(&pReq->Linkage);
  301. DeviceExtension->RequestCount--;
  302. DeviceExtension->Flags |= REQUESTIRP_CANCELED;
  303. break;
  304. }
  305. Entry = Entry->Flink;
  306. }
  307. if (Entry == &DeviceExtension->ProviderRequestList) {
  308. DBGOUT((1,"NdisTapiCancel: Irp %p not in device queue?!?", Irp));
  309. DeviceExtension->Flags |= CANCELIRP_NOTFOUND;
  310. }
  311. }
  312. } while (FALSE);
  313. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  314. //
  315. // Complete the request with STATUS_CANCELLED.
  316. //
  317. Irp->IoStatus.Status = STATUS_CANCELLED;
  318. Irp->IoStatus.Information = 0;
  319. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  320. DBGOUT((2,"NdisTapiCancel: completing irp=%p", Irp));
  321. }
  322. NTSTATUS
  323. NdisTapiCleanup(
  324. IN PDEVICE_OBJECT DeviceObject,
  325. IN PIRP Irp
  326. )
  327. /*++
  328. Routine Description:
  329. This routine is the dispatch routine for cleanup requests.
  330. All requests queued are completed with STATUS_CANCELLED.
  331. Arguments:
  332. DeviceObject - Pointer to device object.
  333. Irp - Pointer to the request packet.
  334. Return Value:
  335. Status is returned.
  336. --*/
  337. {
  338. KIRQL oldIrql;
  339. PNDISTAPI_REQUEST ndisTapiRequest;
  340. PKDEVICE_QUEUE_ENTRY packet;
  341. DBGOUT((2,"NdisTapiCleanup: enter"));
  342. //
  343. // Sync access to EventsRequestIrp by acquiring SpinLock
  344. //
  345. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  346. DeviceExtension->Flags |= CLEANUP_INITIATED;
  347. //
  348. // Check to see if there's a get-events request pending that needs
  349. // completing
  350. //
  351. if ((DeviceExtension->EventsRequestIrp != NULL) &&
  352. (DeviceExtension->EventsRequestIrp->Tail.Overlay.OriginalFileObject ==
  353. Irp->Tail.Overlay.OriginalFileObject)) {
  354. PIRP LocalIrp;
  355. //
  356. // Acquire the cancel spinlock, remove the request from the
  357. // cancellable state, and free the cancel spinlock.
  358. //
  359. LocalIrp = DeviceExtension->EventsRequestIrp;
  360. if (IoSetCancelRoutine (LocalIrp, NULL) != NULL) {
  361. DeviceExtension->EventsRequestIrp = NULL;
  362. LocalIrp->IoStatus.Status = STATUS_CANCELLED;
  363. LocalIrp->IoStatus.Information = 0;
  364. DeviceExtension->IrpsCanceledCount++;
  365. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  366. DBGOUT((2,"NdisTapiCleanup: Completing EventRequestIrp %p", LocalIrp));
  367. IoCompleteRequest (LocalIrp, IO_NO_INCREMENT);
  368. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  369. }
  370. }
  371. //
  372. // Cancel all outstanding QUERY/SET_INFO requests
  373. //
  374. if (!IsListEmpty(&DeviceExtension->ProviderRequestList)) {
  375. PPROVIDER_REQUEST pReq;
  376. pReq = (PPROVIDER_REQUEST)
  377. DeviceExtension->ProviderRequestList.Flink;
  378. //
  379. // Until we have walked the entire list
  380. //
  381. while ((PVOID)pReq != (PVOID)&DeviceExtension->ProviderRequestList) {
  382. PIRP LocalIrp;
  383. LocalIrp = pReq->Irp;
  384. //
  385. // If the current entry's irp has a fileobject that is
  386. // the same as the cleanup irp's fileobject then remove it
  387. // from the list and cancel it
  388. //
  389. if (LocalIrp->Tail.Overlay.OriginalFileObject ==
  390. Irp->Tail.Overlay.OriginalFileObject) {
  391. //
  392. // Remove the IRP from the cancelable state
  393. //
  394. if (IoSetCancelRoutine (LocalIrp, NULL) == NULL) {
  395. //
  396. // The irp has been canceled. Let
  397. // cancel routine cleanup.
  398. //
  399. pReq =
  400. (PPROVIDER_REQUEST)pReq->Linkage.Flink;
  401. continue;
  402. }
  403. RemoveEntryList(&pReq->Linkage);
  404. DeviceExtension->RequestCount--;
  405. //
  406. // Set the status & info size values appropriately, & complete
  407. // the request
  408. //
  409. ndisTapiRequest = LocalIrp->AssociatedIrp.SystemBuffer;
  410. ndisTapiRequest->ulReturnValue = (ULONG) NDIS_STATUS_FAILURE;
  411. LocalIrp->IoStatus.Status = STATUS_CANCELLED;
  412. LocalIrp->IoStatus.Information = 0;
  413. DeviceExtension->IrpsCanceledCount++;
  414. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  415. DBGOUT((2,"NdisTapiCleanup: Completing ProviderRequestIrp %p", LocalIrp));
  416. IoCompleteRequest (LocalIrp, IO_NO_INCREMENT);
  417. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  418. pReq = (PPROVIDER_REQUEST)
  419. DeviceExtension->ProviderRequestList.Flink;
  420. } else {
  421. pReq = (PPROVIDER_REQUEST)
  422. pReq->Linkage.Flink;
  423. }
  424. }
  425. }
  426. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  427. //
  428. // Complete the cleanup request with STATUS_SUCCESS.
  429. //
  430. Irp->IoStatus.Status = STATUS_SUCCESS;
  431. Irp->IoStatus.Information = 0;
  432. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  433. DBGOUT((2,"NdisTapiCleanup: exit"));
  434. return(STATUS_SUCCESS);
  435. }
  436. NTSTATUS
  437. NdisTapiDispatch(
  438. IN PDEVICE_OBJECT DeviceObject,
  439. IN PIRP Irp
  440. )
  441. /*++
  442. Routine Description:
  443. Process the IRPs sent to this device.
  444. Arguments:
  445. DeviceObject - pointer to a device object
  446. Irp - pointer to an I/O Request Packet
  447. Return Value:
  448. --*/
  449. {
  450. NTSTATUS NtStatus;
  451. PVOID ioBuffer;
  452. ULONG inputBufferLength;
  453. ULONG outputBufferLength;
  454. PIO_STACK_LOCATION irpStack;
  455. //
  456. // Get a pointer to the current location in the Irp. This is where
  457. // the function codes and parameters are located.
  458. //
  459. irpStack = IoGetCurrentIrpStackLocation (Irp);
  460. //
  461. // Get the pointer to the input/output buffer and it's length
  462. //
  463. ioBuffer =
  464. Irp->AssociatedIrp.SystemBuffer;
  465. inputBufferLength =
  466. irpStack->Parameters.DeviceIoControl.InputBufferLength;
  467. outputBufferLength =
  468. irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  469. switch (irpStack->MajorFunction) {
  470. case IRP_MJ_CREATE:
  471. DBGOUT ((2, "IRP_MJ_CREATE, Irp=%p", Irp));
  472. InterlockedIncrement(&DeviceExtension->RefCount);
  473. NtStatus = Irp->IoStatus.Status
  474. = STATUS_SUCCESS;
  475. Irp->IoStatus.Information = 0;
  476. break;
  477. case IRP_MJ_CLOSE:
  478. DBGOUT ((2, "IRP_MJ_CLOSE, Irp=%p", Irp));
  479. DoIrpMjCloseWork(Irp);
  480. NtStatus = STATUS_SUCCESS;
  481. break;
  482. case IRP_MJ_DEVICE_CONTROL:
  483. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  484. case IOCTL_NDISTAPI_CONNECT:
  485. DBGOUT ((2, "IOCTL_NDISTAPI_CONNECT, Irp=%p", Irp));
  486. NtStatus =
  487. DoIoctlConnectWork(Irp,
  488. ioBuffer,
  489. inputBufferLength,
  490. outputBufferLength);
  491. break;
  492. case IOCTL_NDISTAPI_QUERY_INFO:
  493. case IOCTL_NDISTAPI_SET_INFO:
  494. DBGOUT ((2, "IOCTL_NDISTAPI_QUERY/SET_INFO, Irp=%p", Irp));
  495. NtStatus =
  496. DoIoctlQuerySetWork(Irp,
  497. ioBuffer,
  498. inputBufferLength,
  499. outputBufferLength);
  500. break;
  501. case IOCTL_NDISTAPI_GET_LINE_EVENTS:
  502. DBGOUT ((2, "IOCTL_NDISTAPI_GET_LINE_EVENTS, Irp=%p", Irp));
  503. NtStatus =
  504. DoGetProviderEventsWork(Irp,
  505. ioBuffer,
  506. inputBufferLength,
  507. outputBufferLength);
  508. break;
  509. case IOCTL_NDISTAPI_CREATE:
  510. DBGOUT ((2, "IOCTL_NDISTAPI_CREATE, Irp=%p", Irp));
  511. NtStatus =
  512. DoLineCreateWork(Irp,
  513. ioBuffer,
  514. inputBufferLength,
  515. outputBufferLength);
  516. break;
  517. default:
  518. DBGOUT ((2, "Unknown IRP_MJ_DEVICE_CONTROL, Irp=%p", Irp));
  519. NtStatus = Irp->IoStatus.Status =
  520. STATUS_INVALID_PARAMETER;
  521. Irp->IoStatus.Information = 0;
  522. break;
  523. }
  524. break;
  525. }
  526. if (NtStatus == STATUS_PENDING) {
  527. return (STATUS_PENDING);
  528. }
  529. ASSERT(NtStatus == Irp->IoStatus.Status);
  530. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  531. DBGOUT((3, "NdisTapiDispatch: completed Irp=%p", Irp));
  532. return NtStatus;
  533. }
  534. VOID
  535. NdisTapiUnload(
  536. IN PDRIVER_OBJECT DriverObject
  537. )
  538. /*++
  539. Routine Description:
  540. Free all the allocated resources, etc.
  541. Arguments:
  542. DriverObject - pointer to a driver object
  543. Return Value:
  544. --*/
  545. {
  546. KIRQL oldIrql;
  547. PPROVIDER_INFO provider, nextProvider;
  548. DBGOUT ((2, "NdisTapiUnload: enter"));
  549. //
  550. // Delete the device object & sundry resources
  551. //
  552. while (!(IsListEmpty(&DeviceExtension->ProviderEventList))) {
  553. PPROVIDER_EVENT ProviderEvent;
  554. ProviderEvent = (PPROVIDER_EVENT)
  555. RemoveHeadList(&DeviceExtension->ProviderEventList);
  556. ExFreeToNPagedLookasideList(&ProviderEventLookaside, ProviderEvent);
  557. }
  558. ExDeleteNPagedLookasideList(&ProviderEventLookaside);
  559. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  560. provider = DeviceExtension->Providers;
  561. while (provider != NULL)
  562. {
  563. nextProvider = provider->Next;
  564. ExFreePool (provider);
  565. provider = nextProvider;
  566. }
  567. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  568. IoDeleteDevice (DriverObject->DeviceObject);
  569. DBGOUT ((2, "NdisTapiUnload: exit"));
  570. return;
  571. }
  572. VOID
  573. NdisTapiRegisterProvider(
  574. IN NDIS_HANDLE ProviderHandle,
  575. IN PNDISTAPI_CHARACTERISTICS Chars
  576. )
  577. /*++
  578. Routine Description:
  579. This func gets called by Ndis as a result of a Mac driver
  580. registering for Connection Wrapper services.
  581. Arguments:
  582. Return Value:
  583. --*/
  584. {
  585. KIRQL oldIrql;
  586. BOOLEAN sendRequest = FALSE;
  587. NDIS_STATUS ndisStatus;
  588. PPROVIDER_INFO provider, newProvider;
  589. DBGOUT ((2, "NdisTapiRegisterProvider: enter"));
  590. //
  591. // Grab the spin lock & add the new provider, and see whether to
  592. // send the provider an init request
  593. //
  594. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  595. //
  596. // See if this provider has already registered once.
  597. //
  598. provider = DeviceExtension->Providers;
  599. while (provider != NULL) {
  600. if (provider->Status == PROVIDER_STATUS_OFFLINE &&
  601. RtlCompareMemory(
  602. &provider->Guid,
  603. &Chars->Guid,
  604. sizeof(provider->Guid)) == sizeof(provider->Guid)) {
  605. DBGOUT((
  606. 1,
  607. "Found a provider %p for Guid %4.4x-%2.2x-%2.2x-%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x",
  608. provider,
  609. provider->Guid.Data1,
  610. provider->Guid.Data2,
  611. provider->Guid.Data3,
  612. provider->Guid.Data4[0],
  613. provider->Guid.Data4[1],
  614. provider->Guid.Data4[2],
  615. provider->Guid.Data4[3],
  616. provider->Guid.Data4[4],
  617. provider->Guid.Data4[5],
  618. provider->Guid.Data4[6],
  619. provider->Guid.Data4[7]
  620. ));
  621. DBGOUT((
  622. 1,
  623. "numDevices %d BaseID %d",
  624. provider->NumDevices,
  625. provider->DeviceIDBase
  626. ));
  627. provider->Status = PROVIDER_STATUS_PENDING_REINIT;
  628. provider->ProviderHandle = ProviderHandle;
  629. provider->RequestProc = Chars->RequestProc;
  630. provider->MediaType = Chars->MediaType;
  631. break;
  632. }
  633. provider = provider->Next;
  634. }
  635. if (provider == NULL) {
  636. //
  637. // Create a new provider instance
  638. //
  639. newProvider = ExAllocatePoolWithTag(
  640. NonPagedPoolCacheAligned,
  641. sizeof(PROVIDER_INFO),
  642. 'IPAT'
  643. );
  644. if (!newProvider) {
  645. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  646. return;
  647. }
  648. RtlZeroMemory(newProvider, sizeof(PROVIDER_INFO));
  649. newProvider->Status = PROVIDER_STATUS_PENDING_INIT;
  650. newProvider->ProviderHandle = ProviderHandle;
  651. newProvider->RequestProc = Chars->RequestProc;
  652. RtlMoveMemory(
  653. &newProvider->Guid,
  654. &Chars->Guid,
  655. sizeof(newProvider->Guid)
  656. );
  657. newProvider->MediaType = Chars->MediaType;
  658. newProvider->Next = NULL;
  659. DBGOUT((
  660. 1,
  661. "New provider for Guid %4.4x-%2.2x-%2.2x-%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x",
  662. newProvider->Guid.Data1,
  663. newProvider->Guid.Data2,
  664. newProvider->Guid.Data3,
  665. newProvider->Guid.Data4[0],
  666. newProvider->Guid.Data4[1],
  667. newProvider->Guid.Data4[2],
  668. newProvider->Guid.Data4[3],
  669. newProvider->Guid.Data4[4],
  670. newProvider->Guid.Data4[5],
  671. newProvider->Guid.Data4[6],
  672. newProvider->Guid.Data4[7]
  673. ));
  674. //
  675. // Add the new provider, and see whether to send the
  676. // provider an init request
  677. //
  678. if ((provider = DeviceExtension->Providers) == NULL) {
  679. DeviceExtension->Providers = newProvider;
  680. }
  681. else {
  682. while (provider->Next != NULL) {
  683. provider = provider->Next;
  684. }
  685. provider->Next = newProvider;
  686. }
  687. provider = newProvider;
  688. }
  689. //
  690. // The only case where we want to send off an init request to the
  691. // provider directly is when we are currently connected to TAPI,
  692. // and even then only when there are no other inits pending (since
  693. // we must synchronize inits due to calculation of DeviceIDBase)
  694. //
  695. if (DeviceExtension->Status == NDISTAPI_STATUS_CONNECTED) {
  696. //
  697. // TAPI is up.
  698. //
  699. // If TAPI already knows about this provider
  700. // go ahead and init the provider with it's current
  701. // DeviceIDBase.
  702. //
  703. // If TAPI does not know about this provider we
  704. // need to give TAPI an indication of a new device
  705. // coming on line.
  706. //
  707. if (provider->Status == PROVIDER_STATUS_PENDING_REINIT) {
  708. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  709. ndisStatus =
  710. SendProviderInitRequest (provider);
  711. if (ndisStatus == NDIS_STATUS_PENDING) {
  712. //
  713. // Wait for completion routine to get called
  714. //
  715. KeWaitForSingleObject (&provider->SyncEvent,
  716. Executive,
  717. KernelMode,
  718. FALSE,
  719. (PTIME) NULL);
  720. }
  721. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  722. //
  723. // Get tapi to reset the state of these lines by
  724. // forcing a line_close...
  725. //
  726. if (provider->DeviceInfo != NULL) {
  727. PDEVICE_INFO DeviceInfo;
  728. ULONG i;
  729. for(i = 0, DeviceInfo = provider->DeviceInfo;
  730. i < provider->NumDevices;
  731. i++, DeviceInfo++) {
  732. NDIS_TAPI_EVENT NdisTapiEvent;
  733. RtlZeroMemory (&NdisTapiEvent, sizeof(NDIS_TAPI_EVENT));
  734. if (DeviceInfo->htLine != (HTAPI_LINE)NULL)
  735. {
  736. NdisTapiEvent.htLine = DeviceInfo->htLine;
  737. NdisTapiEvent.ulMsg = LINE_CLOSE;
  738. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  739. NdisTapiIndicateStatus((ULONG_PTR) provider,
  740. &NdisTapiEvent,
  741. sizeof (NDIS_TAPI_EVENT));
  742. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  743. DeviceInfo->htLine = (HTAPI_LINE)NULL;
  744. DeviceInfo->hdLine = (HDRV_LINE)NULL;
  745. }
  746. }
  747. }
  748. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  749. } else {
  750. NDIS_TAPI_EVENT NdisTapiEvent;
  751. ASSERT(provider->Status == PROVIDER_STATUS_PENDING_INIT);
  752. provider->Status = PROVIDER_STATUS_PENDING_LINE_CREATE;
  753. //
  754. // If there are no providers in the middle of doing
  755. // line_create's then we will kick off creates for this
  756. // provider.
  757. //
  758. // If we already have a line create pending on a provider
  759. // then we will wait until all of its line creates have
  760. // finished before we start sending them from
  761. // this one.
  762. //
  763. if (!(DeviceExtension->Flags & PENDING_LINECREATE)) {
  764. //
  765. // Do a LINE_CREATE so that we can get the starting
  766. // BaseID for this provider. When TAPI calls us back
  767. // with ProviderCreateLineDevice we will have the
  768. // BaseDeviceID to use for this provider and we will
  769. // then init the provider. Once we find out how many
  770. // devices the provider has we will alert TAPI of the
  771. // additional devices.
  772. //
  773. RtlZeroMemory(&NdisTapiEvent, sizeof(NDIS_TAPI_EVENT));
  774. provider->TempID = (ULONG_PTR)provider;
  775. DBGOUT((-1,
  776. "LINE_CREATE %d for provider %p",
  777. provider->CreateCount,
  778. provider->TempID
  779. ));
  780. NdisTapiEvent.ulMsg = LINE_CREATE;
  781. NdisTapiEvent.ulParam1 = 0;
  782. NdisTapiEvent.ulParam2 = provider->TempID;
  783. NdisTapiEvent.ulParam3 = 0;
  784. DeviceExtension->Flags |= PENDING_LINECREATE;
  785. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  786. NdisTapiIndicateStatus((ULONG_PTR)provider, &NdisTapiEvent, sizeof(NDIS_TAPI_EVENT));
  787. }
  788. else
  789. {
  790. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  791. }
  792. }
  793. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  794. }
  795. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  796. ObReferenceObject(DeviceExtension->DeviceObject);
  797. }
  798. VOID
  799. NdisTapiDeregisterProvider(
  800. IN NDIS_HANDLE ProviderHandle
  801. )
  802. /*++
  803. Routine Description:
  804. This func...
  805. Note that this func does not send the provider a shutdown message,
  806. as an implicit shutdown is assumed when the provider deegisters.
  807. Arguments:
  808. Return Value:
  809. --*/
  810. {
  811. KIRQL oldIrql;
  812. BOOLEAN sendShutdownMsg = FALSE;
  813. PPROVIDER_INFO provider, previousProvider;
  814. DBGOUT ((2, "NdisTapiDeregisterProvider: enter"));
  815. //
  816. // Grab the spin lock protecting the device extension
  817. //
  818. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  819. //
  820. // Find the provider instance corresponding to ProviderHandle
  821. //
  822. previousProvider = NULL;
  823. provider = DeviceExtension->Providers;
  824. while (provider != NULL &&
  825. provider->ProviderHandle != ProviderHandle) {
  826. previousProvider = provider;
  827. provider = provider->Next;
  828. }
  829. if (provider == NULL) {
  830. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  831. return;
  832. }
  833. if (provider->Status == PROVIDER_STATUS_ONLINE) {
  834. DeviceExtension->NdisTapiNumDevices -= provider->NumDevices;
  835. }
  836. //
  837. // Send the ProviderShutdown only if the provider
  838. // is not in PROVIDER_STATUS_OFFLINE. Otherwise
  839. // DoIrpMjCloseWork can end up sending
  840. // Providershutdown on a removed adapter.
  841. //
  842. if(provider->Status != PROVIDER_STATUS_OFFLINE)
  843. {
  844. SendProviderShutdown (provider, &oldIrql);
  845. provider->Status = PROVIDER_STATUS_OFFLINE;
  846. }
  847. //
  848. // Do the right thing according to the current NdisTapi state
  849. //
  850. switch (DeviceExtension->Status)
  851. {
  852. case NDISTAPI_STATUS_CONNECTED:
  853. {
  854. UINT i;
  855. //
  856. // Mark provider as offline
  857. //
  858. provider->Status = PROVIDER_STATUS_OFFLINE;
  859. provider->ProviderHandle = NULL;
  860. #if 0
  861. if (provider->DeviceInfo != NULL) {
  862. PDEVICE_INFO DeviceInfo;
  863. for(
  864. i = 0, DeviceInfo = provider->DeviceInfo;
  865. i < provider->NumDevices;
  866. i++, DeviceInfo++
  867. )
  868. {
  869. NDIS_TAPI_EVENT NdisTapiEvent;
  870. RtlZeroMemory (&NdisTapiEvent, sizeof(NDIS_TAPI_EVENT));
  871. if (DeviceInfo->htLine != (HTAPI_LINE)NULL)
  872. {
  873. NdisTapiEvent.htLine = DeviceInfo->htLine;
  874. NdisTapiEvent.ulMsg = LINE_CLOSE;
  875. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  876. NdisTapiIndicateStatus((ULONG_PTR) provider,
  877. &NdisTapiEvent,
  878. sizeof (NDIS_TAPI_EVENT));
  879. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  880. DeviceInfo->htLine = (HTAPI_LINE)NULL;
  881. }
  882. }
  883. }
  884. #endif
  885. // PnP: what if providerInfo->State == PROVIDER_INIT_PENDING
  886. // PnP: what if providerInfo->State == PROVIDER_OFFLINE
  887. break;
  888. }
  889. case NDISTAPI_STATUS_DISCONNECTING:
  890. case NDISTAPI_STATUS_DISCONNECTED:
  891. //
  892. // Fix up pointers, remove provider from list
  893. //
  894. if (previousProvider == NULL) {
  895. DeviceExtension->Providers = provider->Next;
  896. } else {
  897. previousProvider->Next = provider->Next;
  898. }
  899. ExFreePool (provider);
  900. break;
  901. case NDISTAPI_STATUS_CONNECTING:
  902. // PnP: implement
  903. break;
  904. } // switch
  905. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  906. ObDereferenceObject(DeviceExtension->DeviceObject);
  907. DBGOUT((2, "NdisTapiDeregisterProvider: exit"));
  908. }
  909. VOID
  910. NdisTapiIndicateStatus(
  911. IN ULONG_PTR DriverHandle,
  912. IN PVOID StatusBuffer,
  913. IN UINT StatusBufferSize
  914. )
  915. /*++
  916. Routine Description:
  917. This func gets called by Ndis when a miniport driver calls
  918. NdisIndicateStatus to notify us of an async event
  919. (i.e. new call, call state chg, dev state chg, etc.)
  920. Arguments:
  921. Return Value:
  922. --*/
  923. {
  924. PIRP irp;
  925. KIRQL oldIrql;
  926. ULONG bytesInQueue;
  927. ULONG bytesToMove;
  928. ULONG moveSize;
  929. BOOLEAN satisfiedPendingEventsRequest = FALSE;
  930. PNDIS_TAPI_EVENT ndisTapiEvent;
  931. PNDISTAPI_EVENT_DATA ndisTapiEventData;
  932. DBGOUT((2,"NdisTapiIndicateStatus: enter"));
  933. bytesInQueue = StatusBufferSize;
  934. moveSize = 0;
  935. //
  936. // Sync event buf access by acquiring SpinLock
  937. //
  938. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  939. //
  940. // The very first thing to do is check if this is a LINE_NEWCALL
  941. // indication. If so, we need to generate a unique tapi call
  942. // handle, which will be both returned to the calling miniport
  943. // (for use in subsequent status indications) and passed up to
  944. // the tapi server.
  945. //
  946. // The algorithim for computing a unique "htCall" is to start
  947. // at the value 0x80000001, and perpetually increment by 2.
  948. // Keeping the low bit set will allow the user-mode TAPI component
  949. // we talk to to distinguish between these incoming call handles
  950. // and outgoing call handles, the latter of which will always
  951. // have the low bit zero'd (since they're really pointers to heap).
  952. // We are again going to use the space between 0x80000001 and 0xFFFFFFFF
  953. // to identify our call handle. This allows for a maximum of 1GB of
  954. // calls to be active at a time. This is done to avoid a conflict
  955. // with ndiswan's connection table index. A bug in the ddk doc's
  956. // had users providing the connectionid instead of ndiswan's context
  957. // in the line get id oid. Ndiswan has to check both of these and
  958. // now that they overlap it can cause problems. NdisWan will use
  959. // 0x00000000 - 0x80000000 for it's context values.
  960. //
  961. // In <= NT 4.0, valid values used to range between 0x80000000
  962. // and 0xffffffff, as we relied on the fact that user-mode
  963. // addresses always had the low bit zero'd. (Not a valid
  964. // assumption anymore!)
  965. //
  966. ndisTapiEvent = StatusBuffer;
  967. if (ndisTapiEvent->ulMsg == LINE_NEWCALL)
  968. {
  969. ndisTapiEvent->ulParam2 = DeviceExtension->htCall;
  970. DeviceExtension->htCall++;
  971. DeviceExtension->htCall++;
  972. if (DeviceExtension->htCall < 0x80000000) {
  973. DeviceExtension->htCall = 0x80000001;
  974. }
  975. }
  976. //
  977. // Check of there is an outstanding request to satisfy
  978. //
  979. if (DeviceExtension->EventsRequestIrp) {
  980. ASSERT(IsListEmpty(&DeviceExtension->ProviderEventList));
  981. //
  982. // Acquire the cancel spinlock, remove the request from the
  983. // cancellable state, and free the cancel spinlock.
  984. //
  985. irp = DeviceExtension->EventsRequestIrp;
  986. if (IoSetCancelRoutine(irp, NULL) != NULL) {
  987. DeviceExtension->EventsRequestIrp = NULL;
  988. //
  989. // Copy as much of the input data possible from the input data
  990. // queue to the SystemBuffer to satisfy the read.
  991. //
  992. ndisTapiEventData = irp->AssociatedIrp.SystemBuffer;
  993. bytesToMove = ndisTapiEventData->ulTotalSize;
  994. moveSize = (bytesInQueue < bytesToMove) ? bytesInQueue : bytesToMove;
  995. RtlMoveMemory (
  996. ndisTapiEventData->Data,
  997. (PCHAR) StatusBuffer,
  998. moveSize
  999. );
  1000. //
  1001. // Set the flag so that we start the next packet and complete
  1002. // this read request (with STATUS_SUCCESS) prior to return.
  1003. //
  1004. ndisTapiEventData->ulUsedSize = moveSize;
  1005. irp->IoStatus.Status = STATUS_SUCCESS;
  1006. irp->IoStatus.Information = sizeof(NDISTAPI_EVENT_DATA) + moveSize - 1;
  1007. satisfiedPendingEventsRequest = TRUE;
  1008. }
  1009. } else {
  1010. do {
  1011. PPROVIDER_EVENT ProviderEvent;
  1012. ProviderEvent =
  1013. ExAllocateFromNPagedLookasideList(&ProviderEventLookaside);
  1014. if (ProviderEvent == NULL) {
  1015. break;
  1016. }
  1017. RtlMoveMemory(&ProviderEvent->Event, StatusBuffer, sizeof(NDIS_TAPI_EVENT));
  1018. InsertTailList(&DeviceExtension->ProviderEventList,
  1019. &ProviderEvent->Linkage);
  1020. DeviceExtension->EventCount++;
  1021. } while ( FALSE );
  1022. }
  1023. //
  1024. // Release the spinlock
  1025. //
  1026. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1027. //
  1028. // If we satisfied an outstanding get events request then complete it
  1029. //
  1030. if (satisfiedPendingEventsRequest) {
  1031. IoCompleteRequest (irp, IO_NO_INCREMENT);
  1032. DBGOUT((2, "NdisTapiIndicateStatus: completion req %p", irp));
  1033. }
  1034. DBGOUT((2,"NdisTapiIndicateStatus: exit"));
  1035. return;
  1036. }
  1037. VOID
  1038. NdisTapiCompleteRequest(
  1039. IN NDIS_HANDLE NdisHandle,
  1040. IN PNDIS_REQUEST NdisRequest,
  1041. IN NDIS_STATUS NdisStatus
  1042. )
  1043. /*++
  1044. Routine Description:
  1045. This func gets called by Ndis as a result of a Mac driver
  1046. calling NdisCompleteRequest of one of our requests.
  1047. Arguments:
  1048. Return Value:
  1049. --*/
  1050. {
  1051. PIRP Irp;
  1052. KIRQL oldIrql;
  1053. ULONG requestID;
  1054. PNDISTAPI_REQUEST ndisTapiRequest;
  1055. PPROVIDER_REQUEST providerRequest;
  1056. PPROVIDER_REQUEST tempReq;
  1057. PIO_STACK_LOCATION irpStack;
  1058. DBGOUT ((2, "NdisTapiCompleteRequest: enter"));
  1059. providerRequest =
  1060. CONTAINING_RECORD(NdisRequest, PROVIDER_REQUEST, NdisRequest);
  1061. do {
  1062. if (providerRequest->Flags & INTERNAL_REQUEST) {
  1063. //
  1064. // This request originated from NdisTapi.sys
  1065. //
  1066. switch (NdisRequest->DATA.SET_INFORMATION.Oid) {
  1067. case OID_TAPI_PROVIDER_INITIALIZE:
  1068. DBGOUT((3,
  1069. "NdisTapiCompleteRequest: ProviderInit - Provider=%p, reqID=%x, Status=%x",
  1070. providerRequest->Provider,
  1071. providerRequest->RequestID,
  1072. NdisStatus));
  1073. switch (DeviceExtension->Status) {
  1074. case NDISTAPI_STATUS_CONNECTED:
  1075. case NDISTAPI_STATUS_CONNECTING:
  1076. DoProviderInitComplete (providerRequest, NdisStatus);
  1077. break;
  1078. case NDISTAPI_STATUS_DISCONNECTED:
  1079. case NDISTAPI_STATUS_DISCONNECTING:
  1080. default:
  1081. break;
  1082. }
  1083. break;
  1084. case OID_TAPI_PROVIDER_SHUTDOWN:
  1085. DBGOUT((3,
  1086. "NdisTapiCompleteRequest: ProviderShutdown - Provider=%p, reqID=%x, Status=%x",
  1087. providerRequest->Provider,
  1088. providerRequest->RequestID,
  1089. NdisStatus));
  1090. break;
  1091. default:
  1092. DBGOUT((1, "NdisTapiCompleteRequest: unrecognized Oid"));
  1093. break;
  1094. }
  1095. break;
  1096. }
  1097. //
  1098. // This is a request originating from TAPI
  1099. //
  1100. //
  1101. // Acquire the SpinLock since we're going to be removing a
  1102. // TAPI request from the queue, and it might not be the request
  1103. // we're looking for. The primary concern is that we could (if
  1104. // the request we're really looking for has been removed) remove
  1105. // a synchrously-completed request that is about to be removed &
  1106. // completed in NdisTapiDispatch, in which case we want to stick
  1107. // the request back in the queue before NdisTapiDispatch tries
  1108. // to remove it.
  1109. //
  1110. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1111. tempReq =
  1112. (PPROVIDER_REQUEST)DeviceExtension->ProviderRequestList.Flink;
  1113. while ((PVOID)tempReq != (PVOID)&DeviceExtension->ProviderRequestList) {
  1114. if (tempReq == providerRequest) {
  1115. break;
  1116. }
  1117. tempReq =
  1118. (PPROVIDER_REQUEST)tempReq->Linkage.Flink;
  1119. }
  1120. if (tempReq != providerRequest) {
  1121. #if DBG
  1122. DbgPrint("NDISTAPI: NdisTapiCompleteRequest: Request %p not found!\n",
  1123. providerRequest);
  1124. #endif
  1125. DeviceExtension->MissingRequests++;
  1126. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1127. break;
  1128. }
  1129. Irp = providerRequest->Irp;
  1130. ndisTapiRequest = Irp->AssociatedIrp.SystemBuffer;
  1131. ASSERT(providerRequest->RequestID ==
  1132. *((ULONG *)ndisTapiRequest->Data));
  1133. //
  1134. // Remove the IRP from the cancelable state
  1135. //
  1136. if (IoSetCancelRoutine(Irp, NULL) == NULL) {
  1137. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1138. break;
  1139. }
  1140. RemoveEntryList(&providerRequest->Linkage);
  1141. DeviceExtension->RequestCount--;
  1142. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1143. DBGOUT((3,
  1144. "NdisTapiCompleteRequest: Irp=%p, Oid=%x, devID=%d, reqID=%x, Status=%x",
  1145. Irp,
  1146. ndisTapiRequest->Oid,
  1147. ndisTapiRequest->ulDeviceID,
  1148. *((ULONG *)ndisTapiRequest->Data),
  1149. NdisStatus));
  1150. //
  1151. // Copy the relevant info back to the IRP
  1152. //
  1153. irpStack = IoGetCurrentIrpStackLocation (Irp);
  1154. //
  1155. // If this was a succesful QUERY_INFO request copy all the
  1156. // data back to the tapi request buf & set
  1157. // Irp->IoStatus.Information appropriately. Otherwise, we
  1158. // just need to pass back the return value. Also mark irp
  1159. // as successfully completed (regardless of actual op result)
  1160. //
  1161. if ((NdisRequest->RequestType == NdisRequestQueryInformation) &&
  1162. (NdisStatus == NDIS_STATUS_SUCCESS)) {
  1163. RtlMoveMemory(ndisTapiRequest->Data,
  1164. NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
  1165. ndisTapiRequest->ulDataSize);
  1166. Irp->IoStatus.Information =
  1167. irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  1168. } else {
  1169. Irp->IoStatus.Information = sizeof (ULONG);
  1170. }
  1171. if((NdisRequest->RequestType == NdisRequestQueryInformation) &&
  1172. (NdisRequest->DATA.QUERY_INFORMATION.Oid == OID_TAPI_OPEN)) {
  1173. DoLineOpenCompleteWork(ndisTapiRequest,
  1174. providerRequest->Provider);
  1175. }
  1176. Irp->IoStatus.Status = STATUS_SUCCESS;
  1177. ndisTapiRequest->ulReturnValue = NdisStatus;
  1178. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  1179. } while (FALSE);
  1180. ExFreePool (providerRequest);
  1181. DBGOUT ((2, "NdisTapiCompleteRequest: exit"));
  1182. }
  1183. #if DBG
  1184. VOID
  1185. DbgPrt(
  1186. IN LONG DbgLevel,
  1187. IN PUCHAR DbgMessage,
  1188. IN ...
  1189. )
  1190. /*++
  1191. Routine Description:
  1192. Formats the incoming debug message & calls DbgPrint
  1193. Arguments:
  1194. DbgLevel - level of message verboseness
  1195. DbgMessage - printf-style format string, followed by appropriate
  1196. list of arguments
  1197. Return Value:
  1198. --*/
  1199. {
  1200. if (DbgLevel <= NdisTapiDebugLevel)
  1201. {
  1202. char buf[256] = "NDISTAPI: ";
  1203. va_list ap;
  1204. va_start (ap, DbgMessage);
  1205. vsprintf (&buf[10], DbgMessage, ap);
  1206. strcat (buf, "\n");
  1207. DbgPrint (buf);
  1208. va_end(ap);
  1209. }
  1210. return;
  1211. }
  1212. #endif // DBG
  1213. VOID
  1214. DoProviderInitComplete(
  1215. PPROVIDER_REQUEST ProviderRequest,
  1216. NDIS_STATUS Status
  1217. )
  1218. /*++
  1219. Routine Description:
  1220. Arguments:
  1221. ProviderInitRequest - pointer successfully completed init request
  1222. Return Value:
  1223. Note:
  1224. --*/
  1225. {
  1226. PPROVIDER_INFO provider = ProviderRequest->Provider;
  1227. PNDIS_TAPI_PROVIDER_INITIALIZE providerInitData =
  1228. (PNDIS_TAPI_PROVIDER_INITIALIZE) ProviderRequest->Data;
  1229. KIRQL OldIrql;
  1230. DBGOUT ((2, "DoProviderInitComplete: enter"));
  1231. //
  1232. // Wrap this in an exception handler in case the provider was
  1233. // removed during an async completion
  1234. //
  1235. try
  1236. {
  1237. if (Status == NDIS_STATUS_SUCCESS) {
  1238. provider->ProviderID = (ULONG)providerInitData->ulProviderID;
  1239. provider->NumDevices = providerInitData->ulNumLineDevs;
  1240. KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
  1241. DeviceExtension->NdisTapiNumDevices += provider->NumDevices;
  1242. KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
  1243. provider->Status = PROVIDER_STATUS_ONLINE;
  1244. if (provider->DeviceInfo == NULL) {
  1245. provider->DeviceInfo = (PDEVICE_INFO)
  1246. ExAllocatePoolWithTag(
  1247. NonPagedPool,
  1248. sizeof(DEVICE_INFO) * provider->NumDevices,
  1249. 'IPAT'
  1250. );
  1251. if (provider->DeviceInfo != NULL) {
  1252. PDEVICE_INFO DeviceInfo;
  1253. UINT i;
  1254. RtlZeroMemory(
  1255. provider->DeviceInfo,
  1256. sizeof(DEVICE_INFO) * provider->NumDevices
  1257. );
  1258. for(i = 0, DeviceInfo = provider->DeviceInfo;
  1259. i < provider->NumDevices;
  1260. i++, DeviceInfo++) {
  1261. DeviceInfo->DeviceID = provider->DeviceIDBase + i;
  1262. }
  1263. }
  1264. }
  1265. }
  1266. //
  1267. // Set the event which sync's miniport inits
  1268. //
  1269. KeSetEvent(&provider->SyncEvent,
  1270. 0,
  1271. FALSE);
  1272. DBGOUT((3,
  1273. "providerID = 0x%x, numDevices = %d, BaseID = %d",
  1274. provider->ProviderID,
  1275. provider->NumDevices,
  1276. provider->DeviceIDBase));
  1277. }
  1278. except (EXCEPTION_EXECUTE_HANDLER)
  1279. {
  1280. DBGOUT((1, "DoProviderInitComplete: provider invalid"));
  1281. }
  1282. DBGOUT ((2, "DoProviderInitComplete: exit"));
  1283. }
  1284. ULONG
  1285. GetLineEvents(
  1286. PCHAR EventBuffer,
  1287. ULONG BufferSize
  1288. )
  1289. /*++
  1290. Routine Description:
  1291. Arguments:
  1292. Return Value:
  1293. Note:
  1294. Assumes DeviceExtension->SpinLock held by caller.
  1295. --*/
  1296. {
  1297. ULONG BytesLeft;
  1298. ULONG BytesMoved;
  1299. ULONG EventCount;
  1300. BytesLeft = BufferSize;
  1301. BytesMoved = 0;
  1302. EventCount = 0;
  1303. while (!(IsListEmpty(&DeviceExtension->ProviderEventList))) {
  1304. PPROVIDER_EVENT ProviderEvent;
  1305. if (BytesLeft < sizeof(NDIS_TAPI_EVENT)) {
  1306. break;
  1307. }
  1308. ProviderEvent = (PPROVIDER_EVENT)
  1309. RemoveHeadList(&DeviceExtension->ProviderEventList);
  1310. EventCount++;
  1311. RtlMoveMemory(EventBuffer + BytesMoved,
  1312. (PUCHAR)&ProviderEvent->Event,
  1313. sizeof(NDIS_TAPI_EVENT));
  1314. BytesMoved += sizeof(NDIS_TAPI_EVENT);
  1315. BytesLeft -= sizeof(NDIS_TAPI_EVENT);
  1316. ExFreeToNPagedLookasideList(&ProviderEventLookaside,
  1317. ProviderEvent);
  1318. }
  1319. DeviceExtension->EventCount -= EventCount;
  1320. DBGOUT((3, "GetLineEvents: Returned %d Events", EventCount));
  1321. return (BytesMoved);
  1322. }
  1323. NDIS_STATUS
  1324. SendProviderInitRequest(
  1325. PPROVIDER_INFO Provider
  1326. )
  1327. /*++
  1328. Routine Description:
  1329. Arguments:
  1330. Provider - pointer to a PROVIDER_INFO representing provider to initialize
  1331. Return Value:
  1332. Note:
  1333. --*/
  1334. {
  1335. KIRQL oldIrql;
  1336. NDIS_STATUS ndisStatus;
  1337. PNDIS_REQUEST NdisRequest;
  1338. PPROVIDER_INFO tmpProvider;
  1339. PPROVIDER_REQUEST providerRequest;
  1340. PNDIS_TAPI_PROVIDER_INITIALIZE providerInitData;
  1341. DBGOUT ((2, "SendProviderInitRequest: enter"));
  1342. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1343. //
  1344. // Determine the DeviceIDBase to be used for this provider
  1345. //
  1346. if (Provider->Status == PROVIDER_STATUS_PENDING_INIT) {
  1347. Provider->DeviceIDBase = DeviceExtension->ProviderBaseID;
  1348. tmpProvider = DeviceExtension->Providers;
  1349. while (tmpProvider != NULL) {
  1350. if (tmpProvider->Status != PROVIDER_STATUS_PENDING_INIT) {
  1351. Provider->DeviceIDBase += tmpProvider->NumDevices;
  1352. }
  1353. tmpProvider = tmpProvider->Next;
  1354. }
  1355. }
  1356. //
  1357. // Create a provider init request
  1358. //
  1359. providerRequest = ExAllocatePoolWithTag(
  1360. NonPagedPoolCacheAligned,
  1361. sizeof(PROVIDER_REQUEST) + sizeof(NDIS_TAPI_PROVIDER_INITIALIZE) -
  1362. sizeof(ULONG),
  1363. 'IPAT'
  1364. );
  1365. if (!providerRequest) {
  1366. KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
  1367. return NDIS_STATUS_RESOURCES;
  1368. }
  1369. providerRequest->Irp = NULL;
  1370. providerRequest->Flags = INTERNAL_REQUEST;
  1371. providerRequest->Provider = Provider;
  1372. NdisRequest = &providerRequest->NdisRequest;
  1373. NdisRequest->RequestType =
  1374. NdisRequestQueryInformation;
  1375. NdisRequest->DATA.SET_INFORMATION.Oid =
  1376. OID_TAPI_PROVIDER_INITIALIZE;
  1377. NdisRequest->DATA.SET_INFORMATION.InformationBuffer =
  1378. providerRequest->Data;
  1379. NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
  1380. sizeof(NDIS_TAPI_PROVIDER_INITIALIZE);
  1381. providerInitData =
  1382. (PNDIS_TAPI_PROVIDER_INITIALIZE) providerRequest->Data;
  1383. providerRequest->RequestID =
  1384. providerInitData->ulRequestID = ++DeviceExtension->ulRequestID;
  1385. providerInitData->ulDeviceIDBase = Provider->DeviceIDBase;
  1386. KeInitializeEvent(&Provider->SyncEvent,
  1387. SynchronizationEvent,
  1388. FALSE);
  1389. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1390. //
  1391. // Send the request
  1392. //
  1393. ndisStatus=
  1394. (*Provider->RequestProc)
  1395. (Provider->ProviderHandle,NdisRequest);
  1396. if (ndisStatus != NDIS_STATUS_PENDING) {
  1397. DoProviderInitComplete (providerRequest, ndisStatus);
  1398. ExFreePool (providerRequest);
  1399. }
  1400. DBGOUT ((2, "SendProviderInitRequest: exit status %x", ndisStatus));
  1401. return ndisStatus;
  1402. }
  1403. NDIS_STATUS
  1404. SendProviderShutdown(
  1405. PPROVIDER_INFO Provider,
  1406. PKIRQL oldIrql
  1407. )
  1408. /*++
  1409. Routine Description:
  1410. Arguments:
  1411. Return Value:
  1412. A pointer to the next provider in the global providers list
  1413. Note:
  1414. Assumes DeviceExtension->SpinLock held by caller.
  1415. --*/
  1416. {
  1417. NDIS_STATUS ndisStatus;
  1418. PNDIS_REQUEST NdisRequest;
  1419. PPROVIDER_REQUEST providerRequest;
  1420. PNDIS_TAPI_PROVIDER_SHUTDOWN providerShutdownData;
  1421. DBGOUT ((2, "SendProviderShutdown: Provider=%p", Provider));
  1422. //
  1423. // Create a provider init request
  1424. //
  1425. providerRequest =
  1426. ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1427. sizeof(PROVIDER_REQUEST) + sizeof(NDIS_TAPI_PROVIDER_SHUTDOWN) -
  1428. sizeof(ULONG),
  1429. 'IPAT');
  1430. if (!providerRequest) {
  1431. return NDIS_STATUS_RESOURCES;
  1432. }
  1433. providerRequest->Irp = NULL;
  1434. providerRequest->Flags = INTERNAL_REQUEST;
  1435. providerRequest->Provider = Provider;
  1436. NdisRequest = &providerRequest->NdisRequest;
  1437. NdisRequest->RequestType =
  1438. NdisRequestSetInformation;
  1439. NdisRequest->DATA.SET_INFORMATION.Oid =
  1440. OID_TAPI_PROVIDER_SHUTDOWN;
  1441. NdisRequest->DATA.SET_INFORMATION.InformationBuffer =
  1442. providerRequest->Data;
  1443. NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
  1444. sizeof(NDIS_TAPI_PROVIDER_SHUTDOWN);
  1445. providerShutdownData =
  1446. (PNDIS_TAPI_PROVIDER_SHUTDOWN)providerRequest->Data;
  1447. providerRequest->RequestID =
  1448. providerShutdownData->ulRequestID = ++DeviceExtension->ulRequestID;
  1449. KeReleaseSpinLock (&DeviceExtension->SpinLock, *oldIrql);
  1450. //
  1451. // Send the request
  1452. //
  1453. ndisStatus =
  1454. (*Provider->RequestProc)
  1455. (Provider->ProviderHandle, NdisRequest);
  1456. //
  1457. // If request was completed synchronously then free the request
  1458. // (otherwise it will get freed when the completion proc is called)
  1459. //
  1460. if (ndisStatus != NDIS_STATUS_PENDING) {
  1461. ExFreePool (providerRequest);
  1462. }
  1463. DBGOUT ((2, "SendProviderShutdown: Status=%x", ndisStatus));
  1464. KeAcquireSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1465. return ndisStatus;
  1466. }
  1467. BOOLEAN
  1468. SyncInitAllProviders(
  1469. void
  1470. )
  1471. /*++
  1472. Routine Description:
  1473. This functions walks the list of registered providers and sends
  1474. init requests to the providers in the PENDING_INIT state
  1475. Arguments:
  1476. (none)
  1477. Return Value:
  1478. TRUE if all registered providers initialized, or
  1479. FALSE if there are more providers to initialze
  1480. Note:
  1481. --*/
  1482. {
  1483. ULONG numDevices = 0;
  1484. NDIS_STATUS ndisStatus;
  1485. PPROVIDER_INFO provider;
  1486. KIRQL oldIrql;
  1487. DBGOUT((2, "SyncInitAllProviders: enter"));
  1488. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1489. provider = DeviceExtension->Providers;
  1490. while (provider != NULL) {
  1491. if (provider->Status == PROVIDER_STATUS_PENDING_INIT ||
  1492. provider->Status == PROVIDER_STATUS_PENDING_REINIT ||
  1493. provider->Status == PROVIDER_STATUS_PENDING_LINE_CREATE) {
  1494. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1495. ndisStatus = SendProviderInitRequest (provider);
  1496. if (ndisStatus == NDIS_STATUS_PENDING) {
  1497. //
  1498. // Wait for completion routine to get called
  1499. //
  1500. KeWaitForSingleObject (&provider->SyncEvent,
  1501. Executive,
  1502. KernelMode,
  1503. FALSE,
  1504. (PTIME) NULL
  1505. );
  1506. }
  1507. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1508. }
  1509. provider = provider->Next;
  1510. }
  1511. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1512. DBGOUT((2, "SyncInitAllProviders: exit"));
  1513. return TRUE;
  1514. }
  1515. VOID
  1516. DoIrpMjCloseWork(
  1517. PIRP Irp
  1518. )
  1519. {
  1520. KIRQL oldIrql;
  1521. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1522. if (InterlockedDecrement(&DeviceExtension->RefCount) == 0) {
  1523. if (DeviceExtension->Status == NDISTAPI_STATUS_CONNECTED) {
  1524. PPROVIDER_INFO provider;
  1525. DeviceExtension->Status =
  1526. NDISTAPI_STATUS_DISCONNECTING;
  1527. //
  1528. // Send the providers a shutdown request
  1529. //
  1530. provider = DeviceExtension->Providers;
  1531. while (provider != NULL) {
  1532. switch (provider->Status) {
  1533. case PROVIDER_STATUS_ONLINE:
  1534. DeviceExtension->NdisTapiNumDevices -= provider->NumDevices;
  1535. SendProviderShutdown (provider, &oldIrql);
  1536. //
  1537. // fall thru...
  1538. //
  1539. case PROVIDER_STATUS_PENDING_INIT:
  1540. case PROVIDER_STATUS_PENDING_REINIT:
  1541. //
  1542. // Reset provider status
  1543. //
  1544. provider->Status = PROVIDER_STATUS_PENDING_INIT;
  1545. break;
  1546. case PROVIDER_STATUS_OFFLINE:
  1547. break;
  1548. }
  1549. provider = provider->Next;
  1550. }
  1551. DeviceExtension->Status = NDISTAPI_STATUS_DISCONNECTED;
  1552. ASSERT(DeviceExtension->NdisTapiNumDevices == 0);
  1553. }
  1554. }
  1555. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1556. Irp->IoStatus.Status = STATUS_SUCCESS;
  1557. Irp->IoStatus.Information = 0;
  1558. }
  1559. NTSTATUS
  1560. DoIoctlConnectWork(
  1561. PIRP Irp,
  1562. PVOID ioBuffer,
  1563. ULONG inputBufferLength,
  1564. ULONG outputBufferLength
  1565. )
  1566. {
  1567. KIRQL oldIrql;
  1568. ULONG InfoSize;
  1569. NTSTATUS NtStatus;
  1570. //
  1571. // Someone's connecting. Make sure they passed us a valid
  1572. // info buffer
  1573. //
  1574. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1575. do {
  1576. if ((inputBufferLength < 2*sizeof(ULONG)) ||
  1577. (outputBufferLength < sizeof(ULONG))) {
  1578. DBGOUT ((3, "IOCTL_NDISTAPI_CONNECT: buffer too small"));
  1579. NtStatus = STATUS_BUFFER_TOO_SMALL;
  1580. InfoSize = 0;
  1581. break;
  1582. }
  1583. if (DeviceExtension->Status == NDISTAPI_STATUS_DISCONNECTED) {
  1584. DeviceExtension->Status = NDISTAPI_STATUS_CONNECTING;
  1585. DeviceExtension->ProviderBaseID =
  1586. *((ULONG *) ioBuffer);
  1587. DBGOUT ((1, "ProviderBaseID %d",
  1588. DeviceExtension->ProviderBaseID));
  1589. //
  1590. // Synchronously init all providers
  1591. //
  1592. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1593. SyncInitAllProviders();
  1594. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1595. }
  1596. //
  1597. // Return the number of line devs
  1598. //
  1599. {
  1600. ULONG OfflineCount;
  1601. PPROVIDER_INFO provider;
  1602. //
  1603. // Since some providers might be temporarily offline
  1604. // we need to tell tapi about them even though they
  1605. // are not currently useable. This keeps the tapi
  1606. // deviceid space consistent.
  1607. //
  1608. OfflineCount = 0;
  1609. provider = DeviceExtension->Providers;
  1610. while (provider != NULL) {
  1611. if (provider->Status == PROVIDER_STATUS_OFFLINE) {
  1612. OfflineCount += provider->NumDevices;
  1613. }
  1614. provider = provider->Next;
  1615. }
  1616. *((ULONG *) ioBuffer)=
  1617. DeviceExtension->NdisTapiNumDevices + OfflineCount;
  1618. }
  1619. DeviceExtension->Status = NDISTAPI_STATUS_CONNECTED;
  1620. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1621. InfoSize = sizeof(ULONG);
  1622. NtStatus = STATUS_SUCCESS;
  1623. } while (FALSE);
  1624. Irp->IoStatus.Status = NtStatus;
  1625. Irp->IoStatus.Information = InfoSize;
  1626. return (NtStatus);
  1627. }
  1628. NTSTATUS
  1629. DoIoctlQuerySetWork(
  1630. PIRP Irp,
  1631. PVOID ioBuffer,
  1632. ULONG inputBufferLength,
  1633. ULONG outputBufferLength
  1634. )
  1635. {
  1636. KIRQL oldIrql;
  1637. ULONG InfoSize;
  1638. NTSTATUS NtStatus;
  1639. PPROVIDER_INFO provider;
  1640. NDIS_STATUS ndisStatus;
  1641. PNDIS_REQUEST NdisRequest;
  1642. PNDISTAPI_REQUEST ndisTapiRequest;
  1643. PPROVIDER_REQUEST providerRequest;
  1644. PIO_STACK_LOCATION irpStack;
  1645. do {
  1646. ndisTapiRequest = ioBuffer;
  1647. NtStatus = STATUS_SUCCESS;
  1648. InfoSize = 0;
  1649. //
  1650. // Make sure input & output buffers are large enough
  1651. //
  1652. if ((inputBufferLength < sizeof (NDISTAPI_REQUEST)) ||
  1653. (ndisTapiRequest->ulDataSize > 0x10000000) ||
  1654. (inputBufferLength < (sizeof (NDISTAPI_REQUEST) +
  1655. ndisTapiRequest->ulDataSize - sizeof (UCHAR)) ||
  1656. (outputBufferLength < (sizeof (NDISTAPI_REQUEST) +
  1657. ndisTapiRequest->ulDataSize - sizeof (UCHAR))))) {
  1658. DBGOUT((-1, "NdisTapiDispatch: buffer to small!"));
  1659. NtStatus = STATUS_BUFFER_TOO_SMALL;
  1660. break;
  1661. }
  1662. //
  1663. // Verify we're connected, then check the device ID of the
  1664. // incoming request against our list of online devices
  1665. //
  1666. ndisStatus =
  1667. VerifyProvider(ndisTapiRequest, &provider);
  1668. if (ndisStatus != NDIS_STATUS_SUCCESS) {
  1669. ndisTapiRequest->ulReturnValue = ndisStatus;
  1670. InfoSize = sizeof(ULONG);
  1671. break;
  1672. }
  1673. //
  1674. // If this is a line_close, check to see if the line has
  1675. // been opened before sending a line close oid
  1676. //
  1677. if(ndisTapiRequest->Oid == OID_TAPI_CLOSE) {
  1678. ndisStatus = VerifyLineClose(ndisTapiRequest, provider);
  1679. if(ndisStatus != NDIS_STATUS_SUCCESS)
  1680. {
  1681. ndisTapiRequest->ulReturnValue = ndisStatus;
  1682. InfoSize = sizeof(ULONG);
  1683. break;
  1684. }
  1685. }
  1686. //
  1687. // Create the providerRequest & submit it
  1688. //
  1689. providerRequest =
  1690. ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1691. sizeof(PROVIDER_REQUEST) +
  1692. ndisTapiRequest->ulDataSize -
  1693. sizeof(ULONG),
  1694. 'IPAT');
  1695. if (providerRequest == NULL) {
  1696. DBGOUT((-1, "NdisTapiDispatch: unable to alloc request buf"));
  1697. ndisTapiRequest->ulReturnValue = NDIS_STATUS_RESOURCES;
  1698. InfoSize = sizeof (ULONG);
  1699. break;
  1700. }
  1701. if (ndisTapiRequest->Oid == OID_TAPI_OPEN) {
  1702. DoLineOpenWork(ndisTapiRequest, provider);
  1703. }
  1704. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1705. providerRequest->Flags = 0;
  1706. providerRequest->Irp = Irp;
  1707. providerRequest->Provider = provider;
  1708. providerRequest->RequestID =
  1709. *((ULONG *)ndisTapiRequest->Data) = ++DeviceExtension->ulRequestID;
  1710. RtlMoveMemory(providerRequest->Data,
  1711. ndisTapiRequest->Data, ndisTapiRequest->ulDataSize);
  1712. NdisRequest = &providerRequest->NdisRequest;
  1713. irpStack = IoGetCurrentIrpStackLocation (Irp);
  1714. NdisRequest->RequestType =
  1715. (irpStack->Parameters.DeviceIoControl.IoControlCode ==
  1716. IOCTL_NDISTAPI_QUERY_INFO) ? NdisRequestQueryInformation :
  1717. NdisRequestSetInformation;
  1718. NdisRequest->DATA.SET_INFORMATION.Oid =
  1719. ndisTapiRequest->Oid;
  1720. NdisRequest->DATA.SET_INFORMATION.InformationBuffer =
  1721. providerRequest->Data;
  1722. NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
  1723. ndisTapiRequest->ulDataSize;
  1724. DBGOUT((3,
  1725. "DoIoctlQuerySetWork: Oid=%x, devID=%d, reqID=%x",
  1726. ndisTapiRequest->Oid,
  1727. ndisTapiRequest->ulDeviceID,
  1728. *((ULONG *)ndisTapiRequest->Data)));
  1729. //
  1730. // Queue up this TAPI request in our request list.
  1731. //
  1732. InsertTailList(&DeviceExtension->ProviderRequestList,
  1733. &providerRequest->Linkage);
  1734. DeviceExtension->RequestCount++;
  1735. KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
  1736. //
  1737. // Mark the TAPI request pending and set the cancel routine
  1738. //
  1739. IoMarkIrpPending(Irp);
  1740. Irp->IoStatus.Status = STATUS_PENDING;
  1741. IoSetCancelRoutine (Irp, NdisTapiCancel);
  1742. //
  1743. // Call the provider's request proc
  1744. //
  1745. ndisStatus =
  1746. (*provider->RequestProc)
  1747. (provider->ProviderHandle, NdisRequest);
  1748. //
  1749. // If PENDING was returned then just exit & let the completion
  1750. // routine handle the request completion
  1751. //
  1752. // NOTE: If pending was returned then the request may have
  1753. // already been completed, so DO NOT touch anything
  1754. // in the Irp (don't reference the pointer, etc.)
  1755. //
  1756. if (ndisStatus == NDIS_STATUS_PENDING) {
  1757. DBGOUT((1, "DoIoctlQuerySetWork: exit Irp=%p, Status=%x",
  1758. Irp, STATUS_PENDING));
  1759. return (STATUS_PENDING);
  1760. }
  1761. //
  1762. // The provider request completed synchronously, so remove
  1763. // the TAPI request from the device queue. We need to
  1764. // synchronize access to this queue with the
  1765. // SpinLock.
  1766. //
  1767. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1768. do {
  1769. PPROVIDER_REQUEST pReq;
  1770. pReq = (PPROVIDER_REQUEST)
  1771. DeviceExtension->ProviderRequestList.Flink;
  1772. while ((PVOID)pReq != (PVOID)&DeviceExtension->ProviderRequestList) {
  1773. if (pReq == providerRequest) {
  1774. break;
  1775. }
  1776. pReq = (PPROVIDER_REQUEST)
  1777. pReq->Linkage.Flink;
  1778. }
  1779. if (pReq != providerRequest) {
  1780. DBGOUT((0, "DoIoctlQuerySetWork - Request %p not found!",
  1781. providerRequest));
  1782. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1783. return (STATUS_PENDING);
  1784. }
  1785. Irp = providerRequest->Irp;
  1786. ndisTapiRequest = Irp->AssociatedIrp.SystemBuffer;
  1787. ASSERT(providerRequest->RequestID ==
  1788. *((ULONG *)ndisTapiRequest->Data));
  1789. //
  1790. // Remove the IRP from the cancelable state
  1791. //
  1792. if (IoSetCancelRoutine(Irp, NULL) == NULL) {
  1793. DBGOUT((0, "DoIoctlQuerySetWork - Irp %p has been canceled!", Irp));
  1794. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1795. return (STATUS_PENDING);
  1796. }
  1797. RemoveEntryList(&providerRequest->Linkage);
  1798. DeviceExtension->RequestCount--;
  1799. } while (FALSE);
  1800. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1801. //
  1802. // If this was a succesful QUERY_INFO request copy all the
  1803. // data back to the tapi request buf & set
  1804. // Irp->IoStatus.Information appropriately. Otherwise, we
  1805. // just need to pass back the return value.
  1806. //
  1807. if ((irpStack->Parameters.DeviceIoControl.IoControlCode ==
  1808. IOCTL_NDISTAPI_QUERY_INFO) &&
  1809. (ndisStatus == NDIS_STATUS_SUCCESS)) {
  1810. RtlMoveMemory(ndisTapiRequest->Data,
  1811. providerRequest->Data,
  1812. ndisTapiRequest->ulDataSize);
  1813. InfoSize =
  1814. irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  1815. } else {
  1816. InfoSize = sizeof (ULONG);
  1817. }
  1818. ndisTapiRequest->ulReturnValue = ndisStatus;
  1819. //
  1820. // Free the providerRequest
  1821. //
  1822. ExFreePool (providerRequest);
  1823. } while (FALSE);
  1824. Irp->IoStatus.Status = NtStatus;
  1825. Irp->IoStatus.Information = InfoSize;
  1826. DBGOUT((1, "DoIoctlQuerySetWork: exit Irp=%p, Status=%x",
  1827. Irp, NtStatus));
  1828. return (NtStatus);
  1829. }
  1830. VOID
  1831. DoLineOpenCompleteWork(
  1832. PNDISTAPI_REQUEST ndisTapiRequest,
  1833. PPROVIDER_INFO provider
  1834. )
  1835. {
  1836. DBGOUT((2, "DoLineOpenCompleteWork: Open Completed"));
  1837. //
  1838. // Now stash the hdLine for this deviceid
  1839. //
  1840. if (provider->DeviceInfo != NULL) {
  1841. UINT i;
  1842. PDEVICE_INFO DeviceInfo;
  1843. PNDIS_TAPI_OPEN TapiOpen;
  1844. TapiOpen = (PNDIS_TAPI_OPEN) ndisTapiRequest->Data;
  1845. for(i = 0, DeviceInfo = provider->DeviceInfo;
  1846. i < provider->NumDevices;
  1847. i++, DeviceInfo++) {
  1848. if (DeviceInfo->DeviceID == TapiOpen->ulDeviceID) {
  1849. DeviceInfo->hdLine = TapiOpen->hdLine;
  1850. DBGOUT((2, "Complete for open. stashing hdline=0x%x for device %d",
  1851. DeviceInfo->hdLine, DeviceInfo->DeviceID));
  1852. break;
  1853. }
  1854. }
  1855. }
  1856. }
  1857. VOID
  1858. DoLineOpenWork(
  1859. PNDISTAPI_REQUEST ndisTapiRequest,
  1860. PPROVIDER_INFO provider
  1861. )
  1862. {
  1863. KIRQL oldIrql;
  1864. PNDIS_TAPI_OPEN TapiOpen;
  1865. PNDISTAPI_OPENDATA OpenData;
  1866. TapiOpen = (PNDIS_TAPI_OPEN) ndisTapiRequest->Data;
  1867. if (ndisTapiRequest->ulDataSize >= sizeof(NDIS_TAPI_OPEN) +
  1868. sizeof(NDISTAPI_OPENDATA)) {
  1869. OpenData = (PNDISTAPI_OPENDATA)
  1870. ((PUCHAR)ndisTapiRequest->Data + sizeof(NDIS_TAPI_OPEN));
  1871. RtlMoveMemory(&OpenData->Guid,
  1872. &provider->Guid, sizeof(OpenData->Guid));
  1873. OpenData->MediaType = provider->MediaType;
  1874. }
  1875. //
  1876. // Now stash the htLine for this deviceid
  1877. //
  1878. if (provider->DeviceInfo != NULL) {
  1879. UINT i;
  1880. PDEVICE_INFO DeviceInfo;
  1881. for(i = 0, DeviceInfo = provider->DeviceInfo;
  1882. i < provider->NumDevices;
  1883. i++, DeviceInfo++) {
  1884. if (DeviceInfo->DeviceID == TapiOpen->ulDeviceID) {
  1885. DeviceInfo->htLine = TapiOpen->htLine;
  1886. DBGOUT((
  1887. 1,
  1888. "Stash htLine - provider %p DeviceID %d htLine %x",
  1889. provider,
  1890. DeviceInfo->DeviceID,
  1891. DeviceInfo->htLine));
  1892. }
  1893. }
  1894. }
  1895. }
  1896. NDIS_STATUS
  1897. VerifyLineClose(
  1898. PNDISTAPI_REQUEST ndisTapiRequest,
  1899. PPROVIDER_INFO provider
  1900. )
  1901. {
  1902. NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
  1903. if (provider->DeviceInfo != NULL) {
  1904. UINT i;
  1905. PDEVICE_INFO DeviceInfo;
  1906. PNDIS_TAPI_CLOSE TapiClose;
  1907. TapiClose = (PNDIS_TAPI_CLOSE) ndisTapiRequest->Data;
  1908. for(i = 0, DeviceInfo = provider->DeviceInfo;
  1909. i < provider->NumDevices;
  1910. i++, DeviceInfo++) {
  1911. if (DeviceInfo->hdLine == TapiClose->hdLine) {
  1912. break;
  1913. }
  1914. }
  1915. if(i == provider->NumDevices)
  1916. {
  1917. DBGOUT((2,"LINE_CLOSE: didn't find hdLine=0x%x",
  1918. TapiClose->hdLine));
  1919. ndisStatus = NDISTAPIERR_DEVICEOFFLINE;
  1920. }
  1921. else
  1922. {
  1923. DBGOUT((2, "LINE_CLOSE: found hdLine=0x%x",
  1924. TapiClose->hdLine));
  1925. }
  1926. }
  1927. return ndisStatus;
  1928. }
  1929. NDIS_STATUS
  1930. VerifyProvider(
  1931. PNDISTAPI_REQUEST ndisTapiRequest,
  1932. PPROVIDER_INFO *provider
  1933. )
  1934. {
  1935. KIRQL oldIrql;
  1936. PPROVIDER_INFO pp;
  1937. NDIS_STATUS Status;
  1938. ULONG targetDeviceID;
  1939. Status = NDIS_STATUS_SUCCESS;
  1940. *provider = NULL;
  1941. targetDeviceID = ndisTapiRequest->ulDeviceID;
  1942. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1943. do {
  1944. if (DeviceExtension->Status != NDISTAPI_STATUS_CONNECTED) {
  1945. DBGOUT((3, "VerifyProvider: unconnected, returning err"));
  1946. Status = NDISTAPIERR_UNINITIALIZED;
  1947. break;
  1948. }
  1949. pp = DeviceExtension->Providers;
  1950. while (pp != NULL) {
  1951. if ((pp->Status == PROVIDER_STATUS_ONLINE) &&
  1952. (targetDeviceID >= pp->DeviceIDBase) &&
  1953. (targetDeviceID <
  1954. pp->DeviceIDBase + pp->NumDevices)
  1955. ) {
  1956. break;
  1957. }
  1958. pp = pp->Next;
  1959. }
  1960. if (pp == NULL ||
  1961. pp->ProviderHandle == NULL) {
  1962. //
  1963. // Set Irp->IoStatus.Information large enough that err code
  1964. // gets copied back to user buffer
  1965. //
  1966. DBGOUT((3, "VerifyProvider: dev offline, returning err"));
  1967. Status = NDISTAPIERR_DEVICEOFFLINE;
  1968. break;
  1969. }
  1970. *provider = pp;
  1971. } while (FALSE);
  1972. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1973. return (Status);
  1974. }
  1975. NTSTATUS
  1976. DoGetProviderEventsWork(
  1977. PIRP Irp,
  1978. PVOID ioBuffer,
  1979. ULONG inputBufferLength,
  1980. ULONG outputBufferLength
  1981. )
  1982. {
  1983. KIRQL oldIrql;
  1984. ULONG InfoSize;
  1985. NTSTATUS NtStatus;
  1986. PNDISTAPI_EVENT_DATA ndisTapiEventData;
  1987. ndisTapiEventData = ioBuffer;
  1988. NtStatus = STATUS_SUCCESS;
  1989. InfoSize = 0;
  1990. //
  1991. // Sync event buf access by acquiring SpinLock
  1992. //
  1993. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1994. do {
  1995. if ((inputBufferLength < sizeof (NDISTAPI_EVENT_DATA)) ||
  1996. (outputBufferLength < sizeof(NDISTAPI_EVENT_DATA)) ||
  1997. ((outputBufferLength -
  1998. FIELD_OFFSET(NDISTAPI_EVENT_DATA, Data[0])) <
  1999. ndisTapiEventData->ulTotalSize)) {
  2000. NtStatus = STATUS_BUFFER_TOO_SMALL;
  2001. break;
  2002. }
  2003. if (DeviceExtension->Status != NDISTAPI_STATUS_CONNECTED) {
  2004. DBGOUT((3, "DoGetProviderEventsWork: Status!=NDIS_STATUS_CONNECTED!"));
  2005. NtStatus = STATUS_UNSUCCESSFUL;
  2006. break;
  2007. }
  2008. if (DeviceExtension->EventsRequestIrp != NULL) {
  2009. #if DBG
  2010. DbgPrint("NDISTAPI: Attempt to set duplicate EventIrp o:%p, d:%p\n",
  2011. DeviceExtension->EventsRequestIrp, Irp);
  2012. #endif
  2013. NtStatus = STATUS_UNSUCCESSFUL;
  2014. break;
  2015. }
  2016. //
  2017. // Inspect DeviceExtension to see if there's any data available
  2018. //
  2019. if (DeviceExtension->EventCount == 0) {
  2020. //
  2021. // Hold the request pending. It remains in the cancelable
  2022. // state. When new line event input is received
  2023. // (NdisTapiIndicateStatus) or generated (i.e.
  2024. // LINEDEVSTATE_REINIT) the data will get copied & the
  2025. // request completed.
  2026. //
  2027. ASSERT(DeviceExtension->EventsRequestIrp == NULL);
  2028. DeviceExtension->EventsRequestIrp = Irp;
  2029. IoMarkIrpPending(Irp);
  2030. Irp->IoStatus.Status = STATUS_PENDING;
  2031. IoSetCancelRoutine (Irp, NdisTapiCancel);
  2032. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  2033. DBGOUT((3, "DoGetProviderEventsWork: Pending Irp=%p", Irp));
  2034. return(STATUS_PENDING);
  2035. }
  2036. //
  2037. // There's line event data queued in our ring buffer. Grab as
  2038. // much as we can & complete the request.
  2039. //
  2040. ndisTapiEventData->ulUsedSize =
  2041. GetLineEvents(ndisTapiEventData->Data,
  2042. ndisTapiEventData->ulTotalSize);
  2043. InfoSize =
  2044. ndisTapiEventData->ulUsedSize + sizeof(NDISTAPI_EVENT_DATA) - 1;
  2045. DBGOUT((3, "GetLineEvents: SyncComplete Irp=%p", Irp));
  2046. } while (FALSE);
  2047. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  2048. Irp->IoStatus.Status = NtStatus;
  2049. Irp->IoStatus.Information = InfoSize;
  2050. return (NtStatus);
  2051. }
  2052. NTSTATUS
  2053. DoLineCreateWork(
  2054. PIRP Irp,
  2055. PVOID ioBuffer,
  2056. ULONG inputBufferLength,
  2057. ULONG outputBufferLength
  2058. )
  2059. {
  2060. KIRQL oldIrql;
  2061. ULONG InfoSize;
  2062. NTSTATUS NtStatus;
  2063. PPROVIDER_INFO provider;
  2064. PNDISTAPI_CREATE_INFO CreateInfo;
  2065. InfoSize = 0;
  2066. NtStatus = STATUS_SUCCESS;
  2067. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  2068. do {
  2069. if (inputBufferLength < sizeof(CreateInfo)) {
  2070. DBGOUT ((3, "IOCTL_NDISTAPI_CREATE: buffer too small"));
  2071. NtStatus = STATUS_BUFFER_TOO_SMALL;
  2072. break;
  2073. }
  2074. if (DeviceExtension->Status != NDISTAPI_STATUS_CONNECTED) {
  2075. DBGOUT((3, "IOCTL_NDISTAPI_CREATE: while unconnected, returning err"));
  2076. NtStatus = STATUS_UNSUCCESSFUL;
  2077. break;
  2078. }
  2079. CreateInfo = (PNDISTAPI_CREATE_INFO)ioBuffer;
  2080. provider = DeviceExtension->Providers;
  2081. while (provider != NULL) {
  2082. if (provider->TempID == CreateInfo->TempID) {
  2083. break;
  2084. }
  2085. provider = provider->Next;
  2086. }
  2087. if (provider == NULL) {
  2088. DBGOUT((0, "IOCTL_NDISTAPI_CREATE: Provider not found %x",
  2089. CreateInfo->TempID));
  2090. NtStatus = STATUS_UNSUCCESSFUL;
  2091. break;
  2092. }
  2093. if (provider->Status == PROVIDER_STATUS_OFFLINE) {
  2094. DBGOUT((0, "IOCTL_CREATE - Provider %p invalid state %x",
  2095. provider, provider->Status));
  2096. NtStatus = STATUS_UNSUCCESSFUL;
  2097. break;
  2098. }
  2099. DBGOUT((1, "IOCTL_NDISTAPI_CREATE: provider %p ID %d",
  2100. provider, CreateInfo->DeviceID));
  2101. if (provider->CreateCount == 0) {
  2102. NDIS_STATUS ndisStatus;
  2103. //
  2104. // Set the base ID
  2105. //
  2106. provider->DeviceIDBase =
  2107. CreateInfo->DeviceID;
  2108. //
  2109. // Init the provider
  2110. //
  2111. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  2112. ndisStatus = SendProviderInitRequest (provider);
  2113. if (ndisStatus == NDIS_STATUS_PENDING) {
  2114. //
  2115. // Wait for completion routine to get called
  2116. //
  2117. KeWaitForSingleObject (&provider->SyncEvent,
  2118. Executive,
  2119. KernelMode,
  2120. FALSE,
  2121. (PTIME) NULL);
  2122. }
  2123. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  2124. }
  2125. ASSERT(CreateInfo->DeviceID ==
  2126. (provider->DeviceIDBase + provider->CreateCount));
  2127. provider->CreateCount++;
  2128. ASSERT(provider->CreateCount <= provider->NumDevices);
  2129. if (provider->CreateCount == provider->NumDevices) {
  2130. //
  2131. // We have finished all of the line_creates for this
  2132. // provider so find the next provider that needs to be
  2133. // kick started.
  2134. //
  2135. provider = provider->Next;
  2136. while (provider != NULL) {
  2137. if (provider->Status ==
  2138. PROVIDER_STATUS_PENDING_LINE_CREATE) {
  2139. break;
  2140. }
  2141. provider = provider->Next;
  2142. }
  2143. }
  2144. if (provider != NULL) {
  2145. NDIS_TAPI_EVENT NdisTapiEvent;
  2146. //
  2147. // Do a LINE_CREATE for all additional devices
  2148. // on this provider
  2149. //
  2150. RtlZeroMemory(&NdisTapiEvent, sizeof(NDIS_TAPI_EVENT));
  2151. provider->TempID = (ULONG_PTR)provider;
  2152. DBGOUT((
  2153. -1,
  2154. "LINE_CREATE %d for provider %p",
  2155. provider->CreateCount,
  2156. provider->TempID
  2157. ));
  2158. NdisTapiEvent.ulMsg = LINE_CREATE;
  2159. NdisTapiEvent.ulParam1 = 0;
  2160. NdisTapiEvent.ulParam2 = provider->TempID;
  2161. NdisTapiEvent.ulParam3 = 0;
  2162. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  2163. NdisTapiIndicateStatus((ULONG_PTR) provider,
  2164. &NdisTapiEvent,
  2165. sizeof (NDIS_TAPI_EVENT));
  2166. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  2167. } else {
  2168. DeviceExtension->Flags &= ~PENDING_LINECREATE;
  2169. }
  2170. InfoSize = sizeof(NDISTAPI_CREATE_INFO);
  2171. } while (FALSE);
  2172. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  2173. Irp->IoStatus.Status = NtStatus;
  2174. Irp->IoStatus.Information = InfoSize;
  2175. return (NtStatus);
  2176. }