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.

530 lines
16 KiB

  1. // @doc
  2. /**********************************************************************
  3. *
  4. * @module CTRL_Ioctl.c |
  5. *
  6. * Implements basic IOCTL entry points and their handler functions
  7. * for control device objects.
  8. *
  9. * History
  10. * ----------------------------------------------------------
  11. * Mitchell S. Dernis Original
  12. *
  13. * (c) 1986-1998 Microsoft Corporation. All right reserved.
  14. *
  15. * @topic CTRL_Ioctl |
  16. * Any IOCTL call to the Control Device Object gets
  17. * filtered through here.
  18. *
  19. **********************************************************************/
  20. #define __DEBUG_MODULE_IN_USE__ GCK_CTRL_IOCTL_C
  21. #include <WDM.H>
  22. #include <basetyps.h>
  23. #include <initguid.h>
  24. #include "GckShell.h"
  25. #include "debug.h"
  26. DECLARE_MODULE_DEBUG_LEVEL((DBG_WARN|DBG_ERROR|DBG_CRITICAL));
  27. //---------------------------------------------------------------------------
  28. // Alloc_text pragma to specify routines that can be paged out.
  29. //---------------------------------------------------------------------------
  30. #ifdef ALLOC_PRAGMA
  31. #pragma alloc_text (PAGE, GCK_CTRL_Ioctl)
  32. #pragma alloc_text (PAGE, GCK_FindDeviceObject)
  33. #pragma alloc_text (PAGE, GCK_FindDeviceObject)
  34. #endif
  35. /***********************************************************************************
  36. **
  37. ** NTSTATUS GCK_CTRL_Ioctl (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
  38. **
  39. ** @mfunc Handles all IOCTL's to the control object
  40. **
  41. ** @rdesc STATUS_SUCCESS, or various errors
  42. **
  43. *************************************************************************************/
  44. NTSTATUS GCK_CTRL_Ioctl
  45. (
  46. IN PDEVICE_OBJECT pDeviceObject, // @parm pointer to Device Object
  47. IN PIRP pIrp // @parm pointer to IRP
  48. )
  49. {
  50. NTSTATUS NtStatus = STATUS_SUCCESS;
  51. PGCK_CONTROL_EXT pControlExt;
  52. PIO_STACK_LOCATION pIrpStack;
  53. PVOID pvIoBuffer;
  54. ULONG uInLength;
  55. ULONG uOutLength;
  56. ULONG uIoctl;
  57. PDEVICE_OBJECT pFilterHandle;
  58. PULONG puHandle;
  59. PGCK_FILTER_EXT pFilterExt;
  60. PDEVICE_OBJECT pCurDeviceObject;
  61. BOOLEAN bCompleteRequest = TRUE;
  62. PAGED_CODE ();
  63. GCK_DBG_ENTRY_PRINT(("Entering GCK_CTRL_Ioctl, pDeviceObject = 0x%0.8x, pIRP = 0x%0.8x\n", pDeviceObject, pIrp));
  64. //
  65. // Get all the inputs we need
  66. //
  67. pControlExt = (PGCK_CONTROL_EXT) pDeviceObject->DeviceExtension;
  68. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  69. uIoctl = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
  70. pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  71. uInLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
  72. uOutLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  73. //
  74. // Assume we will succeed with no data, we will change if necessary
  75. // later
  76. //
  77. pIrp->IoStatus.Status = STATUS_SUCCESS;
  78. pIrp->IoStatus.Information = 0;
  79. if(IOCTL_GCK_GET_HANDLE == uIoctl)
  80. {
  81. //
  82. // Check buffer size
  83. //
  84. if( uOutLength < sizeof(PVOID) )
  85. {
  86. pIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  87. NtStatus = STATUS_BUFFER_TOO_SMALL;
  88. goto complete_and_return;
  89. }
  90. //
  91. // Get handle (device extension) of requested device
  92. //
  93. pFilterHandle = GCK_FindDeviceObject( (LPWSTR)pvIoBuffer, uInLength );
  94. //
  95. // If we couldn't find the handle,
  96. // it must have been a bad path,
  97. // so return invalid parameter
  98. //
  99. if( NULL == pFilterHandle)
  100. {
  101. pIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  102. NtStatus = STATUS_INVALID_PARAMETER;
  103. goto complete_and_return;
  104. }
  105. //
  106. // copy handle into user buffer
  107. //
  108. puHandle = (ULONG *)pvIoBuffer;
  109. *puHandle = (ULONG)pFilterHandle;
  110. GCK_DBG_TRACE_PRINT(("Returning 0x%0.8x as handle.\n", *puHandle));
  111. pIrp->IoStatus.Information = sizeof(ULONG);
  112. GCKF_ResetKeyboardQueue(pFilterHandle);
  113. goto complete_and_return;
  114. }
  115. //DEBUG only IOCTL to allow changing debug level
  116. #if (DBG==1)
  117. if(IOCTL_GCK_SET_MODULE_DBG_LEVEL == uIoctl)
  118. {
  119. ASSERT(uInLength >= sizeof(ULONG)*2);
  120. //Reusing the name handle which is a misnomer
  121. puHandle = (ULONG *)pvIoBuffer;
  122. //first parameter is the module ID, the second is the flags
  123. SetDebugLevel(puHandle[0], puHandle[1]);
  124. goto complete_and_return;
  125. }
  126. #endif
  127. //
  128. // If the call is not IOCTL_GCK_GET_HANDLE, we expect the first byte to be the handle
  129. //
  130. //
  131. // Check that the inlength is at least large enough
  132. // for a handle PGCK_FILTER_EXT.
  133. //
  134. if( uInLength < sizeof(PGCK_FILTER_EXT) )
  135. {
  136. pIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  137. NtStatus = STATUS_INVALID_PARAMETER;
  138. goto complete_and_return;
  139. }
  140. //
  141. // Get the extension, and the DeviceObject itself
  142. //
  143. pFilterHandle = *((PDEVICE_OBJECT *)pvIoBuffer);
  144. GCK_DBG_TRACE_PRINT(("Filter Handle = 0x%0.8x\n", pFilterHandle));
  145. //
  146. // Make sure the device object is in our linked list
  147. // *** Do not dereference it, until we know it is in the list ***
  148. // *** If it is not in the list it may be garbage ***
  149. pCurDeviceObject = Globals.pFilterObjectList;
  150. while ( pCurDeviceObject )
  151. {
  152. if( pCurDeviceObject == pFilterHandle ) break;
  153. pCurDeviceObject = NEXT_FILTER_DEVICE_OBJECT(pCurDeviceObject);
  154. }
  155. if(!pCurDeviceObject)
  156. {
  157. GCK_DBG_ERROR_PRINT(("Filter Handle, 0x%0.8x, is not valid\n", pFilterHandle));
  158. pIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  159. NtStatus = STATUS_INVALID_PARAMETER;
  160. goto complete_and_return;
  161. }
  162. //
  163. // Get the device extension
  164. //
  165. pFilterExt = pFilterHandle->DeviceExtension;
  166. ASSERT(GCK_DO_TYPE_FILTER == pFilterExt->ulGckDevObjType);
  167. if(
  168. GCK_STATE_STARTED != pFilterExt->eDeviceState &&
  169. GCK_STATE_STOP_PENDING != pFilterExt->eDeviceState
  170. )
  171. {
  172. GCK_DBG_ERROR_PRINT(("Device is stopped or removed or \n"));
  173. pIrp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
  174. NtStatus = STATUS_DEVICE_NOT_CONNECTED; //Causes ERROR_NOT_READY at Win32 level
  175. goto complete_and_return;
  176. }
  177. //
  178. // Determine which IOCTL and handle it
  179. //
  180. switch(uIoctl)
  181. {
  182. case IOCTL_GCK_SEND_COMMAND:
  183. NtStatus = GCKF_ProcessCommands
  184. (
  185. pFilterExt,
  186. ((PCHAR)pvIoBuffer) + sizeof(PDEVICE_OBJECT), //skip the handle
  187. uInLength-sizeof(PDEVICE_OBJECT),
  188. TRUE
  189. );
  190. pIrp->IoStatus.Status = NtStatus;
  191. break;
  192. case IOCTL_GCK_SET_INTERNAL_POLLING:
  193. {
  194. if( uInLength < sizeof(GCK_SET_INTERNAL_POLLING_DATA) )
  195. {
  196. NtStatus = STATUS_BUFFER_TOO_SMALL;
  197. }
  198. else
  199. {
  200. GCK_IP_FullTimePoll(pFilterExt, ((PGCK_SET_INTERNAL_POLLING_DATA)pvIoBuffer)->fEnable);
  201. }
  202. break;
  203. }
  204. case IOCTL_GCK_ENABLE_TEST_KEYBOARD:
  205. {
  206. if( uInLength < sizeof(GCK_ENABLE_TEST_KEYBOARD) )
  207. {
  208. NtStatus = STATUS_BUFFER_TOO_SMALL;
  209. }
  210. else
  211. {
  212. NtStatus = GCKF_EnableTestKeyboard(pFilterExt, ((PGCK_ENABLE_TEST_KEYBOARD)pvIoBuffer)->fEnable, pIrpStack->FileObject);
  213. }
  214. break;
  215. }
  216. case IOCTL_GCK_BEGIN_TEST_SCHEME:
  217. NtStatus = GCKF_BeginTestScheme
  218. (
  219. pFilterExt,
  220. ((PCHAR)pvIoBuffer) + sizeof(PDEVICE_OBJECT), //skip the handle
  221. uInLength-sizeof(PDEVICE_OBJECT),
  222. pIrpStack->FileObject
  223. );
  224. ASSERT(NT_SUCCESS(NtStatus));
  225. break;
  226. case IOCTL_GCK_UPDATE_TEST_SCHEME:
  227. NtStatus = GCKF_UpdateTestScheme
  228. (
  229. pFilterExt,
  230. ((PCHAR)pvIoBuffer) + sizeof(PDEVICE_OBJECT), //skip the handle
  231. uInLength-sizeof(PDEVICE_OBJECT),
  232. pIrpStack->FileObject
  233. );
  234. ASSERT(NT_SUCCESS(NtStatus));
  235. break;
  236. case IOCTL_GCK_END_TEST_SCHEME:
  237. NtStatus = GCKF_EndTestScheme(pFilterExt, pIrpStack->FileObject);
  238. ASSERT(NT_SUCCESS(NtStatus));
  239. break;
  240. case IOCTL_GCK_BACKDOOR_POLL:
  241. if( uInLength < sizeof(GCK_BACKDOOR_POLL_DATA) )
  242. {
  243. NtStatus = STATUS_BUFFER_TOO_SMALL;
  244. }
  245. else
  246. {
  247. //Polling is asynchronous and the filter will deal with that,
  248. //It is extremely important that we just return the status returned by the backdoor poll routine,
  249. //and not complete the IRP
  250. NtStatus = GCKF_BackdoorPoll(pFilterExt, pIrp, ((PGCK_BACKDOOR_POLL_DATA)pvIoBuffer)->ePollingMode);
  251. //Make sure a poll is pending to the actual hardware
  252. GCK_IP_OneTimePoll(pFilterExt);
  253. ASSERT(NT_SUCCESS(NtStatus));
  254. return NtStatus;
  255. }
  256. break;
  257. case IOCTL_GCK_NOTIFY_FF_SCHEME_CHANGE: // Queue up IOCTL
  258. NtStatus = GCKF_IncomingForceFeedbackChangeNotificationRequest(pFilterExt, pIrp);
  259. if (!NT_SUCCESS(NtStatus))
  260. { // Failed, IOCTL is completed below
  261. pIrp->IoStatus.Status = NtStatus;
  262. }
  263. else
  264. { // Success, IOCTL was queued - don't complete
  265. bCompleteRequest = FALSE;
  266. }
  267. break;
  268. case IOCTL_GCK_END_FF_NOTIFICATION: // Complete the Queued FF Ioctls
  269. NtStatus = pIrp->IoStatus.Status = GCKF_ProcessForceFeedbackChangeNotificationRequests(pFilterExt);
  270. break;
  271. case IOCTL_GCK_GET_FF_SCHEME_DATA:
  272. NtStatus = GCKF_GetForceFeedbackData(pIrp, pFilterExt);
  273. break;
  274. case IOCTL_GCK_SET_WORKINGSET:
  275. NtStatus = GCKF_SetWorkingSet(pFilterExt, ((GCK_SET_WORKINGSET*)pvIoBuffer)->ucWorkingSet);
  276. break;
  277. case IOCTL_GCK_QUERY_PROFILESET:
  278. NtStatus = GCKF_QueryProfileSet(pIrp, pFilterExt);
  279. break;
  280. case IOCTL_GCK_LED_BEHAVIOUR:
  281. NtStatus = GCKF_SetLEDBehaviour(pIrp, pFilterExt);
  282. break;
  283. case IOCTL_GCK_TRIGGER:
  284. if ((uInLength < sizeof(GCK_TRIGGER_OUT)) || (uOutLength < sizeof(ULONG)))
  285. {
  286. NtStatus = pIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  287. }
  288. else
  289. {
  290. NtStatus = GCKF_TriggerRequest(pIrp, pFilterExt);
  291. if (!NT_SUCCESS(NtStatus))
  292. { // Failed, IOCTL is completed below
  293. pIrp->IoStatus.Status = NtStatus;
  294. }
  295. else
  296. { // Success, IOCTL was queued (or completed) - don't complete here
  297. bCompleteRequest = FALSE;
  298. }
  299. }
  300. break;
  301. case IOCTL_GCK_GET_CAPS:
  302. case IOCTL_GCK_ENABLE_DEVICE:
  303. default:
  304. pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  305. NtStatus = STATUS_NOT_SUPPORTED;
  306. GCK_DBG_WARN_PRINT( ("Unknown IOCTL: 0x%0.8x\n", uIoctl) );
  307. }
  308. complete_and_return:
  309. if (bCompleteRequest != FALSE)
  310. {
  311. // pIrp->IoStatus.Status = NtStatus; -- This might be nice investigate
  312. IoCompleteRequest (pIrp, IO_NO_INCREMENT);
  313. }
  314. GCK_DBG_EXIT_PRINT(("Exiting GCK_ControlIoctl(2), Status: 0x%0.8x\n", NtStatus));
  315. return NtStatus;
  316. }
  317. /***********************************************************************************
  318. **
  319. ** PDEVICE_OBJECT GCK_FindDeviceObject(IN PWSTR pwszInterfaceReq, IN ULONG uInLength)
  320. **
  321. ** @mfunc Given a Win32 HID interface finds the corresponding PDO among the filter devices
  322. **
  323. ** @rdesc pointer to the PDO on success, NULL if a match is not found
  324. **
  325. *************************************************************************************/
  326. PDEVICE_OBJECT GCK_FindDeviceObject
  327. (
  328. IN PWSTR pwszInterfaceReq, // @parm pointer to Win32 interface name
  329. IN ULONG uInLength // @parm length of interface string
  330. )
  331. {
  332. NTSTATUS NtStatus;
  333. PWSTR pInterfaces;
  334. ULONG uIndex;
  335. ULONG uStringLen;
  336. BOOLEAN fMatchFound;
  337. PDEVICE_OBJECT pCurDeviceObject;
  338. ULONG uInWideChars;
  339. PAGED_CODE();
  340. GCK_DBG_ENTRY_PRINT(("Entering GCK_FindDeviceObject, pwszInterfaceReq = %ws, uInLength = %d\n", pwszInterfaceReq, uInLength));
  341. //
  342. // Get length of string including NULL, but don't overrun uInLength
  343. //
  344. uIndex = 0;
  345. uStringLen = 0;
  346. uInWideChars = uInLength/2; // uInLength is the number of BYTES not WideChars
  347. while( uIndex < uInWideChars )
  348. {
  349. if( 0 == pwszInterfaceReq[uIndex++] )
  350. {
  351. uStringLen = uIndex;
  352. break;
  353. }
  354. }
  355. //
  356. // if the string is not terminated or if it is a NULL string, return NULL for the device.
  357. // plus every string starts with "\\.\" plus at least two or more chars
  358. //
  359. if( 6 > uStringLen ) return NULL;
  360. //
  361. // Walk through all known devices
  362. //
  363. pCurDeviceObject = Globals.pFilterObjectList;
  364. while ( pCurDeviceObject )
  365. {
  366. //
  367. // Get the interfaces for the PDO
  368. //
  369. NtStatus = IoGetDeviceInterfaces(
  370. (LPGUID)&GUID_CLASS_INPUT,
  371. FILTER_DEVICE_OBJECT_PDO(pCurDeviceObject),
  372. 0,
  373. &pInterfaces
  374. );
  375. //
  376. // If we have got the interfaces, then look for match
  377. //
  378. if( STATUS_SUCCESS == NtStatus )
  379. {
  380. fMatchFound=GCK_MatchReqPathtoInterfaces(pwszInterfaceReq, uStringLen, pInterfaces);
  381. ExFreePool(pInterfaces);
  382. if(fMatchFound)
  383. {
  384. GCK_DBG_EXIT_PRINT(("Exiting GCK_FindDeviceObject - match found returning 0x%0.8x\n", pCurDeviceObject));
  385. return pCurDeviceObject;
  386. }
  387. }
  388. //
  389. // Advance to next known device
  390. //
  391. pCurDeviceObject = NEXT_FILTER_DEVICE_OBJECT(pCurDeviceObject);
  392. }
  393. //
  394. // If we are here, there is no match
  395. //
  396. GCK_DBG_EXIT_PRINT(("Exiting GCK_FindDeviceObject - no match found returning NULL\n"));
  397. return NULL;
  398. }
  399. #define UPPERCASE(_x_) (((L'a'<=_x_) && (L'z'>=_x_)) ? ((_x_) - (L'a'-L'A')) : _x_)
  400. /***********************************************************************************
  401. **
  402. ** BOOLEAN GCK_MatchReqPathtoInterfaces(IN PWSTR pwszPath, IN ULONG uStringLen, IN PWSTR pmwszInterfaces)
  403. **
  404. ** @mfunc Determines if a Win32 Path matches any of the Interfaces. This replaces a match between
  405. ** String and a Multi-String. The previous was not sufficient (even though the caller tried
  406. ** to compensate.) The new algorithm is to find the last '\\' in each string before comparing
  407. ** them. It is still a string against any of a multi-string though.
  408. **
  409. ** @rdesc TRUE if a match is found, FALSE otherwise
  410. **
  411. *************************************************************************************/
  412. BOOLEAN GCK_MatchReqPathtoInterfaces
  413. (
  414. IN PWSTR pwszPath, // @parm String to find match
  415. IN ULONG uStringLen, // @parm length of string in WCHARs
  416. IN PWSTR pmwszInterfaces // @parm MutliString
  417. )
  418. {
  419. PWSTR pwszCurInterface;
  420. PWSTR pwszPathInterface;
  421. ULONG uCharIndex;
  422. ULONG uCurIntefaceLen;
  423. ULONG uDiff;
  424. GCK_DBG_ENTRY_PRINT(("Entering GCK_MatchReqPathtoInterfaces, pwszPath = \'%ws\'\n, uStringLen = %d, pmwszStrings = \'%ws\'", pwszPath, uStringLen, pmwszInterfaces));
  425. //
  426. // Find last '\\' in pwszPath and set pszPathInterface to the next character
  427. //
  428. pwszPathInterface = pwszPath;
  429. uCharIndex = 0;
  430. while( pwszPathInterface[uCharIndex] && (uCharIndex != uStringLen)) uCharIndex++; //go to end
  431. while( uCharIndex && (L'\\' != pwszPathInterface[uCharIndex]) ) uCharIndex--; //go to last '\\'
  432. ASSERT(uCharIndex < uStringLen);
  433. pwszPathInterface += uCharIndex+1; //skip last '\\'
  434. GCK_DBG_TRACE_PRINT(("Path to compare is %ws\n", pwszPathInterface));
  435. //
  436. // check if the szString matches any of the strings in mszStrings
  437. //
  438. pwszCurInterface = pmwszInterfaces;
  439. //
  440. // Loop over all strings in pmwszStrings
  441. //
  442. do
  443. {
  444. //Find last '\\'
  445. uCharIndex = 0;
  446. while( pwszCurInterface[uCharIndex]) uCharIndex++; //go to end
  447. uCurIntefaceLen = uCharIndex; //save string length
  448. while( uCharIndex && (L'\\' != pwszCurInterface[uCharIndex]) ) uCharIndex--; //go to last '\\'
  449. pwszCurInterface += uCharIndex+1;
  450. uCurIntefaceLen -= uCharIndex+1; //length after we skip some stuff
  451. GCK_DBG_TRACE_PRINT(("Comparing path with %ws\n", pwszCurInterface));
  452. //
  453. // look for differences in each string.
  454. //
  455. uCharIndex = 0;
  456. uDiff = 0;
  457. do
  458. {
  459. //
  460. // Check if characters match
  461. //
  462. if( UPPERCASE(pwszCurInterface[uCharIndex]) != UPPERCASE(pwszPathInterface[uCharIndex]) )
  463. {
  464. uDiff++; //increment number of differences
  465. break; //One difference is enough
  466. }
  467. } while( (pwszCurInterface[uCharIndex] != 0) && (pwszCurInterface[uCharIndex++] != '}') );
  468. //
  469. // Check for match
  470. //
  471. if( 0 == uDiff )
  472. {
  473. GCK_DBG_EXIT_PRINT(("Exiting GCK_MatchReqPathtoInterfaces - match found returning TRUE\n"));
  474. return TRUE;
  475. }
  476. //
  477. // move to the next string in list
  478. //
  479. pwszCurInterface += uCurIntefaceLen;
  480. } while(pwszCurInterface[0] != 0); //continue while there are more strings
  481. //
  482. // if we fell out we didn't find a match
  483. //
  484. GCK_DBG_EXIT_PRINT(("Exiting GCK_MatchReqPathtoInterfaces - no match found returning FALSE\n"));
  485. return FALSE;
  486. }