Leaked source code of windows server 2003
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.

3024 lines
80 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. //
  531. // Unmark the irp pending since we are completing the
  532. // the irp below.
  533. //
  534. irpStack->Control &= ~SL_PENDING_RETURNED;
  535. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  536. DBGOUT((3, "NdisTapiDispatch: completed Irp=%p", Irp));
  537. return NtStatus;
  538. }
  539. VOID
  540. NdisTapiUnload(
  541. IN PDRIVER_OBJECT DriverObject
  542. )
  543. /*++
  544. Routine Description:
  545. Free all the allocated resources, etc.
  546. Arguments:
  547. DriverObject - pointer to a driver object
  548. Return Value:
  549. --*/
  550. {
  551. KIRQL oldIrql;
  552. PPROVIDER_INFO provider, nextProvider;
  553. DBGOUT ((2, "NdisTapiUnload: enter"));
  554. //
  555. // Delete the device object & sundry resources
  556. //
  557. while (!(IsListEmpty(&DeviceExtension->ProviderEventList))) {
  558. PPROVIDER_EVENT ProviderEvent;
  559. ProviderEvent = (PPROVIDER_EVENT)
  560. RemoveHeadList(&DeviceExtension->ProviderEventList);
  561. ExFreeToNPagedLookasideList(&ProviderEventLookaside, ProviderEvent);
  562. }
  563. ExDeleteNPagedLookasideList(&ProviderEventLookaside);
  564. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  565. provider = DeviceExtension->Providers;
  566. while (provider != NULL)
  567. {
  568. nextProvider = provider->Next;
  569. ExFreePool (provider);
  570. provider = nextProvider;
  571. }
  572. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  573. IoDeleteDevice (DriverObject->DeviceObject);
  574. DBGOUT ((2, "NdisTapiUnload: exit"));
  575. return;
  576. }
  577. VOID
  578. NdisTapiRegisterProvider(
  579. IN NDIS_HANDLE ProviderHandle,
  580. IN PNDISTAPI_CHARACTERISTICS Chars
  581. )
  582. /*++
  583. Routine Description:
  584. This func gets called by Ndis as a result of a Mac driver
  585. registering for Connection Wrapper services.
  586. Arguments:
  587. Return Value:
  588. --*/
  589. {
  590. KIRQL oldIrql;
  591. BOOLEAN sendRequest = FALSE;
  592. NDIS_STATUS ndisStatus;
  593. PPROVIDER_INFO provider, newProvider;
  594. DBGOUT ((2, "NdisTapiRegisterProvider: enter"));
  595. //
  596. // Grab the spin lock & add the new provider, and see whether to
  597. // send the provider an init request
  598. //
  599. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  600. //
  601. // See if this provider has already registered once.
  602. //
  603. provider = DeviceExtension->Providers;
  604. while (provider != NULL) {
  605. if (provider->Status == PROVIDER_STATUS_OFFLINE &&
  606. RtlCompareMemory(
  607. &provider->Guid,
  608. &Chars->Guid,
  609. sizeof(provider->Guid)) == sizeof(provider->Guid)) {
  610. DBGOUT((
  611. 1,
  612. "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",
  613. provider,
  614. provider->Guid.Data1,
  615. provider->Guid.Data2,
  616. provider->Guid.Data3,
  617. provider->Guid.Data4[0],
  618. provider->Guid.Data4[1],
  619. provider->Guid.Data4[2],
  620. provider->Guid.Data4[3],
  621. provider->Guid.Data4[4],
  622. provider->Guid.Data4[5],
  623. provider->Guid.Data4[6],
  624. provider->Guid.Data4[7]
  625. ));
  626. DBGOUT((
  627. 1,
  628. "numDevices %d BaseID %d",
  629. provider->NumDevices,
  630. provider->DeviceIDBase
  631. ));
  632. provider->Status = PROVIDER_STATUS_PENDING_REINIT;
  633. provider->ProviderHandle = ProviderHandle;
  634. provider->RequestProc = Chars->RequestProc;
  635. provider->MediaType = Chars->MediaType;
  636. break;
  637. }
  638. provider = provider->Next;
  639. }
  640. if (provider == NULL) {
  641. //
  642. // Create a new provider instance
  643. //
  644. newProvider = ExAllocatePoolWithTag(
  645. NonPagedPoolCacheAligned,
  646. sizeof(PROVIDER_INFO),
  647. 'IPAT'
  648. );
  649. if (!newProvider) {
  650. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  651. return;
  652. }
  653. RtlZeroMemory(newProvider, sizeof(PROVIDER_INFO));
  654. newProvider->Status = PROVIDER_STATUS_PENDING_INIT;
  655. newProvider->ProviderHandle = ProviderHandle;
  656. newProvider->RequestProc = Chars->RequestProc;
  657. RtlMoveMemory(
  658. &newProvider->Guid,
  659. &Chars->Guid,
  660. sizeof(newProvider->Guid)
  661. );
  662. newProvider->MediaType = Chars->MediaType;
  663. newProvider->Next = NULL;
  664. DBGOUT((
  665. 1,
  666. "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",
  667. newProvider->Guid.Data1,
  668. newProvider->Guid.Data2,
  669. newProvider->Guid.Data3,
  670. newProvider->Guid.Data4[0],
  671. newProvider->Guid.Data4[1],
  672. newProvider->Guid.Data4[2],
  673. newProvider->Guid.Data4[3],
  674. newProvider->Guid.Data4[4],
  675. newProvider->Guid.Data4[5],
  676. newProvider->Guid.Data4[6],
  677. newProvider->Guid.Data4[7]
  678. ));
  679. //
  680. // Add the new provider, and see whether to send the
  681. // provider an init request
  682. //
  683. if ((provider = DeviceExtension->Providers) == NULL) {
  684. DeviceExtension->Providers = newProvider;
  685. }
  686. else {
  687. while (provider->Next != NULL) {
  688. provider = provider->Next;
  689. }
  690. provider->Next = newProvider;
  691. }
  692. provider = newProvider;
  693. }
  694. //
  695. // The only case where we want to send off an init request to the
  696. // provider directly is when we are currently connected to TAPI,
  697. // and even then only when there are no other inits pending (since
  698. // we must synchronize inits due to calculation of DeviceIDBase)
  699. //
  700. if (DeviceExtension->Status == NDISTAPI_STATUS_CONNECTED) {
  701. //
  702. // TAPI is up.
  703. //
  704. // If TAPI already knows about this provider
  705. // go ahead and init the provider with it's current
  706. // DeviceIDBase.
  707. //
  708. // If TAPI does not know about this provider we
  709. // need to give TAPI an indication of a new device
  710. // coming on line.
  711. //
  712. if (provider->Status == PROVIDER_STATUS_PENDING_REINIT) {
  713. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  714. ndisStatus =
  715. SendProviderInitRequest (provider);
  716. if (ndisStatus == NDIS_STATUS_PENDING) {
  717. //
  718. // Wait for completion routine to get called
  719. //
  720. KeWaitForSingleObject (&provider->SyncEvent,
  721. Executive,
  722. KernelMode,
  723. FALSE,
  724. (PTIME) NULL);
  725. }
  726. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  727. //
  728. // Get tapi to reset the state of these lines by
  729. // forcing a line_close...
  730. //
  731. if (provider->DeviceInfo != NULL) {
  732. PDEVICE_INFO DeviceInfo;
  733. ULONG i;
  734. for(i = 0, DeviceInfo = provider->DeviceInfo;
  735. i < provider->NumDevices;
  736. i++, DeviceInfo++) {
  737. NDIS_TAPI_EVENT NdisTapiEvent;
  738. RtlZeroMemory (&NdisTapiEvent, sizeof(NDIS_TAPI_EVENT));
  739. if (DeviceInfo->htLine != (HTAPI_LINE)NULL)
  740. {
  741. NdisTapiEvent.htLine = DeviceInfo->htLine;
  742. NdisTapiEvent.ulMsg = LINE_CLOSE;
  743. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  744. NdisTapiIndicateStatus((ULONG_PTR) provider,
  745. &NdisTapiEvent,
  746. sizeof (NDIS_TAPI_EVENT));
  747. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  748. DeviceInfo->htLine = (HTAPI_LINE)NULL;
  749. DeviceInfo->hdLine = (HDRV_LINE)NULL;
  750. }
  751. }
  752. }
  753. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  754. } else {
  755. NDIS_TAPI_EVENT NdisTapiEvent;
  756. ASSERT(provider->Status == PROVIDER_STATUS_PENDING_INIT);
  757. provider->Status = PROVIDER_STATUS_PENDING_LINE_CREATE;
  758. //
  759. // If there are no providers in the middle of doing
  760. // line_create's then we will kick off creates for this
  761. // provider.
  762. //
  763. // If we already have a line create pending on a provider
  764. // then we will wait until all of its line creates have
  765. // finished before we start sending them from
  766. // this one.
  767. //
  768. if (!(DeviceExtension->Flags & PENDING_LINECREATE)) {
  769. //
  770. // Do a LINE_CREATE so that we can get the starting
  771. // BaseID for this provider. When TAPI calls us back
  772. // with ProviderCreateLineDevice we will have the
  773. // BaseDeviceID to use for this provider and we will
  774. // then init the provider. Once we find out how many
  775. // devices the provider has we will alert TAPI of the
  776. // additional devices.
  777. //
  778. RtlZeroMemory(&NdisTapiEvent, sizeof(NDIS_TAPI_EVENT));
  779. provider->TempID = (ULONG_PTR)provider;
  780. DBGOUT((-1,
  781. "LINE_CREATE %d for provider %p",
  782. provider->CreateCount,
  783. provider->TempID
  784. ));
  785. NdisTapiEvent.ulMsg = LINE_CREATE;
  786. NdisTapiEvent.ulParam1 = 0;
  787. NdisTapiEvent.ulParam2 = provider->TempID;
  788. NdisTapiEvent.ulParam3 = 0;
  789. DeviceExtension->Flags |= PENDING_LINECREATE;
  790. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  791. NdisTapiIndicateStatus((ULONG_PTR)provider, &NdisTapiEvent, sizeof(NDIS_TAPI_EVENT));
  792. }
  793. else
  794. {
  795. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  796. }
  797. }
  798. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  799. }
  800. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  801. ObReferenceObject(DeviceExtension->DeviceObject);
  802. }
  803. VOID
  804. NdisTapiDeregisterProvider(
  805. IN NDIS_HANDLE ProviderHandle
  806. )
  807. /*++
  808. Routine Description:
  809. This func...
  810. Note that this func does not send the provider a shutdown message,
  811. as an implicit shutdown is assumed when the provider deegisters.
  812. Arguments:
  813. Return Value:
  814. --*/
  815. {
  816. KIRQL oldIrql;
  817. BOOLEAN sendShutdownMsg = FALSE;
  818. PPROVIDER_INFO provider, previousProvider;
  819. DBGOUT ((2, "NdisTapiDeregisterProvider: enter"));
  820. //
  821. // Grab the spin lock protecting the device extension
  822. //
  823. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  824. //
  825. // Find the provider instance corresponding to ProviderHandle
  826. //
  827. previousProvider = NULL;
  828. provider = DeviceExtension->Providers;
  829. while (provider != NULL &&
  830. provider->ProviderHandle != ProviderHandle) {
  831. previousProvider = provider;
  832. provider = provider->Next;
  833. }
  834. if (provider == NULL) {
  835. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  836. return;
  837. }
  838. if (provider->Status == PROVIDER_STATUS_ONLINE) {
  839. DeviceExtension->NdisTapiNumDevices -= provider->NumDevices;
  840. }
  841. //
  842. // Send the ProviderShutdown only if the provider
  843. // is not in PROVIDER_STATUS_OFFLINE. Otherwise
  844. // DoIrpMjCloseWork can end up sending
  845. // Providershutdown on a removed adapter.
  846. //
  847. if(provider->Status != PROVIDER_STATUS_OFFLINE)
  848. {
  849. SendProviderShutdown (provider, &oldIrql);
  850. provider->Status = PROVIDER_STATUS_OFFLINE;
  851. }
  852. //
  853. // Do the right thing according to the current NdisTapi state
  854. //
  855. switch (DeviceExtension->Status)
  856. {
  857. case NDISTAPI_STATUS_CONNECTED:
  858. {
  859. UINT i;
  860. //
  861. // Mark provider as offline
  862. //
  863. provider->Status = PROVIDER_STATUS_OFFLINE;
  864. provider->ProviderHandle = NULL;
  865. #if 0
  866. if (provider->DeviceInfo != NULL) {
  867. PDEVICE_INFO DeviceInfo;
  868. for(
  869. i = 0, DeviceInfo = provider->DeviceInfo;
  870. i < provider->NumDevices;
  871. i++, DeviceInfo++
  872. )
  873. {
  874. NDIS_TAPI_EVENT NdisTapiEvent;
  875. RtlZeroMemory (&NdisTapiEvent, sizeof(NDIS_TAPI_EVENT));
  876. if (DeviceInfo->htLine != (HTAPI_LINE)NULL)
  877. {
  878. NdisTapiEvent.htLine = DeviceInfo->htLine;
  879. NdisTapiEvent.ulMsg = LINE_CLOSE;
  880. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  881. NdisTapiIndicateStatus((ULONG_PTR) provider,
  882. &NdisTapiEvent,
  883. sizeof (NDIS_TAPI_EVENT));
  884. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  885. DeviceInfo->htLine = (HTAPI_LINE)NULL;
  886. }
  887. }
  888. }
  889. #endif
  890. // PnP: what if providerInfo->State == PROVIDER_INIT_PENDING
  891. // PnP: what if providerInfo->State == PROVIDER_OFFLINE
  892. break;
  893. }
  894. case NDISTAPI_STATUS_DISCONNECTING:
  895. case NDISTAPI_STATUS_DISCONNECTED:
  896. //
  897. // Fix up pointers, remove provider from list
  898. //
  899. if (previousProvider == NULL) {
  900. DeviceExtension->Providers = provider->Next;
  901. } else {
  902. previousProvider->Next = provider->Next;
  903. }
  904. ExFreePool (provider);
  905. break;
  906. case NDISTAPI_STATUS_CONNECTING:
  907. // PnP: implement
  908. break;
  909. } // switch
  910. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  911. ObDereferenceObject(DeviceExtension->DeviceObject);
  912. DBGOUT((2, "NdisTapiDeregisterProvider: exit"));
  913. }
  914. VOID
  915. NdisTapiIndicateStatus(
  916. IN ULONG_PTR DriverHandle,
  917. IN PVOID StatusBuffer,
  918. IN UINT StatusBufferSize
  919. )
  920. /*++
  921. Routine Description:
  922. This func gets called by Ndis when a miniport driver calls
  923. NdisIndicateStatus to notify us of an async event
  924. (i.e. new call, call state chg, dev state chg, etc.)
  925. Arguments:
  926. Return Value:
  927. --*/
  928. {
  929. PIRP irp;
  930. KIRQL oldIrql;
  931. ULONG bytesInQueue;
  932. ULONG bytesToMove;
  933. ULONG moveSize;
  934. BOOLEAN satisfiedPendingEventsRequest = FALSE;
  935. PNDIS_TAPI_EVENT ndisTapiEvent;
  936. PNDISTAPI_EVENT_DATA ndisTapiEventData;
  937. DBGOUT((2,"NdisTapiIndicateStatus: enter"));
  938. bytesInQueue = StatusBufferSize;
  939. moveSize = 0;
  940. //
  941. // Sync event buf access by acquiring SpinLock
  942. //
  943. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  944. //
  945. // The very first thing to do is check if this is a LINE_NEWCALL
  946. // indication. If so, we need to generate a unique tapi call
  947. // handle, which will be both returned to the calling miniport
  948. // (for use in subsequent status indications) and passed up to
  949. // the tapi server.
  950. //
  951. // The algorithim for computing a unique "htCall" is to start
  952. // at the value 0x80000001, and perpetually increment by 2.
  953. // Keeping the low bit set will allow the user-mode TAPI component
  954. // we talk to to distinguish between these incoming call handles
  955. // and outgoing call handles, the latter of which will always
  956. // have the low bit zero'd (since they're really pointers to heap).
  957. // We are again going to use the space between 0x80000001 and 0xFFFFFFFF
  958. // to identify our call handle. This allows for a maximum of 1GB of
  959. // calls to be active at a time. This is done to avoid a conflict
  960. // with ndiswan's connection table index. A bug in the ddk doc's
  961. // had users providing the connectionid instead of ndiswan's context
  962. // in the line get id oid. Ndiswan has to check both of these and
  963. // now that they overlap it can cause problems. NdisWan will use
  964. // 0x00000000 - 0x80000000 for it's context values.
  965. //
  966. // In <= NT 4.0, valid values used to range between 0x80000000
  967. // and 0xffffffff, as we relied on the fact that user-mode
  968. // addresses always had the low bit zero'd. (Not a valid
  969. // assumption anymore!)
  970. //
  971. ndisTapiEvent = StatusBuffer;
  972. if (ndisTapiEvent->ulMsg == LINE_NEWCALL)
  973. {
  974. ndisTapiEvent->ulParam2 = DeviceExtension->htCall;
  975. DeviceExtension->htCall++;
  976. DeviceExtension->htCall++;
  977. if (DeviceExtension->htCall < 0x80000000) {
  978. DeviceExtension->htCall = 0x80000001;
  979. }
  980. }
  981. //
  982. // Check of there is an outstanding request to satisfy
  983. //
  984. if (DeviceExtension->EventsRequestIrp) {
  985. ASSERT(IsListEmpty(&DeviceExtension->ProviderEventList));
  986. //
  987. // Acquire the cancel spinlock, remove the request from the
  988. // cancellable state, and free the cancel spinlock.
  989. //
  990. irp = DeviceExtension->EventsRequestIrp;
  991. if (IoSetCancelRoutine(irp, NULL) != NULL) {
  992. DeviceExtension->EventsRequestIrp = NULL;
  993. //
  994. // Copy as much of the input data possible from the input data
  995. // queue to the SystemBuffer to satisfy the read.
  996. //
  997. ndisTapiEventData = irp->AssociatedIrp.SystemBuffer;
  998. bytesToMove = ndisTapiEventData->ulTotalSize;
  999. moveSize = (bytesInQueue < bytesToMove) ? bytesInQueue : bytesToMove;
  1000. RtlMoveMemory (
  1001. ndisTapiEventData->Data,
  1002. (PCHAR) StatusBuffer,
  1003. moveSize
  1004. );
  1005. //
  1006. // Set the flag so that we start the next packet and complete
  1007. // this read request (with STATUS_SUCCESS) prior to return.
  1008. //
  1009. ndisTapiEventData->ulUsedSize = moveSize;
  1010. irp->IoStatus.Status = STATUS_SUCCESS;
  1011. irp->IoStatus.Information = sizeof(NDISTAPI_EVENT_DATA) + moveSize - 1;
  1012. satisfiedPendingEventsRequest = TRUE;
  1013. }
  1014. } else {
  1015. do {
  1016. PPROVIDER_EVENT ProviderEvent;
  1017. ProviderEvent =
  1018. ExAllocateFromNPagedLookasideList(&ProviderEventLookaside);
  1019. if (ProviderEvent == NULL) {
  1020. break;
  1021. }
  1022. RtlMoveMemory(&ProviderEvent->Event, StatusBuffer, sizeof(NDIS_TAPI_EVENT));
  1023. InsertTailList(&DeviceExtension->ProviderEventList,
  1024. &ProviderEvent->Linkage);
  1025. DeviceExtension->EventCount++;
  1026. } while ( FALSE );
  1027. }
  1028. //
  1029. // Release the spinlock
  1030. //
  1031. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1032. //
  1033. // If we satisfied an outstanding get events request then complete it
  1034. //
  1035. if (satisfiedPendingEventsRequest) {
  1036. IoCompleteRequest (irp, IO_NO_INCREMENT);
  1037. DBGOUT((2, "NdisTapiIndicateStatus: completion req %p", irp));
  1038. }
  1039. DBGOUT((2,"NdisTapiIndicateStatus: exit"));
  1040. return;
  1041. }
  1042. VOID
  1043. NdisTapiCompleteRequest(
  1044. IN NDIS_HANDLE NdisHandle,
  1045. IN PNDIS_REQUEST NdisRequest,
  1046. IN NDIS_STATUS NdisStatus
  1047. )
  1048. /*++
  1049. Routine Description:
  1050. This func gets called by Ndis as a result of a Mac driver
  1051. calling NdisCompleteRequest of one of our requests.
  1052. Arguments:
  1053. Return Value:
  1054. --*/
  1055. {
  1056. PIRP Irp;
  1057. KIRQL oldIrql;
  1058. ULONG requestID;
  1059. PNDISTAPI_REQUEST ndisTapiRequest;
  1060. PPROVIDER_REQUEST providerRequest;
  1061. PPROVIDER_REQUEST tempReq;
  1062. PIO_STACK_LOCATION irpStack;
  1063. DBGOUT ((2, "NdisTapiCompleteRequest: enter"));
  1064. providerRequest =
  1065. CONTAINING_RECORD(NdisRequest, PROVIDER_REQUEST, NdisRequest);
  1066. do {
  1067. if (providerRequest->Flags & INTERNAL_REQUEST) {
  1068. //
  1069. // This request originated from NdisTapi.sys
  1070. //
  1071. switch (NdisRequest->DATA.SET_INFORMATION.Oid) {
  1072. case OID_TAPI_PROVIDER_INITIALIZE:
  1073. DBGOUT((3,
  1074. "NdisTapiCompleteRequest: ProviderInit - Provider=%p, reqID=%x, Status=%x",
  1075. providerRequest->Provider,
  1076. providerRequest->RequestID,
  1077. NdisStatus));
  1078. switch (DeviceExtension->Status) {
  1079. case NDISTAPI_STATUS_CONNECTED:
  1080. case NDISTAPI_STATUS_CONNECTING:
  1081. DoProviderInitComplete (providerRequest, NdisStatus);
  1082. break;
  1083. case NDISTAPI_STATUS_DISCONNECTED:
  1084. case NDISTAPI_STATUS_DISCONNECTING:
  1085. default:
  1086. break;
  1087. }
  1088. break;
  1089. case OID_TAPI_PROVIDER_SHUTDOWN:
  1090. DBGOUT((3,
  1091. "NdisTapiCompleteRequest: ProviderShutdown - Provider=%p, reqID=%x, Status=%x",
  1092. providerRequest->Provider,
  1093. providerRequest->RequestID,
  1094. NdisStatus));
  1095. break;
  1096. default:
  1097. DBGOUT((1, "NdisTapiCompleteRequest: unrecognized Oid"));
  1098. break;
  1099. }
  1100. break;
  1101. }
  1102. //
  1103. // This is a request originating from TAPI
  1104. //
  1105. //
  1106. // Acquire the SpinLock since we're going to be removing a
  1107. // TAPI request from the queue, and it might not be the request
  1108. // we're looking for. The primary concern is that we could (if
  1109. // the request we're really looking for has been removed) remove
  1110. // a synchrously-completed request that is about to be removed &
  1111. // completed in NdisTapiDispatch, in which case we want to stick
  1112. // the request back in the queue before NdisTapiDispatch tries
  1113. // to remove it.
  1114. //
  1115. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1116. tempReq =
  1117. (PPROVIDER_REQUEST)DeviceExtension->ProviderRequestList.Flink;
  1118. while ((PVOID)tempReq != (PVOID)&DeviceExtension->ProviderRequestList) {
  1119. if (tempReq == providerRequest) {
  1120. break;
  1121. }
  1122. tempReq =
  1123. (PPROVIDER_REQUEST)tempReq->Linkage.Flink;
  1124. }
  1125. if (tempReq != providerRequest) {
  1126. #if DBG
  1127. DbgPrint("NDISTAPI: NdisTapiCompleteRequest: Request %p not found!\n",
  1128. providerRequest);
  1129. #endif
  1130. DeviceExtension->MissingRequests++;
  1131. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1132. break;
  1133. }
  1134. Irp = providerRequest->Irp;
  1135. ndisTapiRequest = Irp->AssociatedIrp.SystemBuffer;
  1136. ASSERT(providerRequest->RequestID ==
  1137. *((ULONG *)ndisTapiRequest->Data));
  1138. //
  1139. // Remove the IRP from the cancelable state
  1140. //
  1141. if (IoSetCancelRoutine(Irp, NULL) == NULL) {
  1142. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1143. break;
  1144. }
  1145. RemoveEntryList(&providerRequest->Linkage);
  1146. DeviceExtension->RequestCount--;
  1147. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1148. DBGOUT((3,
  1149. "NdisTapiCompleteRequest: Irp=%p, Oid=%x, devID=%d, reqID=%x, Status=%x",
  1150. Irp,
  1151. ndisTapiRequest->Oid,
  1152. ndisTapiRequest->ulDeviceID,
  1153. *((ULONG *)ndisTapiRequest->Data),
  1154. NdisStatus));
  1155. //
  1156. // Copy the relevant info back to the IRP
  1157. //
  1158. irpStack = IoGetCurrentIrpStackLocation (Irp);
  1159. //
  1160. // If this was a succesful QUERY_INFO request copy all the
  1161. // data back to the tapi request buf & set
  1162. // Irp->IoStatus.Information appropriately. Otherwise, we
  1163. // just need to pass back the return value. Also mark irp
  1164. // as successfully completed (regardless of actual op result)
  1165. //
  1166. if ((NdisRequest->RequestType == NdisRequestQueryInformation) &&
  1167. (NdisStatus == NDIS_STATUS_SUCCESS)) {
  1168. RtlMoveMemory(ndisTapiRequest->Data,
  1169. NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
  1170. ndisTapiRequest->ulDataSize);
  1171. Irp->IoStatus.Information =
  1172. irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  1173. } else {
  1174. Irp->IoStatus.Information = sizeof (ULONG);
  1175. }
  1176. if((NdisRequest->RequestType == NdisRequestQueryInformation) &&
  1177. (NdisRequest->DATA.QUERY_INFORMATION.Oid == OID_TAPI_OPEN)) {
  1178. DoLineOpenCompleteWork(ndisTapiRequest,
  1179. providerRequest->Provider);
  1180. }
  1181. Irp->IoStatus.Status = STATUS_SUCCESS;
  1182. ndisTapiRequest->ulReturnValue = NdisStatus;
  1183. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  1184. } while (FALSE);
  1185. ExFreePool (providerRequest);
  1186. DBGOUT ((2, "NdisTapiCompleteRequest: exit"));
  1187. }
  1188. #if DBG
  1189. VOID
  1190. DbgPrt(
  1191. IN LONG DbgLevel,
  1192. IN PUCHAR DbgMessage,
  1193. IN ...
  1194. )
  1195. /*++
  1196. Routine Description:
  1197. Formats the incoming debug message & calls DbgPrint
  1198. Arguments:
  1199. DbgLevel - level of message verboseness
  1200. DbgMessage - printf-style format string, followed by appropriate
  1201. list of arguments
  1202. Return Value:
  1203. --*/
  1204. {
  1205. if (DbgLevel <= NdisTapiDebugLevel)
  1206. {
  1207. char buf[256] = "NDISTAPI: ";
  1208. va_list ap;
  1209. va_start (ap, DbgMessage);
  1210. vsprintf (&buf[10], DbgMessage, ap);
  1211. strcat (buf, "\n");
  1212. DbgPrint (buf);
  1213. va_end(ap);
  1214. }
  1215. return;
  1216. }
  1217. #endif // DBG
  1218. VOID
  1219. DoProviderInitComplete(
  1220. PPROVIDER_REQUEST ProviderRequest,
  1221. NDIS_STATUS Status
  1222. )
  1223. /*++
  1224. Routine Description:
  1225. Arguments:
  1226. ProviderInitRequest - pointer successfully completed init request
  1227. Return Value:
  1228. Note:
  1229. --*/
  1230. {
  1231. PPROVIDER_INFO provider = ProviderRequest->Provider;
  1232. PNDIS_TAPI_PROVIDER_INITIALIZE providerInitData =
  1233. (PNDIS_TAPI_PROVIDER_INITIALIZE) ProviderRequest->Data;
  1234. KIRQL OldIrql;
  1235. BOOLEAN fFreeDeviceInfo = FALSE;
  1236. DBGOUT ((2, "DoProviderInitComplete: enter"));
  1237. //
  1238. // Wrap this in an exception handler in case the provider was
  1239. // removed during an async completion
  1240. //
  1241. try
  1242. {
  1243. if (Status == NDIS_STATUS_SUCCESS) {
  1244. provider->ProviderID = (ULONG)providerInitData->ulProviderID;
  1245. // Just in case the provider reports a bigger ulNumLineDevs
  1246. if(providerInitData->ulNumLineDevs > provider->NumDevices)
  1247. {
  1248. fFreeDeviceInfo = TRUE;
  1249. }
  1250. provider->NumDevices = providerInitData->ulNumLineDevs;
  1251. KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
  1252. DeviceExtension->NdisTapiNumDevices += provider->NumDevices;
  1253. KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
  1254. provider->Status = PROVIDER_STATUS_ONLINE;
  1255. if(provider->DeviceInfo && fFreeDeviceInfo)
  1256. {
  1257. ExFreePool (provider->DeviceInfo);
  1258. provider->DeviceInfo = NULL;
  1259. }
  1260. if (provider->DeviceInfo == NULL) {
  1261. provider->DeviceInfo = (PDEVICE_INFO)
  1262. ExAllocatePoolWithTag(
  1263. NonPagedPool,
  1264. sizeof(DEVICE_INFO) * provider->NumDevices,
  1265. 'IPAT'
  1266. );
  1267. }
  1268. if (provider->DeviceInfo != NULL) {
  1269. PDEVICE_INFO DeviceInfo;
  1270. UINT i;
  1271. RtlZeroMemory(
  1272. provider->DeviceInfo,
  1273. sizeof(DEVICE_INFO) * provider->NumDevices
  1274. );
  1275. for(i = 0, DeviceInfo = provider->DeviceInfo;
  1276. i < provider->NumDevices;
  1277. i++, DeviceInfo++) {
  1278. DeviceInfo->DeviceID = provider->DeviceIDBase + i;
  1279. }
  1280. }
  1281. }
  1282. //
  1283. // Set the event which sync's miniport inits
  1284. //
  1285. KeSetEvent(&provider->SyncEvent,
  1286. 0,
  1287. FALSE);
  1288. DBGOUT((3,
  1289. "providerID = 0x%x, numDevices = %d, BaseID = %d",
  1290. provider->ProviderID,
  1291. provider->NumDevices,
  1292. provider->DeviceIDBase));
  1293. }
  1294. except (EXCEPTION_EXECUTE_HANDLER)
  1295. {
  1296. DBGOUT((1, "DoProviderInitComplete: provider invalid"));
  1297. }
  1298. DBGOUT ((2, "DoProviderInitComplete: exit"));
  1299. }
  1300. ULONG
  1301. GetLineEvents(
  1302. PCHAR EventBuffer,
  1303. ULONG BufferSize
  1304. )
  1305. /*++
  1306. Routine Description:
  1307. Arguments:
  1308. Return Value:
  1309. Note:
  1310. Assumes DeviceExtension->SpinLock held by caller.
  1311. --*/
  1312. {
  1313. ULONG BytesLeft;
  1314. ULONG BytesMoved;
  1315. ULONG EventCount;
  1316. BytesLeft = BufferSize;
  1317. BytesMoved = 0;
  1318. EventCount = 0;
  1319. while (!(IsListEmpty(&DeviceExtension->ProviderEventList))) {
  1320. PPROVIDER_EVENT ProviderEvent;
  1321. if (BytesLeft < sizeof(NDIS_TAPI_EVENT)) {
  1322. break;
  1323. }
  1324. ProviderEvent = (PPROVIDER_EVENT)
  1325. RemoveHeadList(&DeviceExtension->ProviderEventList);
  1326. EventCount++;
  1327. RtlMoveMemory(EventBuffer + BytesMoved,
  1328. (PUCHAR)&ProviderEvent->Event,
  1329. sizeof(NDIS_TAPI_EVENT));
  1330. BytesMoved += sizeof(NDIS_TAPI_EVENT);
  1331. BytesLeft -= sizeof(NDIS_TAPI_EVENT);
  1332. ExFreeToNPagedLookasideList(&ProviderEventLookaside,
  1333. ProviderEvent);
  1334. }
  1335. DeviceExtension->EventCount -= EventCount;
  1336. DBGOUT((3, "GetLineEvents: Returned %d Events", EventCount));
  1337. return (BytesMoved);
  1338. }
  1339. NDIS_STATUS
  1340. SendProviderInitRequest(
  1341. PPROVIDER_INFO Provider
  1342. )
  1343. /*++
  1344. Routine Description:
  1345. Arguments:
  1346. Provider - pointer to a PROVIDER_INFO representing provider to initialize
  1347. Return Value:
  1348. Note:
  1349. --*/
  1350. {
  1351. KIRQL oldIrql;
  1352. NDIS_STATUS ndisStatus;
  1353. PNDIS_REQUEST NdisRequest;
  1354. PPROVIDER_INFO tmpProvider;
  1355. PPROVIDER_REQUEST providerRequest;
  1356. PNDIS_TAPI_PROVIDER_INITIALIZE providerInitData;
  1357. DBGOUT ((2, "SendProviderInitRequest: enter"));
  1358. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1359. //
  1360. // Determine the DeviceIDBase to be used for this provider
  1361. //
  1362. if (Provider->Status == PROVIDER_STATUS_PENDING_INIT) {
  1363. Provider->DeviceIDBase = DeviceExtension->ProviderBaseID;
  1364. tmpProvider = DeviceExtension->Providers;
  1365. while (tmpProvider != NULL) {
  1366. if (tmpProvider->Status != PROVIDER_STATUS_PENDING_INIT) {
  1367. Provider->DeviceIDBase += tmpProvider->NumDevices;
  1368. }
  1369. tmpProvider = tmpProvider->Next;
  1370. }
  1371. }
  1372. //
  1373. // Create a provider init request
  1374. //
  1375. providerRequest = ExAllocatePoolWithTag(
  1376. NonPagedPoolCacheAligned,
  1377. sizeof(PROVIDER_REQUEST) + sizeof(NDIS_TAPI_PROVIDER_INITIALIZE) -
  1378. sizeof(ULONG),
  1379. 'IPAT'
  1380. );
  1381. if (!providerRequest) {
  1382. KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
  1383. return NDIS_STATUS_RESOURCES;
  1384. }
  1385. providerRequest->Irp = NULL;
  1386. providerRequest->Flags = INTERNAL_REQUEST;
  1387. providerRequest->Provider = Provider;
  1388. NdisRequest = &providerRequest->NdisRequest;
  1389. NdisRequest->RequestType =
  1390. NdisRequestQueryInformation;
  1391. NdisRequest->DATA.SET_INFORMATION.Oid =
  1392. OID_TAPI_PROVIDER_INITIALIZE;
  1393. NdisRequest->DATA.SET_INFORMATION.InformationBuffer =
  1394. providerRequest->Data;
  1395. NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
  1396. sizeof(NDIS_TAPI_PROVIDER_INITIALIZE);
  1397. providerInitData =
  1398. (PNDIS_TAPI_PROVIDER_INITIALIZE) providerRequest->Data;
  1399. providerRequest->RequestID =
  1400. providerInitData->ulRequestID = ++DeviceExtension->ulRequestID;
  1401. providerInitData->ulDeviceIDBase = Provider->DeviceIDBase;
  1402. KeInitializeEvent(&Provider->SyncEvent,
  1403. SynchronizationEvent,
  1404. FALSE);
  1405. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1406. //
  1407. // Send the request
  1408. //
  1409. ndisStatus=
  1410. (*Provider->RequestProc)
  1411. (Provider->ProviderHandle,NdisRequest);
  1412. if (ndisStatus != NDIS_STATUS_PENDING) {
  1413. DoProviderInitComplete (providerRequest, ndisStatus);
  1414. ExFreePool (providerRequest);
  1415. }
  1416. DBGOUT ((2, "SendProviderInitRequest: exit status %x", ndisStatus));
  1417. return ndisStatus;
  1418. }
  1419. NDIS_STATUS
  1420. SendProviderShutdown(
  1421. PPROVIDER_INFO Provider,
  1422. PKIRQL oldIrql
  1423. )
  1424. /*++
  1425. Routine Description:
  1426. Arguments:
  1427. Return Value:
  1428. A pointer to the next provider in the global providers list
  1429. Note:
  1430. Assumes DeviceExtension->SpinLock held by caller.
  1431. --*/
  1432. {
  1433. NDIS_STATUS ndisStatus;
  1434. PNDIS_REQUEST NdisRequest;
  1435. PPROVIDER_REQUEST providerRequest;
  1436. PNDIS_TAPI_PROVIDER_SHUTDOWN providerShutdownData;
  1437. DBGOUT ((2, "SendProviderShutdown: Provider=%p", Provider));
  1438. //
  1439. // Create a provider init request
  1440. //
  1441. providerRequest =
  1442. ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1443. sizeof(PROVIDER_REQUEST) + sizeof(NDIS_TAPI_PROVIDER_SHUTDOWN) -
  1444. sizeof(ULONG),
  1445. 'IPAT');
  1446. if (!providerRequest) {
  1447. return NDIS_STATUS_RESOURCES;
  1448. }
  1449. providerRequest->Irp = NULL;
  1450. providerRequest->Flags = INTERNAL_REQUEST;
  1451. providerRequest->Provider = Provider;
  1452. NdisRequest = &providerRequest->NdisRequest;
  1453. NdisRequest->RequestType =
  1454. NdisRequestSetInformation;
  1455. NdisRequest->DATA.SET_INFORMATION.Oid =
  1456. OID_TAPI_PROVIDER_SHUTDOWN;
  1457. NdisRequest->DATA.SET_INFORMATION.InformationBuffer =
  1458. providerRequest->Data;
  1459. NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
  1460. sizeof(NDIS_TAPI_PROVIDER_SHUTDOWN);
  1461. providerShutdownData =
  1462. (PNDIS_TAPI_PROVIDER_SHUTDOWN)providerRequest->Data;
  1463. providerRequest->RequestID =
  1464. providerShutdownData->ulRequestID = ++DeviceExtension->ulRequestID;
  1465. KeReleaseSpinLock (&DeviceExtension->SpinLock, *oldIrql);
  1466. //
  1467. // Send the request
  1468. //
  1469. ndisStatus =
  1470. (*Provider->RequestProc)
  1471. (Provider->ProviderHandle, NdisRequest);
  1472. //
  1473. // If request was completed synchronously then free the request
  1474. // (otherwise it will get freed when the completion proc is called)
  1475. //
  1476. if (ndisStatus != NDIS_STATUS_PENDING) {
  1477. ExFreePool (providerRequest);
  1478. }
  1479. DBGOUT ((2, "SendProviderShutdown: Status=%x", ndisStatus));
  1480. KeAcquireSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1481. return ndisStatus;
  1482. }
  1483. BOOLEAN
  1484. SyncInitAllProviders(
  1485. void
  1486. )
  1487. /*++
  1488. Routine Description:
  1489. This functions walks the list of registered providers and sends
  1490. init requests to the providers in the PENDING_INIT state
  1491. Arguments:
  1492. (none)
  1493. Return Value:
  1494. TRUE if all registered providers initialized, or
  1495. FALSE if there are more providers to initialze
  1496. Note:
  1497. --*/
  1498. {
  1499. ULONG numDevices = 0;
  1500. NDIS_STATUS ndisStatus;
  1501. PPROVIDER_INFO provider;
  1502. KIRQL oldIrql;
  1503. DBGOUT((2, "SyncInitAllProviders: enter"));
  1504. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1505. provider = DeviceExtension->Providers;
  1506. while (provider != NULL) {
  1507. if (provider->Status == PROVIDER_STATUS_PENDING_INIT ||
  1508. provider->Status == PROVIDER_STATUS_PENDING_REINIT ||
  1509. provider->Status == PROVIDER_STATUS_PENDING_LINE_CREATE) {
  1510. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1511. ndisStatus = SendProviderInitRequest (provider);
  1512. if (ndisStatus == NDIS_STATUS_PENDING) {
  1513. //
  1514. // Wait for completion routine to get called
  1515. //
  1516. KeWaitForSingleObject (&provider->SyncEvent,
  1517. Executive,
  1518. KernelMode,
  1519. FALSE,
  1520. (PTIME) NULL
  1521. );
  1522. }
  1523. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1524. }
  1525. provider = provider->Next;
  1526. }
  1527. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1528. DBGOUT((2, "SyncInitAllProviders: exit"));
  1529. return TRUE;
  1530. }
  1531. VOID
  1532. DoIrpMjCloseWork(
  1533. PIRP Irp
  1534. )
  1535. {
  1536. KIRQL oldIrql;
  1537. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1538. if (InterlockedDecrement(&DeviceExtension->RefCount) == 0) {
  1539. if (DeviceExtension->Status == NDISTAPI_STATUS_CONNECTED) {
  1540. PPROVIDER_INFO provider;
  1541. DeviceExtension->Status =
  1542. NDISTAPI_STATUS_DISCONNECTING;
  1543. //
  1544. // Send the providers a shutdown request
  1545. //
  1546. provider = DeviceExtension->Providers;
  1547. while (provider != NULL) {
  1548. switch (provider->Status) {
  1549. case PROVIDER_STATUS_ONLINE:
  1550. DeviceExtension->NdisTapiNumDevices -= provider->NumDevices;
  1551. SendProviderShutdown (provider, &oldIrql);
  1552. //
  1553. // fall thru...
  1554. //
  1555. case PROVIDER_STATUS_PENDING_INIT:
  1556. case PROVIDER_STATUS_PENDING_REINIT:
  1557. //
  1558. // Reset provider status
  1559. //
  1560. provider->Status = PROVIDER_STATUS_PENDING_INIT;
  1561. break;
  1562. case PROVIDER_STATUS_OFFLINE:
  1563. break;
  1564. }
  1565. provider = provider->Next;
  1566. }
  1567. DeviceExtension->Status = NDISTAPI_STATUS_DISCONNECTED;
  1568. ASSERT(DeviceExtension->NdisTapiNumDevices == 0);
  1569. }
  1570. }
  1571. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1572. Irp->IoStatus.Status = STATUS_SUCCESS;
  1573. Irp->IoStatus.Information = 0;
  1574. }
  1575. NTSTATUS
  1576. DoIoctlConnectWork(
  1577. PIRP Irp,
  1578. PVOID ioBuffer,
  1579. ULONG inputBufferLength,
  1580. ULONG outputBufferLength
  1581. )
  1582. {
  1583. KIRQL oldIrql;
  1584. ULONG InfoSize;
  1585. NTSTATUS NtStatus;
  1586. //
  1587. // Someone's connecting. Make sure they passed us a valid
  1588. // info buffer
  1589. //
  1590. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1591. do {
  1592. if ((inputBufferLength < 2*sizeof(ULONG)) ||
  1593. (outputBufferLength < sizeof(ULONG))) {
  1594. DBGOUT ((3, "IOCTL_NDISTAPI_CONNECT: buffer too small"));
  1595. NtStatus = STATUS_BUFFER_TOO_SMALL;
  1596. InfoSize = 0;
  1597. break;
  1598. }
  1599. if (DeviceExtension->Status == NDISTAPI_STATUS_DISCONNECTED) {
  1600. DeviceExtension->Status = NDISTAPI_STATUS_CONNECTING;
  1601. DeviceExtension->ProviderBaseID =
  1602. *((ULONG *) ioBuffer);
  1603. DBGOUT ((1, "ProviderBaseID %d",
  1604. DeviceExtension->ProviderBaseID));
  1605. //
  1606. // Synchronously init all providers
  1607. //
  1608. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1609. SyncInitAllProviders();
  1610. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1611. }
  1612. //
  1613. // Return the number of line devs
  1614. //
  1615. {
  1616. ULONG OfflineCount;
  1617. PPROVIDER_INFO provider;
  1618. //
  1619. // Since some providers might be temporarily offline
  1620. // we need to tell tapi about them even though they
  1621. // are not currently useable. This keeps the tapi
  1622. // deviceid space consistent.
  1623. //
  1624. OfflineCount = 0;
  1625. provider = DeviceExtension->Providers;
  1626. while (provider != NULL) {
  1627. if (provider->Status == PROVIDER_STATUS_OFFLINE) {
  1628. OfflineCount += provider->NumDevices;
  1629. }
  1630. provider = provider->Next;
  1631. }
  1632. *((ULONG *) ioBuffer)=
  1633. DeviceExtension->NdisTapiNumDevices + OfflineCount;
  1634. }
  1635. DeviceExtension->Status = NDISTAPI_STATUS_CONNECTED;
  1636. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1637. InfoSize = sizeof(ULONG);
  1638. NtStatus = STATUS_SUCCESS;
  1639. } while (FALSE);
  1640. Irp->IoStatus.Status = NtStatus;
  1641. Irp->IoStatus.Information = InfoSize;
  1642. return (NtStatus);
  1643. }
  1644. NTSTATUS
  1645. DoIoctlQuerySetWork(
  1646. PIRP Irp,
  1647. PVOID ioBuffer,
  1648. ULONG inputBufferLength,
  1649. ULONG outputBufferLength
  1650. )
  1651. {
  1652. KIRQL oldIrql;
  1653. ULONG InfoSize;
  1654. NTSTATUS NtStatus;
  1655. PPROVIDER_INFO provider;
  1656. NDIS_STATUS ndisStatus;
  1657. PNDIS_REQUEST NdisRequest;
  1658. PNDISTAPI_REQUEST ndisTapiRequest;
  1659. PPROVIDER_REQUEST providerRequest;
  1660. PIO_STACK_LOCATION irpStack;
  1661. do {
  1662. ndisTapiRequest = ioBuffer;
  1663. NtStatus = STATUS_SUCCESS;
  1664. InfoSize = 0;
  1665. //
  1666. // Make sure input & output buffers are large enough
  1667. //
  1668. if ((inputBufferLength < sizeof (NDISTAPI_REQUEST)) ||
  1669. (ndisTapiRequest->ulDataSize > 0x10000000) ||
  1670. (inputBufferLength < (sizeof (NDISTAPI_REQUEST) +
  1671. ndisTapiRequest->ulDataSize - sizeof (UCHAR)) ||
  1672. (outputBufferLength < (sizeof (NDISTAPI_REQUEST) +
  1673. ndisTapiRequest->ulDataSize - sizeof (UCHAR))))) {
  1674. DBGOUT((-1, "NdisTapiDispatch: buffer to small!"));
  1675. NtStatus = STATUS_BUFFER_TOO_SMALL;
  1676. break;
  1677. }
  1678. //
  1679. // Verify we're connected, then check the device ID of the
  1680. // incoming request against our list of online devices
  1681. //
  1682. ndisStatus =
  1683. VerifyProvider(ndisTapiRequest, &provider);
  1684. if (ndisStatus != NDIS_STATUS_SUCCESS) {
  1685. ndisTapiRequest->ulReturnValue = ndisStatus;
  1686. InfoSize = sizeof(ULONG);
  1687. break;
  1688. }
  1689. //
  1690. // If this is a line_close, check to see if the line has
  1691. // been opened before sending a line close oid
  1692. //
  1693. if(ndisTapiRequest->Oid == OID_TAPI_CLOSE) {
  1694. ndisStatus = VerifyLineClose(ndisTapiRequest, provider);
  1695. if(ndisStatus != NDIS_STATUS_SUCCESS)
  1696. {
  1697. ndisTapiRequest->ulReturnValue = ndisStatus;
  1698. InfoSize = sizeof(ULONG);
  1699. break;
  1700. }
  1701. }
  1702. //
  1703. // Create the providerRequest & submit it
  1704. //
  1705. providerRequest =
  1706. ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1707. sizeof(PROVIDER_REQUEST) +
  1708. ndisTapiRequest->ulDataSize -
  1709. sizeof(ULONG),
  1710. 'IPAT');
  1711. if (providerRequest == NULL) {
  1712. DBGOUT((-1, "NdisTapiDispatch: unable to alloc request buf"));
  1713. ndisTapiRequest->ulReturnValue = NDIS_STATUS_RESOURCES;
  1714. InfoSize = sizeof (ULONG);
  1715. break;
  1716. }
  1717. if (ndisTapiRequest->Oid == OID_TAPI_OPEN) {
  1718. DoLineOpenWork(ndisTapiRequest, provider);
  1719. }
  1720. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1721. providerRequest->Flags = 0;
  1722. providerRequest->Irp = Irp;
  1723. providerRequest->Provider = provider;
  1724. providerRequest->RequestID =
  1725. *((ULONG *)ndisTapiRequest->Data) = ++DeviceExtension->ulRequestID;
  1726. RtlMoveMemory(providerRequest->Data,
  1727. ndisTapiRequest->Data, ndisTapiRequest->ulDataSize);
  1728. NdisRequest = &providerRequest->NdisRequest;
  1729. irpStack = IoGetCurrentIrpStackLocation (Irp);
  1730. NdisRequest->RequestType =
  1731. (irpStack->Parameters.DeviceIoControl.IoControlCode ==
  1732. IOCTL_NDISTAPI_QUERY_INFO) ? NdisRequestQueryInformation :
  1733. NdisRequestSetInformation;
  1734. NdisRequest->DATA.SET_INFORMATION.Oid =
  1735. ndisTapiRequest->Oid;
  1736. NdisRequest->DATA.SET_INFORMATION.InformationBuffer =
  1737. providerRequest->Data;
  1738. NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
  1739. ndisTapiRequest->ulDataSize;
  1740. DBGOUT((3,
  1741. "DoIoctlQuerySetWork: Oid=%x, devID=%d, reqID=%x",
  1742. ndisTapiRequest->Oid,
  1743. ndisTapiRequest->ulDeviceID,
  1744. *((ULONG *)ndisTapiRequest->Data)));
  1745. //
  1746. // Queue up this TAPI request in our request list.
  1747. //
  1748. InsertTailList(&DeviceExtension->ProviderRequestList,
  1749. &providerRequest->Linkage);
  1750. DeviceExtension->RequestCount++;
  1751. KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
  1752. //
  1753. // Mark the TAPI request pending and set the cancel routine
  1754. //
  1755. IoMarkIrpPending(Irp);
  1756. Irp->IoStatus.Status = STATUS_PENDING;
  1757. IoSetCancelRoutine (Irp, NdisTapiCancel);
  1758. //
  1759. // Call the provider's request proc
  1760. //
  1761. ndisStatus =
  1762. (*provider->RequestProc)
  1763. (provider->ProviderHandle, NdisRequest);
  1764. //
  1765. // If PENDING was returned then just exit & let the completion
  1766. // routine handle the request completion
  1767. //
  1768. // NOTE: If pending was returned then the request may have
  1769. // already been completed, so DO NOT touch anything
  1770. // in the Irp (don't reference the pointer, etc.)
  1771. //
  1772. if (ndisStatus == NDIS_STATUS_PENDING) {
  1773. DBGOUT((1, "DoIoctlQuerySetWork: exit Irp=%p, Status=%x",
  1774. Irp, STATUS_PENDING));
  1775. return (STATUS_PENDING);
  1776. }
  1777. //
  1778. // The provider request completed synchronously, so remove
  1779. // the TAPI request from the device queue. We need to
  1780. // synchronize access to this queue with the
  1781. // SpinLock.
  1782. //
  1783. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1784. do {
  1785. PPROVIDER_REQUEST pReq;
  1786. pReq = (PPROVIDER_REQUEST)
  1787. DeviceExtension->ProviderRequestList.Flink;
  1788. while ((PVOID)pReq != (PVOID)&DeviceExtension->ProviderRequestList) {
  1789. if (pReq == providerRequest) {
  1790. break;
  1791. }
  1792. pReq = (PPROVIDER_REQUEST)
  1793. pReq->Linkage.Flink;
  1794. }
  1795. if (pReq != providerRequest) {
  1796. DBGOUT((0, "DoIoctlQuerySetWork - Request %p not found!",
  1797. providerRequest));
  1798. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1799. return (STATUS_PENDING);
  1800. }
  1801. Irp = providerRequest->Irp;
  1802. ndisTapiRequest = Irp->AssociatedIrp.SystemBuffer;
  1803. ASSERT(providerRequest->RequestID ==
  1804. *((ULONG *)ndisTapiRequest->Data));
  1805. //
  1806. // Remove the IRP from the cancelable state
  1807. //
  1808. if (IoSetCancelRoutine(Irp, NULL) == NULL) {
  1809. DBGOUT((0, "DoIoctlQuerySetWork - Irp %p has been canceled!", Irp));
  1810. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1811. return (STATUS_PENDING);
  1812. }
  1813. RemoveEntryList(&providerRequest->Linkage);
  1814. DeviceExtension->RequestCount--;
  1815. } while (FALSE);
  1816. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1817. //
  1818. // If this was a succesful QUERY_INFO request copy all the
  1819. // data back to the tapi request buf & set
  1820. // Irp->IoStatus.Information appropriately. Otherwise, we
  1821. // just need to pass back the return value.
  1822. //
  1823. if ((irpStack->Parameters.DeviceIoControl.IoControlCode ==
  1824. IOCTL_NDISTAPI_QUERY_INFO) &&
  1825. (ndisStatus == NDIS_STATUS_SUCCESS)) {
  1826. RtlMoveMemory(ndisTapiRequest->Data,
  1827. providerRequest->Data,
  1828. ndisTapiRequest->ulDataSize);
  1829. InfoSize =
  1830. irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  1831. } else {
  1832. InfoSize = sizeof (ULONG);
  1833. }
  1834. ndisTapiRequest->ulReturnValue = ndisStatus;
  1835. //
  1836. // Free the providerRequest
  1837. //
  1838. ExFreePool (providerRequest);
  1839. } while (FALSE);
  1840. Irp->IoStatus.Status = NtStatus;
  1841. Irp->IoStatus.Information = InfoSize;
  1842. DBGOUT((1, "DoIoctlQuerySetWork: exit Irp=%p, Status=%x",
  1843. Irp, NtStatus));
  1844. return (NtStatus);
  1845. }
  1846. VOID
  1847. DoLineOpenCompleteWork(
  1848. PNDISTAPI_REQUEST ndisTapiRequest,
  1849. PPROVIDER_INFO provider
  1850. )
  1851. {
  1852. DBGOUT((2, "DoLineOpenCompleteWork: Open Completed"));
  1853. //
  1854. // Now stash the hdLine for this deviceid
  1855. //
  1856. if (provider->DeviceInfo != NULL) {
  1857. UINT i;
  1858. PDEVICE_INFO DeviceInfo;
  1859. PNDIS_TAPI_OPEN TapiOpen;
  1860. TapiOpen = (PNDIS_TAPI_OPEN) ndisTapiRequest->Data;
  1861. for(i = 0, DeviceInfo = provider->DeviceInfo;
  1862. i < provider->NumDevices;
  1863. i++, DeviceInfo++) {
  1864. if (DeviceInfo->DeviceID == TapiOpen->ulDeviceID) {
  1865. DeviceInfo->hdLine = TapiOpen->hdLine;
  1866. DBGOUT((2, "Complete for open. stashing hdline=0x%x for device %d",
  1867. DeviceInfo->hdLine, DeviceInfo->DeviceID));
  1868. break;
  1869. }
  1870. }
  1871. }
  1872. }
  1873. VOID
  1874. DoLineOpenWork(
  1875. PNDISTAPI_REQUEST ndisTapiRequest,
  1876. PPROVIDER_INFO provider
  1877. )
  1878. {
  1879. KIRQL oldIrql;
  1880. PNDIS_TAPI_OPEN TapiOpen;
  1881. PNDISTAPI_OPENDATA OpenData;
  1882. TapiOpen = (PNDIS_TAPI_OPEN) ndisTapiRequest->Data;
  1883. if (ndisTapiRequest->ulDataSize >= sizeof(NDIS_TAPI_OPEN) +
  1884. sizeof(NDISTAPI_OPENDATA)) {
  1885. OpenData = (PNDISTAPI_OPENDATA)
  1886. ((PUCHAR)ndisTapiRequest->Data + sizeof(NDIS_TAPI_OPEN));
  1887. RtlMoveMemory(&OpenData->Guid,
  1888. &provider->Guid, sizeof(OpenData->Guid));
  1889. OpenData->MediaType = provider->MediaType;
  1890. }
  1891. //
  1892. // Now stash the htLine for this deviceid
  1893. //
  1894. if (provider->DeviceInfo != NULL) {
  1895. UINT i;
  1896. PDEVICE_INFO DeviceInfo;
  1897. for(i = 0, DeviceInfo = provider->DeviceInfo;
  1898. i < provider->NumDevices;
  1899. i++, DeviceInfo++) {
  1900. if (DeviceInfo->DeviceID == TapiOpen->ulDeviceID) {
  1901. DeviceInfo->htLine = TapiOpen->htLine;
  1902. DBGOUT((
  1903. 1,
  1904. "Stash htLine - provider %p DeviceID %d htLine %x",
  1905. provider,
  1906. DeviceInfo->DeviceID,
  1907. DeviceInfo->htLine));
  1908. }
  1909. }
  1910. }
  1911. }
  1912. NDIS_STATUS
  1913. VerifyLineClose(
  1914. PNDISTAPI_REQUEST ndisTapiRequest,
  1915. PPROVIDER_INFO provider
  1916. )
  1917. {
  1918. NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
  1919. if (provider->DeviceInfo != NULL) {
  1920. UINT i;
  1921. PDEVICE_INFO DeviceInfo;
  1922. PNDIS_TAPI_CLOSE TapiClose;
  1923. TapiClose = (PNDIS_TAPI_CLOSE) ndisTapiRequest->Data;
  1924. for(i = 0, DeviceInfo = provider->DeviceInfo;
  1925. i < provider->NumDevices;
  1926. i++, DeviceInfo++) {
  1927. if (DeviceInfo->hdLine == TapiClose->hdLine) {
  1928. break;
  1929. }
  1930. }
  1931. if(i == provider->NumDevices)
  1932. {
  1933. DBGOUT((2,"LINE_CLOSE: didn't find hdLine=0x%x",
  1934. TapiClose->hdLine));
  1935. ndisStatus = NDISTAPIERR_DEVICEOFFLINE;
  1936. }
  1937. else
  1938. {
  1939. DBGOUT((2, "LINE_CLOSE: found hdLine=0x%x",
  1940. TapiClose->hdLine));
  1941. }
  1942. }
  1943. return ndisStatus;
  1944. }
  1945. NDIS_STATUS
  1946. VerifyProvider(
  1947. PNDISTAPI_REQUEST ndisTapiRequest,
  1948. PPROVIDER_INFO *provider
  1949. )
  1950. {
  1951. KIRQL oldIrql;
  1952. PPROVIDER_INFO pp;
  1953. NDIS_STATUS Status;
  1954. ULONG targetDeviceID;
  1955. Status = NDIS_STATUS_SUCCESS;
  1956. *provider = NULL;
  1957. targetDeviceID = ndisTapiRequest->ulDeviceID;
  1958. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  1959. do {
  1960. if (DeviceExtension->Status != NDISTAPI_STATUS_CONNECTED) {
  1961. DBGOUT((3, "VerifyProvider: unconnected, returning err"));
  1962. Status = NDISTAPIERR_UNINITIALIZED;
  1963. break;
  1964. }
  1965. pp = DeviceExtension->Providers;
  1966. while (pp != NULL) {
  1967. if ((pp->Status == PROVIDER_STATUS_ONLINE) &&
  1968. (targetDeviceID >= pp->DeviceIDBase) &&
  1969. (targetDeviceID <
  1970. pp->DeviceIDBase + pp->NumDevices)
  1971. ) {
  1972. break;
  1973. }
  1974. pp = pp->Next;
  1975. }
  1976. if (pp == NULL ||
  1977. pp->ProviderHandle == NULL) {
  1978. //
  1979. // Set Irp->IoStatus.Information large enough that err code
  1980. // gets copied back to user buffer
  1981. //
  1982. DBGOUT((3, "VerifyProvider: dev offline, returning err"));
  1983. Status = NDISTAPIERR_DEVICEOFFLINE;
  1984. break;
  1985. }
  1986. *provider = pp;
  1987. } while (FALSE);
  1988. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  1989. return (Status);
  1990. }
  1991. NTSTATUS
  1992. DoGetProviderEventsWork(
  1993. PIRP Irp,
  1994. PVOID ioBuffer,
  1995. ULONG inputBufferLength,
  1996. ULONG outputBufferLength
  1997. )
  1998. {
  1999. KIRQL oldIrql;
  2000. ULONG InfoSize;
  2001. NTSTATUS NtStatus;
  2002. PNDISTAPI_EVENT_DATA ndisTapiEventData;
  2003. ndisTapiEventData = ioBuffer;
  2004. NtStatus = STATUS_SUCCESS;
  2005. InfoSize = 0;
  2006. //
  2007. // Sync event buf access by acquiring SpinLock
  2008. //
  2009. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  2010. do {
  2011. if ((inputBufferLength < sizeof (NDISTAPI_EVENT_DATA)) ||
  2012. (outputBufferLength < sizeof(NDISTAPI_EVENT_DATA)) ||
  2013. ((outputBufferLength -
  2014. FIELD_OFFSET(NDISTAPI_EVENT_DATA, Data[0])) <
  2015. ndisTapiEventData->ulTotalSize)) {
  2016. NtStatus = STATUS_BUFFER_TOO_SMALL;
  2017. break;
  2018. }
  2019. if (DeviceExtension->Status != NDISTAPI_STATUS_CONNECTED) {
  2020. DBGOUT((3, "DoGetProviderEventsWork: Status!=NDIS_STATUS_CONNECTED!"));
  2021. NtStatus = STATUS_UNSUCCESSFUL;
  2022. break;
  2023. }
  2024. if (DeviceExtension->EventsRequestIrp != NULL) {
  2025. #if DBG
  2026. DbgPrint("NDISTAPI: Attempt to set duplicate EventIrp o:%p, d:%p\n",
  2027. DeviceExtension->EventsRequestIrp, Irp);
  2028. #endif
  2029. NtStatus = STATUS_UNSUCCESSFUL;
  2030. break;
  2031. }
  2032. //
  2033. // Inspect DeviceExtension to see if there's any data available
  2034. //
  2035. if (DeviceExtension->EventCount == 0) {
  2036. //
  2037. // Hold the request pending. It remains in the cancelable
  2038. // state. When new line event input is received
  2039. // (NdisTapiIndicateStatus) or generated (i.e.
  2040. // LINEDEVSTATE_REINIT) the data will get copied & the
  2041. // request completed.
  2042. //
  2043. ASSERT(DeviceExtension->EventsRequestIrp == NULL);
  2044. DeviceExtension->EventsRequestIrp = Irp;
  2045. IoMarkIrpPending(Irp);
  2046. Irp->IoStatus.Status = STATUS_PENDING;
  2047. IoSetCancelRoutine (Irp, NdisTapiCancel);
  2048. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  2049. DBGOUT((3, "DoGetProviderEventsWork: Pending Irp=%p", Irp));
  2050. return(STATUS_PENDING);
  2051. }
  2052. //
  2053. // There's line event data queued in our ring buffer. Grab as
  2054. // much as we can & complete the request.
  2055. //
  2056. ndisTapiEventData->ulUsedSize =
  2057. GetLineEvents(ndisTapiEventData->Data,
  2058. ndisTapiEventData->ulTotalSize);
  2059. InfoSize =
  2060. ndisTapiEventData->ulUsedSize + sizeof(NDISTAPI_EVENT_DATA) - 1;
  2061. DBGOUT((3, "GetLineEvents: SyncComplete Irp=%p", Irp));
  2062. } while (FALSE);
  2063. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  2064. Irp->IoStatus.Status = NtStatus;
  2065. Irp->IoStatus.Information = InfoSize;
  2066. return (NtStatus);
  2067. }
  2068. NTSTATUS
  2069. DoLineCreateWork(
  2070. PIRP Irp,
  2071. PVOID ioBuffer,
  2072. ULONG inputBufferLength,
  2073. ULONG outputBufferLength
  2074. )
  2075. {
  2076. KIRQL oldIrql;
  2077. ULONG InfoSize;
  2078. NTSTATUS NtStatus;
  2079. PPROVIDER_INFO provider;
  2080. PNDISTAPI_CREATE_INFO CreateInfo;
  2081. InfoSize = 0;
  2082. NtStatus = STATUS_SUCCESS;
  2083. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  2084. do {
  2085. if (inputBufferLength < sizeof(CreateInfo)) {
  2086. DBGOUT ((3, "IOCTL_NDISTAPI_CREATE: buffer too small"));
  2087. NtStatus = STATUS_BUFFER_TOO_SMALL;
  2088. break;
  2089. }
  2090. if (DeviceExtension->Status != NDISTAPI_STATUS_CONNECTED) {
  2091. DBGOUT((3, "IOCTL_NDISTAPI_CREATE: while unconnected, returning err"));
  2092. NtStatus = STATUS_UNSUCCESSFUL;
  2093. break;
  2094. }
  2095. CreateInfo = (PNDISTAPI_CREATE_INFO)ioBuffer;
  2096. provider = DeviceExtension->Providers;
  2097. while (provider != NULL) {
  2098. if (provider->TempID == CreateInfo->TempID) {
  2099. break;
  2100. }
  2101. provider = provider->Next;
  2102. }
  2103. if (provider == NULL) {
  2104. DBGOUT((0, "IOCTL_NDISTAPI_CREATE: Provider not found %x",
  2105. CreateInfo->TempID));
  2106. NtStatus = STATUS_UNSUCCESSFUL;
  2107. break;
  2108. }
  2109. if (provider->Status == PROVIDER_STATUS_OFFLINE) {
  2110. DBGOUT((0, "IOCTL_CREATE - Provider %p invalid state %x",
  2111. provider, provider->Status));
  2112. NtStatus = STATUS_UNSUCCESSFUL;
  2113. break;
  2114. }
  2115. DBGOUT((1, "IOCTL_NDISTAPI_CREATE: provider %p ID %d",
  2116. provider, CreateInfo->DeviceID));
  2117. if (provider->CreateCount == 0) {
  2118. NDIS_STATUS ndisStatus;
  2119. //
  2120. // Set the base ID
  2121. //
  2122. provider->DeviceIDBase =
  2123. CreateInfo->DeviceID;
  2124. //
  2125. // Init the provider
  2126. //
  2127. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  2128. ndisStatus = SendProviderInitRequest (provider);
  2129. if (ndisStatus == NDIS_STATUS_PENDING) {
  2130. //
  2131. // Wait for completion routine to get called
  2132. //
  2133. KeWaitForSingleObject (&provider->SyncEvent,
  2134. Executive,
  2135. KernelMode,
  2136. FALSE,
  2137. (PTIME) NULL);
  2138. }
  2139. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  2140. }
  2141. ASSERT(CreateInfo->DeviceID ==
  2142. (provider->DeviceIDBase + provider->CreateCount));
  2143. provider->CreateCount++;
  2144. ASSERT(provider->CreateCount <= provider->NumDevices);
  2145. if (provider->CreateCount == provider->NumDevices) {
  2146. //
  2147. // We have finished all of the line_creates for this
  2148. // provider so find the next provider that needs to be
  2149. // kick started.
  2150. //
  2151. provider = provider->Next;
  2152. while (provider != NULL) {
  2153. if (provider->Status ==
  2154. PROVIDER_STATUS_PENDING_LINE_CREATE) {
  2155. break;
  2156. }
  2157. provider = provider->Next;
  2158. }
  2159. }
  2160. if (provider != NULL) {
  2161. NDIS_TAPI_EVENT NdisTapiEvent;
  2162. //
  2163. // Do a LINE_CREATE for all additional devices
  2164. // on this provider
  2165. //
  2166. RtlZeroMemory(&NdisTapiEvent, sizeof(NDIS_TAPI_EVENT));
  2167. provider->TempID = (ULONG_PTR)provider;
  2168. DBGOUT((
  2169. -1,
  2170. "LINE_CREATE %d for provider %p",
  2171. provider->CreateCount,
  2172. provider->TempID
  2173. ));
  2174. NdisTapiEvent.ulMsg = LINE_CREATE;
  2175. NdisTapiEvent.ulParam1 = 0;
  2176. NdisTapiEvent.ulParam2 = provider->TempID;
  2177. NdisTapiEvent.ulParam3 = 0;
  2178. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  2179. NdisTapiIndicateStatus((ULONG_PTR) provider,
  2180. &NdisTapiEvent,
  2181. sizeof (NDIS_TAPI_EVENT));
  2182. KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
  2183. } else {
  2184. DeviceExtension->Flags &= ~PENDING_LINECREATE;
  2185. }
  2186. InfoSize = sizeof(NDISTAPI_CREATE_INFO);
  2187. } while (FALSE);
  2188. KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
  2189. Irp->IoStatus.Status = NtStatus;
  2190. Irp->IoStatus.Information = InfoSize;
  2191. return (NtStatus);
  2192. }