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.

1278 lines
34 KiB

  1. /*++
  2. Copyright (c) 2000-2000 Microsoft Corporation
  3. Module Name:
  4. Driver.c
  5. Abstract:
  6. This module implements the DRIVER_INITIALIZATION routine for
  7. the PGM Transport and other routines that are specific to the
  8. NT implementation of a driver.
  9. Author:
  10. Mohammad Shabbir Alam (MAlam) 3-30-2000
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #ifdef FILE_LOGGING
  15. #include "driver.tmh"
  16. #else
  17. #if DBG
  18. enum eLOGGING_LEVEL PgmLoggingLevel = LogStatus;
  19. #endif // DBG
  20. #endif // FILE_LOGGING
  21. tPGM_STATIC_CONFIG PgmStaticConfig;
  22. tPGM_DYNAMIC_CONFIG PgmDynamicConfig;
  23. tPGM_REGISTRY_CONFIG *pPgmRegistryConfig = NULL;
  24. tPGM_DEVICE *pgPgmDevice = NULL;
  25. DEVICE_OBJECT *pPgmDeviceObject = NULL;
  26. NTSTATUS
  27. PgmDispatchCreate(
  28. IN PDEVICE_OBJECT pDeviceObject,
  29. IN PIRP pIrp
  30. );
  31. NTSTATUS
  32. PgmDispatchInternalDeviceControl(
  33. IN PDEVICE_OBJECT pDeviceObject,
  34. IN PIRP pIrp
  35. );
  36. NTSTATUS
  37. PgmDispatchDeviceControl(
  38. IN PDEVICE_OBJECT pDeviceObject,
  39. IN PIRP pIrp
  40. );
  41. NTSTATUS
  42. PgmDispatchCleanup(
  43. IN PDEVICE_OBJECT pDeviceObject,
  44. IN PIRP pIrp
  45. );
  46. NTSTATUS
  47. PgmDispatchClose(
  48. IN PDEVICE_OBJECT pDeviceObject,
  49. IN PIRP pIrp
  50. );
  51. //******************* Pageable Routine Declarations ****************
  52. #ifdef ALLOC_PRAGMA
  53. #pragma alloc_text(INIT, DriverEntry)
  54. #pragma alloc_text(PAGE, PgmUnload)
  55. #endif
  56. //******************* Pageable Routine Declarations ****************
  57. //----------------------------------------------------------------------------
  58. //
  59. // Internal routines
  60. //
  61. FILE_FULL_EA_INFORMATION *
  62. FindEA(
  63. IN PFILE_FULL_EA_INFORMATION StartEA,
  64. IN CHAR *pTargetName,
  65. IN USHORT TargetNameLength
  66. );
  67. VOID
  68. CompleteDispatchIrp(
  69. IN PIRP pIrp,
  70. IN NTSTATUS status
  71. );
  72. //----------------------------------------------------------------------------
  73. NTSTATUS
  74. DriverEntry(
  75. IN PDRIVER_OBJECT DriverObject,
  76. IN PUNICODE_STRING RegistryPath
  77. )
  78. /*++
  79. Routine Description:
  80. This is the initialization routine for the PGM device driver.
  81. This routine creates the device object for the PGM
  82. device and does other driver initialization.
  83. Arguments:
  84. IN DriverObject - Pointer to driver object created by the system.
  85. IN RegistryPath - Pgm driver's registry location
  86. Return Value:
  87. NTSTATUS - The function value is the final status from the initialization
  88. operation.
  89. --*/
  90. {
  91. NTSTATUS status;
  92. PAGED_CODE();
  93. #ifdef FILE_LOGGING
  94. //---------------------------------------------------------------------------------------
  95. WPP_INIT_TRACING (DriverObject, RegistryPath);
  96. #endif // FILE_LOGGING
  97. //---------------------------------------------------------------------------------------
  98. status = InitPgm (DriverObject, RegistryPath);
  99. if (!NT_SUCCESS (status))
  100. {
  101. PgmTrace (LogError, ("DriverEntry: ERROR -- " \
  102. "InitPgm returned <%x>\n", status));
  103. return (status);
  104. }
  105. //---------------------------------------------------------------------------------------
  106. //
  107. // Initialize the driver object with this driver's entry points.
  108. //
  109. DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)PgmDispatchCreate;
  110. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)PgmDispatchDeviceControl;
  111. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = (PDRIVER_DISPATCH)PgmDispatchInternalDeviceControl;
  112. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)PgmDispatchCleanup;
  113. DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)PgmDispatchClose;
  114. DriverObject->DriverUnload = PgmUnload;
  115. //---------------------------------------------------------------------------------------
  116. status = SetTdiHandlers ();
  117. if (!NT_SUCCESS (status))
  118. {
  119. PgmTrace (LogError, ("DriverEntry: ERROR -- " \
  120. "SetTdiHandlers returned <%x>\n", status));
  121. CleanupInit (E_CLEANUP_DEVICE);
  122. return (status);
  123. }
  124. //---------------------------------------------------------------------------------------
  125. //
  126. // Return to the caller.
  127. //
  128. PgmTrace (LogAllFuncs, ("DriverEntry: " \
  129. "Succeeded! ...\n"));
  130. return (status);
  131. }
  132. //----------------------------------------------------------------------------
  133. VOID
  134. CleanupInit(
  135. enum eCLEANUP_STAGE CleanupStage
  136. )
  137. /*++
  138. Routine Description:
  139. This routine is called either at DriverEntry or DriverUnload
  140. to cleanup (or do partial cleanup) of items initialized at Init-time
  141. Arguments:
  142. IN CleanupStage -- determines the stage to which we had initialized
  143. settings
  144. Return Value:
  145. NONE
  146. --*/
  147. {
  148. NTSTATUS status;
  149. LIST_ENTRY *pEntry;
  150. PGMLockHandle OldIrq;
  151. tADDRESS_CONTEXT *pAddress;
  152. PGM_WORKER_CONTEXT *pWorkerContext;
  153. PPGM_WORKER_ROUTINE pDelayedWorkerRoutine;
  154. tLOCAL_INTERFACE *pLocalInterface = NULL;
  155. tADDRESS_ON_INTERFACE *pLocalAddress = NULL;
  156. PgmTrace (LogAllFuncs, ("CleanupInit: " \
  157. "CleanupStage=<%d>\n", CleanupStage));
  158. switch (CleanupStage)
  159. {
  160. case (E_CLEANUP_UNLOAD):
  161. {
  162. //
  163. // Ensure that there are no more worker threads to be cleaned up
  164. //
  165. //
  166. // See if there are any worker threads currently executing, and if so, wait for
  167. // them to complete
  168. //
  169. KeClearEvent (&PgmDynamicConfig.LastWorkerItemEvent);
  170. PgmLock (&PgmDynamicConfig, OldIrq);
  171. if (PgmDynamicConfig.NumWorkerThreadsQueued)
  172. {
  173. PgmUnlock (&PgmDynamicConfig, OldIrq);
  174. status = KeWaitForSingleObject(&PgmDynamicConfig.LastWorkerItemEvent, // Object to wait on.
  175. Executive, // Reason for waiting
  176. KernelMode, // Processor mode
  177. FALSE, // Alertable
  178. NULL); // Timeout
  179. ASSERT (status == STATUS_SUCCESS);
  180. PgmLock (&PgmDynamicConfig, OldIrq);
  181. }
  182. ASSERT (!PgmDynamicConfig.NumWorkerThreadsQueued);
  183. //
  184. // Dequeue each of the requests in the Worker Queue and complete them
  185. //
  186. while (!IsListEmpty (&PgmDynamicConfig.WorkerQList))
  187. {
  188. pWorkerContext = CONTAINING_RECORD(PgmDynamicConfig.WorkerQList.Flink, PGM_WORKER_CONTEXT, PgmConfigLinkage);
  189. RemoveEntryList (&pWorkerContext->PgmConfigLinkage);
  190. PgmUnlock (&PgmDynamicConfig, OldIrq);
  191. pDelayedWorkerRoutine = pWorkerContext->WorkerRoutine;
  192. PgmTrace (LogAllFuncs, ("CleanupInit: " \
  193. "Completing Worker request <%p>\n", pDelayedWorkerRoutine));
  194. (*pDelayedWorkerRoutine) (pWorkerContext->Context1,
  195. pWorkerContext->Context2,
  196. pWorkerContext->Context3);
  197. PgmFreeMem ((PVOID) pWorkerContext);
  198. //
  199. // Acquire Lock again to check if we have completed all the requests
  200. //
  201. PgmLock (&PgmDynamicConfig, OldIrq);
  202. }
  203. PgmUnlock (&PgmDynamicConfig, OldIrq);
  204. }
  205. // no break -- Fall through!
  206. case (E_CLEANUP_PNP):
  207. {
  208. status = TdiDeregisterPnPHandlers (TdiClientHandle);
  209. while (!IsListEmpty (&PgmDynamicConfig.LocalInterfacesList))
  210. {
  211. pEntry = RemoveHeadList (&PgmDynamicConfig.LocalInterfacesList);
  212. pLocalInterface = CONTAINING_RECORD (pEntry, tLOCAL_INTERFACE, Linkage);
  213. while (!IsListEmpty (&pLocalInterface->Addresses))
  214. {
  215. pEntry = RemoveHeadList (&pLocalInterface->Addresses);
  216. pLocalAddress = CONTAINING_RECORD (pEntry, tADDRESS_ON_INTERFACE, Linkage);
  217. PgmFreeMem (pLocalAddress);
  218. }
  219. PgmFreeMem (pLocalInterface);
  220. }
  221. }
  222. // no break -- Fall through!
  223. case (E_CLEANUP_DEVICE):
  224. {
  225. PGM_DEREFERENCE_DEVICE (&pgPgmDevice, REF_DEV_CREATE);
  226. }
  227. // no break -- Fall through!
  228. case (E_CLEANUP_STRUCTURES):
  229. {
  230. // Nothing specific to cleanup
  231. }
  232. // no break -- Fall through!
  233. case (E_CLEANUP_REGISTRY_PARAMETERS):
  234. {
  235. if (pPgmRegistryConfig)
  236. {
  237. if (pPgmRegistryConfig->ucSenderFileLocation.Buffer)
  238. {
  239. PgmFreeMem (pPgmRegistryConfig->ucSenderFileLocation.Buffer);
  240. pPgmRegistryConfig->ucSenderFileLocation.Buffer = NULL;
  241. }
  242. PgmFreeMem (pPgmRegistryConfig);
  243. pPgmRegistryConfig = NULL;
  244. }
  245. }
  246. // no break -- Fall through!
  247. case (E_CLEANUP_DYNAMIC_CONFIG):
  248. {
  249. // See if there are any addresses we were unable to close earlier
  250. while (!IsListEmpty (&PgmDynamicConfig.DestroyedAddresses))
  251. {
  252. pEntry = RemoveHeadList (&PgmDynamicConfig.DestroyedAddresses);
  253. pAddress = CONTAINING_RECORD (pEntry, tADDRESS_CONTEXT, Linkage);
  254. PgmDestroyAddress (pAddress, NULL, NULL);
  255. }
  256. }
  257. // no break -- Fall through!
  258. case (E_CLEANUP_STATIC_CONFIG):
  259. {
  260. #ifdef OLD_LOGGING
  261. ExDeleteNPagedLookasideList(&PgmStaticConfig.DebugMessagesLookasideList);
  262. #endif // OLD_LOGGING
  263. ExDeleteNPagedLookasideList(&PgmStaticConfig.TdiLookasideList);
  264. PgmFreeMem (PgmStaticConfig.RegistryPath.Buffer);
  265. //
  266. // Dereference FipsFileObject.
  267. //
  268. if (PgmStaticConfig.FipsFileObject)
  269. {
  270. ASSERT (PgmStaticConfig.FipsInitialized);
  271. PgmStaticConfig.FipsInitialized = FALSE;
  272. ObDereferenceObject (PgmStaticConfig.FipsFileObject);
  273. PgmStaticConfig.FipsFileObject = NULL;
  274. }
  275. else
  276. {
  277. ASSERT (!PgmStaticConfig.FipsInitialized);
  278. }
  279. }
  280. // no break -- Fall through!
  281. default:
  282. {
  283. break;
  284. }
  285. }
  286. }
  287. //----------------------------------------------------------------------------
  288. VOID
  289. PgmUnload(
  290. IN PDRIVER_OBJECT DriverObject
  291. )
  292. /*++
  293. Routine Description:
  294. This is the Pgm driver's function for Unload requests
  295. Arguments:
  296. IN DriverObject - Pointer to driver object created by the system.
  297. Return Value:
  298. None
  299. --*/
  300. {
  301. NTSTATUS status;
  302. PAGED_CODE();
  303. PgmDynamicConfig.GlobalFlags |= PGM_CONFIG_FLAG_UNLOADING;
  304. PgmTrace (LogStatus, ("PgmUnload: " \
  305. "Unloading ...\n"));
  306. CleanupInit (E_CLEANUP_UNLOAD);
  307. #ifdef FILE_LOGGING
  308. WPP_CLEANUP (DriverObject);
  309. #endif // FILE_LOGGING
  310. }
  311. //----------------------------------------------------------------------------
  312. NTSTATUS
  313. PgmDispatchCreate(
  314. IN PDEVICE_OBJECT pDeviceObject,
  315. IN PIRP pIrp
  316. )
  317. /*++
  318. Routine Description:
  319. Dispatch function for creating Pgm objects
  320. Arguments:
  321. IN pDeviceObject - ptr to device object for target device
  322. IN pIrp - ptr to I/O request packet
  323. Return Value:
  324. NTSTATUS - Final status of the create request
  325. --*/
  326. {
  327. tPGM_DEVICE *pPgmDevice = pDeviceObject->DeviceExtension;
  328. PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  329. UCHAR IrpFlags = pIrpSp->Control;
  330. tCONTROL_CONTEXT *pControlContext = NULL;
  331. FILE_FULL_EA_INFORMATION *ea = (PFILE_FULL_EA_INFORMATION) pIrp->AssociatedIrp.SystemBuffer;
  332. FILE_FULL_EA_INFORMATION *TargetEA;
  333. TRANSPORT_ADDRESS UNALIGNED *pTransportAddr;
  334. TA_ADDRESS *pAddress;
  335. NTSTATUS status;
  336. PAGED_CODE();
  337. pIrp->IoStatus.Information = 0;
  338. pIrp->IoStatus.Status = STATUS_PENDING;
  339. IoMarkIrpPending(pIrp);
  340. //
  341. // See if this is a Control Channel open.
  342. //
  343. if (!ea)
  344. {
  345. PgmTrace (LogAllFuncs, ("PgmDispatchCreate: " \
  346. "Opening control channel for file object %p\n", pIrpSp->FileObject));
  347. if (pControlContext = PgmAllocMem (sizeof(tCONTROL_CONTEXT), PGM_TAG('0')))
  348. {
  349. PgmZeroMemory (pControlContext, sizeof (tCONTROL_CONTEXT));
  350. InitializeListHead (&pControlContext->Linkage);
  351. PgmInitLock (pControlContext, CONTROL_LOCK);
  352. pControlContext->Verify = PGM_VERIFY_CONTROL;
  353. PGM_REFERENCE_CONTROL (pControlContext, REF_CONTROL_CREATE, TRUE);
  354. pIrpSp->FileObject->FsContext = pControlContext;
  355. pIrpSp->FileObject->FsContext2 = (PVOID) TDI_CONTROL_CHANNEL_FILE;
  356. status = STATUS_SUCCESS;
  357. }
  358. else
  359. {
  360. status = STATUS_INSUFFICIENT_RESOURCES;
  361. }
  362. }
  363. //
  364. // See if this is a Connection Object open.
  365. //
  366. else if (TargetEA = FindEA (ea, TdiConnectionContext, TDI_CONNECTION_CONTEXT_LENGTH))
  367. {
  368. status = PgmCreateConnection (pPgmDevice, pIrp, pIrpSp, TargetEA);
  369. PgmTrace (LogAllFuncs, ("PgmDispatchCreate: " \
  370. "Open Connection, pIrp=<%p>, status=<%x>\n", pIrp, status));
  371. }
  372. //
  373. // See if this is an Address Object open.
  374. //
  375. else if (TargetEA = FindEA (ea, TdiTransportAddress, TDI_TRANSPORT_ADDRESS_LENGTH))
  376. {
  377. status = PgmCreateAddress (pPgmDevice, pIrp, pIrpSp, TargetEA);
  378. PgmTrace (LogAllFuncs, ("PgmDispatchCreate: " \
  379. "Open Address, pIrp=<%p>, status=<%x>\n", pIrp, status));
  380. }
  381. else
  382. {
  383. PgmTrace (LogError, ("PgmDispatchCreate: ERROR -- " \
  384. "Unsupported EA!\n"));
  385. status = STATUS_INVALID_EA_NAME;
  386. }
  387. if (status != STATUS_PENDING)
  388. {
  389. // reset the pending returned bit, since we are NOT returning pending
  390. pIrpSp->Control = IrpFlags;
  391. CompleteDispatchIrp (pIrp, status);
  392. }
  393. return (status);
  394. }
  395. //----------------------------------------------------------------------------
  396. NTSTATUS
  397. PgmDispatchCleanup(
  398. IN PDEVICE_OBJECT pDeviceObject,
  399. IN PIRP pIrp
  400. )
  401. /*++
  402. Routine Description:
  403. Dispatch function for cleaning-up Pgm objects
  404. Arguments:
  405. IN pDeviceObject - ptr to device object for target device
  406. IN pIrp - ptr to I/O request packet
  407. Return Value:
  408. NTSTATUS - Final status of the cleanup request
  409. --*/
  410. {
  411. NTSTATUS status = STATUS_SUCCESS;
  412. PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  413. UCHAR IrpFlags = pIrpSp->Control;
  414. PVOID *pContext = pIrpSp->FileObject->FsContext;
  415. PAGED_CODE();
  416. pIrp->IoStatus.Information = 0;
  417. pIrp->IoStatus.Status = STATUS_PENDING;
  418. IoMarkIrpPending(pIrp);
  419. switch (PtrToUlong (pIrpSp->FileObject->FsContext2))
  420. {
  421. case TDI_TRANSPORT_ADDRESS_FILE:
  422. {
  423. status = PgmCleanupAddress ((tADDRESS_CONTEXT *) pContext, pIrp);
  424. PgmTrace (LogAllFuncs, ("PgmDispatchCleanup: " \
  425. "pConnect=<%p>, pIrp=<%p>, status=<%x>\n", pContext, pIrp, status));
  426. break;
  427. }
  428. case TDI_CONNECTION_FILE:
  429. {
  430. status = PgmCleanupConnection ((tCOMMON_SESSION_CONTEXT *) pContext, pIrp);
  431. PgmTrace (LogAllFuncs, ("PgmDispatchCleanup: " \
  432. "pConnect=<%p>, pIrp=<%p>, status=<%x>\n", pContext, pIrp, status));
  433. break;
  434. }
  435. case TDI_CONTROL_CHANNEL_FILE:
  436. {
  437. //
  438. // Nothing to Cleanup here!
  439. //
  440. PgmTrace (LogAllFuncs, ("PgmDispatchCleanup: " \
  441. "pControl=<%p>, pIrp=<%p>, status=<%x>\n", pContext, pIrp, status));
  442. break;
  443. }
  444. default:
  445. {
  446. PgmTrace (LogError, ("PgmDispatchCleanup: ERROR -- " \
  447. "pIrp=<%p>, Context=[%p:%p] ...\n",
  448. pIrp, pContext, pIrpSp->FileObject->FsContext2));
  449. status = STATUS_INVALID_PARAMETER;
  450. break;
  451. }
  452. }
  453. if (status != STATUS_PENDING)
  454. {
  455. // reset the pending returned bit, since we are NOT returning pending
  456. pIrpSp->Control = IrpFlags;
  457. CompleteDispatchIrp (pIrp, status);
  458. }
  459. return (status);
  460. }
  461. //----------------------------------------------------------------------------
  462. NTSTATUS
  463. PgmDispatchClose(
  464. IN PDEVICE_OBJECT pDeviceObject,
  465. IN PIRP pIrp
  466. )
  467. /*++
  468. Routine Description:
  469. This routine completes the cleanup, closing handles, free'ing all
  470. memory associated with the object
  471. Arguments:
  472. IN pDeviceObject - ptr to device object for target device
  473. IN pIrp - ptr to I/O request packet
  474. Return Value:
  475. NTSTATUS - Final status of the close request
  476. --*/
  477. {
  478. NTSTATUS status = STATUS_SUCCESS;
  479. PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  480. UCHAR IrpFlags = pIrpSp->Control;
  481. PVOID *pContext = pIrpSp->FileObject->FsContext;
  482. PAGED_CODE();
  483. pIrp->IoStatus.Information = 0;
  484. pIrp->IoStatus.Status = STATUS_PENDING;
  485. IoMarkIrpPending(pIrp);
  486. switch (PtrToUlong (pIrpSp->FileObject->FsContext2))
  487. {
  488. case TDI_TRANSPORT_ADDRESS_FILE:
  489. {
  490. status = PgmCloseAddress (pIrp, pIrpSp);
  491. PgmTrace (LogAllFuncs, ("PgmDispatchClose: " \
  492. "pAddress=<%p>, pIrp=<%p>, status=<%x>\n", pContext, pIrp, status));
  493. break;
  494. }
  495. case TDI_CONNECTION_FILE:
  496. {
  497. status = PgmCloseConnection (pIrp, pIrpSp);
  498. PgmTrace (LogAllFuncs, ("PgmDispatchClose: " \
  499. "pConnect=<%p>, pIrp=<%p>, status=<%x>\n", pContext, pIrp, status));
  500. break;
  501. }
  502. case TDI_CONTROL_CHANNEL_FILE:
  503. {
  504. //
  505. // There is nothing special to do here so just dereference!
  506. //
  507. PgmTrace (LogAllFuncs, ("PgmDispatchClose: " \
  508. "pControl=<%p>, pIrp=<%p>, status=<%x>\n", pIrpSp->FileObject->FsContext, pIrp, status));
  509. PGM_DEREFERENCE_CONTROL ((tCONTROL_CONTEXT *) pContext, REF_CONTROL_CREATE);
  510. break;
  511. }
  512. default:
  513. {
  514. PgmTrace (LogError, ("PgmDispatchClose: ERROR -- " \
  515. "pIrp=<%p>, Context=[%p:%p] ...\n",
  516. pIrp, pIrpSp->FileObject->FsContext, pIrpSp->FileObject->FsContext2));
  517. status = STATUS_INVALID_PARAMETER;
  518. break;
  519. }
  520. }
  521. if (status != STATUS_PENDING)
  522. {
  523. // reset the pending returned bit, since we are NOT returning pending
  524. pIrpSp->Control = IrpFlags;
  525. CompleteDispatchIrp (pIrp, status);
  526. }
  527. return (status);
  528. }
  529. //----------------------------------------------------------------------------
  530. NTSTATUS
  531. PgmDispatchInternalDeviceControl(
  532. IN PDEVICE_OBJECT pDeviceObject,
  533. IN PIRP pIrp
  534. )
  535. /*++
  536. Routine Description:
  537. This routine primarily handles Tdi requests since we are a Tdi component
  538. Arguments:
  539. IN pDeviceObject - ptr to device object for target device
  540. IN pIrp - ptr to I/O request packet
  541. Return Value:
  542. NTSTATUS - Final status of the request
  543. --*/
  544. {
  545. tPGM_DEVICE *pPgmDevice = pDeviceObject->DeviceExtension;
  546. PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  547. UCHAR IrpFlags = pIrpSp->Control;
  548. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  549. PgmTrace (LogAllFuncs, ("PgmDispatchInternalDeviceControl: " \
  550. "[%d] Context=<%p> ...\n", pIrpSp->MinorFunction, pIrpSp->FileObject->FsContext));
  551. pIrp->IoStatus.Information = 0;
  552. pIrp->IoStatus.Status = STATUS_PENDING;
  553. IoMarkIrpPending(pIrp);
  554. switch (pIrpSp->MinorFunction)
  555. {
  556. case TDI_QUERY_INFORMATION:
  557. {
  558. Status = PgmQueryInformation (pPgmDevice, pIrp, pIrpSp);
  559. break;
  560. }
  561. case TDI_SET_EVENT_HANDLER:
  562. {
  563. Status = PgmSetEventHandler (pPgmDevice, pIrp, pIrpSp);
  564. break;
  565. }
  566. case TDI_ASSOCIATE_ADDRESS:
  567. {
  568. Status = PgmAssociateAddress (pPgmDevice, pIrp, pIrpSp);
  569. break;
  570. }
  571. case TDI_DISASSOCIATE_ADDRESS:
  572. {
  573. Status = PgmDisassociateAddress (pIrp, pIrpSp);
  574. break;
  575. }
  576. case TDI_CONNECT:
  577. {
  578. Status = PgmConnect (pPgmDevice, pIrp, pIrpSp);
  579. break;
  580. }
  581. case TDI_DISCONNECT:
  582. {
  583. Status = PgmDisconnect (pPgmDevice, pIrp, pIrpSp);
  584. break;
  585. }
  586. case TDI_SEND:
  587. {
  588. Status = PgmSendRequestFromClient (pPgmDevice, pIrp, pIrpSp);
  589. break;
  590. }
  591. case TDI_RECEIVE:
  592. {
  593. Status = PgmReceive (pPgmDevice, pIrp, pIrpSp);
  594. break;
  595. }
  596. /*
  597. case TDI_SEND_DATAGRAM:
  598. {
  599. Status = PgmSendDatagram (pPgmDevice, pIrp, pIrpSp);
  600. break;
  601. }
  602. */
  603. default:
  604. {
  605. PgmTrace (LogAllFuncs, ("PgmDispatchInternalDeviceControl: ERROR -- " \
  606. "[%x]: Context=<%p> ...\n", pIrpSp->MinorFunction, pIrpSp->FileObject->FsContext));
  607. Status = STATUS_NOT_IMPLEMENTED;
  608. break;
  609. }
  610. }
  611. if (Status != STATUS_PENDING)
  612. {
  613. // reset the pending returned bit, since we are NOT returning pending
  614. pIrpSp->Control = IrpFlags;
  615. CompleteDispatchIrp (pIrp, Status);
  616. }
  617. return (Status);
  618. }
  619. //----------------------------------------------------------------------------
  620. NTSTATUS
  621. PgmDispatchDeviceControl(
  622. IN PDEVICE_OBJECT pDeviceObject,
  623. IN PIRP pIrp
  624. )
  625. /*++
  626. Routine Description:
  627. This routine handles private Ioctls into Pgm. These Ioctls are
  628. to be called only by the Pgm Winsock helper (WshPgm.dll)
  629. Arguments:
  630. IN pDeviceObject - ptr to device object for target device
  631. IN pIrp - ptr to I/O request packet
  632. Return Value:
  633. NTSTATUS - Final status of the request
  634. --*/
  635. {
  636. NTSTATUS status;
  637. PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  638. UCHAR IrpFlags = pIrpSp->Control;
  639. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  640. if (STATUS_SUCCESS == TdiMapUserRequest (pDeviceObject, pIrp, pIrpSp))
  641. {
  642. //
  643. // This is a Tdi request!
  644. //
  645. status = PgmDispatchInternalDeviceControl (pDeviceObject, pIrp);
  646. return (status);
  647. }
  648. pIrp->IoStatus.Information = 0;
  649. pIrp->IoStatus.Status = STATUS_PENDING;
  650. IoMarkIrpPending (pIrp);
  651. switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode)
  652. {
  653. case IOCTL_PGM_WSH_SET_WINDOW_SIZE_RATE:
  654. {
  655. status = PgmSetWindowSizeAndSendRate (pIrp, pIrpSp);
  656. break;
  657. }
  658. case IOCTL_PGM_WSH_QUERY_WINDOW_SIZE_RATE:
  659. {
  660. status = PgmQueryWindowSizeAndSendRate (pIrp, pIrpSp);
  661. break;
  662. }
  663. case IOCTL_PGM_WSH_SET_ADVANCE_WINDOW_RATE:
  664. {
  665. status = PgmSetWindowAdvanceRate (pIrp, pIrpSp);
  666. break;
  667. }
  668. case IOCTL_PGM_WSH_QUERY_ADVANCE_WINDOW_RATE:
  669. {
  670. status = PgmQueryWindowAdvanceRate (pIrp, pIrpSp);
  671. break;
  672. }
  673. case IOCTL_PGM_WSH_SET_LATE_JOINER_PERCENTAGE:
  674. {
  675. status = PgmSetLateJoinerPercentage (pIrp, pIrpSp);
  676. break;
  677. }
  678. case IOCTL_PGM_WSH_QUERY_LATE_JOINER_PERCENTAGE:
  679. {
  680. status = PgmQueryLateJoinerPercentage (pIrp, pIrpSp);
  681. break;
  682. }
  683. case IOCTL_PGM_WSH_SET_WINDOW_ADVANCE_METHOD:
  684. {
  685. status = PgmSetWindowAdvanceMethod (pIrp, pIrpSp);
  686. break;
  687. }
  688. case IOCTL_PGM_WSH_QUERY_WINDOW_ADVANCE_METHOD:
  689. {
  690. status = PgmQueryWindowAdvanceMethod (pIrp, pIrpSp);
  691. break;
  692. }
  693. case IOCTL_PGM_WSH_SET_NEXT_MESSAGE_BOUNDARY:
  694. {
  695. status = PgmSetNextMessageBoundary (pIrp, pIrpSp);
  696. break;
  697. }
  698. case IOCTL_PGM_WSH_SET_SEND_IF:
  699. {
  700. status = PgmSetMCastOutIf (pIrp, pIrpSp);
  701. break;
  702. }
  703. case IOCTL_PGM_WSH_ADD_RECEIVE_IF:
  704. case IOCTL_PGM_WSH_JOIN_MCAST_LEAF:
  705. {
  706. status = PgmAddMCastReceiveIf (pIrp, pIrpSp);
  707. break;
  708. }
  709. case IOCTL_PGM_WSH_DEL_RECEIVE_IF:
  710. {
  711. status = PgmDelMCastReceiveIf (pIrp, pIrpSp);
  712. break;
  713. }
  714. case IOCTL_PGM_WSH_SET_RCV_BUFF_LEN:
  715. {
  716. status = PgmSetRcvBufferLength (pIrp, pIrpSp);
  717. break;
  718. }
  719. case IOCTL_PGM_WSH_QUERY_SENDER_STATS:
  720. {
  721. status = PgmQuerySenderStats (pIrp, pIrpSp);
  722. break;
  723. }
  724. case IOCTL_PGM_WSH_QUERY_RECEIVER_STATS:
  725. {
  726. status = PgmQueryReceiverStats (pIrp, pIrpSp);
  727. break;
  728. }
  729. case IOCTL_PGM_WSH_USE_FEC:
  730. {
  731. status = PgmSetFECInfo (pIrp, pIrpSp);
  732. break;
  733. }
  734. case IOCTL_PGM_WSH_QUERY_FEC_INFO:
  735. {
  736. status = PgmQueryFecInfo (pIrp, pIrpSp);
  737. break;
  738. }
  739. case IOCTL_PGM_WSH_SET_MCAST_TTL:
  740. {
  741. status = PgmSetMCastTtl (pIrp, pIrpSp);
  742. break;
  743. }
  744. case IOCTL_PGM_WSH_QUERY_HIGH_SPEED_INTRANET_OPT:
  745. {
  746. status = PgmQueryHighSpeedOptimization (pIrp, pIrpSp);
  747. break;
  748. }
  749. case IOCTL_PGM_WSH_SET_HIGH_SPEED_INTRANET_OPT:
  750. {
  751. status = PgmSetHighSpeedOptimization (pIrp, pIrpSp);
  752. break;
  753. }
  754. default:
  755. {
  756. PgmTrace (LogAllFuncs, ("PgmDispatchIoctls: " \
  757. "WARNING: Invalid Ioctl=[%x]: Context=<%p> ...\n",
  758. pIrpSp->Parameters.DeviceIoControl.IoControlCode,
  759. pIrpSp->FileObject->FsContext));
  760. status = STATUS_NOT_IMPLEMENTED;
  761. break;
  762. }
  763. }
  764. PgmTrace (LogAllFuncs, ("PgmDispatchIoctls: " \
  765. "[%d]: Context=<%p>, status=<%x>\n",
  766. pIrpSp->Parameters.DeviceIoControl.IoControlCode,
  767. pIrpSp->FileObject->FsContext, status));
  768. if (status != STATUS_PENDING)
  769. {
  770. // reset the pending returned bit, since we are NOT returning pending
  771. pIrpSp->Control = IrpFlags;
  772. CompleteDispatchIrp (pIrp, status);
  773. }
  774. return (status);
  775. }
  776. //----------------------------------------------------------------------------
  777. //
  778. // Utility functions
  779. //
  780. //----------------------------------------------------------------------------
  781. FILE_FULL_EA_INFORMATION *
  782. FindEA(
  783. IN PFILE_FULL_EA_INFORMATION StartEA,
  784. IN CHAR *pTargetName,
  785. IN USHORT TargetNameLength
  786. )
  787. /*++
  788. Routine Description:
  789. Parses and extended attribute list for a given target attribute.
  790. Arguments:
  791. IN StartEA - the first extended attribute in the list.
  792. IN pTargetName - the name of the target attribute.
  793. IN TargetNameLength - the length of the name of the target attribute.
  794. Return Value:
  795. A pointer to the requested attribute or NULL if the target wasn't found.
  796. --*/
  797. {
  798. USHORT i;
  799. BOOLEAN found;
  800. FILE_FULL_EA_INFORMATION *CurrentEA;
  801. for (CurrentEA = StartEA;
  802. CurrentEA;
  803. CurrentEA = (PFILE_FULL_EA_INFORMATION) ((PUCHAR)CurrentEA + CurrentEA->NextEntryOffset))
  804. {
  805. if (strncmp (CurrentEA->EaName, pTargetName, CurrentEA->EaNameLength) == 0)
  806. {
  807. PgmTrace (LogAllFuncs, ("FindEA: " \
  808. "Found EA, Target=<%s>\n", pTargetName));
  809. return (CurrentEA);
  810. }
  811. if (CurrentEA->NextEntryOffset == 0)
  812. {
  813. break;
  814. }
  815. }
  816. PgmTrace (LogAllFuncs, ("FindEA: " \
  817. "FAILed to find EA, Target=<%s>\n", pTargetName));
  818. return (NULL);
  819. }
  820. //----------------------------------------------------------------------------
  821. VOID
  822. PgmIoComplete(
  823. IN PIRP pIrp,
  824. IN NTSTATUS Status,
  825. IN ULONG SentLength
  826. )
  827. /*++
  828. Routine Description:
  829. This routine
  830. Arguments:
  831. IN pIrp -- Pointer to I/O request packet
  832. IN Status -- the final status of the request
  833. IN SentLength -- the value to be set in the Information field
  834. Return Value:
  835. NONE
  836. --*/
  837. {
  838. pIrp->IoStatus.Status = Status;
  839. // use -1 as a flag to mean do not adjust the sent length since it is
  840. // already set
  841. if (SentLength != -1)
  842. {
  843. pIrp->IoStatus.Information = SentLength;
  844. }
  845. // set the Irps cancel routine to null or the system may bugcheck
  846. // with a bug code of CANCEL_STATE_IN_COMPLETED_IRP
  847. //
  848. // refer to IoCancelIrp() ..\ntos\io\iosubs.c
  849. //
  850. PgmCancelCancelRoutine (pIrp);
  851. PgmTrace (LogAllFuncs, ("PgmIoComplete: " \
  852. "pIrp=<%p>, Status=<%x>, SentLength=<%d>\n", pIrp, Status, SentLength));
  853. IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT);
  854. }
  855. //----------------------------------------------------------------------------
  856. VOID
  857. CompleteDispatchIrp(
  858. IN PIRP pIrp,
  859. IN NTSTATUS status
  860. )
  861. /*++
  862. Routine Description:
  863. This function completes an IRP, and arranges for return parameters,
  864. if any, to be copied.
  865. Although somewhat a misnomer, this function is named after a similar
  866. function in the SpiderSTREAMS emulator.
  867. Arguments:
  868. IN pIrp - pointer to the IRP to complete
  869. IN status - completion status of the IRP
  870. Return Value:
  871. NONE
  872. --*/
  873. {
  874. CCHAR priboost;
  875. //
  876. // pIrp->IoStatus.Information is meaningful only for STATUS_SUCCESS
  877. //
  878. // set the Irps cancel routine to null or the system may bugcheck
  879. // with a bug code of CANCEL_STATE_IN_COMPLETED_IRP
  880. //
  881. // refer to IoCancelIrp() ..\ntos\io\iosubs.c
  882. //
  883. PgmCancelCancelRoutine (pIrp);
  884. pIrp->IoStatus.Status = status;
  885. priboost = (CCHAR) ((status == STATUS_SUCCESS) ? IO_NETWORK_INCREMENT : IO_NO_INCREMENT);
  886. PgmTrace (LogAllFuncs, ("CompleteDispatchIrp: " \
  887. "Completing pIrp=<%p>, status=<%x>\n", pIrp, status));
  888. IoCompleteRequest (pIrp, priboost);
  889. return;
  890. }
  891. //----------------------------------------------------------------------------
  892. NTSTATUS
  893. PgmCheckSetCancelRoutine(
  894. IN PIRP pIrp,
  895. IN PVOID CancelRoutine,
  896. IN BOOLEAN fLocked
  897. )
  898. /*++
  899. Routine Description:
  900. This Routine sets the cancel routine for an Irp.
  901. Arguments:
  902. status - a completion status for the Irp
  903. Return Value:
  904. NTSTATUS - status of the request
  905. --*/
  906. {
  907. NTSTATUS status;
  908. PGMLockHandle CancelIrql;
  909. //
  910. // Check if the irp was cancelled yet and if not, then set the
  911. // irp cancel routine.
  912. //
  913. if (!fLocked)
  914. {
  915. IoAcquireCancelSpinLock (&CancelIrql);
  916. }
  917. if (pIrp->Cancel)
  918. {
  919. pIrp->IoStatus.Status = STATUS_CANCELLED;
  920. status = STATUS_CANCELLED;
  921. }
  922. else
  923. {
  924. // setup the cancel routine
  925. IoMarkIrpPending (pIrp);
  926. IoSetCancelRoutine (pIrp, CancelRoutine);
  927. status = STATUS_SUCCESS;
  928. }
  929. if (!fLocked)
  930. {
  931. IoReleaseCancelSpinLock (CancelIrql);
  932. }
  933. return(status);
  934. }
  935. //----------------------------------------------------------------------------
  936. NTSTATUS
  937. PgmCancelCancelRoutine(
  938. IN PIRP pIrp
  939. )
  940. /*++
  941. Routine Description:
  942. This Routine sets the cancel routine for an Irp to NULL
  943. Arguments:
  944. status - a completion status for the Irp
  945. Return Value:
  946. NTSTATUS - status of the request
  947. --*/
  948. {
  949. NTSTATUS status = STATUS_SUCCESS;
  950. PGMLockHandle CancelIrql;
  951. //
  952. // Check if the irp was cancelled yet and if not, then set the
  953. // irp cancel routine.
  954. //
  955. IoAcquireCancelSpinLock (&CancelIrql);
  956. if (pIrp->Cancel)
  957. {
  958. status = STATUS_CANCELLED;
  959. }
  960. IoSetCancelRoutine (pIrp, NULL);
  961. IoReleaseCancelSpinLock (CancelIrql);
  962. return(status);
  963. }