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.

532 lines
15 KiB

  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2001 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // tdisample.cpp
  7. //
  8. // Abstract:
  9. // This module contains functions called directly from the system,
  10. // at startup(DriverEntry), at shutdown(TdiUnloadDriver), and to service
  11. // requests (TdiDispatch). It also contains functions called only by
  12. // DriverEntry.
  13. //
  14. /////////////////////////////////////////////////////////////////////////////
  15. #define _IN_MAIN_
  16. #include "sysvars.h"
  17. ///////////////////////////////////////////////////////////////////////////
  18. // local constants, prototypes, and variables
  19. ///////////////////////////////////////////////////////////////////////////
  20. const PWCHAR wstrDD_TDI_DEVICE_NAME = L"\\Device\\TdiSample";
  21. const PWCHAR wstrDOS_DEVICE_NAME = L"\\DosDevices\\TdiSample";
  22. const PCHAR strFunc1 = "TSDriverEntry";
  23. const PCHAR strFunc2 = "TSDispatch";
  24. const PCHAR strFunc3 = "TSUnloadDriver";
  25. //const PCHAR strFuncP1 = "TSCreateDeviceContext";
  26. //const PCHAR strFuncP2 = "TSCreateSymbolicLinkObject";
  27. HANDLE hTdiSamplePnp;
  28. ////////////////////////////////////////////////////////////////////////////
  29. // Local Prototypes
  30. ////////////////////////////////////////////////////////////////////////////
  31. NTSTATUS
  32. TSCreateSymbolicLinkObject(
  33. VOID
  34. );
  35. NTSTATUS
  36. TSDispatch(
  37. IN PDEVICE_OBJECT pDeviceObject,
  38. IN PIRP pIrp
  39. );
  40. VOID
  41. TSUnloadDriver(
  42. IN PDRIVER_OBJECT pDriverObject
  43. );
  44. NTSTATUS
  45. TSCreateDeviceContext(
  46. IN PDRIVER_OBJECT DriverObject,
  47. IN OUT PDEVICE_CONTEXT *ppDeviceContext
  48. );
  49. ///////////////////////////////////////////////////////////////////////////
  50. // Functions called from system
  51. ///////////////////////////////////////////////////////////////////////////
  52. // -----------------------------------------------------------------
  53. //
  54. // Function: DriverEntry
  55. //
  56. // Arguments: DriverObject -- ptr to driver object created by the system
  57. // RegistryPath -- unreferenced parameter
  58. //
  59. // Returns: Final status of the initialization operation
  60. // (STATUS_SUCCESS if no error, else error code)
  61. //
  62. // Descript: This routine performs initialization of the tdi sample
  63. // driver. It creates the device objects for the driver and
  64. // performs other driver initialization.
  65. //
  66. // -----------------------------------------------------------------
  67. #pragma warning(disable: UNREFERENCED_PARAM)
  68. extern "C"
  69. NTSTATUS
  70. DriverEntry(PDRIVER_OBJECT pDriverObject,
  71. PUNICODE_STRING pRegistryPath)
  72. {
  73. PDEVICE_CONTEXT pDeviceContext; // device context (to create)
  74. NTSTATUS lStatus; // status of operations
  75. //
  76. // General Version Information
  77. //
  78. TSAllocateSpinLock(&MemTdiSpinLock);
  79. DebugPrint1("\nTdiSample Driver for Windows2000/WindowsXP -- Built %s \n\n",
  80. __DATE__);
  81. //
  82. // show the version id...
  83. //
  84. DebugPrint1("TdiSample version %s\n\n", VER_FILEVERSION_STR);
  85. //
  86. // First initialize the DeviceContext struct,
  87. //
  88. lStatus = TSCreateDeviceContext(pDriverObject,
  89. &pDeviceContext);
  90. if (!NT_SUCCESS (lStatus))
  91. {
  92. DebugPrint2("%s: failed to create device context: Status = 0x%08x\n",
  93. strFunc1,
  94. lStatus);
  95. return lStatus;
  96. }
  97. //
  98. // Create symbolic link between the Dos Device name and Nt
  99. // Device name for the test protocol driver.
  100. //
  101. lStatus = TSCreateSymbolicLinkObject();
  102. if (!NT_SUCCESS(lStatus))
  103. {
  104. DebugPrint2("%s: failed to create symbolic link. Status = 0x%08x\n",
  105. strFunc1,
  106. lStatus);
  107. return lStatus;
  108. }
  109. //
  110. // put on debug for handlers during pnp callbacks
  111. //
  112. ulDebugLevel = ulDebugShowHandlers;
  113. //
  114. // allocate all necessary memory blocks
  115. //
  116. if ((TSAllocateMemory((PVOID *)&pTdiDevnodeList,
  117. sizeof(TDI_DEVNODE_LIST),
  118. strFunc1,
  119. "DevnodeList")) == STATUS_SUCCESS)
  120. {
  121. if ((TSAllocateMemory((PVOID *)&pObjectList,
  122. sizeof(OBJECT_LIST),
  123. strFunc1,
  124. "ObjectList")) != STATUS_SUCCESS)
  125. {
  126. TSFreeMemory(pTdiDevnodeList);
  127. return STATUS_UNSUCCESSFUL;
  128. }
  129. }
  130. else
  131. {
  132. return STATUS_UNSUCCESSFUL;
  133. }
  134. TSAllocateSpinLock(&pTdiDevnodeList->TdiSpinLock);
  135. //
  136. // register pnp handlers
  137. //
  138. UNICODE_STRING Name;
  139. TDI_CLIENT_INTERFACE_INFO ClientInfo;
  140. RtlInitUnicodeString(&Name, L"TDISAMPLE");
  141. ClientInfo.MajorTdiVersion = 2;
  142. ClientInfo.MinorTdiVersion = 0;
  143. ClientInfo.ClientName = &Name;
  144. ClientInfo.BindingHandler = TSPnpBindCallback;
  145. ClientInfo.AddAddressHandlerV2 = TSPnpAddAddressCallback;
  146. ClientInfo.DelAddressHandlerV2 = TSPnpDelAddressCallback;
  147. ClientInfo.PnPPowerHandler = TSPnpPowerHandler;
  148. lStatus = TdiRegisterPnPHandlers(&ClientInfo,
  149. sizeof(TDI_CLIENT_INTERFACE_INFO),
  150. &hTdiSamplePnp);
  151. if (!NT_SUCCESS( lStatus ) )
  152. {
  153. DebugPrint1("TdiRegisterPnPHandlers: status 0x%08x\n", lStatus );
  154. }
  155. //
  156. // default -- debug on for commands only
  157. //
  158. ulDebugLevel = ulDebugShowCommand;
  159. TSAllocateSpinLock(&pObjectList->TdiSpinLock);
  160. return STATUS_SUCCESS;
  161. }
  162. #pragma warning(default: UNREFERENCED_PARAM)
  163. // -------------------------------------------------------------
  164. //
  165. // Function: TSDispatch
  166. //
  167. // Arguments: pDeviceObject -- ptr to the device object for this driver
  168. // pIrp -- ptr to the request packet representing
  169. // the i/o request
  170. //
  171. // Returns: Status of the operation
  172. // (usually, STATUS_SUCCESS or STATUS_PENDING)
  173. //
  174. // Descript: This is the main dispatch routine for the tdisample driver.
  175. // It deals with requests that the dll sends via
  176. // DeviceIoControl. It accepts an I/O request packet,
  177. // performs the request, and then returns the appropriate
  178. // status. If there is an error, the exact error code will
  179. // be returned as part of the "return buffer"
  180. //
  181. // --------------------------------------------------------------
  182. NTSTATUS
  183. TSDispatch(PDEVICE_OBJECT pDeviceObject,
  184. PIRP pIrp)
  185. {
  186. PDEVICE_CONTEXT pDeviceContext // get global data struct for driver
  187. = (PDEVICE_CONTEXT)pDeviceObject;
  188. PIO_STACK_LOCATION pIrpSp; // ptr to DeviceIoControl args
  189. NTSTATUS lStatus; // status of operations
  190. //
  191. // Sanity check. Driver better be initialized.
  192. //
  193. if (!pDeviceContext->fInitialized)
  194. {
  195. return STATUS_UNSUCCESSFUL;
  196. }
  197. //
  198. // initialize status information
  199. //
  200. pIrp->IoStatus.Information = 0;
  201. pIrp->IoStatus.Status = STATUS_PENDING;
  202. //
  203. // Get a pointer to the current stack location in the IRP. This is where
  204. // the function codes and parameters are stored.
  205. //
  206. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  207. //
  208. // switch on the function that is being performed by the requestor. If the
  209. // operation is a valid one for this device, then make it look like it
  210. // was successfully completed, where possible.
  211. //
  212. switch (pIrpSp->MajorFunction)
  213. {
  214. //
  215. // The Create function is called when the DLL tries to open the driver
  216. //
  217. case IRP_MJ_CREATE:
  218. lStatus = STATUS_SUCCESS;
  219. pDeviceContext->ulOpenCount++;
  220. DebugPrint2("\n%s: IRP_MJ_CREATE. OpenCount = %d\n",
  221. strFunc2,
  222. pDeviceContext->ulOpenCount);
  223. break;
  224. //
  225. // The Close function is the second function called when the DLL tries
  226. // to close the driver. It does nothing (all the work is done by the
  227. // first part -- IRP_MJ_CLEANUP
  228. //
  229. case IRP_MJ_CLOSE:
  230. DebugPrint1("\n%s: IRP_MJ_CLOSE.\n", strFunc2);
  231. lStatus = STATUS_SUCCESS;
  232. break;
  233. //
  234. // The DeviceControl function is the main interface to the tdi sample
  235. // driver. Every request is has an Io Control
  236. // code that is used by this function to determine the routine to
  237. // call. Returns either STATUS_PENDING or STATUS_SUCCESS
  238. //
  239. case IRP_MJ_DEVICE_CONTROL:
  240. IoMarkIrpPending(pIrp);
  241. lStatus = TSIssueRequest(pDeviceContext, pIrp, pIrpSp);
  242. break;
  243. //
  244. // Handle the two stage IRP for a file close operation. We really only
  245. // need to do this work when the last dll closes us.
  246. //
  247. case IRP_MJ_CLEANUP:
  248. if (!pDeviceContext->ulOpenCount) // sanity check
  249. {
  250. DebugPrint1("\n%s: IRP_MJ_CLEANUP -- no active opens!\n", strFunc2);
  251. lStatus = STATUS_SUCCESS; // what should happen here?
  252. }
  253. else
  254. {
  255. pDeviceContext->ulOpenCount--;
  256. DebugPrint2("\n%s: IRP_MJ_CLEANUP, OpenCount = %d\n",
  257. strFunc2,
  258. pDeviceContext->ulOpenCount);
  259. lStatus = STATUS_SUCCESS;
  260. }
  261. break;
  262. default:
  263. DebugPrint1("\n%s: OTHER (DEFAULT).\n", strFunc2);
  264. lStatus = STATUS_INVALID_DEVICE_REQUEST;
  265. } // major function switch
  266. //
  267. // If the request did not pend, then complete it now, otherwise it
  268. // will be completed when the pending routine finishes.
  269. //
  270. if (lStatus != STATUS_PENDING)
  271. {
  272. pIrp->IoStatus.Status = STATUS_SUCCESS;
  273. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  274. }
  275. //
  276. // Return the immediate status code to the caller.
  277. //
  278. return lStatus;
  279. }
  280. // ---------------------------------------------------------------
  281. //
  282. // Function: TSUnloadDriver
  283. //
  284. // Arguments: DriverObject -- ptr to the object for this driver
  285. //
  286. // Returns: none
  287. //
  288. // Descript: This function deals with cleanup if this driver is ever
  289. // unloaded by the system.
  290. //
  291. // ---------------------------------------------------------------
  292. BOOLEAN fInUnload = FALSE;
  293. VOID
  294. TSUnloadDriver(PDRIVER_OBJECT pDriverObject)
  295. {
  296. if (fInUnload)
  297. {
  298. DebugPrint0("TSUnloadDriver: re-entry!\n");
  299. return;
  300. }
  301. fInUnload = TRUE;
  302. PDEVICE_CONTEXT pDeviceContext // global data for driver
  303. = (PDEVICE_CONTEXT)pDriverObject->DeviceObject;
  304. //
  305. // unload pnp handlers
  306. //
  307. NTSTATUS lStatus = TdiDeregisterPnPHandlers(hTdiSamplePnp);
  308. hTdiSamplePnp = NULL;
  309. if (lStatus != STATUS_SUCCESS)
  310. {
  311. DebugPrint1("TdiDeregisterPnPHandlers: 0x%08x\n", lStatus);
  312. }
  313. //
  314. // free any device nodes that may still remain
  315. //
  316. for (ULONG ulCount = 0; ulCount < ulMAX_DEVICE_NODES; ulCount++)
  317. {
  318. PTDI_DEVICE_NODE pTdiDeviceNode = &(pTdiDevnodeList->TdiDeviceNode[ulCount]);
  319. if (pTdiDeviceNode->ulState > ulDEVSTATE_UNUSED)
  320. {
  321. TSFreeMemory(pTdiDeviceNode->ustrDeviceName.Buffer);
  322. TSFreeMemory(pTdiDeviceNode->pTaAddress);
  323. }
  324. }
  325. TSFreeSpinLock(&pTdiDevnodeList->TdiSpinLock);
  326. TSFreeSpinLock(&pObjectList->TdiSpinLock);
  327. TSFreeMemory(pTdiDevnodeList);
  328. TSFreeMemory(pObjectList);
  329. TSScanMemoryPool();
  330. TSFreeSpinLock(&MemTdiSpinLock);
  331. //
  332. // Close the Dos Symbolic link to remove traces of the device
  333. //
  334. UNICODE_STRING wstrDosUnicodeString; // dosdevices string
  335. RtlInitUnicodeString(&wstrDosUnicodeString, wstrDOS_DEVICE_NAME);
  336. IoDeleteSymbolicLink(&wstrDosUnicodeString);
  337. //
  338. // Then delete the device object from the system.
  339. //
  340. IoDeleteDevice((PDEVICE_OBJECT)pDeviceContext);
  341. }
  342. ////////////////////////////////////////////////////////////////////////////
  343. // Local functions
  344. ////////////////////////////////////////////////////////////////////////////
  345. // --------------------------------------------------------------
  346. //
  347. // Function: TSCreateDeviceContext
  348. //
  349. // Arguments: DriverObject -- ptr to the IO subsystem supplied
  350. // driver object
  351. // DeviceContext -- ptr to a ptr to a transport device
  352. // context object
  353. //
  354. // Returns: STATUS_SUCCESS if ok, else error code
  355. // (probably STATUS_INSUFFICIENT_RESOURCES)
  356. //
  357. // Descript: Create and initialize the driver object for this driver
  358. //
  359. // --------------------------------------------------------------
  360. NTSTATUS
  361. TSCreateDeviceContext(PDRIVER_OBJECT pDriverObject,
  362. PDEVICE_CONTEXT *ppDeviceContext)
  363. {
  364. PDEVICE_OBJECT pDeviceObject; // local work copy of device object
  365. PDEVICE_CONTEXT pLocDeviceContext; // portion of device object
  366. NTSTATUS lStatus; // operation status
  367. UNICODE_STRING wstrDeviceName; // name of device
  368. //
  369. // set up the name of the device
  370. //
  371. RtlInitUnicodeString(&wstrDeviceName, wstrDD_TDI_DEVICE_NAME);
  372. //
  373. // Create the device object for tditest.sys
  374. //
  375. lStatus = IoCreateDevice(pDriverObject,
  376. sizeof(DEVICE_CONTEXT) - sizeof(DEVICE_OBJECT),
  377. &wstrDeviceName,
  378. FILE_DEVICE_TRANSPORT,
  379. 0,
  380. FALSE,
  381. &pDeviceObject );
  382. if (!NT_SUCCESS(lStatus))
  383. {
  384. return lStatus;
  385. }
  386. pDeviceObject->Flags |= DO_DIRECT_IO;
  387. //
  388. // Initialize the driver object with this driver's entry points.
  389. //
  390. pDriverObject->MajorFunction [IRP_MJ_CREATE] = TSDispatch;
  391. pDriverObject->MajorFunction [IRP_MJ_CLOSE] = TSDispatch;
  392. pDriverObject->MajorFunction [IRP_MJ_CLEANUP] = TSDispatch;
  393. pDriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = TSDispatch;
  394. pDriverObject->DriverUnload = TSUnloadDriver;
  395. pLocDeviceContext = (PDEVICE_CONTEXT)pDeviceObject;
  396. //
  397. // Now initialize the Device Context structure Signatures.
  398. //
  399. pLocDeviceContext->fInitialized = TRUE;
  400. *ppDeviceContext = pLocDeviceContext;
  401. return STATUS_SUCCESS;
  402. }
  403. // -------------------------------------------------------------------
  404. //
  405. // Function: TSCreateSymbolicLinkObject
  406. //
  407. // Arguments: none
  408. //
  409. // Returns: status of the operation (STATUS_SUCCESS or error status)
  410. //
  411. // Descript: Set up a name for us so our dll can grab hold of us..
  412. //
  413. // -------------------------------------------------------------------
  414. NTSTATUS
  415. TSCreateSymbolicLinkObject(VOID)
  416. {
  417. UNICODE_STRING wstrDosUnicodeString; // dosdevices string
  418. UNICODE_STRING wstrNtUnicodeString; // nt device name
  419. RtlInitUnicodeString(&wstrDosUnicodeString, wstrDOS_DEVICE_NAME);
  420. RtlInitUnicodeString(&wstrNtUnicodeString, wstrDD_TDI_DEVICE_NAME);
  421. return IoCreateSymbolicLink(&wstrDosUnicodeString, &wstrNtUnicodeString);
  422. }
  423. ////////////////////////////////////////////////////////////////////////////
  424. // end of file tditest.cpp
  425. ////////////////////////////////////////////////////////////////////////////