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

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