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.

452 lines
11 KiB

  1. #include "iopack.h"
  2. #include "kernel.h"
  3. #pragma LOCKEDCODE
  4. NTSTATUS onRequestComplete(PDEVICE_OBJECT pDO,IN PIRP Irp, IN PVOID context)
  5. {
  6. //DBG_PRINT(" ======= Request completion Irp %8.8lX, Packet %8.8lX\n",Irp,context);
  7. CIoPacket* packet = (CIoPacket*) context;
  8. if(packet)
  9. {
  10. return packet->onRequestComplete();
  11. }
  12. return STATUS_MORE_PROCESSING_REQUIRED;
  13. }
  14. #pragma PAGEDCODE
  15. CIoPacket::CIoPacket(UCHAR StackSize)
  16. {
  17. m_Status = STATUS_INSUFFICIENT_RESOURCES;
  18. systemIrp = FALSE;
  19. m_DoNotFreeIrp = FALSE;
  20. CompletionEvent = NULL;
  21. IoStatus.Status = STATUS_SUCCESS;
  22. IoStatus.Information = 0;
  23. SystemBuffer = NULL;
  24. m_Irp = NULL;
  25. m_TimeOut = 60000;// Default timeout 60 seconds for any kind of IORequest
  26. __try
  27. {
  28. debug = kernel->createDebug();
  29. memory = kernel->createMemory();
  30. event = kernel->createEvent();
  31. irp = kernel->createIrp();
  32. if( !ALLOCATED_OK(memory) || !ALLOCATED_OK(event) ||
  33. !ALLOCATED_OK(irp)) __leave;
  34. SystemBuffer = memory->allocate(NonPagedPool,PAGE_SIZE);
  35. if(!SystemBuffer) __leave;
  36. m_Irp = irp->allocate(StackSize+1, FALSE);
  37. if (!m_Irp) __leave;
  38. irp->initialize(m_Irp,irp->sizeOfIrp(StackSize+1),StackSize+1);
  39. Stack = *(irp->getNextStackLocation(m_Irp));
  40. irp->setCompletionRoutine(m_Irp,CALLBACK_FUNCTION(onRequestComplete),NULL,TRUE,TRUE,TRUE);
  41. m_Status = STATUS_SUCCESS;
  42. }
  43. __finally
  44. {
  45. if(!NT_SUCCESS(m_Status))
  46. {
  47. // Remove all allocated objects...
  48. // In this constructor we know that it is not system Irp...
  49. TRACE("FAILED TO CREATE IoPacket object %x\n",m_Status);
  50. TRACE("SystemBuffer - %x\n",SystemBuffer);
  51. TRACE("debug - %x, memory - %x\n",debug,memory);
  52. TRACE("event - %x, irp - %x\n",event,irp);
  53. if(ALLOCATED_OK(memory))
  54. {
  55. if(SystemBuffer) memory->free(SystemBuffer);
  56. SystemBuffer = NULL;
  57. }
  58. if(ALLOCATED_OK(irp))
  59. {
  60. if(m_Irp) irp->free(m_Irp);
  61. m_Irp = NULL;
  62. }
  63. DISPOSE_OBJECT(irp);
  64. DISPOSE_OBJECT(event);
  65. DISPOSE_OBJECT(memory);
  66. DISPOSE_OBJECT(debug);
  67. }
  68. }
  69. };
  70. CIoPacket::CIoPacket(PIRP Irp)
  71. {
  72. m_Status = STATUS_INSUFFICIENT_RESOURCES;
  73. systemIrp = TRUE;
  74. m_DoNotFreeIrp = FALSE;
  75. CompletionEvent = NULL;
  76. IoStatus.Status = STATUS_SUCCESS;
  77. IoStatus.Information = 0;
  78. SystemBuffer = NULL;
  79. m_TimeOut = 60000;// Default timeout 60 seconds for any kind of IORequest
  80. m_Irp = NULL;
  81. __try
  82. {
  83. if(!Irp) __leave;
  84. debug = kernel->createDebug();
  85. memory = kernel->createMemory();
  86. event = kernel->createEvent();
  87. irp = kernel->createIrp();
  88. if( !ALLOCATED_OK(memory) || !ALLOCATED_OK(event) ||
  89. !ALLOCATED_OK(irp)) __leave;
  90. m_Irp = Irp;
  91. Stack = *(irp->getNextStackLocation(m_Irp));
  92. SystemBuffer = m_Irp->AssociatedIrp.SystemBuffer;
  93. // We do not care here if system buffers is NULL
  94. // but we will not copy data if it will be not initialized (NULL)
  95. m_Status = STATUS_SUCCESS;
  96. }
  97. __finally
  98. {
  99. if(!NT_SUCCESS(m_Status))
  100. {
  101. TRACE("FAILED TO CREATE IoPacket object %x\n",m_Status);
  102. TRACE("SystemBuffer - %x, Irp - %x\n",SystemBuffer,Irp);
  103. TRACE("debug - %x, memory - %x\n",debug,memory);
  104. TRACE("event - %x, irp - %x\n",event,irp);
  105. // Remove all allocated objects...
  106. DISPOSE_OBJECT(irp);
  107. DISPOSE_OBJECT(event);
  108. DISPOSE_OBJECT(memory);
  109. DISPOSE_OBJECT(debug);
  110. }
  111. }
  112. };
  113. CIoPacket::~CIoPacket()
  114. {
  115. if(!systemIrp)
  116. {
  117. if(SystemBuffer) memory->free(SystemBuffer);
  118. SystemBuffer = NULL;
  119. }
  120. DISPOSE_OBJECT(irp);
  121. DISPOSE_OBJECT(event);
  122. DISPOSE_OBJECT(memory);
  123. DISPOSE_OBJECT(debug);
  124. };
  125. VOID CIoPacket::setMajorIOCtl(UCHAR controlCode)
  126. {
  127. Stack.MajorFunction = controlCode;
  128. };
  129. UCHAR CIoPacket::getMajorIOCtl()
  130. {
  131. return Stack.MajorFunction;
  132. };
  133. VOID CIoPacket::setMinorIOCtl(UCHAR controlCode)
  134. {
  135. Stack.MinorFunction = controlCode;
  136. };
  137. NTSTATUS CIoPacket::buildStack(PDEVICE_OBJECT DeviceObject, ULONG Major, UCHAR Minor, ULONG IoCtl, PVOID Context)
  138. {
  139. // Create copy of the next stack
  140. if(!m_Irp) return STATUS_INVALID_DEVICE_STATE;
  141. Stack = *(irp->getNextStackLocation(m_Irp));
  142. Stack.DeviceObject = DeviceObject;
  143. switch(Major)
  144. {
  145. case IRP_MJ_INTERNAL_DEVICE_CONTROL:
  146. {
  147. // Set stack parameters...
  148. Stack.MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  149. Stack.Parameters.Others.Argument1 = Context;
  150. Stack.Parameters.DeviceIoControl.IoControlCode = IoCtl;
  151. }
  152. break;
  153. case IRP_MJ_PNP:
  154. {
  155. // Set stack parameters...
  156. Stack.MajorFunction = IRP_MJ_PNP;
  157. Stack.MinorFunction = Minor;
  158. if(Minor==IRP_MN_QUERY_CAPABILITIES)
  159. {
  160. Stack.Parameters.DeviceCapabilities.Capabilities = (PDEVICE_CAPABILITIES) Context;
  161. }
  162. }
  163. break;
  164. default:
  165. // Copy current stack location to next...
  166. if(systemIrp) Stack = *(irp->getCurrentStackLocation(m_Irp));
  167. else
  168. {
  169. Stack.DeviceObject = DeviceObject;
  170. Stack.MajorFunction = (UCHAR)Major;
  171. Stack.MinorFunction = Minor;
  172. }
  173. }
  174. return STATUS_SUCCESS;
  175. };
  176. VOID CIoPacket::copyStackToNext()
  177. {
  178. PIO_STACK_LOCATION nextStack;
  179. if(!m_Irp) return;
  180. nextStack = irp->getNextStackLocation(m_Irp);
  181. if(nextStack) *nextStack = Stack;
  182. };
  183. VOID CIoPacket::copyCurrentStackToNext()
  184. {
  185. if(!m_Irp) return;
  186. irp->copyCurrentStackLocationToNext(m_Irp);
  187. }
  188. // Function will set completion routine for the Irp.
  189. VOID CIoPacket::setCompletion(PIO_COMPLETION_ROUTINE CompletionFunction)
  190. {
  191. PIO_COMPLETION_ROUTINE Completion;
  192. if(!m_Irp) return;
  193. Completion = CompletionFunction==NULL ? CALLBACK_FUNCTION(onRequestComplete) : CompletionFunction;
  194. if(m_Irp) irp->setCompletionRoutine(m_Irp,Completion,this,TRUE,TRUE,TRUE);
  195. };
  196. VOID CIoPacket::setDefaultCompletionFunction()
  197. {
  198. if(m_Irp) irp->setCompletionRoutine(m_Irp,CALLBACK_FUNCTION(onRequestComplete),this,TRUE,TRUE,TRUE);
  199. };
  200. NTSTATUS CIoPacket::copyBuffer(PUCHAR pBuffer, ULONG BufferLength)
  201. {
  202. if(!pBuffer || !BufferLength || BufferLength>PAGE_SIZE) return STATUS_INVALID_PARAMETER;
  203. if(m_Irp)
  204. {
  205. if(!systemIrp)
  206. {
  207. if(!m_Irp->AssociatedIrp.SystemBuffer)
  208. {
  209. if(!SystemBuffer)
  210. {
  211. SystemBuffer = memory->allocate(NonPagedPool,PAGE_SIZE);
  212. if(!SystemBuffer) return STATUS_INSUFFICIENT_RESOURCES;
  213. }
  214. m_Irp->AssociatedIrp.SystemBuffer = SystemBuffer;
  215. }
  216. }
  217. if(m_Irp->AssociatedIrp.SystemBuffer)
  218. memory->copy(m_Irp->AssociatedIrp.SystemBuffer,pBuffer,BufferLength);
  219. else
  220. {
  221. TRACE(" ***** AssociatedIrp SYSTEM BUFFER IS NULL!\nFailed to copy bus driver reply with len %x!\n",BufferLength);
  222. }
  223. return STATUS_SUCCESS;
  224. }
  225. else return STATUS_INSUFFICIENT_RESOURCES;
  226. };
  227. PIO_STACK_LOCATION CIoPacket::getStack()
  228. {
  229. return &Stack;
  230. };
  231. PVOID CIoPacket::getBuffer()
  232. {
  233. return SystemBuffer;
  234. };
  235. ULONG CIoPacket::getReadLength()
  236. {
  237. return Stack.Parameters.Read.Length;
  238. };
  239. VOID CIoPacket::setWriteLength(ULONG length)
  240. {
  241. Stack.Parameters.Write.Length = length;
  242. };
  243. VOID CIoPacket::setReadLength(ULONG length)
  244. {
  245. Stack.Parameters.Read.Length = length;
  246. };
  247. ULONG CIoPacket::getWriteLength()
  248. {
  249. return Stack.Parameters.Write.Length;
  250. };
  251. VOID CIoPacket::setInformation(ULONG_PTR information)
  252. {
  253. if(m_Irp) m_Irp->IoStatus.Information = information;
  254. IoStatus.Information = information;
  255. };
  256. ULONG_PTR CIoPacket::getInformation()
  257. {
  258. return IoStatus.Information;
  259. };
  260. VOID CIoPacket::updateInformation()
  261. {
  262. if(m_Irp) IoStatus.Information = m_Irp->IoStatus.Information;
  263. };
  264. NTSTATUS CIoPacket::getSystemReply(PUCHAR pReply,ULONG Length)
  265. {
  266. if(!pReply || !Length || Length> PAGE_SIZE) return STATUS_INVALID_PARAMETER;
  267. if(SystemBuffer)
  268. {
  269. memory->copy(pReply,SystemBuffer,Length);
  270. return STATUS_SUCCESS;
  271. }
  272. else return STATUS_INSUFFICIENT_RESOURCES;
  273. };
  274. #pragma LOCKEDCODE
  275. NTSTATUS CIoPacket::onRequestComplete()
  276. { // Callback to finish previously sended request
  277. TRACE(" =======> IoPacket processes Completion()\n");
  278. if(systemIrp)
  279. {
  280. if (m_Irp->PendingReturned)
  281. {
  282. TRACE(" Irp marked as pending...\n");
  283. irp->markPending(m_Irp);
  284. }
  285. }
  286. IoStatus.Status = m_Irp->IoStatus.Status;
  287. IoStatus.Information = m_Irp->IoStatus.Information;
  288. TRACE(" Irp completes with status %8.8lX , info %8.8lX\n",IoStatus.Status,IoStatus.Information);
  289. if(!systemIrp)
  290. {
  291. if(!m_DoNotFreeIrp)
  292. {
  293. PIRP Irp = m_Irp;
  294. m_Irp = NULL;
  295. if(Irp) irp->free(Irp);
  296. }
  297. }
  298. if(CompletionEvent) event->set(CompletionEvent,IO_NO_INCREMENT,FALSE);
  299. return STATUS_MORE_PROCESSING_REQUIRED;
  300. };
  301. #pragma PAGEDCODE
  302. VOID CIoPacket::setCompletionEvent(PKEVENT CompletionEvent)
  303. {
  304. if(CompletionEvent)
  305. {
  306. this->CompletionEvent = CompletionEvent;
  307. }
  308. }
  309. VOID CIoPacket::setStatus(NTSTATUS status)
  310. {
  311. IoStatus.Status = status;
  312. }
  313. NTSTATUS CIoPacket::getStatus()
  314. {
  315. return IoStatus.Status;
  316. }
  317. VOID CIoPacket::setDefaultCompletionEvent()
  318. {
  319. event->initialize(&DefaultCompletionEvent,NotificationEvent, FALSE);
  320. setCompletionEvent(&DefaultCompletionEvent);
  321. }
  322. NTSTATUS CIoPacket::waitForCompletion()
  323. { // Set current timeout
  324. return waitForCompletion(getTimeout());
  325. }
  326. NTSTATUS CIoPacket::waitForCompletion(LONG TimeOut)
  327. {
  328. // Because we set Alertable parameter to FALSE,
  329. // there are only two possible statuses from the function STATUS_SUCCESS and
  330. // STATUS_TIMEOUT...
  331. // We should not try to cancel system Irps!
  332. if(systemIrp)
  333. {
  334. NTSTATUS status;
  335. status = event->waitForSingleObject(CompletionEvent, Executive,KernelMode, FALSE, NULL);
  336. if(!NT_SUCCESS(status))
  337. {
  338. TRACE("waitForCompletion() reports error %x\n", status);
  339. setStatus(STATUS_IO_TIMEOUT);
  340. setInformation(0);
  341. }
  342. status = getStatus();
  343. return status;
  344. }
  345. else
  346. {
  347. LARGE_INTEGER timeout;
  348. timeout.QuadPart = -TimeOut * 10000;
  349. if (event->waitForSingleObject(CompletionEvent, Executive, KernelMode, FALSE, &timeout) == STATUS_TIMEOUT)
  350. {
  351. KIRQL oldIrql;
  352. // Ok! We've got timeout..
  353. // Completion function still can be called.
  354. // First tell completion not to free our Irp
  355. IoAcquireCancelSpinLock(&oldIrql);
  356. if(m_Irp) m_DoNotFreeIrp = TRUE;
  357. IoReleaseCancelSpinLock(oldIrql);
  358. DEBUG_START();
  359. TRACE("######## waitForCompletion() reports TIMEOUT after %d msec ############\n",getTimeout());
  360. if(m_Irp)
  361. {
  362. irp->cancel(m_Irp); // okay in this context
  363. // Wait for the cancel callback to be called
  364. event->waitForSingleObject(CompletionEvent, Executive, KernelMode, FALSE, NULL);
  365. TRACE("######## Current Irp cancelled!!! ############\n");
  366. // Now we can safely free our Irp
  367. if(m_DoNotFreeIrp)
  368. {
  369. if(m_Irp) irp->free(m_Irp);
  370. m_Irp = NULL;
  371. m_DoNotFreeIrp = FALSE;
  372. }
  373. // Report Irp timeout
  374. setStatus(STATUS_IO_TIMEOUT);
  375. setInformation(0);
  376. }
  377. }
  378. return getStatus();
  379. }
  380. }
  381. VOID CIoPacket::setStackDefaults()
  382. {
  383. setDefaultCompletionEvent();
  384. copyStackToNext();
  385. setDefaultCompletionFunction();
  386. }
  387. // Normally IoPacket will be created on the next stack location.
  388. // The function allows to take current stack location.
  389. // It is useful if we want to forward system IRP down the stack.
  390. VOID CIoPacket::setCurrentStack()
  391. {
  392. if(m_Irp) Stack = *(irp->getCurrentStackLocation(m_Irp));
  393. }
  394. VOID CIoPacket::setTimeout(LONG TimeOut)
  395. {
  396. m_TimeOut = TimeOut;
  397. };
  398. ULONG CIoPacket::getTimeout()
  399. {
  400. return m_TimeOut;
  401. };