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.

345 lines
9.4 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. ntload.c
  5. This module contains support for loading and unloading WD/PD/TD's as
  6. standard NT drivers.
  7. --*/
  8. #include <precomp.h>
  9. #pragma hdrstop
  10. #if DBG
  11. #define DBGPRINT(x) DbgPrint x
  12. #else
  13. #define DBGPRINT(x)
  14. #endif
  15. #define DEVICE_NAME_PREFIX L"\\Device\\"
  16. #define SERVICE_PATH L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
  17. NTSTATUS
  18. _IcaLoadSdWorker(
  19. IN PDLLNAME SdName,
  20. OUT PSDLOAD *ppSdLoad
  21. )
  22. /*++
  23. Routine Description:
  24. Replacement routine for Citrix _IcaLoadSdWorker that uses
  25. standard NT driver loading.
  26. Arguments:
  27. SdName - Name of the stack driver to load
  28. ppSdLoad - Pointer to return stack driver structure in.
  29. Return Value:
  30. NTSTATUS code.
  31. Environment:
  32. Kernel mode, DDK
  33. --*/
  34. {
  35. PIRP Irp;
  36. PKEVENT pEvent;
  37. NTSTATUS Status;
  38. PSDLOAD pSdLoad;
  39. UNICODE_STRING DriverName;
  40. UNICODE_STRING DeviceName;
  41. PFILE_OBJECT FileObject;
  42. PDEVICE_OBJECT DeviceObject;
  43. IO_STATUS_BLOCK Iosb;
  44. PSD_MODULE_INIT pmi;
  45. PIO_STACK_LOCATION IrpSp;
  46. PWCHAR pDriverPath;
  47. PWCHAR pDeviceName;
  48. ULONG szDriverPath;
  49. ULONG szDeviceName;
  50. ASSERT( ExIsResourceAcquiredExclusiveLite( IcaSdLoadResource ) );
  51. //
  52. // Allocate a SDLOAD struct
  53. //
  54. pSdLoad = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(*pSdLoad) );
  55. if ( pSdLoad == NULL )
  56. return( STATUS_INSUFFICIENT_RESOURCES );
  57. pEvent = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(KEVENT) );
  58. if( pEvent == NULL ) {
  59. ICA_FREE_POOL( pSdLoad );
  60. return( STATUS_INSUFFICIENT_RESOURCES );
  61. }
  62. pmi = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(SD_MODULE_INIT) );
  63. if( pmi == NULL ) {
  64. ICA_FREE_POOL( pEvent );
  65. ICA_FREE_POOL( pSdLoad );
  66. return( STATUS_INSUFFICIENT_RESOURCES );
  67. }
  68. szDeviceName = sizeof(DEVICE_NAME_PREFIX) + sizeof(pSdLoad->SdName) + sizeof(WCHAR);
  69. pDeviceName = ICA_ALLOCATE_POOL( NonPagedPool, szDeviceName );
  70. if( pDeviceName == NULL ) {
  71. ICA_FREE_POOL( pmi );
  72. ICA_FREE_POOL( pEvent );
  73. ICA_FREE_POOL( pSdLoad );
  74. return( STATUS_INSUFFICIENT_RESOURCES );
  75. }
  76. RtlZeroMemory( pmi, sizeof(*pmi) );
  77. pSdLoad->RefCount = 1;
  78. RtlCopyMemory( pSdLoad->SdName, SdName, sizeof( pSdLoad->SdName ) );
  79. szDriverPath = sizeof(SERVICE_PATH) + sizeof(pSdLoad->SdName) + sizeof(WCHAR);
  80. pDriverPath = ICA_ALLOCATE_POOL( NonPagedPool, szDriverPath );
  81. if( pDriverPath == NULL ) {
  82. ICA_FREE_POOL( pDeviceName );
  83. ICA_FREE_POOL( pmi );
  84. ICA_FREE_POOL( pEvent );
  85. ICA_FREE_POOL( pSdLoad );
  86. return( STATUS_INSUFFICIENT_RESOURCES );
  87. }
  88. wcscpy(pDriverPath, SERVICE_PATH);
  89. wcscat(pDriverPath, pSdLoad->SdName);
  90. RtlInitUnicodeString( &DriverName, pDriverPath );
  91. wcscpy(pDeviceName, DEVICE_NAME_PREFIX);
  92. wcscat(pDeviceName, pSdLoad->SdName);
  93. pSdLoad->pUnloadWorkItem = NULL;
  94. RtlInitUnicodeString( &DeviceName, pDeviceName );
  95. KeInitializeEvent( pEvent, NotificationEvent, FALSE );
  96. // Load the NT driver
  97. Status = ZwLoadDriver( &DriverName );
  98. if ( !NT_SUCCESS( Status ) && (Status != STATUS_IMAGE_ALREADY_LOADED)) {
  99. DBGPRINT(("TermDD: ZwLoadDriver %wZ failed, 0x%x, 0x%x\n", &DriverName, Status, &DriverName ));
  100. ICA_FREE_POOL( pDeviceName );
  101. ICA_FREE_POOL( pDriverPath );
  102. ICA_FREE_POOL( pmi );
  103. ICA_FREE_POOL( pEvent );
  104. ICA_FREE_POOL( pSdLoad );
  105. return( Status );
  106. }
  107. //
  108. // Now open the driver and get our stack driver pointers
  109. //
  110. Status = IoGetDeviceObjectPointer(
  111. &DeviceName, // Device name is module name IE: \Device\TDTCP
  112. GENERIC_ALL,
  113. &FileObject,
  114. &DeviceObject
  115. );
  116. if ( !NT_SUCCESS( Status ) ) {
  117. DBGPRINT(( "TermDD: IoGetDeviceObjectPointer %wZ failed, 0x%x\n", &DeviceName, Status ));
  118. ZwUnloadDriver( &DriverName );
  119. ICA_FREE_POOL( pDeviceName );
  120. ICA_FREE_POOL( pDriverPath );
  121. ICA_FREE_POOL( pmi );
  122. ICA_FREE_POOL( pEvent );
  123. ICA_FREE_POOL( pSdLoad );
  124. return( Status );
  125. }
  126. //
  127. // Send the internal IOCTL_SD_MODULE_INIT to the device to
  128. // get its stack interface pointers.
  129. //
  130. Irp = IoBuildDeviceIoControlRequest(
  131. IOCTL_SD_MODULE_INIT,
  132. DeviceObject,
  133. NULL, // InputBuffer
  134. 0, // InputBufferLength
  135. (PVOID)pmi, // OutputBuffer
  136. sizeof(*pmi), // OutputBufferLength
  137. TRUE, // Use IRP_MJ_INTERNAL_DEVICE_CONTROL
  138. pEvent,
  139. &Iosb
  140. );
  141. if( Irp == NULL ) {
  142. ObDereferenceObject( FileObject );
  143. ZwUnloadDriver( &DriverName );
  144. ICA_FREE_POOL( pDeviceName );
  145. ICA_FREE_POOL( pDriverPath );
  146. ICA_FREE_POOL( pmi );
  147. ICA_FREE_POOL( pEvent );
  148. ICA_FREE_POOL( pSdLoad );
  149. DBGPRINT(( "TermDD: Could not allocate IRP %S failed\n", SdName ));
  150. return( Status );
  151. }
  152. ObReferenceObject( FileObject );
  153. Irp->Tail.Overlay.OriginalFileObject = FileObject;
  154. IrpSp = IoGetNextIrpStackLocation( Irp );
  155. IrpSp->FileObject = FileObject;
  156. Irp->Flags |= IRP_SYNCHRONOUS_API;
  157. // Call the driver
  158. Status = IoCallDriver( DeviceObject, Irp );
  159. if( Status == STATUS_PENDING ) {
  160. Status = KeWaitForSingleObject( pEvent, UserRequest, KernelMode, FALSE, NULL );
  161. }
  162. // Get the result from the actual I/O operation
  163. if( Status == STATUS_SUCCESS ) {
  164. Status = Iosb.Status;
  165. }
  166. if( NT_SUCCESS(Status) ) {
  167. ASSERT( Iosb.Information == sizeof(*pmi) );
  168. pSdLoad->DriverLoad = pmi->SdLoadProc;
  169. pSdLoad->FileObject = FileObject;
  170. pSdLoad->DeviceObject = DeviceObject;
  171. InsertHeadList( &IcaSdLoadListHead, &pSdLoad->Links );
  172. *ppSdLoad = pSdLoad;
  173. }
  174. else {
  175. DBGPRINT(("TermDD: Error getting module pointers 0x%x\n",Status));
  176. #if DBG
  177. DbgBreakPoint();
  178. #endif
  179. ObDereferenceObject( FileObject );
  180. ZwUnloadDriver( &DriverName );
  181. ICA_FREE_POOL( pSdLoad );
  182. ICA_FREE_POOL( pDeviceName );
  183. ICA_FREE_POOL( pmi );
  184. ICA_FREE_POOL( pEvent );
  185. ICA_FREE_POOL( pDriverPath );
  186. return( Status );
  187. }
  188. // Cleanup
  189. ICA_FREE_POOL( pDeviceName );
  190. ICA_FREE_POOL( pDriverPath );
  191. ICA_FREE_POOL( pmi );
  192. ICA_FREE_POOL( pEvent );
  193. return( Status );
  194. }
  195. NTSTATUS
  196. _IcaUnloadSdWorker(
  197. IN PSDLOAD pSdLoad
  198. )
  199. /*++
  200. Replacement routine for Citrix _IcaUnloadSdWorker that uses
  201. standard NT driver unloading.
  202. Arguments:
  203. SdName - Name of the stack driver to load
  204. ppSdLoad - Pointer to return stack driver structure in.
  205. Environment:
  206. Kernel mode, DDK
  207. --*/
  208. {
  209. NTSTATUS Status = STATUS_SUCCESS;
  210. UNICODE_STRING DriverName;
  211. WCHAR DriverPath[sizeof(SERVICE_PATH) +
  212. sizeof(pSdLoad->SdName) +
  213. sizeof(WCHAR)];
  214. PSDLOAD pSdLoadInList;
  215. PLIST_ENTRY Head, Next;
  216. /*
  217. * free the workitem
  218. */
  219. ASSERT(pSdLoad->pUnloadWorkItem != NULL);
  220. ICA_FREE_POOL(pSdLoad->pUnloadWorkItem);
  221. pSdLoad->pUnloadWorkItem = NULL;
  222. wcscpy(DriverPath, SERVICE_PATH);
  223. wcscat(DriverPath, pSdLoad->SdName);
  224. RtlInitUnicodeString(&DriverName, DriverPath);
  225. /*
  226. * Lock the ICA Resource exclusively to search the SdLoad list.
  227. * Note when holding a resource we need to prevent APC calls, so
  228. * use KeEnterCriticalRegion().
  229. */
  230. KeEnterCriticalRegion();
  231. ExAcquireResourceExclusiveLite( IcaSdLoadResource, TRUE );
  232. /*
  233. * Look for the requested SD. If found, and refcount is still 0, then
  234. * unload it. If refcount is not zero then someone has referenced it since
  235. * we have posted the workitem and we do not want to unload it anymore.
  236. *
  237. */
  238. Head = &IcaSdLoadListHead;
  239. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  240. pSdLoadInList = CONTAINING_RECORD( Next, SDLOAD, Links );
  241. if ( !wcscmp( pSdLoad->SdName, pSdLoadInList->SdName ) ) {
  242. ASSERT(pSdLoad == pSdLoadInList);
  243. if (--pSdLoad->RefCount != 0) {
  244. break;
  245. }
  246. /*
  247. * We found the driver and Refcount is Zero let unload it
  248. */
  249. Status = ZwUnloadDriver(&DriverName);
  250. if (Status != STATUS_INVALID_DEVICE_REQUEST) {
  251. RemoveEntryList(&pSdLoad->Links);
  252. ObDereferenceObject (pSdLoad->FileObject);
  253. ICA_FREE_POOL(pSdLoad);
  254. }
  255. else {
  256. // If the driver unloading fails because of invalid request,
  257. // we keep this pSdLoad around. It will get cleaned up
  258. // either unload succeeds or the driver exits.
  259. // TODO: termdd currently not cleanup all the memory it allocates
  260. // It does not have unload correctly implemented. So, we didn't put
  261. // cleanup for this in the unload function. That needs to be looked
  262. // at it once unload function is hooked up.
  263. DBGPRINT(("TermDD: ZwUnLoadDriver %wZ failed, 0x%x, 0x%x\n", &DriverName, Status, &DriverName ));
  264. }
  265. break;
  266. }
  267. }
  268. /*
  269. * We should always find the driver in the list
  270. */
  271. ASSERT(Next != Head);
  272. ExReleaseResourceLite( IcaSdLoadResource);
  273. KeLeaveCriticalRegion();
  274. return Status;
  275. }