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.

1252 lines
34 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. smcnt.c
  5. Abstract:
  6. This module handles all IOCTL requests to the smart card reader.
  7. Environment:
  8. Kernel mode only.
  9. Notes:
  10. Revision History:
  11. - Created December 1996 by Klaus Schutz
  12. --*/
  13. #include <stdarg.h>
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <ntddk.h>
  17. #include <strsafe.h>
  18. #define SMARTCARD_POOL_TAG 'bLCS'
  19. #define _ISO_TABLES_
  20. #include "smclib.h"
  21. typedef struct _TAG_LIST_ENTRY {
  22. ULONG Tag;
  23. LIST_ENTRY List;
  24. } TAG_LIST_ENTRY, *PTAG_LIST_ENTRY;
  25. NTSTATUS
  26. DriverEntry(
  27. IN PDRIVER_OBJECT DriverObject,
  28. IN PUNICODE_STRING RegistryPath
  29. );
  30. void
  31. SmartcardDeleteLink(
  32. IN PUNICODE_STRING LinkName
  33. );
  34. #pragma alloc_text(PAGEABLE,DriverEntry)
  35. #pragma alloc_text(PAGEABLE,SmartcardCreateLink)
  36. #pragma alloc_text(PAGEABLE,SmartcardDeleteLink)
  37. #pragma alloc_text(PAGEABLE,SmartcardInitialize)
  38. #pragma alloc_text(PAGEABLE,SmartcardExit)
  39. NTSTATUS
  40. SmartcardDeviceIoControl(
  41. PSMARTCARD_EXTENSION SmartcardExtension
  42. );
  43. PUCHAR
  44. MapIoControlCodeToString(
  45. ULONG IoControlCode
  46. );
  47. #if DEBUG_INTERFACE
  48. #include "smcdbg.c"
  49. #else
  50. NTSTATUS
  51. DriverEntry(
  52. IN PDRIVER_OBJECT DriverObject,
  53. IN PUNICODE_STRING RegistryPath
  54. )
  55. {
  56. return STATUS_SUCCESS;
  57. }
  58. #endif
  59. NTSTATUS
  60. SmartcardCreateLink(
  61. IN OUT PUNICODE_STRING LinkName,
  62. IN PUNICODE_STRING DeviceName
  63. )
  64. /*++
  65. Routine Description:
  66. This routine creates a symbolic link name for the given device name.
  67. NOTE: The buffer for the link name will be allocated here. The caller
  68. is responsible for freeing the buffer.
  69. If the function fails no buffer is allocated.
  70. Arguments:
  71. LinkName - receives the created link name
  72. DeviceName - the device name for which the link should be created
  73. Return Value:
  74. None
  75. --*/
  76. {
  77. NTSTATUS status;
  78. ULONG i;
  79. PWCHAR buffer;
  80. ASSERT(LinkName != NULL);
  81. ASSERT(DeviceName != NULL);
  82. if (LinkName == NULL) {
  83. return STATUS_INVALID_PARAMETER_1;
  84. }
  85. if (DeviceName == NULL) {
  86. return STATUS_INVALID_PARAMETER_2;
  87. }
  88. buffer = ExAllocatePool(
  89. NonPagedPool,
  90. 32 * sizeof(WCHAR)
  91. );
  92. ASSERT(buffer != NULL);
  93. if (buffer == NULL) {
  94. return STATUS_INSUFFICIENT_RESOURCES;
  95. }
  96. for (i = 0; i < MAXIMUM_SMARTCARD_READERS; i++) {
  97. StringCchPrintfW(buffer,
  98. 32,
  99. L"\\DosDevices\\SCReader%d", i);
  100. RtlInitUnicodeString(
  101. LinkName,
  102. buffer
  103. );
  104. status = IoCreateSymbolicLink(
  105. LinkName,
  106. DeviceName
  107. );
  108. if (NT_SUCCESS(status)) {
  109. SmartcardDebug(
  110. DEBUG_INFO,
  111. ("%s!SmartcardCreateLink: %ws linked to %ws\n",
  112. DRIVER_NAME,
  113. DeviceName->Buffer,
  114. LinkName->Buffer)
  115. );
  116. return status;
  117. }
  118. }
  119. ExFreePool(LinkName->Buffer);
  120. return status;
  121. }
  122. void
  123. SmartcardDeleteLink(
  124. IN PUNICODE_STRING LinkName
  125. )
  126. {
  127. //
  128. // Delete the symbolic link of the smart card reader
  129. //
  130. IoDeleteSymbolicLink(
  131. LinkName
  132. );
  133. //
  134. // Free allocated buffer
  135. //
  136. ExFreePool(
  137. LinkName->Buffer
  138. );
  139. }
  140. NTSTATUS
  141. SmartcardInitialize(
  142. IN PSMARTCARD_EXTENSION SmartcardExtension
  143. )
  144. /*++
  145. Routine Description:
  146. This function allocated the send and receive buffers for smart card
  147. data. It also sets the pointer to 2 ISO tables to make them accessible
  148. to the driver
  149. Arguments:
  150. SmartcardExtension
  151. Return Value:
  152. NTSTATUS
  153. --*/
  154. {
  155. NTSTATUS status = STATUS_SUCCESS;
  156. SmartcardDebug(
  157. DEBUG_INFO,
  158. ("%s!SmartcardInitialize: Enter. Version %lx, %s %s\n",
  159. DRIVER_NAME,
  160. SMCLIB_VERSION,
  161. __DATE__,
  162. __TIME__)
  163. );
  164. ASSERT(SmartcardExtension != NULL);
  165. ASSERT(SmartcardExtension->OsData == NULL);
  166. if (SmartcardExtension == NULL) {
  167. return STATUS_INVALID_PARAMETER_1;
  168. }
  169. if (SmartcardExtension->Version > SMCLIB_VERSION ||
  170. SmartcardExtension->Version < SMCLIB_VERSION_REQUIRED) {
  171. SmartcardDebug(
  172. DEBUG_ERROR,
  173. ("%s!SmartcardInitialize: Incompatible version in SMARTCARD_EXTENSION.\n",
  174. DRIVER_NAME)
  175. );
  176. return STATUS_UNSUCCESSFUL;
  177. }
  178. if (SmartcardExtension->SmartcardRequest.BufferSize < MIN_BUFFER_SIZE) {
  179. SmartcardDebug(
  180. DEBUG_ERROR,
  181. ("%s!SmartcardInitialize: WARNING: SmartcardRequest.BufferSize (%ld) < MIN_BUFFER_SIZE (%ld)\n",
  182. DRIVER_NAME,
  183. SmartcardExtension->SmartcardRequest.BufferSize,
  184. MIN_BUFFER_SIZE)
  185. );
  186. SmartcardExtension->SmartcardRequest.BufferSize = MIN_BUFFER_SIZE;
  187. }
  188. if (SmartcardExtension->SmartcardReply.BufferSize < MIN_BUFFER_SIZE) {
  189. SmartcardDebug(
  190. DEBUG_ERROR,
  191. ("%s!SmartcardInitialize: WARNING: SmartcardReply.BufferSize (%ld) < MIN_BUFFER_SIZE (%ld)\n",
  192. DRIVER_NAME,
  193. SmartcardExtension->SmartcardReply.BufferSize,
  194. MIN_BUFFER_SIZE)
  195. );
  196. SmartcardExtension->SmartcardReply.BufferSize = MIN_BUFFER_SIZE;
  197. }
  198. SmartcardExtension->SmartcardRequest.Buffer = ExAllocatePool(
  199. NonPagedPool,
  200. SmartcardExtension->SmartcardRequest.BufferSize
  201. );
  202. SmartcardExtension->SmartcardReply.Buffer = ExAllocatePool(
  203. NonPagedPool,
  204. SmartcardExtension->SmartcardReply.BufferSize
  205. );
  206. SmartcardExtension->OsData = ExAllocatePool(
  207. NonPagedPool,
  208. sizeof(OS_DEP_DATA)
  209. );
  210. #if defined(DEBUG) && defined(SMCLIB_NT)
  211. SmartcardExtension->PerfInfo = ExAllocatePool(
  212. NonPagedPool,
  213. sizeof(PERF_INFO)
  214. );
  215. #endif
  216. //
  217. // Check if one of the above allocations failed
  218. //
  219. if (SmartcardExtension->SmartcardRequest.Buffer == NULL ||
  220. SmartcardExtension->SmartcardReply.Buffer == NULL ||
  221. SmartcardExtension->OsData == NULL
  222. #if defined(DEBUG) && defined(SMCLIB_NT)
  223. || SmartcardExtension->PerfInfo == NULL
  224. #endif
  225. ) {
  226. status = STATUS_INSUFFICIENT_RESOURCES;
  227. if (SmartcardExtension->SmartcardRequest.Buffer) {
  228. ExFreePool(SmartcardExtension->SmartcardRequest.Buffer);
  229. }
  230. if (SmartcardExtension->SmartcardReply.Buffer) {
  231. ExFreePool(SmartcardExtension->SmartcardReply.Buffer);
  232. }
  233. if (SmartcardExtension->OsData) {
  234. ExFreePool(SmartcardExtension->OsData);
  235. }
  236. #if defined(DEBUG) && defined(SMCLIB_NT)
  237. if (SmartcardExtension->PerfInfo) {
  238. ExFreePool(SmartcardExtension->PerfInfo);
  239. }
  240. #endif
  241. }
  242. if (status != STATUS_SUCCESS) {
  243. return status;
  244. }
  245. RtlZeroMemory(
  246. SmartcardExtension->OsData,
  247. sizeof(OS_DEP_DATA)
  248. );
  249. #if defined(DEBUG) && defined(SMCLIB_NT)
  250. RtlZeroMemory(
  251. SmartcardExtension->PerfInfo,
  252. sizeof(PERF_INFO)
  253. );
  254. #endif
  255. // Initialize the mutex that is used to synch. access to the driver
  256. KeInitializeMutex(
  257. &(SmartcardExtension->OsData->Mutex),
  258. 0
  259. );
  260. KeInitializeSpinLock(
  261. &(SmartcardExtension->OsData->SpinLock)
  262. );
  263. // initialize the remove lock
  264. SmartcardExtension->OsData->RemoveLock.Removed = FALSE;
  265. SmartcardExtension->OsData->RemoveLock.RefCount = 1;
  266. KeInitializeEvent(
  267. &SmartcardExtension->OsData->RemoveLock.RemoveEvent,
  268. SynchronizationEvent,
  269. FALSE
  270. );
  271. InitializeListHead(&SmartcardExtension->OsData->RemoveLock.TagList);
  272. // Make the 2 ISO tables accessible to the driver
  273. SmartcardExtension->CardCapabilities.ClockRateConversion =
  274. &ClockRateConversion[0];
  275. SmartcardExtension->CardCapabilities.BitRateAdjustment =
  276. &BitRateAdjustment[0];
  277. #ifdef DEBUG_INTERFACE
  278. SmclibCreateDebugInterface(SmartcardExtension);
  279. #endif
  280. SmartcardDebug(
  281. DEBUG_TRACE,
  282. ("%s!SmartcardInitialize: Exit\n",
  283. DRIVER_NAME)
  284. );
  285. return status;
  286. }
  287. VOID
  288. SmartcardExit(
  289. IN PSMARTCARD_EXTENSION SmartcardExtension
  290. )
  291. /*++
  292. Routine Description:
  293. This routine frees the send and receive buffer.
  294. It is usually called when the driver unloads.
  295. Arguments:
  296. SmartcardExtension
  297. --*/
  298. {
  299. SmartcardDebug(
  300. DEBUG_TRACE,
  301. ("%s!SmartcardExit: Enter\n",
  302. DRIVER_NAME)
  303. );
  304. #ifdef DEBUG_INTERFACE
  305. SmclibDeleteDebugInterface(SmartcardExtension);
  306. #endif
  307. //
  308. // Free all allocated buffers
  309. //
  310. if (SmartcardExtension->SmartcardRequest.Buffer) {
  311. ExFreePool(SmartcardExtension->SmartcardRequest.Buffer);
  312. SmartcardExtension->SmartcardRequest.Buffer = NULL;
  313. }
  314. if (SmartcardExtension->SmartcardReply.Buffer) {
  315. ExFreePool(SmartcardExtension->SmartcardReply.Buffer);
  316. SmartcardExtension->SmartcardReply.Buffer = NULL;
  317. }
  318. if (SmartcardExtension->OsData) {
  319. ExFreePool(SmartcardExtension->OsData);
  320. SmartcardExtension->OsData = NULL;
  321. }
  322. #if defined(DEBUG) && defined(SMCLIB_NT)
  323. if (SmartcardExtension->PerfInfo) {
  324. ExFreePool(SmartcardExtension->PerfInfo);
  325. SmartcardExtension->OsData = NULL;
  326. }
  327. #endif
  328. if (SmartcardExtension->T1.ReplyData) {
  329. // free the reply data buffer for T=1 transmissions
  330. ExFreePool(SmartcardExtension->T1.ReplyData);
  331. SmartcardExtension->T1.ReplyData = NULL;
  332. }
  333. SmartcardDebug(
  334. DEBUG_INFO,
  335. ("%s!SmartcardExit: Exit - Device %.*s\n",
  336. DRIVER_NAME,
  337. SmartcardExtension->VendorAttr.VendorName.Length,
  338. SmartcardExtension->VendorAttr.VendorName.Buffer)
  339. );
  340. }
  341. NTSTATUS
  342. SmartcardAcquireRemoveLockWithTag(
  343. IN PSMARTCARD_EXTENSION SmartcardExtension,
  344. ULONG Tag
  345. )
  346. {
  347. NTSTATUS status = STATUS_SUCCESS;
  348. LONG refCount;
  349. #ifdef DEBUG
  350. PTAG_LIST_ENTRY tagListEntry;
  351. #endif
  352. refCount = InterlockedIncrement(
  353. &SmartcardExtension->OsData->RemoveLock.RefCount
  354. );
  355. ASSERT(refCount > 0);
  356. if (SmartcardExtension->OsData->RemoveLock.Removed == TRUE) {
  357. if (InterlockedDecrement (
  358. &SmartcardExtension->OsData->RemoveLock.RefCount
  359. ) == 0) {
  360. KeSetEvent(
  361. &SmartcardExtension->OsData->RemoveLock.RemoveEvent,
  362. 0,
  363. FALSE
  364. );
  365. }
  366. status = STATUS_DELETE_PENDING;
  367. }
  368. #ifdef DEBUG
  369. tagListEntry = (PTAG_LIST_ENTRY) ExAllocatePoolWithTag(
  370. NonPagedPool,
  371. sizeof(TAG_LIST_ENTRY),
  372. SMARTCARD_POOL_TAG
  373. );
  374. ASSERT(tagListEntry);
  375. if (tagListEntry == NULL) {
  376. return status;
  377. }
  378. tagListEntry->Tag = Tag;
  379. InsertHeadList(
  380. &SmartcardExtension->OsData->RemoveLock.TagList,
  381. &tagListEntry->List
  382. );
  383. #endif
  384. return status;
  385. }
  386. NTSTATUS
  387. SmartcardAcquireRemoveLock(
  388. IN PSMARTCARD_EXTENSION SmartcardExtension
  389. )
  390. {
  391. return SmartcardAcquireRemoveLockWithTag(
  392. SmartcardExtension,
  393. 0
  394. );
  395. }
  396. VOID
  397. SmartcardReleaseRemoveLockWithTag(
  398. IN PSMARTCARD_EXTENSION SmartcardExtension,
  399. IN ULONG Tag
  400. )
  401. {
  402. LONG refCount;
  403. #ifdef DEBUG
  404. PLIST_ENTRY entry;
  405. BOOLEAN tagFound = FALSE;
  406. #endif
  407. refCount = InterlockedDecrement(
  408. &SmartcardExtension->OsData->RemoveLock.RefCount
  409. );
  410. ASSERT(refCount >= 0);
  411. #ifdef DEBUG
  412. for (entry = SmartcardExtension->OsData->RemoveLock.TagList.Flink;
  413. entry->Flink != SmartcardExtension->OsData->RemoveLock.TagList.Flink;
  414. entry = entry->Flink) {
  415. PTAG_LIST_ENTRY tagListEntry = CONTAINING_RECORD(entry, TAG_LIST_ENTRY, List);
  416. if (Tag == tagListEntry->Tag) {
  417. tagFound = TRUE;
  418. RemoveEntryList(entry);
  419. ExFreePool(tagListEntry);
  420. break;
  421. }
  422. }
  423. ASSERTMSG("SmartcardReleaseRemoveLock() called with unknown tag", tagFound == TRUE);
  424. #endif
  425. if (refCount == 0) {
  426. ASSERT (SmartcardExtension->OsData->RemoveLock.Removed);
  427. //
  428. // The device needs to be removed. Signal the remove event
  429. // that it's safe to go ahead.
  430. //
  431. KeSetEvent(
  432. &SmartcardExtension->OsData->RemoveLock.RemoveEvent,
  433. IO_NO_INCREMENT,
  434. FALSE
  435. );
  436. }
  437. }
  438. VOID
  439. SmartcardReleaseRemoveLock(
  440. IN PSMARTCARD_EXTENSION SmartcardExtension
  441. )
  442. {
  443. SmartcardReleaseRemoveLockWithTag(SmartcardExtension, 0);
  444. }
  445. VOID
  446. SmartcardReleaseRemoveLockAndWait(
  447. IN PSMARTCARD_EXTENSION SmartcardExtension
  448. )
  449. {
  450. LONG refCount;
  451. PAGED_CODE ();
  452. ASSERT(SmartcardExtension->OsData->RemoveLock.Removed == FALSE);
  453. SmartcardExtension->OsData->RemoveLock.Removed = TRUE;
  454. refCount = InterlockedDecrement (
  455. &SmartcardExtension->OsData->RemoveLock.RefCount
  456. );
  457. ASSERT (refCount > 0);
  458. if (InterlockedDecrement (
  459. &SmartcardExtension->OsData->RemoveLock.RefCount
  460. ) > 0) {
  461. #ifdef DEBUG
  462. // walk the tag list and print all currently held locks
  463. PLIST_ENTRY entry;
  464. for (entry = SmartcardExtension->OsData->RemoveLock.TagList.Flink;
  465. entry->Flink != SmartcardExtension->OsData->RemoveLock.TagList.Flink;
  466. entry = entry->Flink) {
  467. PTAG_LIST_ENTRY tagListEntry = CONTAINING_RECORD(entry, TAG_LIST_ENTRY, List);
  468. SmartcardDebug(
  469. DEBUG_ERROR,
  470. ("%s!SmartcardReleaseRemoveLockAndWait: Device %.*s holds lock '%.4s'\n",
  471. DRIVER_NAME,
  472. SmartcardExtension->VendorAttr.VendorName.Length,
  473. SmartcardExtension->VendorAttr.VendorName.Buffer,
  474. &(tagListEntry->Tag))
  475. );
  476. }
  477. #endif
  478. KeWaitForSingleObject (
  479. &SmartcardExtension->OsData->RemoveLock.RemoveEvent,
  480. Executive,
  481. KernelMode,
  482. FALSE,
  483. NULL
  484. );
  485. #ifdef DEBUG
  486. // free all locks.
  487. entry = SmartcardExtension->OsData->RemoveLock.TagList.Flink;
  488. while (entry->Flink !=
  489. SmartcardExtension->OsData->RemoveLock.TagList.Flink) {
  490. PTAG_LIST_ENTRY tagListEntry = CONTAINING_RECORD(entry, TAG_LIST_ENTRY, List);
  491. RemoveEntryList(entry);
  492. ExFreePool(tagListEntry);
  493. entry = SmartcardExtension->OsData->RemoveLock.TagList.Flink;
  494. }
  495. #endif
  496. }
  497. SmartcardDebug(
  498. DEBUG_INFO,
  499. ("%s!SmartcardReleaseRemoveLockAndWait: Exit - Device %.*s\n",
  500. DRIVER_NAME,
  501. SmartcardExtension->VendorAttr.VendorName.Length,
  502. SmartcardExtension->VendorAttr.VendorName.Buffer)
  503. );
  504. }
  505. VOID
  506. SmartcardLogError(
  507. IN PVOID Object,
  508. IN NTSTATUS ErrorCode,
  509. IN PUNICODE_STRING Insertion,
  510. IN ULONG DumpData
  511. )
  512. /*++
  513. Routine Description:
  514. This routine allocates an error log entry, copies the supplied data
  515. to it, and requests that it be written to the error log file.
  516. Arguments:
  517. DeviceObject - Supplies a pointer to the device object associated
  518. with the device that had the error, early in
  519. initialization, one may not yet exist.
  520. Insertion - An insertion string that can be used to log
  521. additional data. Note that the message file
  522. needs %2 for this insertion, since %1
  523. is the name of the driver
  524. ErrorCode - Supplies the IO status for this particular error.
  525. DumpData - One word to dump
  526. Return Value:
  527. None.
  528. --*/
  529. {
  530. PIO_ERROR_LOG_PACKET errorLogEntry;
  531. errorLogEntry = IoAllocateErrorLogEntry(
  532. Object,
  533. (UCHAR) (
  534. sizeof(IO_ERROR_LOG_PACKET) +
  535. (Insertion ? Insertion->Length + sizeof(WCHAR) : 0)
  536. )
  537. );
  538. ASSERT(errorLogEntry != NULL);
  539. if (errorLogEntry == NULL) {
  540. return;
  541. }
  542. errorLogEntry->ErrorCode = ErrorCode;
  543. errorLogEntry->SequenceNumber = 0;
  544. errorLogEntry->MajorFunctionCode = 0;
  545. errorLogEntry->RetryCount = 0;
  546. errorLogEntry->UniqueErrorValue = 0;
  547. errorLogEntry->FinalStatus = STATUS_SUCCESS;
  548. errorLogEntry->DumpDataSize = (DumpData ? sizeof(ULONG) : 0);
  549. errorLogEntry->DumpData[0] = DumpData;
  550. if (Insertion) {
  551. errorLogEntry->StringOffset =
  552. sizeof(IO_ERROR_LOG_PACKET);
  553. errorLogEntry->NumberOfStrings = 1;
  554. RtlCopyMemory(
  555. ((PCHAR)(errorLogEntry) + errorLogEntry->StringOffset),
  556. Insertion->Buffer,
  557. Insertion->Length
  558. );
  559. }
  560. IoWriteErrorLogEntry(errorLogEntry);
  561. }
  562. NTSTATUS
  563. SmartcardDeviceControl(
  564. PSMARTCARD_EXTENSION SmartcardExtension,
  565. PIRP Irp
  566. )
  567. /*++
  568. Routine Description:
  569. The routine is the general device control dispatch function.
  570. Arguments:
  571. SmartcardExtension - The pointer to the smart card datae
  572. Irp - Supplies the Irp making the request.
  573. Return Value:
  574. NTSTATUS
  575. --*/
  576. {
  577. PIO_STACK_LOCATION ioStackLocation = IoGetCurrentIrpStackLocation(Irp);
  578. NTSTATUS status = STATUS_SUCCESS;
  579. BOOLEAN ClearCurrentIrp = TRUE;
  580. UNICODE_STRING Message;
  581. static BOOLEAN logged = FALSE;
  582. ULONG ioControlCode = ioStackLocation->Parameters.DeviceIoControl.IoControlCode;
  583. // Check the pointer to the smart card extension
  584. ASSERT(SmartcardExtension != NULL);
  585. if (SmartcardExtension == NULL) {
  586. status = STATUS_INVALID_PARAMETER_1;
  587. Irp->IoStatus.Status = status;
  588. IoCompleteRequest(
  589. Irp,
  590. IO_NO_INCREMENT
  591. );
  592. return status;
  593. }
  594. // Check the version that the driver requires
  595. ASSERT(SmartcardExtension->Version >= SMCLIB_VERSION_REQUIRED);
  596. if (SmartcardExtension->Version < SMCLIB_VERSION_REQUIRED) {
  597. status = STATUS_INVALID_PARAMETER;
  598. Irp->IoStatus.Status = status;
  599. IoCompleteRequest(
  600. Irp,
  601. IO_NO_INCREMENT
  602. );
  603. return status;
  604. }
  605. //
  606. // Check the OsData pointer. This can be NULL if SmartcardInit
  607. // has not been called or SmartcardExit has already been called
  608. //
  609. ASSERT(SmartcardExtension->OsData != NULL);
  610. // Check that the driver has set the DeviceObject
  611. ASSERT(SmartcardExtension->OsData->DeviceObject != NULL);
  612. if (SmartcardExtension->OsData == NULL ||
  613. SmartcardExtension->OsData->DeviceObject == NULL) {
  614. status = STATUS_INVALID_PARAMETER;
  615. Irp->IoStatus.Status = status;
  616. IoCompleteRequest(
  617. Irp,
  618. IO_NO_INCREMENT
  619. );
  620. return status;
  621. }
  622. // We must run at passive level otherwise IoCompleteRequest won't work properly
  623. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  624. // check that no one wants us to do unbuffered io
  625. if (ioControlCode & (METHOD_IN_DIRECT | METHOD_OUT_DIRECT)) {
  626. status = STATUS_INVALID_PARAMETER;
  627. Irp->IoStatus.Status = status;
  628. IoCompleteRequest(
  629. Irp,
  630. IO_NO_INCREMENT
  631. );
  632. return status;
  633. }
  634. //
  635. // This resource acts as a mutex. We can't use a 'real' mutex here,
  636. // since a mutex rises the Irql to APC_LEVEL. This leads to some
  637. // side effects we don't want.
  638. // E.g. IoCompleteRequest() will not copy requested data at APC_LEVEL
  639. //
  640. KeWaitForMutexObject(
  641. &(SmartcardExtension->OsData->Mutex),
  642. UserRequest,
  643. KernelMode,
  644. FALSE,
  645. NULL
  646. );
  647. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  648. #ifdef developerversion
  649. #if DEBUG
  650. if(!logged) {
  651. RtlInitUnicodeString(
  652. &Message,
  653. L"Developer version of smclib.sys installed"
  654. );
  655. SmartcardLogError(
  656. SmartcardExtension->OsData->DeviceObject,
  657. STATUS_LICENSE_VIOLATION,
  658. &Message,
  659. 0
  660. );
  661. logged = TRUE;
  662. }
  663. #endif
  664. #endif
  665. SmartcardDebug(
  666. DEBUG_IOCTL,
  667. ("SMCLIB!SmartcardDeviceControl: Enter <%.*s:%1d>, IOCTL = %s, IRP = %lx\n",
  668. SmartcardExtension->VendorAttr.VendorName.Length,
  669. SmartcardExtension->VendorAttr.VendorName.Buffer,
  670. SmartcardExtension->VendorAttr.UnitNo,
  671. MapIoControlCodeToString(ioControlCode),
  672. Irp)
  673. );
  674. // Return if device is busy
  675. if (InterlockedCompareExchangePointer(&SmartcardExtension->OsData->CurrentIrp,
  676. Irp,
  677. NULL)) {
  678. SmartcardDebug(
  679. DEBUG_ERROR,
  680. ("%s!SmartcardDeviceControl: Device %.*s is busy\n",
  681. DRIVER_NAME,
  682. SmartcardExtension->VendorAttr.VendorName.Length,
  683. SmartcardExtension->VendorAttr.VendorName.Buffer)
  684. );
  685. // This flag is used to signal that we can't set the current irp to NULL
  686. ClearCurrentIrp = FALSE;
  687. status = STATUS_DEVICE_BUSY;
  688. }
  689. if (status == STATUS_SUCCESS) {
  690. PIRP notificationIrp;
  691. ULONG currentState;
  692. KIRQL irql;
  693. switch (ioControlCode) {
  694. //
  695. // We have to check for _IS_ABSENT and _IS_PRESENT first,
  696. // since these are (the only allowed) asynchronous requests
  697. //
  698. case IOCTL_SMARTCARD_IS_ABSENT:
  699. ClearCurrentIrp = FALSE;
  700. InterlockedExchangePointer(&SmartcardExtension->OsData->CurrentIrp,
  701. NULL);
  702. if (SmartcardExtension->ReaderFunction[RDF_CARD_TRACKING] == NULL) {
  703. status = STATUS_NOT_SUPPORTED;
  704. break;
  705. }
  706. AccessUnsafeData(&irql);
  707. currentState = SmartcardExtension->ReaderCapabilities.CurrentState;
  708. // Now check if the driver is already processing a notification irp
  709. if (SmartcardExtension->OsData->NotificationIrp != NULL) {
  710. status = STATUS_DEVICE_BUSY;
  711. EndAccessUnsafeData(irql);
  712. break;
  713. }
  714. //
  715. // if the current state is not known, it doesn't make sense
  716. // to process this call
  717. //
  718. if (currentState == SCARD_UNKNOWN) {
  719. status = STATUS_INVALID_DEVICE_STATE;
  720. EndAccessUnsafeData(irql);
  721. break;
  722. }
  723. //
  724. // If the card is already (or still) absent, we can return immediatly.
  725. // Otherwise we must statrt event tracking.
  726. //
  727. if (currentState > SCARD_ABSENT) {
  728. SmartcardExtension->OsData->NotificationIrp = Irp;
  729. SmartcardExtension->MajorIoControlCode =
  730. IOCTL_SMARTCARD_IS_ABSENT;
  731. EndAccessUnsafeData(irql);
  732. status = SmartcardExtension->ReaderFunction[RDF_CARD_TRACKING](
  733. SmartcardExtension
  734. );
  735. } else {
  736. EndAccessUnsafeData(irql);
  737. }
  738. break;
  739. case IOCTL_SMARTCARD_IS_PRESENT:
  740. ClearCurrentIrp = FALSE;
  741. InterlockedExchangePointer(&SmartcardExtension->OsData->CurrentIrp,
  742. NULL);
  743. if (SmartcardExtension->ReaderFunction[RDF_CARD_TRACKING] == NULL) {
  744. status = STATUS_NOT_SUPPORTED;
  745. break;
  746. }
  747. AccessUnsafeData(&irql);
  748. currentState = SmartcardExtension->ReaderCapabilities.CurrentState;
  749. // Now check if the driver is already processing a notification irp
  750. if (SmartcardExtension->OsData->NotificationIrp != NULL) {
  751. status = STATUS_DEVICE_BUSY;
  752. EndAccessUnsafeData(irql);
  753. break;
  754. }
  755. //
  756. // if the current state is not known, it doesn't make sense
  757. // to process this call
  758. //
  759. if (currentState == SCARD_UNKNOWN) {
  760. status = STATUS_INVALID_DEVICE_STATE;
  761. EndAccessUnsafeData(irql);
  762. break;
  763. }
  764. //
  765. // If the card is already (or still) present, we can return immediatly.
  766. // Otherwise we must statrt event tracking.
  767. //
  768. if (currentState <= SCARD_ABSENT) {
  769. #if defined(DEBUG) && defined(SMCLIB_NT)
  770. ULONG timeInMilliSec = (ULONG)
  771. SmartcardExtension->PerfInfo->IoTickCount.QuadPart *
  772. KeQueryTimeIncrement() /
  773. 10000;
  774. ULONG bytesTransferred =
  775. SmartcardExtension->PerfInfo->BytesSent +
  776. SmartcardExtension->PerfInfo->BytesReceived;
  777. // to avoid div. errors and to display only useful information
  778. // we check for a valid time.
  779. if (timeInMilliSec > 0) {
  780. SmartcardDebug(
  781. DEBUG_PERF,
  782. ("%s!SmartcardDeviceControl: I/O statistics for device %.*s:\n Transferrate: %5ld bps\n Total bytes: %5ld\n I/O time: %5ld ms\n Transmissions: %5ld\n",
  783. DRIVER_NAME,
  784. SmartcardExtension->VendorAttr.VendorName.Length,
  785. SmartcardExtension->VendorAttr.VendorName.Buffer,
  786. bytesTransferred * 1000 / timeInMilliSec,
  787. bytesTransferred,
  788. timeInMilliSec,
  789. SmartcardExtension->PerfInfo->NumTransmissions)
  790. );
  791. }
  792. // reset performance info
  793. RtlZeroMemory(
  794. SmartcardExtension->PerfInfo,
  795. sizeof(PERF_INFO)
  796. );
  797. #endif
  798. SmartcardExtension->OsData->NotificationIrp = Irp;
  799. SmartcardExtension->MajorIoControlCode =
  800. IOCTL_SMARTCARD_IS_PRESENT;
  801. EndAccessUnsafeData(irql);
  802. status = SmartcardExtension->ReaderFunction[RDF_CARD_TRACKING](
  803. SmartcardExtension
  804. );
  805. } else {
  806. EndAccessUnsafeData(irql);
  807. }
  808. break;
  809. default:
  810. // Get major io control code
  811. SmartcardExtension->MajorIoControlCode = ioControlCode;
  812. // Check if buffers are properly allocated
  813. ASSERT(SmartcardExtension->SmartcardRequest.Buffer);
  814. ASSERT(SmartcardExtension->SmartcardReply.Buffer);
  815. if (Irp->AssociatedIrp.SystemBuffer &&
  816. ioStackLocation->Parameters.DeviceIoControl.InputBufferLength >=
  817. sizeof(ULONG)) {
  818. //
  819. // Transfer minor io control code, even if it doesn't make sense for
  820. // this particular major code
  821. //
  822. SmartcardExtension->MinorIoControlCode =
  823. *(PULONG) (Irp->AssociatedIrp.SystemBuffer);
  824. }
  825. // Save pointer to and length of request buffer
  826. SmartcardExtension->IoRequest.RequestBuffer =
  827. Irp->AssociatedIrp.SystemBuffer;
  828. SmartcardExtension->IoRequest.RequestBufferLength =
  829. ioStackLocation->Parameters.DeviceIoControl.InputBufferLength,
  830. // Save pointer to and length of reply buffer
  831. SmartcardExtension->IoRequest.ReplyBuffer =
  832. Irp->AssociatedIrp.SystemBuffer;
  833. SmartcardExtension->IoRequest.ReplyBufferLength =
  834. ioStackLocation->Parameters.DeviceIoControl.OutputBufferLength;
  835. //
  836. // Pointer to variable that receives the actual number
  837. // of bytes returned
  838. //
  839. SmartcardExtension->IoRequest.Information =
  840. (PULONG) &Irp->IoStatus.Information;
  841. // Default number of bytes returned
  842. Irp->IoStatus.Information = 0;
  843. // Process the device io-control-request
  844. status = SmartcardDeviceIoControl(SmartcardExtension);
  845. if (status == STATUS_PENDING) {
  846. IoMarkIrpPending(Irp);
  847. }
  848. #ifndef NO_LOG
  849. if (!NT_SUCCESS(status) && status != STATUS_NOT_SUPPORTED) {
  850. UNICODE_STRING error;
  851. WCHAR buffer[128];
  852. swprintf(
  853. buffer,
  854. L"IOCTL %S failed with status 0x%lx",
  855. MapIoControlCodeToString(ioControlCode),
  856. status
  857. );
  858. RtlInitUnicodeString(
  859. &error,
  860. buffer
  861. );
  862. SmartcardLogError(
  863. SmartcardExtension->OsData->DeviceObject,
  864. 0,
  865. &error,
  866. 0
  867. );
  868. }
  869. #endif
  870. break;
  871. }
  872. }
  873. if (status == STATUS_PENDING) {
  874. KIRQL irql;
  875. BOOLEAN pending = FALSE;
  876. //
  877. // Send command to smartcard. The ISR receives the result and queues a dpc function
  878. // that handles the completion of the call;
  879. //
  880. SmartcardDebug(
  881. DEBUG_IOCTL,
  882. ("%s!SmartcardDeviceControl: IoMarkIrpPending. IRP = %x\n",
  883. DRIVER_NAME,
  884. Irp)
  885. );
  886. //
  887. // When the driver completes an Irp (Notification or Current) it has
  888. // to set either the Irp back to 0 in order to show that it completed
  889. // the Irp.
  890. //
  891. AccessUnsafeData(&irql);
  892. if (Irp == SmartcardExtension->OsData->NotificationIrp ||
  893. Irp == SmartcardExtension->OsData->CurrentIrp) {
  894. pending = TRUE;
  895. }
  896. EndAccessUnsafeData(irql);
  897. if (pending &&
  898. SmartcardExtension->OsData->DeviceObject->DriverObject->DriverStartIo) {
  899. SmartcardDebug(
  900. DEBUG_IOCTL,
  901. ("%s!SmartcardDeviceControl: IoStartPacket. IRP = %x\n",
  902. DRIVER_NAME,
  903. Irp)
  904. );
  905. // Start io-processing of a lowest level driver
  906. IoStartPacket(
  907. SmartcardExtension->OsData->DeviceObject,
  908. Irp,
  909. NULL,
  910. NULL
  911. );
  912. }
  913. } else {
  914. SmartcardDebug(
  915. DEBUG_IOCTL,
  916. ("%s!SmartcardDeviceControl: IoCompleteRequest. IRP = %x (%lxh)\n",
  917. DRIVER_NAME,
  918. Irp,
  919. status)
  920. );
  921. Irp->IoStatus.Status = status;
  922. IoCompleteRequest(
  923. Irp,
  924. IO_NO_INCREMENT
  925. );
  926. if (ClearCurrentIrp) {
  927. //
  928. // If the devcie is not busy, we can set the current irp back to NULL
  929. //
  930. InterlockedExchangePointer(&SmartcardExtension->OsData->CurrentIrp,
  931. NULL);
  932. RtlZeroMemory(
  933. &(SmartcardExtension->IoRequest),
  934. sizeof(SmartcardExtension->IoRequest)
  935. );
  936. }
  937. }
  938. SmartcardDebug(
  939. (NT_SUCCESS(status) ? DEBUG_IOCTL : DEBUG_ERROR),
  940. ("SMCLIB!SmartcardDeviceControl: Exit. IOCTL = %s, IRP = %x (%lxh)\n",
  941. MapIoControlCodeToString(ioControlCode),
  942. Irp,
  943. status)
  944. );
  945. //
  946. // Release our 'mutex'
  947. //
  948. KeReleaseMutex(
  949. &(SmartcardExtension->OsData->Mutex),
  950. FALSE
  951. );
  952. return status;
  953. }