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.

6352 lines
230 KiB

  1. /*+
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. san.c
  5. Abstract:
  6. Contains routines for SAN switch support
  7. Author:
  8. Vadim Eydelman (VadimE) 1-Jul-1998
  9. Revision History:
  10. --*/
  11. #include "afdp.h"
  12. VOID
  13. AfdSanCancelConnect (
  14. IN PDEVICE_OBJECT DeviceObject,
  15. IN PIRP Irp
  16. );
  17. VOID
  18. AfdSanCancelRequest (
  19. IN PDEVICE_OBJECT DeviceObject,
  20. IN PIRP Irp
  21. );
  22. PIRP
  23. AfdSanDequeueRequest (
  24. PAFD_ENDPOINT SanEndpoint,
  25. PVOID RequestCtx
  26. );
  27. VOID
  28. AfdSanInitEndpoint (
  29. PAFD_ENDPOINT SanHlprEndpoint,
  30. PFILE_OBJECT SanFile,
  31. PAFD_SWITCH_CONTEXT SwitchContext
  32. );
  33. NTSTATUS
  34. AfdSanNotifyRequest (
  35. PAFD_ENDPOINT SanEndpoint,
  36. PVOID RequestCtx,
  37. NTSTATUS Status,
  38. ULONG_PTR Information
  39. );
  40. NTSTATUS
  41. AfdSanReferenceSwitchSocketByHandle (
  42. IN HANDLE SocketHandle,
  43. IN ACCESS_MASK DesiredAccess,
  44. IN KPROCESSOR_MODE RequestorMode,
  45. IN PAFD_ENDPOINT SanHlprEndpoint,
  46. IN PAFD_SWITCH_CONTEXT SwitchContext OPTIONAL,
  47. OUT PFILE_OBJECT *FileObject
  48. );
  49. NTSTATUS
  50. AfdSanDupEndpointIntoServiceProcess (
  51. PFILE_OBJECT SanFileObject,
  52. PVOID SavedContext,
  53. ULONG ContextLength
  54. );
  55. NTSTATUS
  56. AfdSanSetAskDupeToServiceState (
  57. PAFD_ENDPOINT SanEndpoint
  58. );
  59. BOOLEAN
  60. AfdSanSetDupingToServiceState (
  61. PAFD_ENDPOINT SanEndpoint
  62. );
  63. BOOLEAN
  64. AfdSanReferenceEndpointObject (
  65. PAFD_ENDPOINT Endpoint
  66. );
  67. NTSTATUS
  68. AfdSanFindSwitchSocketByProcessContext (
  69. IN NTSTATUS Status,
  70. IN PAFD_ENDPOINT SanHlprEndpoint,
  71. IN PAFD_SWITCH_CONTEXT SwitchContext,
  72. OUT PFILE_OBJECT *FileObject
  73. );
  74. VOID
  75. AfdSanProcessAddrListForProviderChange (
  76. PAFD_ENDPOINT SpecificEndpoint
  77. );
  78. NTSTATUS
  79. AfdSanGetCompletionObjectTypePointer (
  80. VOID
  81. );
  82. #ifdef ALLOC_PRAGMA
  83. #pragma alloc_text (PAGE,AfdSanCreateHelper)
  84. #pragma alloc_text (PAGE,AfdSanCleanupHelper)
  85. #pragma alloc_text (PAGE,AfdSanCleanupEndpoint)
  86. #pragma alloc_text (PAGE,AfdSanReferenceSwitchSocketByHandle)
  87. #pragma alloc_text (PAGE,AfdSanFindSwitchSocketByProcessContext)
  88. #pragma alloc_text (PAGESAN,AfdSanReferenceEndpointObject)
  89. #pragma alloc_text (PAGE,AfdSanDupEndpointIntoServiceProcess)
  90. #pragma alloc_text (PAGESAN,AfdSanSetAskDupeToServiceState)
  91. #pragma alloc_text (PAGESAN,AfdSanSetDupingToServiceState)
  92. #pragma alloc_text (PAGESAN,AfdSanFastCementEndpoint)
  93. #pragma alloc_text (PAGESAN,AfdSanFastSetEvents)
  94. #pragma alloc_text (PAGESAN,AfdSanFastResetEvents)
  95. #pragma alloc_text (PAGESAN,AfdSanAcceptCore)
  96. #pragma alloc_text (PAGESAN,AfdSanConnectHandler)
  97. #pragma alloc_text (PAGESAN,AfdSanReleaseConnection)
  98. #pragma alloc_text (PAGESAN,AfdSanFastCompleteAccept)
  99. #pragma alloc_text (PAGESAN,AfdSanCancelAccept)
  100. #pragma alloc_text (PAGESAN,AfdSanCancelConnect)
  101. #pragma alloc_text (PAGESAN,AfdSanRedirectRequest)
  102. #pragma alloc_text (PAGESAN,AfdSanFastCompleteRequest)
  103. #pragma alloc_text (PAGE, AfdSanFastCompleteIo)
  104. #pragma alloc_text (PAGESAN,AfdSanDequeueRequest)
  105. #pragma alloc_text (PAGESAN,AfdSanCancelRequest)
  106. #pragma alloc_text (PAGESAN,AfdSanFastRefreshEndpoint)
  107. #pragma alloc_text (PAGE, AfdSanFastGetPhysicalAddr)
  108. #pragma alloc_text (PAGE, AfdSanFastGetServicePid)
  109. #pragma alloc_text (PAGE, AfdSanFastSetServiceProcess)
  110. #pragma alloc_text (PAGE, AfdSanFastProviderChange)
  111. #pragma alloc_text (PAGE, AfdSanAddrListChange)
  112. #pragma alloc_text (PAGESAN, AfdSanProcessAddrListForProviderChange)
  113. #pragma alloc_text (PAGE, AfdSanFastUnlockAll)
  114. #pragma alloc_text (PAGE, AfdSanPollBegin)
  115. #pragma alloc_text (PAGE, AfdSanPollEnd)
  116. #pragma alloc_text (PAGESAN, AfdSanPollUpdate)
  117. #pragma alloc_text (PAGE, AfdSanPollMerge)
  118. #pragma alloc_text (PAGE, AfdSanFastTransferCtx)
  119. #pragma alloc_text (PAGESAN, AfdSanAcquireContext)
  120. #pragma alloc_text (PAGESAN, AfdSanInitEndpoint)
  121. #pragma alloc_text (PAGE, AfdSanNotifyRequest)
  122. #pragma alloc_text (PAGESAN, AfdSanRestartRequestProcessing)
  123. #pragma alloc_text (PAGE, AfdSanGetCompletionObjectTypePointer)
  124. #pragma alloc_text (PAGESAN, AfdSanAbortConnection)
  125. #endif
  126. //
  127. // Dispatch level routines - external SAN entry points.
  128. //
  129. NTSTATUS
  130. AfdSanCreateHelper (
  131. PIRP Irp,
  132. PFILE_FULL_EA_INFORMATION EaBuffer,
  133. PAFD_ENDPOINT *Endpoint
  134. )
  135. /*++
  136. Routine Description:
  137. Allocates and initializes SAN helper endpoint for communication between switch
  138. and AFD.
  139. Arguments:
  140. Irp - Create IRP
  141. EaBuffer - Create IRP Ea buffer (AFD_SWITCH_OPEN_PACKET structure)
  142. CompletionPort - completion port to reflect kernel calls to switch
  143. CompletionEvent - event to identify overlapped IO triggered by the
  144. switch as opposed to the application
  145. Endpoint - buffer to place created endpoint pointer.
  146. Return Value:
  147. STATUS_SUCCESS - operation succeeded
  148. STATUS_ACCESS_VIOLATION - incorrect input buffer size.
  149. other - failed to access port/event object or allocation failure..
  150. --*/
  151. {
  152. NTSTATUS status;
  153. HANDLE port, event;
  154. PVOID ioCompletionPort;
  155. PVOID ioCompletionEvent;
  156. if ( !MmIsThisAnNtAsSystem () ) {
  157. #ifndef DONT_CHECK_FOR_DTC
  158. return STATUS_NOT_SUPPORTED;
  159. #else
  160. DbgPrint ("AFD: Temporarily allowing SAN support on non-server build\n");
  161. #endif //DONT_CHECK_FOR_DTC
  162. }
  163. #ifdef _WIN64
  164. if (IoIs32bitProcess (Irp)) {
  165. PAFD_SWITCH_OPEN_PACKET32 openPacket32;
  166. if (EaBuffer->EaValueLength<sizeof (*openPacket32)) {
  167. IF_DEBUG(SAN_SWITCH) {
  168. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  169. "AfdSanCreateHelper: Invalid switch open packet size.\n"));
  170. }
  171. return STATUS_ACCESS_VIOLATION;
  172. }
  173. openPacket32 = (PAFD_SWITCH_OPEN_PACKET32)(EaBuffer->EaName +
  174. EaBuffer->EaNameLength + 1);
  175. event = openPacket32->CompletionEvent;
  176. port = openPacket32->CompletionPort;
  177. }
  178. else
  179. #endif //_WIN64
  180. {
  181. PAFD_SWITCH_OPEN_PACKET openPacket;
  182. if (EaBuffer->EaValueLength<sizeof (*openPacket)) {
  183. IF_DEBUG (SAN_SWITCH) {
  184. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  185. "AfdSanCreateHelper: Invalid switch open packet size.\n"));
  186. }
  187. return STATUS_ACCESS_VIOLATION;
  188. }
  189. openPacket = (PAFD_SWITCH_OPEN_PACKET)(EaBuffer->EaName +
  190. EaBuffer->EaNameLength + 1);
  191. event = openPacket->CompletionEvent;
  192. port = openPacket->CompletionPort;
  193. }
  194. if (IoCompletionObjectType==NULL) {
  195. status = AfdSanGetCompletionObjectTypePointer ();
  196. if (!NT_SUCCESS (status)) {
  197. IF_DEBUG(SAN_SWITCH) {
  198. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  199. "AfdSanCreateHelper: Could not get completion OT:%lx\n",
  200. status));
  201. }
  202. return status;
  203. }
  204. }
  205. //
  206. // Get references to completion port and event
  207. //
  208. status = ObReferenceObjectByHandle (
  209. port,
  210. IO_COMPLETION_ALL_ACCESS,
  211. IoCompletionObjectType,
  212. Irp->RequestorMode,
  213. &ioCompletionPort,
  214. NULL
  215. );
  216. if (!NT_SUCCESS (status)) {
  217. IF_DEBUG (SAN_SWITCH) {
  218. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  219. "AfdSanCreateHelper: Could not reference completion port (%p).\n",
  220. status));
  221. }
  222. return status;
  223. }
  224. status = ObReferenceObjectByHandle (
  225. event,
  226. EVENT_ALL_ACCESS,
  227. *ExEventObjectType,
  228. Irp->RequestorMode,
  229. &ioCompletionEvent,
  230. NULL
  231. );
  232. if (!NT_SUCCESS (status)) {
  233. ObDereferenceObject (ioCompletionPort);
  234. IF_DEBUG(SAN_SWITCH) {
  235. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  236. "AfdSanCreateHelper: Could not reference completion event (%p).\n",
  237. status));
  238. }
  239. return status;
  240. }
  241. //
  242. // Allocate an AFD "helper" endpoint.
  243. //
  244. status = AfdAllocateEndpoint(
  245. Endpoint,
  246. NULL,
  247. 0
  248. );
  249. if( !NT_SUCCESS(status) ) {
  250. ObDereferenceObject (ioCompletionPort);
  251. ObDereferenceObject (ioCompletionEvent);
  252. return status;
  253. }
  254. (*Endpoint)->Type = AfdBlockTypeSanHelper;
  255. (*Endpoint)->Common.SanHlpr.IoCompletionPort = ioCompletionPort;
  256. (*Endpoint)->Common.SanHlpr.IoCompletionEvent = ioCompletionEvent;
  257. (*Endpoint)->Common.SanHlpr.Plsn = 0;
  258. (*Endpoint)->Common.SanHlpr.PendingRequests = 0;
  259. KeEnterCriticalRegion ();
  260. ExAcquireResourceExclusiveLite( AfdResource, TRUE );
  261. if (AfdSanCodeHandle==NULL) {
  262. AfdSanCodeHandle = MmLockPagableCodeSection( (PVOID)AfdSanFastCementEndpoint );
  263. ASSERT( AfdDiscardableCodeHandle != NULL );
  264. InitializeListHead (&AfdSanHelperList);
  265. }
  266. InsertTailList (&AfdSanHelperList, &(*Endpoint)->Common.SanHlpr.SanListLink);
  267. ExReleaseResourceLite( AfdResource );
  268. KeLeaveCriticalRegion ();
  269. //
  270. // HACKHACK. Force IO subsystem to call us when last handle to the file is closed
  271. // in any given process.
  272. //
  273. IoGetCurrentIrpStackLocation (Irp)->FileObject->LockOperation = TRUE;
  274. return STATUS_SUCCESS;
  275. }
  276. NTSTATUS
  277. AfdSanFastCementEndpoint (
  278. IN PFILE_OBJECT FileObject,
  279. IN ULONG IoctlCode,
  280. IN KPROCESSOR_MODE RequestorMode,
  281. IN PVOID InputBuffer,
  282. IN ULONG InputBufferLength,
  283. IN PVOID OutputBuffer,
  284. IN ULONG OutputBufferLength,
  285. OUT PULONG_PTR Information
  286. )
  287. /*++
  288. Routine Description:
  289. Changes the endpoint type to SAN to indicate that
  290. it is used for support of user mode SAN providers
  291. Associates switch context with the endpoint.
  292. Arguments:
  293. FileObject - SAN helper object - communication channel between the
  294. switch and AFD in the process.
  295. IoctlCode - operation IOCTL code (IOCTL_AFD_SWITCH_CEMENT_SAN)
  296. RequestorMode - mode of the caller
  297. InputBuffer - input parameters for the operation (AFD_SWITCH_CONTEXT_INFO)
  298. SocketHandle - handle of the endpoint being changed to SAN
  299. SwitchContext - switch context associated with the endpoint
  300. InputBufferLength - sizeof(AFD_SWITCH_CONTEXT_INFO)
  301. OutputBuffer - unused
  302. OutputBufferLength - unused
  303. Information - pointer for buffer to place return information into, unused
  304. Return Value:
  305. STATUS_SUCCESS - operation succeeded
  306. STATUS_INVALID_HANDLE - helper endpoint or switch socket is of incorrect type
  307. STATUS_INVALID_PARAMETER - input buffer is of incorrect size
  308. other - failed when attempting to access switch socket, input buffer, or switch context.
  309. --*/
  310. {
  311. NTSTATUS status;
  312. AFD_LOCK_QUEUE_HANDLE lockHandle;
  313. PFILE_OBJECT sanFileObject;
  314. AFD_SWITCH_CONTEXT_INFO contextInfo;
  315. PAFD_ENDPOINT sanEndpoint, sanHlprEndpoint;
  316. PVOID context;
  317. UNREFERENCED_PARAMETER (OutputBuffer);
  318. UNREFERENCED_PARAMETER (OutputBufferLength);
  319. *Information = 0;
  320. AFD_W4_INIT status = STATUS_SUCCESS;
  321. try {
  322. #ifdef _WIN64
  323. if (IoIs32bitProcess (NULL)) {
  324. PAFD_SWITCH_CONTEXT_INFO32 contextInfo32;
  325. if (InputBufferLength<sizeof (*contextInfo32)) {
  326. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  327. }
  328. if (RequestorMode!=KernelMode) {
  329. ProbeForReadSmallStructure (InputBuffer,
  330. sizeof (*contextInfo32),
  331. PROBE_ALIGNMENT32 (AFD_SWITCH_CONTEXT_INFO32));
  332. }
  333. contextInfo32 = InputBuffer;
  334. contextInfo.SocketHandle = contextInfo32->SocketHandle;
  335. contextInfo.SwitchContext = UlongToPtr(contextInfo32->SwitchContext);
  336. }
  337. else
  338. #endif _WIN64
  339. {
  340. if (InputBufferLength<sizeof (contextInfo)) {
  341. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  342. }
  343. if (RequestorMode!=KernelMode) {
  344. ProbeForReadSmallStructure (InputBuffer,
  345. sizeof (contextInfo),
  346. PROBE_ALIGNMENT (AFD_SWITCH_CONTEXT_INFO));
  347. }
  348. contextInfo = *((PAFD_SWITCH_CONTEXT_INFO)InputBuffer);
  349. }
  350. if (contextInfo.SwitchContext==NULL) {
  351. IF_DEBUG(SAN_SWITCH) {
  352. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  353. "AFD: Switch context is NULL in AfdSanFastCementEndpoint\n"));
  354. }
  355. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  356. }
  357. if (RequestorMode!=KernelMode) {
  358. ProbeForWrite (contextInfo.SwitchContext,
  359. sizeof (*contextInfo.SwitchContext),
  360. PROBE_ALIGNMENT (AFD_SWITCH_CONTEXT));
  361. }
  362. }
  363. except (AFD_EXCEPTION_FILTER (status)) {
  364. ASSERT (NT_ERROR (status));
  365. return status;
  366. }
  367. sanHlprEndpoint = FileObject->FsContext;
  368. ASSERT (IS_SAN_HELPER (sanHlprEndpoint));
  369. status = AfdSanReferenceSwitchSocketByHandle (
  370. contextInfo.SocketHandle,
  371. (IoctlCode>>14)&3,
  372. RequestorMode,
  373. sanHlprEndpoint,
  374. NULL,
  375. &sanFileObject
  376. );
  377. if (!NT_SUCCESS (status)) {
  378. return status;
  379. }
  380. sanEndpoint = sanFileObject->FsContext;
  381. IF_DEBUG(SAN_SWITCH) {
  382. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  383. "AfdFastCementSanEndpoint: endp-%p, hlpr-%p.\n",
  384. sanEndpoint, sanHlprEndpoint));
  385. }
  386. //
  387. // Make sure that san endpoint is in the state where it can
  388. // be given to the san provider.
  389. //
  390. if (AFD_PREVENT_STATE_CHANGE (sanEndpoint)) { // Prevents state change
  391. context = AfdLockEndpointContext (sanEndpoint); // Locks out select
  392. AfdAcquireSpinLock (&sanEndpoint->SpinLock, &lockHandle); // Locks out cleanup
  393. // from looking at partially
  394. // initialized data.
  395. if (!sanEndpoint->EndpointCleanedUp &&
  396. (sanEndpoint->Type==AfdBlockTypeEndpoint) &&
  397. (sanEndpoint->State==AfdEndpointStateBound) ) {
  398. AFD_SWITCH_CONTEXT localContext = {0,0,0,0};
  399. AfdSanInitEndpoint (sanHlprEndpoint, sanFileObject, contextInfo.SwitchContext);
  400. sanEndpoint->DisableFastIoSend = TRUE;
  401. sanEndpoint->DisableFastIoRecv = TRUE;
  402. sanEndpoint->EnableSendEvent = TRUE;
  403. sanEndpoint->Common.SanEndp.SelectEventsActive = AFD_POLL_SEND;
  404. sanEndpoint->State = AfdEndpointStateConnected;
  405. sanEndpoint->Common.SanEndp.LocalContext = &localContext;
  406. AfdIndicateEventSelectEvent (sanEndpoint, AFD_POLL_CONNECT|AFD_POLL_SEND, STATUS_SUCCESS);
  407. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  408. AfdIndicatePollEvent (sanEndpoint, AFD_POLL_CONNECT|AFD_POLL_SEND, STATUS_SUCCESS);
  409. status = AfdSanPollMerge (sanEndpoint, &localContext);
  410. sanEndpoint->Common.SanEndp.LocalContext = NULL;
  411. }
  412. else {
  413. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  414. status = STATUS_INVALID_HANDLE;
  415. }
  416. AfdUnlockEndpointContext (sanEndpoint, context);
  417. AFD_REALLOW_STATE_CHANGE (sanEndpoint);
  418. }
  419. else {
  420. status = STATUS_INVALID_HANDLE;
  421. }
  422. UPDATE_ENDPOINT2 (sanEndpoint, "AfdSanFastCementEndpoint, status: 0x%lX", status);
  423. ObDereferenceObject (sanFileObject);
  424. return status;
  425. }
  426. NTSTATUS
  427. AfdSanFastSetEvents (
  428. IN PFILE_OBJECT FileObject,
  429. IN ULONG IoctlCode,
  430. IN KPROCESSOR_MODE RequestorMode,
  431. IN PVOID InputBuffer,
  432. IN ULONG InputBufferLength,
  433. IN PVOID OutputBuffer,
  434. IN ULONG OutputBufferLength,
  435. OUT PULONG_PTR Information
  436. )
  437. /*++
  438. Routine Description:
  439. Sets the poll event on the san endpoint to report
  440. to the application via various forms of the select
  441. Arguments:
  442. FileObject - SAN helper object - communication channel between the
  443. switch and AFD in the process.
  444. IoctlCode - operation IOCTL code (IOCTL_AFD_SWITCH_SET_EVENTS)
  445. RequestorMode - mode of the caller
  446. InputBuffer - input parameters for the operation (AFD_SWITCH_EVENT_INFO)
  447. SocketHandle - handle of the endpoint being changed to SAN
  448. EventBit - event bit to set
  449. Status - associated status (for AFD_POLL_EVENT_CONNECT_FAIL)
  450. InputBufferLength - sizeof(AFD_SWITCH_EVENT_INFO)
  451. OutputBuffer - unused
  452. OutputBufferLength - unused
  453. Information - pointer for buffer to place return information into, unused
  454. Return Value:
  455. STATUS_SUCCESS - operation succeeded
  456. STATUS_INVALID_HANDLE - helper endpoint or switch socket is of incorrect type
  457. STATUS_INVALID_PARAMETER - input buffer is of incorrect size, invalid event bit.
  458. other - failed when attempting to access switch socket, input buffer, or switch context.
  459. --*/
  460. {
  461. NTSTATUS status;
  462. PFILE_OBJECT sanFileObject;
  463. AFD_SWITCH_EVENT_INFO eventInfo;
  464. PAFD_ENDPOINT sanEndpoint, sanHlprEndpoint;
  465. AFD_LOCK_QUEUE_HANDLE lockHandle;
  466. UNREFERENCED_PARAMETER (OutputBuffer);
  467. UNREFERENCED_PARAMETER (OutputBufferLength);
  468. *Information = 0;
  469. AFD_W4_INIT status = STATUS_SUCCESS;
  470. try {
  471. #ifdef _WIN64
  472. if (IoIs32bitProcess (NULL)) {
  473. PAFD_SWITCH_EVENT_INFO32 eventInfo32;
  474. if (InputBufferLength<sizeof (*eventInfo32)) {
  475. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  476. }
  477. if (RequestorMode!=KernelMode) {
  478. ProbeForReadSmallStructure (InputBuffer,
  479. sizeof (*eventInfo32),
  480. PROBE_ALIGNMENT32 (AFD_SWITCH_EVENT_INFO32));
  481. }
  482. eventInfo32 = InputBuffer;
  483. eventInfo.SocketHandle = eventInfo32->SocketHandle;
  484. eventInfo.SwitchContext = UlongToPtr(eventInfo32->SwitchContext);
  485. eventInfo.EventBit = eventInfo32->EventBit;
  486. eventInfo.Status = eventInfo32->Status;
  487. }
  488. else
  489. #endif _WIN64
  490. {
  491. if (InputBufferLength<sizeof (eventInfo)) {
  492. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  493. }
  494. if (RequestorMode!=KernelMode) {
  495. ProbeForReadSmallStructure (InputBuffer,
  496. sizeof (eventInfo),
  497. PROBE_ALIGNMENT (AFD_SWITCH_EVENT_INFO));
  498. }
  499. eventInfo = *((PAFD_SWITCH_EVENT_INFO)InputBuffer);
  500. }
  501. }
  502. except (AFD_EXCEPTION_FILTER (status)) {
  503. ASSERT (NT_ERROR (status));
  504. return status;
  505. }
  506. if (eventInfo.EventBit >= AFD_NUM_POLL_EVENTS) {
  507. IF_DEBUG(SAN_SWITCH) {
  508. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  509. "AFD: Invalid EventBit=%d passed to AfdSanFastSetEvents\n",
  510. eventInfo.EventBit));
  511. }
  512. return STATUS_INVALID_PARAMETER;
  513. }
  514. eventInfo.Status = AfdValidateStatus (eventInfo.Status);
  515. //
  516. // If event is connect failure, then context should not exist.
  517. // If event is not connect failure, context should exist.
  518. //
  519. if ((eventInfo.EventBit==AFD_POLL_CONNECT_FAIL_BIT) ^
  520. (eventInfo.SwitchContext==NULL)) {
  521. IF_DEBUG(SAN_SWITCH) {
  522. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  523. "AFD: AfdSanFastSetEvents-bit:%ld, context:%p inconsistent\n",
  524. eventInfo.EventBit,
  525. eventInfo.SwitchContext));
  526. }
  527. return STATUS_INVALID_PARAMETER;
  528. }
  529. sanHlprEndpoint = FileObject->FsContext;
  530. ASSERT (IS_SAN_HELPER (sanHlprEndpoint));
  531. status = AfdSanReferenceSwitchSocketByHandle (
  532. eventInfo.SocketHandle,
  533. (IoctlCode>>14)&3,
  534. RequestorMode,
  535. sanHlprEndpoint,
  536. eventInfo.SwitchContext,
  537. &sanFileObject
  538. );
  539. if (!NT_SUCCESS (status)) {
  540. return status;
  541. }
  542. sanEndpoint = sanFileObject->FsContext;
  543. //
  544. // Prevent endpoint reuse
  545. //
  546. if (!AFD_PREVENT_STATE_CHANGE (sanEndpoint)) {
  547. status = STATUS_INVALID_HANDLE;
  548. goto complete;
  549. }
  550. if (sanEndpoint->State==AfdEndpointStateConnected ||
  551. (eventInfo.EventBit==AFD_POLL_CONNECT_FAIL_BIT &&
  552. sanEndpoint->State==AfdEndpointStateBound) ) {
  553. IF_DEBUG(SAN_SWITCH) {
  554. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  555. "AfdFastSetSanEvents: endp-%p, bit-%lx, status-%lx.\n",
  556. sanEndpoint, eventInfo.EventBit, eventInfo.Status));
  557. }
  558. try {
  559. LONG currentEvents, newEvents;
  560. //
  561. // Update our event record. Make sure endpoint is connected, otherwise
  562. // sanEndpoint->Common.SanEndp.SwitchContext will not be valid
  563. //
  564. if (sanEndpoint->State==AfdEndpointStateConnected) {
  565. do {
  566. currentEvents = *((LONG volatile *)&sanEndpoint->Common.SanEndp.SelectEventsActive);
  567. newEvents = *((LONG volatile *)&sanEndpoint->Common.SanEndp.SwitchContext->EventsActive);
  568. }
  569. while (InterlockedCompareExchange (
  570. (PLONG)&sanEndpoint->Common.SanEndp.SelectEventsActive,
  571. newEvents,
  572. currentEvents)!=currentEvents);
  573. }
  574. }
  575. except (AFD_EXCEPTION_FILTER (status)) {
  576. ASSERT (NT_ERROR (status));
  577. goto complete_state_change;
  578. }
  579. //
  580. // Signal the event.
  581. //
  582. AfdAcquireSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  583. AfdIndicateEventSelectEvent (sanEndpoint, 1<<eventInfo.EventBit, eventInfo.Status);
  584. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  585. AfdIndicatePollEvent (sanEndpoint, 1<<eventInfo.EventBit, eventInfo.Status);
  586. status = STATUS_SUCCESS;
  587. }
  588. else {
  589. status = STATUS_INVALID_HANDLE;
  590. }
  591. complete_state_change:
  592. AFD_REALLOW_STATE_CHANGE (sanEndpoint);
  593. complete:
  594. UPDATE_ENDPOINT2 (sanEndpoint,
  595. "AfdFastSetEvents, event/status: 0x%lX",
  596. NT_SUCCESS (status) ? eventInfo.EventBit : status);
  597. ObDereferenceObject (sanFileObject);
  598. return status;
  599. }
  600. NTSTATUS
  601. AfdSanFastResetEvents (
  602. IN PFILE_OBJECT FileObject,
  603. IN ULONG IoctlCode,
  604. IN KPROCESSOR_MODE RequestorMode,
  605. IN PVOID InputBuffer,
  606. IN ULONG InputBufferLength,
  607. IN PVOID OutputBuffer,
  608. IN ULONG OutputBufferLength,
  609. OUT PULONG_PTR Information
  610. )
  611. /*++
  612. Routine Description:
  613. Resets the poll event on the san endpoint so that it is no
  614. longer reported to the application via various forms of the select
  615. Arguments:
  616. FileObject - SAN helper object - communication channel between the
  617. switch and AFD in the process.
  618. IoctlCode - operation IOCTL code (IOCTL_AFD_SWITCH_RESET_EVENTS)
  619. RequestorMode - mode of the caller
  620. InputBuffer - input parameters for the operation (AFD_SWITCH_EVENT_INFO)
  621. SocketHandle - handle of the endpoint being changed to SAN
  622. EventBit - event bit to reset
  623. Status - associated status (ignored)
  624. InputBufferLength - sizeof(AFD_SWITCH_EVENT_INFO)
  625. OutputBuffer - unused
  626. OutputBufferLength - unused
  627. Information - pointer for buffer to place return information into, unused
  628. Return Value:
  629. STATUS_SUCCESS - operation succeeded
  630. STATUS_INVALID_HANDLE - helper endpoint or switch socket is of incorrect type
  631. STATUS_INVALID_PARAMETER - input buffer is of incorrect size, invalid event bit.
  632. other - failed when attempting to access switch socket, input buffer, or switch context.
  633. --*/
  634. {
  635. AFD_LOCK_QUEUE_HANDLE lockHandle;
  636. NTSTATUS status;
  637. PFILE_OBJECT sanFileObject;
  638. AFD_SWITCH_EVENT_INFO eventInfo;
  639. PAFD_ENDPOINT sanEndpoint, sanHlprEndpoint;
  640. UNREFERENCED_PARAMETER (OutputBuffer);
  641. UNREFERENCED_PARAMETER (OutputBufferLength);
  642. *Information = 0;
  643. AFD_W4_INIT status = STATUS_SUCCESS;
  644. try {
  645. #ifdef _WIN64
  646. if (IoIs32bitProcess (NULL)) {
  647. PAFD_SWITCH_EVENT_INFO32 eventInfo32;
  648. if (InputBufferLength<sizeof (*eventInfo32)) {
  649. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  650. }
  651. if (RequestorMode!=KernelMode) {
  652. ProbeForReadSmallStructure (InputBuffer,
  653. sizeof (*eventInfo32),
  654. PROBE_ALIGNMENT32 (AFD_SWITCH_EVENT_INFO32));
  655. }
  656. eventInfo32 = InputBuffer;
  657. eventInfo.SocketHandle = eventInfo32->SocketHandle;
  658. eventInfo.SwitchContext = UlongToPtr(eventInfo32->SwitchContext);
  659. eventInfo.EventBit = eventInfo32->EventBit;
  660. eventInfo.Status = eventInfo32->Status;
  661. }
  662. else
  663. #endif _WIN64
  664. {
  665. if (InputBufferLength<sizeof (eventInfo)) {
  666. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  667. }
  668. if (RequestorMode!=KernelMode) {
  669. ProbeForReadSmallStructure (InputBuffer,
  670. sizeof (eventInfo),
  671. PROBE_ALIGNMENT (AFD_SWITCH_EVENT_INFO));
  672. }
  673. eventInfo = *((PAFD_SWITCH_EVENT_INFO)InputBuffer);
  674. }
  675. }
  676. except (AFD_EXCEPTION_FILTER (status)) {
  677. ASSERT (NT_ERROR (status));
  678. return status;
  679. }
  680. if (eventInfo.EventBit >= AFD_NUM_POLL_EVENTS) {
  681. IF_DEBUG(SAN_SWITCH) {
  682. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  683. "AFD: Invalid EventBit=%d passed to AfdSanFastResetEvents\n",
  684. eventInfo.EventBit));
  685. }
  686. return STATUS_INVALID_PARAMETER;
  687. }
  688. if (eventInfo.SwitchContext==NULL) {
  689. KdPrint (("AFD: Switch context is NULL in AfdSanFastResetEvents\n"));
  690. return STATUS_INVALID_PARAMETER;
  691. }
  692. sanHlprEndpoint = FileObject->FsContext;
  693. ASSERT (IS_SAN_HELPER (sanHlprEndpoint));
  694. status = AfdSanReferenceSwitchSocketByHandle (
  695. eventInfo.SocketHandle,
  696. (IoctlCode>>14)&3,
  697. RequestorMode,
  698. sanHlprEndpoint,
  699. eventInfo.SwitchContext,
  700. &sanFileObject
  701. );
  702. if (!NT_SUCCESS (status)) {
  703. return status;
  704. }
  705. sanEndpoint = sanFileObject->FsContext;
  706. //
  707. // Prevent endpoint reuse
  708. //
  709. if (!AFD_PREVENT_STATE_CHANGE (sanEndpoint)) {
  710. status = STATUS_INVALID_HANDLE;
  711. goto complete;
  712. }
  713. if (!IS_SAN_ENDPOINT (sanEndpoint)) {
  714. goto complete_state_change;
  715. }
  716. IF_DEBUG(SAN_SWITCH) {
  717. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  718. "AfdFastResetSanEvents: endp-%p, bit-%lx, status-%lx.\n",
  719. sanEndpoint, eventInfo.EventBit, eventInfo.Status));
  720. }
  721. try {
  722. LONG currentEvents, newEvents;
  723. //
  724. // Update our event record.
  725. //
  726. do {
  727. currentEvents = *((LONG volatile *)&sanEndpoint->Common.SanEndp.SelectEventsActive);
  728. newEvents = *((LONG volatile *)&sanEndpoint->Common.SanEndp.SwitchContext->EventsActive);
  729. }
  730. while (InterlockedCompareExchange (
  731. (PLONG)&sanEndpoint->Common.SanEndp.SelectEventsActive,
  732. newEvents,
  733. currentEvents)!=currentEvents);
  734. }
  735. except (AFD_EXCEPTION_FILTER (status)) {
  736. ASSERT (NT_ERROR (status));
  737. goto complete_state_change;
  738. }
  739. AfdAcquireSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  740. //
  741. // Reset EventSelect mask
  742. sanEndpoint->EventsActive &= (~ (1<<(eventInfo.EventBit)));
  743. if (eventInfo.EventBit == AFD_POLL_SEND_BIT)
  744. sanEndpoint->EnableSendEvent = TRUE;
  745. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  746. status = STATUS_SUCCESS;
  747. complete_state_change:
  748. AFD_REALLOW_STATE_CHANGE (sanEndpoint);
  749. complete:
  750. UPDATE_ENDPOINT2 (sanEndpoint,
  751. "AfdFastResetEvents, event/status: 0x%lX",
  752. NT_SUCCESS (status) ? eventInfo.EventBit : status);
  753. ObDereferenceObject (sanFileObject);
  754. return status;
  755. }
  756. //
  757. // Macros to make the super accept restart code more maintainable.
  758. //
  759. #define AfdRestartSuperAcceptInfo DeviceIoControl
  760. // Used while IRP is in AFD queue (otherwise AfdAcceptFileObject
  761. // is stored as completion routine context).
  762. #define AfdAcceptFileObject Type3InputBuffer
  763. // Used when IRP is passed to the transport (otherwise MdlAddress
  764. // is stored in the IRP itself).
  765. #define AfdMdlAddress Type3InputBuffer
  766. #define AfdReceiveDataLength OutputBufferLength
  767. #define AfdRemoteAddressLength InputBufferLength
  768. #define AfdLocalAddressLength IoControlCode
  769. NTSTATUS
  770. FASTCALL
  771. AfdSanConnectHandler (
  772. PIRP Irp,
  773. PIO_STACK_LOCATION IrpSp
  774. )
  775. /*++
  776. Routine Description:
  777. Implements connect indication from SAN provider.
  778. Picks up the accept from the listening endpoint queue
  779. or queues the IRP an signals the application to come
  780. down with an accept.
  781. Arguments:
  782. Irp - SAN connect IRP
  783. IrpSp - stack location
  784. Return Value:
  785. NTSTATUS
  786. --*/
  787. {
  788. NTSTATUS status;
  789. PAFD_SWITCH_CONNECT_INFO connectInfo;
  790. union {
  791. #ifdef _WIN64
  792. PAFD_SWITCH_ACCEPT_INFO32 acceptInfo32;
  793. #endif //_WIN64
  794. PAFD_SWITCH_ACCEPT_INFO acceptInfo;
  795. } u;
  796. PFILE_OBJECT listenFileObject;
  797. PAFD_ENDPOINT sanHlprEndpoint;
  798. PAFD_ENDPOINT listenEndpoint;
  799. PAFD_CONNECTION connection;
  800. ULONG RemoteAddressLength;
  801. AFD_LOCK_QUEUE_HANDLE lockHandle;
  802. PIRP acceptIrp;
  803. PTA_ADDRESS localAddress;
  804. listenFileObject = NULL;
  805. #ifdef _WIN64
  806. if (IoIs32bitProcess (Irp)) {
  807. PAFD_SWITCH_CONNECT_INFO newSystemBuffer;
  808. PAFD_SWITCH_CONNECT_INFO32 oldSystemBuffer = Irp->AssociatedIrp.SystemBuffer;
  809. ULONG newLength;
  810. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  811. sizeof(*oldSystemBuffer) ) {
  812. status = STATUS_INVALID_PARAMETER;
  813. goto complete;
  814. }
  815. newLength = (sizeof(*newSystemBuffer) - sizeof(*oldSystemBuffer));
  816. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength > (MAXULONG - newLength)) {
  817. status = STATUS_INVALID_PARAMETER;
  818. goto complete;
  819. }
  820. newLength += IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  821. try {
  822. newSystemBuffer = ExAllocatePoolWithQuotaTag (
  823. NonPagedPool|POOL_RAISE_IF_ALLOCATION_FAILURE,
  824. newLength,
  825. AFD_SYSTEM_BUFFER_POOL_TAG);
  826. }
  827. except (EXCEPTION_EXECUTE_HANDLER) {
  828. status = GetExceptionCode ();
  829. goto complete;
  830. }
  831. newSystemBuffer->ListenHandle = oldSystemBuffer->ListenHandle;
  832. newSystemBuffer->SwitchContext = UlongToPtr(oldSystemBuffer->SwitchContext);
  833. RtlMoveMemory (&newSystemBuffer->RemoteAddress,
  834. &oldSystemBuffer->RemoteAddress,
  835. IrpSp->Parameters.DeviceIoControl.InputBufferLength-
  836. FIELD_OFFSET (AFD_SWITCH_CONNECT_INFO32, RemoteAddress));
  837. ExFreePool (Irp->AssociatedIrp.SystemBuffer);
  838. Irp->AssociatedIrp.SystemBuffer = newSystemBuffer;
  839. IrpSp->Parameters.DeviceIoControl.InputBufferLength = newLength;
  840. }
  841. #endif // _WIN64
  842. //
  843. // Set up local variables.
  844. //
  845. sanHlprEndpoint = IrpSp->FileObject->FsContext;
  846. ASSERT( sanHlprEndpoint->Type == AfdBlockTypeSanHelper);
  847. Irp->IoStatus.Information = 0;
  848. connectInfo = Irp->AssociatedIrp.SystemBuffer;
  849. //
  850. // Verify input parameters
  851. //
  852. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  853. sizeof (*connectInfo) ||
  854. connectInfo->RemoteAddress.TAAddressCount!=2 || // Must have local and remote addresses
  855. (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  856. FIELD_OFFSET (AFD_SWITCH_CONNECT_INFO,
  857. RemoteAddress.Address[0].Address[
  858. connectInfo->RemoteAddress.Address[0].AddressLength])+sizeof(TA_ADDRESS))) {
  859. status = STATUS_INVALID_PARAMETER;
  860. goto complete;
  861. }
  862. #ifdef _WIN64
  863. if (IoIs32bitProcess (Irp)) {
  864. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  865. sizeof (*u.acceptInfo32)) {
  866. status = STATUS_INVALID_PARAMETER;
  867. goto complete;
  868. }
  869. }
  870. else
  871. #endif // _WIN64
  872. {
  873. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  874. sizeof (*u.acceptInfo)) {
  875. status = STATUS_INVALID_PARAMETER;
  876. goto complete;
  877. }
  878. }
  879. RemoteAddressLength = FIELD_OFFSET (TRANSPORT_ADDRESS, Address[0].Address[
  880. connectInfo->RemoteAddress.Address[0].AddressLength]);
  881. localAddress = (PTA_ADDRESS)
  882. &(connectInfo->RemoteAddress.Address[0].Address[
  883. connectInfo->RemoteAddress.Address[0].AddressLength]);
  884. if (&localAddress->Address[localAddress->AddressLength]-(PUCHAR)Irp->AssociatedIrp.SystemBuffer>
  885. (LONG)IrpSp->Parameters.DeviceIoControl.InputBufferLength) {
  886. status = STATUS_INVALID_PARAMETER;
  887. goto complete;
  888. }
  889. if (!IS_SAN_HELPER(sanHlprEndpoint) ||
  890. sanHlprEndpoint->OwningProcess!=IoGetCurrentProcess ()) {
  891. status = STATUS_INVALID_HANDLE;
  892. goto complete;
  893. }
  894. try {
  895. if (connectInfo->SwitchContext == NULL) {
  896. IF_DEBUG(SAN_SWITCH) {
  897. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  898. "AFD: Switch context is NULL in AfdSanConnectHandler\n"));
  899. }
  900. ExRaiseStatus(STATUS_INVALID_PARAMETER);
  901. }
  902. if (Irp->RequestorMode != KernelMode) {
  903. ProbeForWrite(connectInfo->SwitchContext,
  904. sizeof(*connectInfo->SwitchContext),
  905. PROBE_ALIGNMENT(AFD_SWITCH_CONTEXT));
  906. }
  907. }
  908. except (EXCEPTION_EXECUTE_HANDLER) {
  909. status = GetExceptionCode();
  910. goto complete;
  911. }
  912. //
  913. // We will separate addresses, so change the count
  914. //
  915. connectInfo->RemoteAddress.TAAddressCount = 1;
  916. #ifdef _WIN64
  917. if (IoIs32bitProcess (Irp)) {
  918. u.acceptInfo32 = MmGetMdlVirtualAddress (Irp->MdlAddress);
  919. ASSERT (u.acceptInfo32!=NULL);
  920. ASSERT (MmGetMdlByteCount (Irp->MdlAddress)>=sizeof (*u.acceptInfo32));
  921. }
  922. else
  923. #endif // _WIN64
  924. {
  925. u.acceptInfo = MmGetMdlVirtualAddress (Irp->MdlAddress);
  926. ASSERT (u.acceptInfo!=NULL);
  927. ASSERT (MmGetMdlByteCount (Irp->MdlAddress)>=sizeof (*u.acceptInfo));
  928. }
  929. //
  930. // Get the listening file object and verify its type and state
  931. //
  932. status = ObReferenceObjectByHandle (
  933. connectInfo->ListenHandle,
  934. (IrpSp->Parameters.DeviceIoControl.IoControlCode >> 14) & 3, // DesiredAccess
  935. *IoFileObjectType,
  936. Irp->RequestorMode,
  937. (PVOID)&listenFileObject,
  938. NULL);
  939. if (!NT_SUCCESS (status)) {
  940. goto complete;
  941. }
  942. if (IoGetRelatedDeviceObject (listenFileObject)!=AfdDeviceObject) {
  943. status = STATUS_INVALID_HANDLE;
  944. goto complete;
  945. }
  946. listenEndpoint = listenFileObject->FsContext;
  947. if ( !listenEndpoint->Listening ||
  948. listenEndpoint->State == AfdEndpointStateClosing ||
  949. listenEndpoint->EndpointCleanedUp ) {
  950. status = STATUS_INVALID_HANDLE;
  951. goto complete;
  952. }
  953. IF_DEBUG(SAN_SWITCH) {
  954. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  955. "AfdSanConnectHandler: endp-%p, irp-%p.\n",
  956. listenEndpoint,
  957. Irp));
  958. }
  959. if (!IS_DELAYED_ACCEPTANCE_ENDPOINT (listenEndpoint)) {
  960. //
  961. // Keep getting accept IRPs/connection structures till
  962. // we find one that can be used to satisfy connect indication
  963. // or queue it.
  964. //
  965. while ((connection = AfdGetFreeConnection( listenEndpoint, &acceptIrp ))!=NULL
  966. && acceptIrp!=NULL) {
  967. PAFD_ENDPOINT acceptEndpoint;
  968. PFILE_OBJECT acceptFileObject;
  969. PIO_STACK_LOCATION irpSp;
  970. IF_DEBUG(LISTEN) {
  971. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  972. "AfdSanConnectHandler: using connection %lx\n",
  973. connection ));
  974. }
  975. ASSERT( connection->Type == AfdBlockTypeConnection );
  976. irpSp = IoGetCurrentIrpStackLocation (acceptIrp);
  977. acceptFileObject = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdAcceptFileObject;
  978. acceptEndpoint = acceptFileObject->FsContext;
  979. ASSERT (IS_AFD_ENDPOINT_TYPE (acceptEndpoint));
  980. ASSERT (acceptIrp->Tail.Overlay.DriverContext[0] == connection);
  981. ASSERT (connection->Endpoint == NULL);
  982. InterlockedDecrement (
  983. &listenEndpoint->Common.VcListening.FailedConnectionAdds);
  984. InterlockedPushEntrySList (
  985. &listenEndpoint->Common.VcListening.FreeConnectionListHead,
  986. &connection->SListEntry
  987. );
  988. DEBUG connection = NULL;
  989. //
  990. // Make sure connection indication comes from current process.
  991. // (we do check it indirectly up above when validating the request.
  992. // This check is explicit).
  993. //
  994. if (IoThreadToProcess (Irp->Tail.Overlay.Thread)==IoGetCurrentProcess ()) {
  995. //
  996. // Check if super accept Irp has enough space for
  997. // the remote address
  998. //
  999. if( (ULONG)RemoteAddressLength <=
  1000. irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdRemoteAddressLength ) {
  1001. //
  1002. // Check if we have enough system PTE's to map
  1003. // the buffer.
  1004. //
  1005. status = AfdMapMdlChain (acceptIrp->MdlAddress);
  1006. if( NT_SUCCESS (status) ) {
  1007. HANDLE acceptHandle;
  1008. BOOLEAN handleDuplicated;
  1009. if (IoThreadToProcess (Irp->Tail.Overlay.Thread)==
  1010. IoThreadToProcess (acceptIrp->Tail.Overlay.Thread)) {
  1011. acceptHandle = acceptIrp->Tail.Overlay.DriverContext[3];
  1012. status = STATUS_SUCCESS;
  1013. handleDuplicated = FALSE;
  1014. }
  1015. else {
  1016. //
  1017. // Listen process is different than the accepting one.
  1018. // We need to duplicate accepting handle into the listening
  1019. // process so that accept can take place there and the accepting
  1020. // socket will later get dup-ed into the accepting process when
  1021. // that process performs an IO operation on it.
  1022. //
  1023. status = ObOpenObjectByPointer (
  1024. acceptFileObject,
  1025. OBJ_CASE_INSENSITIVE,
  1026. NULL,
  1027. MAXIMUM_ALLOWED,
  1028. *IoFileObjectType,
  1029. KernelMode,
  1030. &acceptHandle);
  1031. handleDuplicated = TRUE; // If we fail duplication above,
  1032. // this variable is not used
  1033. // so setting it to TRUE won't
  1034. // have any effect.
  1035. }
  1036. if (NT_SUCCESS (status)) {
  1037. AfdAcquireSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  1038. if (!acceptEndpoint->EndpointCleanedUp) {
  1039. IoSetCancelRoutine (acceptIrp, AfdSanCancelAccept);
  1040. if (!acceptIrp->Cancel) {
  1041. //
  1042. // Copy the remote address from the connection object
  1043. //
  1044. #ifndef i386
  1045. if (acceptEndpoint->Common.VcConnecting.FixAddressAlignment) {
  1046. USHORT addressLength =
  1047. connectInfo->RemoteAddress.Address[0].AddressLength
  1048. + sizeof (USHORT);
  1049. USHORT UNALIGNED *pAddrLength = (PVOID)
  1050. ((PUCHAR)MmGetSystemAddressForMdl (acceptIrp->MdlAddress)
  1051. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength
  1052. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength
  1053. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdRemoteAddressLength
  1054. - sizeof (USHORT));
  1055. RtlMoveMemory (
  1056. (PUCHAR)MmGetSystemAddressForMdl (acceptIrp->MdlAddress)
  1057. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength
  1058. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength,
  1059. &connectInfo->RemoteAddress.Address[0].AddressType,
  1060. addressLength);
  1061. *pAddrLength = addressLength;
  1062. }
  1063. else
  1064. #endif
  1065. {
  1066. RtlMoveMemory (
  1067. (PUCHAR)MmGetSystemAddressForMdl (acceptIrp->MdlAddress)
  1068. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength
  1069. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength,
  1070. &connectInfo->RemoteAddress,
  1071. RemoteAddressLength);
  1072. }
  1073. if (irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength>0) {
  1074. TDI_ADDRESS_INFO UNALIGNED *addressInfo = (PVOID)
  1075. ((PUCHAR)MmGetSystemAddressForMdl(acceptIrp->MdlAddress)
  1076. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength);
  1077. #ifndef i386
  1078. if (acceptEndpoint->Common.VcConnecting.FixAddressAlignment) {
  1079. USHORT UNALIGNED * pAddrLength = (PVOID)
  1080. ((PUCHAR)addressInfo
  1081. +irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength
  1082. -sizeof(USHORT));
  1083. RtlMoveMemory (
  1084. addressInfo,
  1085. &localAddress->AddressType,
  1086. localAddress->AddressLength+sizeof (USHORT));
  1087. *pAddrLength = localAddress->AddressLength+sizeof (USHORT);
  1088. }
  1089. else
  1090. #endif
  1091. {
  1092. addressInfo->ActivityCount = 0;
  1093. addressInfo->Address.TAAddressCount = 1;
  1094. RtlMoveMemory (
  1095. &addressInfo->Address.Address,
  1096. localAddress,
  1097. FIELD_OFFSET (TA_ADDRESS, Address[localAddress->AddressLength]));
  1098. }
  1099. }
  1100. ASSERT (acceptEndpoint->Irp==acceptIrp);
  1101. acceptEndpoint->Irp = NULL;
  1102. //
  1103. // Convert endpoint to SAN
  1104. //
  1105. AfdSanInitEndpoint (sanHlprEndpoint, acceptFileObject, connectInfo->SwitchContext);
  1106. UPDATE_ENDPOINT2 (acceptEndpoint,
  1107. "AfdSanConnectHandler, accepted with bytes: 0x%d",
  1108. irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength);
  1109. InsertTailList (&acceptEndpoint->Common.SanEndp.IrpList,
  1110. &acceptIrp->Tail.Overlay.ListEntry);
  1111. //
  1112. // Setup output for switch and complete its IRP
  1113. //
  1114. // Do this under protection of exception handler since application
  1115. // can change protection attributes of the virtual address range
  1116. // or even deallocate it.
  1117. try {
  1118. #ifdef _WIN64
  1119. if (IoIs32bitProcess (Irp)) {
  1120. u.acceptInfo32->AcceptHandle = (VOID * POINTER_32)acceptHandle;
  1121. u.acceptInfo32->ReceiveLength = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength;
  1122. Irp->IoStatus.Information = sizeof (*u.acceptInfo32);
  1123. }
  1124. else
  1125. #endif //_WIN64
  1126. {
  1127. u.acceptInfo->AcceptHandle = acceptHandle;
  1128. u.acceptInfo->ReceiveLength = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength;
  1129. Irp->IoStatus.Information = sizeof (*u.acceptInfo);
  1130. }
  1131. }
  1132. except (AFD_EXCEPTION_FILTER_NO_STATUS()) {
  1133. //
  1134. // If the app is playing with switch's virtual addresses
  1135. // we can't help much - it's accept IRP will probably
  1136. // just hang since the switch is not going to follow
  1137. // the failed connect IRP with accept completion.
  1138. //
  1139. }
  1140. AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  1141. AfdRecordConnectionsPreaccepted ();
  1142. Irp->IoStatus.Status = STATUS_SUCCESS;
  1143. IoCompleteRequest (Irp, AfdPriorityBoost);
  1144. ObDereferenceObject (listenFileObject);
  1145. IF_DEBUG(SAN_SWITCH) {
  1146. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1147. "AfdSanConnectHandler: pre-accepted, endp-%p, SuperAccept irp-%p\n",
  1148. acceptEndpoint, acceptIrp));
  1149. }
  1150. return STATUS_SUCCESS;
  1151. }
  1152. else { //if (!acceptIrp->Cancel
  1153. if (IoSetCancelRoutine (acceptIrp, NULL)==NULL) {
  1154. KIRQL cancelIrql;
  1155. AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  1156. IoAcquireCancelSpinLock (&cancelIrql);
  1157. IoReleaseCancelSpinLock (cancelIrql);
  1158. }
  1159. else {
  1160. AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  1161. }
  1162. }
  1163. }
  1164. else { // if (!acceptEndpoint->EndpointCleanedUp)
  1165. AfdReleaseSpinLock (&acceptEndpoint->SpinLock, &lockHandle);
  1166. IF_DEBUG(SAN_SWITCH) {
  1167. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1168. "AfdSanConnectHandler: accept endpoint cleanedup. endp=%lx",
  1169. acceptEndpoint));
  1170. }
  1171. }
  1172. if (handleDuplicated) {
  1173. #if DBG
  1174. status =
  1175. #endif
  1176. NtClose (acceptHandle);
  1177. }
  1178. ASSERT (NT_SUCCESS (status));
  1179. status = STATUS_CANCELLED;
  1180. } // if (!accept handle duplication succeeded)
  1181. } // if (!MDL mapping succeeded).
  1182. }
  1183. else {
  1184. status = STATUS_BUFFER_TOO_SMALL;
  1185. }
  1186. }
  1187. else {
  1188. status = STATUS_INVALID_HANDLE;
  1189. }
  1190. UPDATE_ENDPOINT2 (acceptEndpoint,
  1191. "AfdSanConnectHandler, Superaccept failed with status: 0x%lX",
  1192. status);
  1193. AfdCleanupSuperAccept (acceptIrp, status);
  1194. IoCompleteRequest (acceptIrp, AfdPriorityBoost);
  1195. }
  1196. }
  1197. else {
  1198. //
  1199. // We have little choice but create an extra connection
  1200. // on the fly since regular connection are posted to
  1201. // the transport as TDI_LISTENs.
  1202. //
  1203. status = AfdCreateConnection(
  1204. listenEndpoint->TransportInfo,
  1205. listenEndpoint->AddressHandle,
  1206. IS_TDI_BUFFERRING(listenEndpoint),
  1207. listenEndpoint->InLine,
  1208. listenEndpoint->OwningProcess,
  1209. &connection
  1210. );
  1211. if (!NT_SUCCESS (status)) {
  1212. goto complete;
  1213. }
  1214. InterlockedDecrement (
  1215. &listenEndpoint->Common.VcListening.FailedConnectionAdds);
  1216. }
  1217. if (connection!=NULL) {
  1218. LIST_ENTRY irpList;
  1219. ASSERT (connection->Endpoint == NULL);
  1220. if ( connection->RemoteAddress != NULL &&
  1221. connection->RemoteAddressLength < (ULONG)RemoteAddressLength ) {
  1222. AFD_RETURN_REMOTE_ADDRESS(
  1223. connection->RemoteAddress,
  1224. connection->RemoteAddressLength
  1225. );
  1226. connection->RemoteAddress = NULL;
  1227. }
  1228. if ( connection->RemoteAddress == NULL ) {
  1229. connection->RemoteAddress = AFD_ALLOCATE_REMOTE_ADDRESS (RemoteAddressLength);
  1230. if (connection->RemoteAddress==NULL) {
  1231. AfdSanReleaseConnection (listenEndpoint, connection, TRUE);
  1232. status = STATUS_INSUFFICIENT_RESOURCES;
  1233. goto complete;
  1234. }
  1235. }
  1236. connection->RemoteAddressLength = RemoteAddressLength;
  1237. RtlMoveMemory(
  1238. connection->RemoteAddress,
  1239. &connectInfo->RemoteAddress,
  1240. RemoteAddressLength
  1241. );
  1242. //
  1243. // We just got a connection without AcceptEx IRP
  1244. // We'll have to queue the IRP, setup cancel routine and pend it
  1245. //
  1246. AfdAcquireSpinLock (&listenEndpoint->SpinLock, &lockHandle);
  1247. //
  1248. // Setup the connection, so cancel routine can
  1249. // operate on it properly.
  1250. //
  1251. connection->ConnectIrp = NULL;
  1252. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = connection;
  1253. IoSetCancelRoutine (Irp, AfdSanCancelConnect);
  1254. if (Irp->Cancel) {
  1255. if (IoSetCancelRoutine (Irp, NULL)==NULL) {
  1256. KIRQL cancelIrql;
  1257. AfdReleaseSpinLock (&listenEndpoint->SpinLock, &lockHandle);
  1258. //
  1259. // Cancel routine is running, let it complete
  1260. //
  1261. IoAcquireCancelSpinLock (&cancelIrql);
  1262. IoReleaseCancelSpinLock (cancelIrql);
  1263. }
  1264. else {
  1265. AfdReleaseSpinLock (&listenEndpoint->SpinLock, &lockHandle);
  1266. }
  1267. AfdSanReleaseConnection (listenEndpoint, connection, TRUE);
  1268. status = STATUS_CANCELLED;
  1269. goto complete;
  1270. }
  1271. IoMarkIrpPending (Irp);
  1272. connection->Endpoint = listenEndpoint;
  1273. REFERENCE_ENDPOINT (listenEndpoint);
  1274. connection->ConnectIrp = Irp;
  1275. connection->SanConnection = TRUE;
  1276. connection->State = AfdConnectionStateUnaccepted;
  1277. InitializeListHead (&irpList);
  1278. //
  1279. // Try to find AcceptEx or Listen IRP to complete.
  1280. //
  1281. while (1) {
  1282. PIRP waitForListenIrp;
  1283. if (!IS_DELAYED_ACCEPTANCE_ENDPOINT (listenEndpoint)) {
  1284. if (AfdServiceSuperAccept (listenEndpoint, connection, &lockHandle, &irpList)) {
  1285. goto CompleteIrps;
  1286. }
  1287. }
  1288. //
  1289. // Complete listen IRPs until we find the one that has enough space
  1290. // for the remote address.
  1291. //
  1292. if (IsListEmpty( &listenEndpoint->Common.VcListening.ListeningIrpListHead ) )
  1293. break;
  1294. //
  1295. // Get a pointer to the current IRP, and get a pointer to the
  1296. // current stack lockation.
  1297. //
  1298. waitForListenIrp = CONTAINING_RECORD(
  1299. listenEndpoint->Common.VcListening.ListeningIrpListHead.Flink,
  1300. IRP,
  1301. Tail.Overlay.ListEntry
  1302. );
  1303. //
  1304. // Take the first IRP off the listening list.
  1305. //
  1306. RemoveEntryList(
  1307. &waitForListenIrp->Tail.Overlay.ListEntry
  1308. );
  1309. waitForListenIrp->Tail.Overlay.ListEntry.Flink = NULL;
  1310. IF_DEBUG(SAN_SWITCH) {
  1311. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1312. "AfdSanConnectHandler: completing IRP %lx\n",
  1313. waitForListenIrp ));
  1314. }
  1315. status = AfdServiceWaitForListen (waitForListenIrp,
  1316. connection,
  1317. &lockHandle);
  1318. if (NT_SUCCESS (status)) {
  1319. ObDereferenceObject (listenFileObject);
  1320. return STATUS_PENDING;
  1321. }
  1322. //
  1323. // Synchronize with cancel routine if it is running
  1324. //
  1325. if (IoSetCancelRoutine (waitForListenIrp, NULL)==NULL) {
  1326. KIRQL cancelIrql;
  1327. //
  1328. // The cancel routine won't find the IRP on the list
  1329. // Just make sure it completes before we complete the IRP.
  1330. //
  1331. IoAcquireCancelSpinLock (&cancelIrql);
  1332. IoReleaseCancelSpinLock (cancelIrql);
  1333. }
  1334. IoCompleteRequest (waitForListenIrp, AfdPriorityBoost);
  1335. AfdAcquireSpinLock (&listenEndpoint->SpinLock, &lockHandle);
  1336. }
  1337. //
  1338. // At this point, we still hold the AFD spinlock.
  1339. // and we could find matching listen request.
  1340. // Put the connection on unaccepted list.
  1341. //
  1342. InsertTailList(
  1343. &listenEndpoint->Common.VcListening.UnacceptedConnectionListHead,
  1344. &connection->ListEntry
  1345. );
  1346. IF_DEBUG(SAN_SWITCH) {
  1347. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1348. "AfdSanConnectHandler: unaccepted, conn-%p\n",
  1349. connection));
  1350. }
  1351. //
  1352. // Listening endpoint is never a specifically SAN endpoint.
  1353. // Poll/EventSelect events on it are handled like on a regular
  1354. // TCP/IP endpoint - no need for special tricks like on connected/accepted
  1355. // endpoints.
  1356. //
  1357. AfdIndicateEventSelectEvent(
  1358. listenEndpoint,
  1359. AFD_POLL_ACCEPT,
  1360. STATUS_SUCCESS
  1361. );
  1362. AfdReleaseSpinLock (&listenEndpoint->SpinLock, &lockHandle);
  1363. //
  1364. // If there are outstanding polls waiting for a connection on this
  1365. // endpoint, complete them.
  1366. //
  1367. AfdIndicatePollEvent(
  1368. listenEndpoint,
  1369. AFD_POLL_ACCEPT,
  1370. STATUS_SUCCESS
  1371. );
  1372. CompleteIrps:
  1373. //
  1374. // Complete previously failed accept irps if any.
  1375. //
  1376. while (!IsListEmpty (&irpList)) {
  1377. PIRP irp;
  1378. irp = CONTAINING_RECORD (irpList.Flink, IRP, Tail.Overlay.ListEntry);
  1379. RemoveEntryList (&irp->Tail.Overlay.ListEntry);
  1380. IoCompleteRequest (irp, AfdPriorityBoost);
  1381. }
  1382. ObDereferenceObject (listenFileObject);
  1383. return STATUS_PENDING;
  1384. }
  1385. else {
  1386. status = STATUS_INSUFFICIENT_RESOURCES;
  1387. }
  1388. UPDATE_ENDPOINT2 (listenEndpoint,
  1389. "AfdSanConnectHandler, accept failed with status: 0x%lX",
  1390. status);
  1391. complete:
  1392. if (listenFileObject!=NULL) {
  1393. ObDereferenceObject (listenFileObject);
  1394. }
  1395. Irp->IoStatus.Status = status;
  1396. IoCompleteRequest (Irp, AfdPriorityBoost);
  1397. return status;
  1398. }
  1399. NTSTATUS
  1400. AfdSanFastCompleteAccept (
  1401. IN PFILE_OBJECT FileObject,
  1402. IN ULONG IoctlCode,
  1403. IN KPROCESSOR_MODE RequestorMode,
  1404. IN PVOID InputBuffer,
  1405. IN ULONG InputBufferLength,
  1406. IN PVOID OutputBuffer,
  1407. IN ULONG OutputBufferLength,
  1408. OUT PULONG_PTR Information
  1409. )
  1410. /*++
  1411. Routine Description:
  1412. Completes the Accept operation initiated by the SAN provider
  1413. Arguments:
  1414. FileObject - SAN helper object - communication channel between the
  1415. switch and AFD in the process.
  1416. IoctlCode - operation IOCTL code (IOCTL_AFD_SWITCH_CMPL_ACCEPT)
  1417. RequestorMode - mode of the caller
  1418. InputBuffer - input parameters for the operation (AFD_SWITCH_CONTEXT_INFO)
  1419. SocketHandle - handle of the accepting endpoint
  1420. SwitchContext - switch context associated with the endpoint
  1421. InputBufferLength - sizeof(AFD_SWITCH_CONTEXT_INFO)
  1422. OutputBuffer - data to copy into the AcceptEx receive buffer
  1423. OutputBufferLength - size of received data
  1424. Information - pointer for buffer to place return information into, unused
  1425. Return Value:
  1426. STATUS_SUCCESS - operation succeeded
  1427. STATUS_INVALID_HANDLE - helper endpoint or switch socket is of incorrect type
  1428. STATUS_INVALID_PARAMETER - input buffer is of incorrect size.
  1429. STATIS_LOCAL_DISCONNECT - accept was aborted by the application.
  1430. other - failed when attempting to access accept socket, input buffer, or switch context.
  1431. --*/
  1432. {
  1433. NTSTATUS status;
  1434. PIRP acceptIrp;
  1435. AFD_LOCK_QUEUE_HANDLE lockHandle;
  1436. PFILE_OBJECT sanFileObject;
  1437. AFD_SWITCH_CONTEXT_INFO contextInfo;
  1438. PAFD_ENDPOINT sanEndpoint, sanHlprEndpoint;
  1439. PVOID context;
  1440. *Information = 0;
  1441. AFD_W4_INIT status = STATUS_SUCCESS;
  1442. try {
  1443. #ifdef _WIN64
  1444. if (IoIs32bitProcess (NULL)) {
  1445. PAFD_SWITCH_CONTEXT_INFO32 contextInfo32;
  1446. if (InputBufferLength<sizeof (*contextInfo32)) {
  1447. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  1448. }
  1449. if (RequestorMode!=KernelMode) {
  1450. ProbeForReadSmallStructure (InputBuffer,
  1451. sizeof (*contextInfo32),
  1452. PROBE_ALIGNMENT32 (AFD_SWITCH_CONTEXT_INFO32));
  1453. }
  1454. contextInfo32 = InputBuffer;
  1455. contextInfo.SocketHandle = contextInfo32->SocketHandle;
  1456. contextInfo.SwitchContext = UlongToPtr(contextInfo32->SwitchContext);
  1457. }
  1458. else
  1459. #endif _WIN64
  1460. {
  1461. if (InputBufferLength<sizeof (contextInfo)) {
  1462. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  1463. }
  1464. if (RequestorMode!=KernelMode) {
  1465. ProbeForReadSmallStructure (InputBuffer,
  1466. sizeof (contextInfo),
  1467. PROBE_ALIGNMENT (AFD_SWITCH_CONTEXT_INFO));
  1468. }
  1469. contextInfo = *((PAFD_SWITCH_CONTEXT_INFO)InputBuffer);
  1470. }
  1471. if (contextInfo.SwitchContext==NULL) {
  1472. IF_DEBUG(SAN_SWITCH) {
  1473. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1474. "AFD: Switch context is NULL in AfdSanFastCompleteAccept\n"));
  1475. }
  1476. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  1477. }
  1478. if (RequestorMode!=KernelMode) {
  1479. ProbeForWrite (contextInfo.SwitchContext,
  1480. sizeof (*contextInfo.SwitchContext),
  1481. PROBE_ALIGNMENT (AFD_SWITCH_CONTEXT));
  1482. }
  1483. }
  1484. except (AFD_EXCEPTION_FILTER (status)) {
  1485. ASSERT (NT_ERROR (status));
  1486. return status;
  1487. }
  1488. sanHlprEndpoint = FileObject->FsContext;
  1489. ASSERT (IS_SAN_HELPER (sanHlprEndpoint));
  1490. status = AfdSanReferenceSwitchSocketByHandle (
  1491. contextInfo.SocketHandle,
  1492. (IoctlCode>>14)&3,
  1493. RequestorMode,
  1494. sanHlprEndpoint,
  1495. contextInfo.SwitchContext,
  1496. &sanFileObject
  1497. );
  1498. if (!NT_SUCCESS (status)) {
  1499. return status;
  1500. }
  1501. sanEndpoint = sanFileObject->FsContext;
  1502. //
  1503. // Make sure that endpoints are of correct type
  1504. //
  1505. context = AfdLockEndpointContext (sanEndpoint);
  1506. AfdAcquireSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  1507. if (!sanEndpoint->EndpointCleanedUp &&
  1508. sanEndpoint->State==AfdEndpointStateOpen) {
  1509. //
  1510. // See if accept IRP is still there
  1511. //
  1512. if (!IsListEmpty (&sanEndpoint->Common.SanEndp.IrpList)) {
  1513. AFD_SWITCH_CONTEXT localContext = {0,0,0,0};
  1514. acceptIrp = CONTAINING_RECORD (
  1515. sanEndpoint->Common.SanEndp.IrpList.Flink,
  1516. IRP,
  1517. Tail.Overlay.ListEntry);
  1518. RemoveEntryList (&acceptIrp->Tail.Overlay.ListEntry);
  1519. acceptIrp->Tail.Overlay.ListEntry.Flink = NULL;
  1520. sanEndpoint->Common.SanEndp.SelectEventsActive = AFD_POLL_SEND;
  1521. sanEndpoint->State = AfdEndpointStateConnected;
  1522. sanEndpoint->DisableFastIoSend = TRUE;
  1523. sanEndpoint->DisableFastIoRecv = TRUE;
  1524. sanEndpoint->EnableSendEvent = TRUE;
  1525. ASSERT (sanEndpoint->Common.SanEndp.LocalContext==NULL);
  1526. sanEndpoint->Common.SanEndp.LocalContext = &localContext;
  1527. AFD_END_STATE_CHANGE (sanEndpoint);
  1528. AfdIndicateEventSelectEvent (sanEndpoint, AFD_POLL_SEND, STATUS_SUCCESS);
  1529. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  1530. AfdIndicatePollEvent (sanEndpoint, AFD_POLL_SEND, STATUS_SUCCESS);
  1531. status = AfdSanPollMerge (sanEndpoint, &localContext);
  1532. sanEndpoint->Common.SanEndp.LocalContext = NULL;
  1533. IF_DEBUG(SAN_SWITCH) {
  1534. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1535. "AfdFastSanCompleteAccept: endp-%p, irp-%p\n",
  1536. sanEndpoint,
  1537. acceptIrp));
  1538. }
  1539. if (IoSetCancelRoutine (acceptIrp, NULL)==NULL) {
  1540. KIRQL cancelIrql;
  1541. //
  1542. // Irp is being cancelled, sync up with cancel routine
  1543. //
  1544. IoAcquireCancelSpinLock (&cancelIrql);
  1545. IoReleaseCancelSpinLock (cancelIrql);
  1546. }
  1547. //
  1548. // Copy receive data if passed and IRP has buffer for it
  1549. //
  1550. if ((OutputBufferLength>0) && (acceptIrp->MdlAddress!=NULL)) {
  1551. AFD_W4_INIT ASSERT (status == STATUS_SUCCESS);
  1552. try {
  1553. ULONG bytesCopied;
  1554. NTSTATUS tdiStatus;
  1555. tdiStatus = TdiCopyBufferToMdl (
  1556. OutputBuffer,
  1557. 0,
  1558. OutputBufferLength,
  1559. acceptIrp->MdlAddress,
  1560. 0,
  1561. &bytesCopied);
  1562. ASSERT (NT_SUCCESS (tdiStatus));
  1563. *Information = bytesCopied;
  1564. acceptIrp->IoStatus.Information = bytesCopied;
  1565. }
  1566. except (AFD_EXCEPTION_FILTER (status)) {
  1567. ASSERT (NT_ERROR (status));
  1568. //
  1569. // Even if copy failed, we still have to complete
  1570. // the accept IRP because we have already removed
  1571. // cancel routine and modified endpoint state.
  1572. //
  1573. }
  1574. }
  1575. else {
  1576. acceptIrp->IoStatus.Information = 0;
  1577. }
  1578. acceptIrp->IoStatus.Status = status;
  1579. //
  1580. // Complete the accept IRP.
  1581. //
  1582. IoCompleteRequest (acceptIrp, AfdPriorityBoost);
  1583. //
  1584. // undo the references done in AfdAcceptCore()
  1585. //
  1586. ASSERT( InterlockedDecrement( &sanEndpoint->ObReferenceBias ) >= 0 );
  1587. ObDereferenceObject (sanFileObject);
  1588. }
  1589. else {
  1590. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  1591. status = STATUS_LOCAL_DISCONNECT;
  1592. }
  1593. }
  1594. else {
  1595. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  1596. status = STATUS_INVALID_HANDLE;
  1597. }
  1598. AfdUnlockEndpointContext (sanEndpoint, context);
  1599. UPDATE_ENDPOINT2 (sanEndpoint, "AfdSanFastCompletAccept, status: %lX", status);
  1600. ObDereferenceObject (sanFileObject); // undo reference we did earlier in this routine
  1601. return status;
  1602. }
  1603. //
  1604. // Macros to make request/context passing code readable.
  1605. //
  1606. #define AfdSanRequestInfo Tail.Overlay
  1607. #define AfdSanRequestCtx DriverContext[0]
  1608. #define AfdSanSwitchCtx DriverContext[1]
  1609. #define AfdSanProcessId DriverContext[2]
  1610. #define AfdSanHelperEndp DriverContext[3]
  1611. NTSTATUS
  1612. FASTCALL
  1613. AfdSanRedirectRequest (
  1614. IN PIRP Irp,
  1615. IN PIO_STACK_LOCATION IrpSp
  1616. )
  1617. /*++
  1618. Routine Description:
  1619. Redirects file system Read/Write IRP to SAN provider
  1620. Arguments:
  1621. Irp - the to be redirected.
  1622. IrpSp - current stack location
  1623. Return Value:
  1624. Status of the redirect operation.
  1625. --*/
  1626. {
  1627. PAFD_ENDPOINT sanEndpoint;
  1628. NTSTATUS status;
  1629. AFD_LOCK_QUEUE_HANDLE lockHandle;
  1630. ULONG_PTR requestInfo;
  1631. ULONG requestType;
  1632. PVOID requestCtx;
  1633. BOOLEAN postRequest;
  1634. Irp->IoStatus.Information = 0;
  1635. //
  1636. // Get the endpoint and validate it.
  1637. //
  1638. sanEndpoint = IrpSp->FileObject->FsContext;
  1639. //
  1640. // Make sure Irp has not been cancelled meanwhile
  1641. //
  1642. AfdAcquireSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  1643. if (!IS_SAN_ENDPOINT (sanEndpoint) ||
  1644. sanEndpoint->State!=AfdEndpointStateConnected) {
  1645. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  1646. status = STATUS_INVALID_CONNECTION;
  1647. goto complete;
  1648. }
  1649. if (sanEndpoint->Common.SanEndp.CtxTransferStatus!=STATUS_PENDING &&
  1650. sanEndpoint->Common.SanEndp.CtxTransferStatus!=STATUS_MORE_PROCESSING_REQUIRED) {
  1651. if (!NT_SUCCESS (sanEndpoint->Common.SanEndp.CtxTransferStatus)) {
  1652. status = sanEndpoint->Common.SanEndp.CtxTransferStatus;
  1653. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  1654. goto complete;
  1655. }
  1656. //
  1657. // Get the request information based on IRP MJ code
  1658. //
  1659. switch (IrpSp->MajorFunction) {
  1660. case IRP_MJ_READ:
  1661. requestType = AFD_SWITCH_REQUEST_READ;
  1662. requestInfo = IrpSp->Parameters.Read.Length;
  1663. break;
  1664. case IRP_MJ_WRITE:
  1665. requestType = AFD_SWITCH_REQUEST_WRITE;
  1666. requestInfo = IrpSp->Parameters.Write.Length;
  1667. break;
  1668. default:
  1669. ASSERT (!"Unsupported IRP Major Function");
  1670. status = STATUS_INVALID_DEVICE_REQUEST;
  1671. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  1672. goto complete;
  1673. }
  1674. //
  1675. // Generate request context that uniquely identifies
  1676. // it among other requests on the same endpoint.
  1677. //
  1678. requestCtx = AFD_SWITCH_MAKE_REQUEST_CONTEXT(
  1679. sanEndpoint->Common.SanEndp.RequestId,
  1680. requestType);
  1681. sanEndpoint->Common.SanEndp.RequestId += 1;
  1682. //
  1683. // Store the request context in the Irp and insert it into
  1684. // the list
  1685. //
  1686. Irp->AfdSanRequestInfo.AfdSanRequestCtx = requestCtx;
  1687. postRequest = TRUE;
  1688. UPDATE_ENDPOINT2 (sanEndpoint,
  1689. "AfdSanRedirectRequest, pended request: 0x%lX",
  1690. PtrToUlong (requestCtx));
  1691. }
  1692. else {
  1693. postRequest = FALSE;
  1694. AFD_W4_INIT requestInfo = 0; // Depend on variable above, but compiler
  1695. AFD_W4_INIT requestCtx = NULL;// does not see the connection.
  1696. Irp->AfdSanRequestInfo.AfdSanRequestCtx = NULL;
  1697. UPDATE_ENDPOINT2 (sanEndpoint,
  1698. "AfdSanRedirectRequest, request suspended due to pending dup: 0x%lX",
  1699. PtrToUlong (Irp));
  1700. }
  1701. IoSetCancelRoutine (Irp, AfdSanCancelRequest);
  1702. if (Irp->Cancel) {
  1703. //
  1704. // Oops, let it go
  1705. //
  1706. Irp->Tail.Overlay.ListEntry.Flink = NULL;
  1707. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  1708. if (IoSetCancelRoutine (Irp, NULL)==NULL) {
  1709. KIRQL cancelIrql;
  1710. //
  1711. // Cancel routine must be running, make sure
  1712. // it complete before we complete the IRP
  1713. //
  1714. IoAcquireCancelSpinLock (&cancelIrql);
  1715. IoReleaseCancelSpinLock (cancelIrql);
  1716. }
  1717. status = STATUS_CANCELLED;
  1718. goto complete;
  1719. }
  1720. //
  1721. // We are going to pend this IRP, mark it so
  1722. //
  1723. IoMarkIrpPending (Irp);
  1724. InsertTailList (&sanEndpoint->Common.SanEndp.IrpList,
  1725. &Irp->Tail.Overlay.ListEntry);
  1726. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  1727. IF_DEBUG(SAN_SWITCH) {
  1728. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1729. "AfdSanRedirectRequest: endp-%p, irp-%p, context-%p\n",
  1730. sanEndpoint, Irp, requestCtx));
  1731. }
  1732. if (postRequest) {
  1733. status = AfdSanNotifyRequest (sanEndpoint, requestCtx, STATUS_SUCCESS, requestInfo);
  1734. if (!NT_SUCCESS (status)) {
  1735. PIRP irp;
  1736. //
  1737. // If notification failed, fail the request.
  1738. // Note that we cannot return the failure status directly
  1739. // as we already marked IRP as pending. Also, the IRP
  1740. // could have been cancelled, so we have to search for
  1741. // it in the list.
  1742. //
  1743. irp = AfdSanDequeueRequest (sanEndpoint, requestCtx);
  1744. if (irp!=NULL) {
  1745. ASSERT (irp==Irp);
  1746. irp->IoStatus.Status = status;
  1747. IoCompleteRequest (irp, AfdPriorityBoost);
  1748. }
  1749. }
  1750. }
  1751. return STATUS_PENDING;
  1752. complete:
  1753. //
  1754. // Failure before we queued the IRP, complete and return
  1755. // status to the caller.
  1756. //
  1757. Irp->IoStatus.Status = status;
  1758. IoCompleteRequest (Irp, AfdPriorityBoost);
  1759. return status;
  1760. }
  1761. NTSTATUS
  1762. AfdSanFastCompleteRequest (
  1763. IN PFILE_OBJECT FileObject,
  1764. IN ULONG IoctlCode,
  1765. IN KPROCESSOR_MODE RequestorMode,
  1766. IN PVOID InputBuffer,
  1767. IN ULONG InputBufferLength,
  1768. IN PVOID OutputBuffer,
  1769. IN ULONG OutputBufferLength,
  1770. OUT PULONG_PTR Information
  1771. )
  1772. /*++
  1773. Routine Description:
  1774. Completes the redirected read/write request processed by SAN provider
  1775. Arguments:
  1776. FileObject - SAN helper object - communication channel between the
  1777. switch and AFD in the process.
  1778. IoctlCode - operation IOCTL code (IOCTL_AFD_SWITCH_CMPL_ACCEPT)
  1779. RequestorMode - mode of the caller
  1780. InputBuffer - input parameters for the operation (AFD_SWITCH_REQUEST_INFO)
  1781. SocketHandle - SAN endpoint on which to complete the request
  1782. SwitchContext - switch context associated with endpoint
  1783. to validate the handle-endpoint association
  1784. RequestContext - value that identifies the request to complete
  1785. RequestStatus - status with which to complete the request (
  1786. STATUS_PENDING has special meaning, request
  1787. is not completed - merely data is copied)
  1788. DataOffset - offset in the request buffer to read/write the data
  1789. InputBufferLength - sizeof (AFD_SWITCH_REQUEST_INFO)
  1790. OutputBuffer - switch buffer to read/write data
  1791. OutputBufferLength - length of the buffer
  1792. Information - pointer to buffer to return number of bytes copied
  1793. Return Value:
  1794. STATUS_SUCCESS - operation succeeded
  1795. STATUS_INVALID_HANDLE - helper or SAN endpoint is of incorrect type
  1796. STATUS_INVALID_PARAMETER - input buffer is of incorrect size.
  1797. STATUS_CANCELLED - request to be completed has already been cancelled
  1798. other - failed when attempting to access SAN endpoint, input buffer or output buffers.
  1799. --*/
  1800. {
  1801. NTSTATUS status;
  1802. PIO_STACK_LOCATION irpSp;
  1803. PIRP irp;
  1804. ULONG bytesCopied;
  1805. AFD_LOCK_QUEUE_HANDLE lockHandle;
  1806. PFILE_OBJECT sanFileObject;
  1807. AFD_SWITCH_REQUEST_INFO requestInfo;
  1808. PAFD_ENDPOINT sanEndpoint, sanHlprEndpoint;
  1809. *Information = 0;
  1810. AFD_W4_INIT status = STATUS_SUCCESS;
  1811. try {
  1812. #ifdef _WIN64
  1813. if (IoIs32bitProcess (NULL)) {
  1814. PAFD_SWITCH_REQUEST_INFO32 requestInfo32;
  1815. if (InputBufferLength<sizeof (*requestInfo32)) {
  1816. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  1817. }
  1818. if (RequestorMode!=KernelMode) {
  1819. ProbeForReadSmallStructure (InputBuffer,
  1820. sizeof (*requestInfo32),
  1821. PROBE_ALIGNMENT32 (AFD_SWITCH_REQUEST_INFO32));
  1822. }
  1823. requestInfo32 = InputBuffer;
  1824. requestInfo.SocketHandle = requestInfo32->SocketHandle;
  1825. requestInfo.SwitchContext = UlongToPtr(requestInfo32->SwitchContext);
  1826. requestInfo.RequestContext = UlongToPtr(requestInfo32->RequestContext);
  1827. requestInfo.RequestStatus = requestInfo32->RequestStatus;
  1828. requestInfo.DataOffset = requestInfo32->DataOffset;
  1829. }
  1830. else
  1831. #endif _WIN64
  1832. {
  1833. if (InputBufferLength<sizeof (requestInfo)) {
  1834. return STATUS_INVALID_PARAMETER;
  1835. }
  1836. if (RequestorMode!=KernelMode) {
  1837. ProbeForReadSmallStructure (InputBuffer,
  1838. sizeof (requestInfo),
  1839. PROBE_ALIGNMENT (AFD_SWITCH_REQUEST_INFO));
  1840. }
  1841. requestInfo = *((PAFD_SWITCH_REQUEST_INFO)InputBuffer);
  1842. }
  1843. if (requestInfo.SwitchContext==NULL) {
  1844. IF_DEBUG(SAN_SWITCH) {
  1845. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1846. "AFD: Switch context is NULL in AfdSanFastCompleteRequest\n"));
  1847. }
  1848. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  1849. }
  1850. }
  1851. except (AFD_EXCEPTION_FILTER (status)) {
  1852. ASSERT (NT_ERROR (status));
  1853. return status;
  1854. }
  1855. sanHlprEndpoint = FileObject->FsContext;
  1856. ASSERT (IS_SAN_HELPER (sanHlprEndpoint));
  1857. status = AfdSanReferenceSwitchSocketByHandle (
  1858. requestInfo.SocketHandle,
  1859. (IoctlCode>>14)&3,
  1860. RequestorMode,
  1861. sanHlprEndpoint,
  1862. requestInfo.SwitchContext,
  1863. &sanFileObject
  1864. );
  1865. if (!NT_SUCCESS (status)) {
  1866. return status;
  1867. }
  1868. sanEndpoint = sanFileObject->FsContext;
  1869. //
  1870. // Find and dequeue the request in question
  1871. //
  1872. irp = AfdSanDequeueRequest (sanEndpoint, requestInfo.RequestContext);
  1873. if (irp!=NULL) {
  1874. IF_DEBUG(SAN_SWITCH) {
  1875. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1876. "AfdSanFastCompleteRequest: endp-%p, irp-%p, context-%p, status-%lx\n",
  1877. sanEndpoint, irp,
  1878. requestInfo.RequestContext,
  1879. requestInfo.RequestStatus));
  1880. }
  1881. //
  1882. // Expect the operation to succeed
  1883. //
  1884. AFD_W4_INIT ASSERT (status == STATUS_SUCCESS);
  1885. //
  1886. // Get IRP stack location and perform data copy
  1887. //
  1888. irpSp = IoGetCurrentIrpStackLocation (irp);
  1889. switch (irpSp->MajorFunction) {
  1890. case IRP_MJ_READ:
  1891. //
  1892. // Read request, data is copied from switch buffer
  1893. // to the request MDL
  1894. //
  1895. ASSERT (AFD_SWITCH_REQUEST_TYPE(requestInfo.RequestContext)==AFD_SWITCH_REQUEST_READ);
  1896. if (NT_SUCCESS (requestInfo.RequestStatus)) {
  1897. if (irp->MdlAddress!=NULL &&
  1898. MmGetMdlByteCount (irp->MdlAddress)>requestInfo.DataOffset) {
  1899. try {
  1900. if (RequestorMode!=KernelMode) {
  1901. ProbeForRead (OutputBuffer,
  1902. OutputBufferLength,
  1903. sizeof (UCHAR));
  1904. }
  1905. status = TdiCopyBufferToMdl (
  1906. OutputBuffer,
  1907. 0,
  1908. OutputBufferLength,
  1909. irp->MdlAddress,
  1910. requestInfo.DataOffset,
  1911. &bytesCopied
  1912. );
  1913. *Information = bytesCopied;
  1914. ASSERT (irp->IoStatus.Information==requestInfo.DataOffset);
  1915. irp->IoStatus.Information += bytesCopied;
  1916. }
  1917. except (AFD_EXCEPTION_FILTER (status)) {
  1918. ASSERT (NT_ERROR (status));
  1919. }
  1920. }
  1921. else if (irp->MdlAddress==NULL &&
  1922. requestInfo.DataOffset==0 &&
  1923. OutputBufferLength==0) {
  1924. ASSERT (irp->IoStatus.Information==0);
  1925. ASSERT (status==STATUS_SUCCESS);
  1926. }
  1927. else {
  1928. //
  1929. // Indicate to the switch that offset
  1930. // is outside of the buffer
  1931. //
  1932. status = STATUS_INVALID_PARAMETER;
  1933. }
  1934. }
  1935. break;
  1936. case IRP_MJ_WRITE:
  1937. //
  1938. // Write request, data is copied to switch buffer
  1939. // from the request MDL
  1940. //
  1941. ASSERT (AFD_SWITCH_REQUEST_TYPE(requestInfo.RequestContext)==AFD_SWITCH_REQUEST_WRITE);
  1942. if (NT_SUCCESS (requestInfo.RequestStatus)) {
  1943. if (irp->MdlAddress!=NULL &&
  1944. MmGetMdlByteCount (irp->MdlAddress)>requestInfo.DataOffset) {
  1945. try {
  1946. if (RequestorMode!=KernelMode) {
  1947. ProbeForWrite (OutputBuffer,
  1948. OutputBufferLength,
  1949. sizeof (UCHAR));
  1950. }
  1951. status = TdiCopyMdlToBuffer (
  1952. irp->MdlAddress,
  1953. requestInfo.DataOffset,
  1954. OutputBuffer,
  1955. 0,
  1956. OutputBufferLength,
  1957. &bytesCopied
  1958. );
  1959. *Information = bytesCopied;
  1960. ASSERT (irp->IoStatus.Information==requestInfo.DataOffset);
  1961. irp->IoStatus.Information += bytesCopied;
  1962. }
  1963. except (AFD_EXCEPTION_FILTER (status)) {
  1964. ASSERT (NT_ERROR (status));
  1965. }
  1966. }
  1967. else if (irp->MdlAddress==NULL &&
  1968. requestInfo.DataOffset==0 &&
  1969. OutputBufferLength==0) {
  1970. ASSERT (irp->IoStatus.Information==0);
  1971. ASSERT (status==STATUS_SUCCESS);
  1972. }
  1973. else {
  1974. //
  1975. // Indicate to the switch that offset
  1976. // is outside of the buffer
  1977. //
  1978. status = STATUS_INVALID_PARAMETER;
  1979. }
  1980. }
  1981. break;
  1982. default:
  1983. ASSERT (!"Unsupported IRP Major Function");
  1984. status = STATUS_INVALID_DEVICE_REQUEST;
  1985. }
  1986. //
  1987. // If switch did not ask to pend the request, complete it
  1988. //
  1989. if (NT_SUCCESS (status) && requestInfo.RequestStatus!=STATUS_PENDING) {
  1990. //
  1991. // Prepeare the request for completion
  1992. //
  1993. irp->IoStatus.Status = AfdValidateStatus (requestInfo.RequestStatus);
  1994. IoCompleteRequest (irp, AfdPriorityBoost);
  1995. }
  1996. else {
  1997. //
  1998. // Otherwise, put it back into the queue
  1999. //
  2000. AfdAcquireSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  2001. IoSetCancelRoutine (irp, AfdSanCancelRequest);
  2002. //
  2003. // Of course, we need to make sure that request
  2004. // was not cancelled while we were processing it.
  2005. //
  2006. if (!irp->Cancel) {
  2007. InsertHeadList (&sanEndpoint->Common.SanEndp.IrpList,
  2008. &irp->Tail.Overlay.ListEntry);
  2009. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  2010. }
  2011. else {
  2012. //
  2013. // Request has already been cancelled
  2014. //
  2015. ASSERT (irp->Tail.Overlay.ListEntry.Flink == NULL);
  2016. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  2017. if (IoSetCancelRoutine (irp, NULL)==NULL) {
  2018. KIRQL cancelIrql;
  2019. //
  2020. // Cancel routine is running, synchronize with
  2021. // it
  2022. //
  2023. IoAcquireCancelSpinLock (&cancelIrql);
  2024. IoReleaseCancelSpinLock (cancelIrql);
  2025. }
  2026. //
  2027. // Complete the request and indicate to the
  2028. // switch that it was cancelled
  2029. //
  2030. irp->IoStatus.Status = STATUS_CANCELLED;
  2031. IoCompleteRequest (irp, AfdPriorityBoost);
  2032. status = STATUS_CANCELLED;
  2033. }
  2034. }
  2035. }
  2036. else {
  2037. //
  2038. // Could not find the request, it must have been
  2039. // cancelled already
  2040. //
  2041. status = STATUS_CANCELLED;
  2042. }
  2043. UPDATE_ENDPOINT2 (sanEndpoint, "AfdSanFastCompleteRequest, status: 0x%lX", status);
  2044. ObDereferenceObject (sanFileObject);
  2045. return status;
  2046. }
  2047. NTSTATUS
  2048. AfdSanFastCompleteIo (
  2049. IN PFILE_OBJECT FileObject,
  2050. IN ULONG IoctlCode,
  2051. IN KPROCESSOR_MODE RequestorMode,
  2052. IN PVOID InputBuffer,
  2053. IN ULONG InputBufferLength,
  2054. IN PVOID OutputBuffer,
  2055. IN ULONG OutputBufferLength,
  2056. OUT PULONG_PTR Information
  2057. )
  2058. /*++
  2059. Routine Description:
  2060. Simulates async IO completion for the switch.
  2061. Arguments:
  2062. FileObject - SAN endpoint on which to complete the IO
  2063. IoctlCode - operation IOCTL code (IOCTL_AFD_SWITCH_CMPL_IO)
  2064. RequestorMode - mode of the caller
  2065. InputBuffer - input parameters for the operation (IO_STATUS_BLOCK)
  2066. Status - final operation status
  2067. Information - associated information (number of bytes
  2068. transferred to/from request buffer(s))
  2069. InputBufferLength - sizeof (IO_STATUS_BLOCK)
  2070. OutputBuffer - unused
  2071. OutputBufferLength - unused
  2072. Information - pointer to buffer to return number of bytes transferred
  2073. Return Value:
  2074. STATUS_INVALID_PARAMETER - input buffer is of invalid size.
  2075. other - status of the IO operation or failure code when attempting to access input buffer.
  2076. --*/
  2077. {
  2078. NTSTATUS status;
  2079. #if !DBG
  2080. UNREFERENCED_PARAMETER (FileObject);
  2081. #endif
  2082. UNREFERENCED_PARAMETER (IoctlCode);
  2083. UNREFERENCED_PARAMETER (OutputBuffer);
  2084. UNREFERENCED_PARAMETER (OutputBufferLength);
  2085. PAGED_CODE ();
  2086. #ifdef _WIN64
  2087. if (IoIs32bitProcess (NULL)) {
  2088. if (InputBufferLength>=sizeof (IO_STATUS_BLOCK32)) {
  2089. // Carefully write status info
  2090. AFD_W4_INIT status = STATUS_SUCCESS;
  2091. try {
  2092. if (RequestorMode!=KernelMode) {
  2093. ProbeForReadSmallStructure (InputBuffer,
  2094. sizeof (IO_STATUS_BLOCK32),
  2095. PROBE_ALIGNMENT32 (IO_STATUS_BLOCK32));
  2096. }
  2097. *Information = ((PIO_STATUS_BLOCK32)InputBuffer)->Information;
  2098. status = AfdValidateStatus (((PIO_STATUS_BLOCK32)InputBuffer)->Status);
  2099. }
  2100. except (AFD_EXCEPTION_FILTER (status)) {
  2101. ASSERT (NT_ERROR (status));
  2102. }
  2103. }
  2104. else {
  2105. status = STATUS_INVALID_PARAMETER;
  2106. }
  2107. }
  2108. else
  2109. #endif //_WIN64
  2110. {
  2111. if (InputBufferLength>=sizeof (IO_STATUS_BLOCK)) {
  2112. // Carefully write status info
  2113. AFD_W4_INIT status = STATUS_SUCCESS;
  2114. try {
  2115. if (RequestorMode!=KernelMode) {
  2116. ProbeForReadSmallStructure (InputBuffer,
  2117. sizeof (IO_STATUS_BLOCK),
  2118. PROBE_ALIGNMENT (IO_STATUS_BLOCK));
  2119. }
  2120. *Information = ((PIO_STATUS_BLOCK)InputBuffer)->Information;
  2121. status = AfdValidateStatus (((PIO_STATUS_BLOCK)InputBuffer)->Status);
  2122. }
  2123. except (AFD_EXCEPTION_FILTER (status)) {
  2124. ASSERT (NT_ERROR (status));
  2125. }
  2126. }
  2127. else {
  2128. status = STATUS_INVALID_PARAMETER;
  2129. }
  2130. }
  2131. UPDATE_ENDPOINT2 (FileObject->FsContext, "AfdSanFastCompletIo, status: 0x%lX", status);
  2132. return status;
  2133. }
  2134. NTSTATUS
  2135. AfdSanFastRefreshEndpoint (
  2136. IN PFILE_OBJECT FileObject,
  2137. IN ULONG IoctlCode,
  2138. IN KPROCESSOR_MODE RequestorMode,
  2139. IN PVOID InputBuffer,
  2140. IN ULONG InputBufferLength,
  2141. IN PVOID OutputBuffer,
  2142. IN ULONG OutputBufferLength,
  2143. OUT PULONG_PTR Information
  2144. )
  2145. /*++
  2146. Routine Description:
  2147. Refreshes endpoint so it can be used again in AcceptEx
  2148. Arguments:
  2149. FileObject - SAN helper object - communication channel between the
  2150. switch and AFD in the process.
  2151. IoctlCode - operation IOCTL code (IOCTL_AFD_SWITCH_REFRESH_ENDP)
  2152. RequestorMode - mode of the caller
  2153. InputBuffer - input parameters for the operation (AFD_SWITCH_CONTEXT_INFO)
  2154. SocketHandle - SAN endpoint on which to referesh
  2155. SwitchContext - switch context associated with endpoint
  2156. to validate the handle-endpoint association
  2157. InputBufferLength - unused
  2158. OutputBuffer - unused
  2159. OutputBufferLength - unused
  2160. Information - pointer for buffer to place return information into, unused
  2161. Return Value:
  2162. STATUS_SUCCESS - operation succeeded
  2163. STATUS_INVALID_HANDLE - helper endpoint or switch socket is of incorrect type
  2164. other - failed when attempting to access SAN socket.
  2165. --*/
  2166. {
  2167. AFD_LOCK_QUEUE_HANDLE lockHandle;
  2168. KIRQL oldIrql;
  2169. NTSTATUS status;
  2170. PFILE_OBJECT sanFileObject;
  2171. AFD_SWITCH_CONTEXT_INFO contextInfo;
  2172. PAFD_ENDPOINT sanEndpoint, sanHlprEndpoint;
  2173. PVOID context;
  2174. UNREFERENCED_PARAMETER (OutputBuffer);
  2175. UNREFERENCED_PARAMETER (OutputBufferLength);
  2176. *Information = 0;
  2177. AFD_W4_INIT status = STATUS_SUCCESS;
  2178. try {
  2179. #ifdef _WIN64
  2180. if (IoIs32bitProcess (NULL)) {
  2181. PAFD_SWITCH_CONTEXT_INFO32 contextInfo32;
  2182. if (InputBufferLength<sizeof (*contextInfo32)) {
  2183. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  2184. }
  2185. if (RequestorMode!=KernelMode) {
  2186. ProbeForReadSmallStructure (InputBuffer,
  2187. sizeof (*contextInfo32),
  2188. PROBE_ALIGNMENT32 (AFD_SWITCH_CONTEXT_INFO32));
  2189. }
  2190. contextInfo32 = InputBuffer;
  2191. contextInfo.SocketHandle = contextInfo32->SocketHandle;
  2192. contextInfo.SwitchContext = UlongToPtr(contextInfo32->SwitchContext);
  2193. }
  2194. else
  2195. #endif _WIN64
  2196. {
  2197. if (InputBufferLength<sizeof (contextInfo)) {
  2198. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  2199. }
  2200. if (RequestorMode!=KernelMode) {
  2201. ProbeForReadSmallStructure (InputBuffer,
  2202. sizeof (contextInfo),
  2203. PROBE_ALIGNMENT (AFD_SWITCH_CONTEXT_INFO));
  2204. }
  2205. contextInfo = *((PAFD_SWITCH_CONTEXT_INFO)InputBuffer);
  2206. }
  2207. if (contextInfo.SwitchContext==NULL) {
  2208. IF_DEBUG(SAN_SWITCH) {
  2209. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2210. "AFD: Switch context is NULL in AfdSanFastRefereshEndpoint\n"));
  2211. }
  2212. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  2213. }
  2214. if (RequestorMode!=KernelMode) {
  2215. ProbeForWrite (contextInfo.SwitchContext,
  2216. sizeof (*contextInfo.SwitchContext),
  2217. PROBE_ALIGNMENT (AFD_SWITCH_CONTEXT));
  2218. }
  2219. }
  2220. except (AFD_EXCEPTION_FILTER (status)) {
  2221. ASSERT (NT_ERROR (status));
  2222. return status;
  2223. }
  2224. sanHlprEndpoint = FileObject->FsContext;
  2225. ASSERT (IS_SAN_HELPER (sanHlprEndpoint));
  2226. status = AfdSanReferenceSwitchSocketByHandle (
  2227. contextInfo.SocketHandle,
  2228. (IoctlCode>>14)&3,
  2229. RequestorMode,
  2230. sanHlprEndpoint,
  2231. contextInfo.SwitchContext,
  2232. &sanFileObject
  2233. );
  2234. if (!NT_SUCCESS (status)) {
  2235. return status;
  2236. }
  2237. sanEndpoint = sanFileObject->FsContext;
  2238. if (!AFD_START_STATE_CHANGE (sanEndpoint, sanEndpoint->State)) {
  2239. goto complete;
  2240. }
  2241. context = AfdLockEndpointContext (sanEndpoint);
  2242. //
  2243. // Just make sure that endpoints are of correct type
  2244. // and in correct state
  2245. //
  2246. KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
  2247. AfdAcquireSpinLockAtDpcLevel (&sanEndpoint->SpinLock, &lockHandle);
  2248. if (!sanEndpoint->EndpointCleanedUp &&
  2249. sanEndpoint->State==AfdEndpointStateConnected) {
  2250. //
  2251. // Reset the state so we can't get anymore IRPs
  2252. //
  2253. sanEndpoint->State = AfdEndpointStateTransmitClosing;
  2254. //
  2255. // Cleanup all IRPs on the endpoint.
  2256. //
  2257. if (!IsListEmpty (&sanEndpoint->Common.SanEndp.IrpList)) {
  2258. PIRP irp;
  2259. PDRIVER_CANCEL cancelRoutine;
  2260. KIRQL cancelIrql;
  2261. AfdReleaseSpinLockFromDpcLevel (&sanEndpoint->SpinLock, &lockHandle);
  2262. //
  2263. // Acquire cancel spinlock and endpoint spinlock in
  2264. // this order and recheck the IRP list
  2265. //
  2266. IoAcquireCancelSpinLock (&cancelIrql);
  2267. ASSERT (cancelIrql==DISPATCH_LEVEL);
  2268. AfdAcquireSpinLockAtDpcLevel (&sanEndpoint->SpinLock, &lockHandle);
  2269. //
  2270. // While list is not empty attempt to cancel the IRPs
  2271. //
  2272. while (!IsListEmpty (&sanEndpoint->Common.SanEndp.IrpList)) {
  2273. irp = CONTAINING_RECORD (
  2274. sanEndpoint->Common.SanEndp.IrpList.Flink,
  2275. IRP,
  2276. Tail.Overlay.ListEntry);
  2277. //
  2278. // Reset the cancel routine.
  2279. //
  2280. cancelRoutine = IoSetCancelRoutine (irp, NULL);
  2281. if (cancelRoutine!=NULL) {
  2282. //
  2283. // Cancel routine was not NULL, cancel it here.
  2284. // If someone else attempts to complete this IRP
  2285. // it will have to wait at least until cancel
  2286. // spinlock is released, so we can release
  2287. // the endpoint spinlock
  2288. //
  2289. AfdReleaseSpinLockFromDpcLevel (&sanEndpoint->SpinLock, &lockHandle);
  2290. irp->CancelIrql = DISPATCH_LEVEL;
  2291. irp->Cancel = TRUE;
  2292. (*cancelRoutine) (AfdDeviceObject, irp);
  2293. }
  2294. else {
  2295. IoAcquireCancelSpinLock (&cancelIrql);
  2296. ASSERT (cancelIrql==DISPATCH_LEVEL);
  2297. AfdAcquireSpinLockAtDpcLevel (&sanEndpoint->SpinLock, &lockHandle);
  2298. }
  2299. }
  2300. IoReleaseCancelSpinLock (DISPATCH_LEVEL);
  2301. }
  2302. ASSERT (sanEndpoint->Common.SanEndp.SanHlpr!=NULL);
  2303. DEREFERENCE_ENDPOINT (sanEndpoint->Common.SanEndp.SanHlpr);
  2304. //
  2305. // Make sure we cleanup all the fields since they will be
  2306. // treated as other part (VC) of the endpoint union.
  2307. //
  2308. RtlZeroMemory (&sanEndpoint->Common.SanEndp,
  2309. sizeof (sanEndpoint->Common.SanEndp));
  2310. //
  2311. // Reinitialize the endpoint structure.
  2312. //
  2313. sanEndpoint->Type = AfdBlockTypeEndpoint;
  2314. if (sanEndpoint->AddressFileObject!=NULL) {
  2315. //
  2316. // This is TransmitFile after SuperConnect
  2317. //
  2318. sanEndpoint->State = AfdEndpointStateBound;
  2319. }
  2320. else {
  2321. //
  2322. // This is TransmitFile after SuperAccept
  2323. //
  2324. sanEndpoint->State = AfdEndpointStateOpen;
  2325. }
  2326. sanEndpoint->DisconnectMode = 0;
  2327. sanEndpoint->EndpointStateFlags = 0;
  2328. sanEndpoint->EventsActive = 0;
  2329. AfdRecordEndpointsReused ();
  2330. status = STATUS_SUCCESS;
  2331. }
  2332. else {
  2333. status = STATUS_INVALID_HANDLE;
  2334. }
  2335. AfdReleaseSpinLockFromDpcLevel (&sanEndpoint->SpinLock, &lockHandle);
  2336. KeLowerIrql (oldIrql);
  2337. AfdUnlockEndpointContext (sanEndpoint, context);
  2338. AFD_END_STATE_CHANGE (sanEndpoint);
  2339. complete:
  2340. UPDATE_ENDPOINT2 (sanEndpoint, "AfdSanFastRefreshEndpoint, status: 0x%lX", status);
  2341. ObDereferenceObject( sanFileObject );
  2342. return status;
  2343. }
  2344. NTSTATUS
  2345. AfdSanFastGetPhysicalAddr (
  2346. IN PFILE_OBJECT FileObject,
  2347. IN ULONG IoctlCode,
  2348. IN KPROCESSOR_MODE RequestorMode,
  2349. IN PVOID InputBuffer,
  2350. IN ULONG InputBufferLength,
  2351. IN PVOID OutputBuffer,
  2352. IN ULONG OutputBufferLength,
  2353. OUT PULONG_PTR Information
  2354. )
  2355. /*++
  2356. Routine Description:
  2357. Returns physical address corresponding to provided virtual address.
  2358. Arguments:
  2359. FileObject - SAN helper object - communication channel between the
  2360. switch and AFD in the process.
  2361. IoctlCode - operation IOCTL code (IOCTL_AFD_SWITCH_GET_PHYSICAL_ADDR)
  2362. RequestorMode - mode of the caller
  2363. InputBuffer - user mode virtual address
  2364. InputBufferLength - access mode
  2365. OutputBuffer - Buffer to place physical address into.
  2366. OutputBufferLength - sizeof (PHYSICAL_ADDRESS)
  2367. Information - pointer for buffer to place the size of the return information into
  2368. Return Value:
  2369. STATUS_SUCCESS - operation succeeded
  2370. STATUS_INVALID_HANDLE - helper endpoint is of incorrect type
  2371. STATUS_INVALID_PARAMETER - invalid access mode.
  2372. STATUS_BUFFER_TOO_SMALL - output buffer is of incorrect size.
  2373. other - failed when attempting to access input virtual address or output buffer.
  2374. --*/
  2375. {
  2376. #ifndef TEST_RDMA_CACHE
  2377. UNREFERENCED_PARAMETER (FileObject);
  2378. UNREFERENCED_PARAMETER (IoctlCode);
  2379. UNREFERENCED_PARAMETER (RequestorMode);
  2380. UNREFERENCED_PARAMETER (InputBuffer);
  2381. UNREFERENCED_PARAMETER (InputBufferLength);
  2382. UNREFERENCED_PARAMETER (OutputBuffer);
  2383. UNREFERENCED_PARAMETER (OutputBufferLength);
  2384. UNREFERENCED_PARAMETER (Information);
  2385. return STATUS_INVALID_PARAMETER;
  2386. #else
  2387. NTSTATUS status;
  2388. PVOID Va; // virtual address
  2389. ULONG accessMode;
  2390. PAFD_ENDPOINT sanHlprEndpoint;
  2391. PAGED_CODE ();
  2392. *Information = 0;
  2393. Va = InputBuffer;
  2394. accessMode = InputBufferLength;
  2395. if (accessMode!=MEM_READ_ACCESS &&
  2396. accessMode!=MEM_WRITE_ACCESS) {
  2397. return STATUS_INVALID_PARAMETER;
  2398. }
  2399. if (OutputBufferLength<sizeof(PHYSICAL_ADDRESS)) {
  2400. return STATUS_BUFFER_TOO_SMALL;
  2401. }
  2402. sanHlprEndpoint = FileObject->FsContext;
  2403. if (!IS_SAN_HELPER(sanHlprEndpoint) ||
  2404. sanHlprEndpoint->OwningProcess!=IoGetCurrentProcess ()) {
  2405. return STATUS_INVALID_HANDLE;
  2406. }
  2407. AFD_W4_INIT status = STATUS_SUCCESS;
  2408. try {
  2409. if (RequestorMode!=KernelMode) {
  2410. //
  2411. // Do some verification on the app buffer. Make sure it is
  2412. // mapped and that it is a user-mode address with appropriate
  2413. // read or write permissions
  2414. //
  2415. if (accessMode == MEM_READ_ACCESS) {
  2416. ProbeAndReadChar ((PCHAR)Va);
  2417. }
  2418. else {
  2419. ProbeForWriteChar ((PCHAR)Va);
  2420. }
  2421. }
  2422. //
  2423. // Validate the output structure if it comes from the user mode
  2424. // application
  2425. //
  2426. if (RequestorMode != KernelMode ) {
  2427. ASSERT(sizeof(PHYSICAL_ADDRESS) == sizeof(QUAD));
  2428. ProbeForWriteQuad ((PQUAD)OutputBuffer);
  2429. }
  2430. *(PPHYSICAL_ADDRESS)OutputBuffer = MmGetPhysicalAddress(Va);
  2431. *Information = sizeof(PHYSICAL_ADDRESS);
  2432. status = STATUS_SUCCESS;
  2433. } except( AFD_EXCEPTION_FILTER (status) ) {
  2434. ASSERT (NT_ERROR (status));
  2435. }
  2436. UPDATE_ENDPOINT2 (sanHlprEndpoint, "AfdSanGetPhysicalAddress, status: 0x%lX", status);
  2437. return status;
  2438. #endif // 0
  2439. }
  2440. NTSTATUS
  2441. AfdSanFastGetServicePid (
  2442. IN PFILE_OBJECT FileObject,
  2443. IN ULONG IoctlCode,
  2444. IN KPROCESSOR_MODE RequestorMode,
  2445. IN PVOID InputBuffer,
  2446. IN ULONG InputBufferLength,
  2447. IN PVOID OutputBuffer,
  2448. IN ULONG OutputBufferLength,
  2449. OUT PULONG_PTR Information
  2450. )
  2451. /*++
  2452. Routine Description:
  2453. Returns PID of SAN service process.
  2454. Arguments:
  2455. FileObject - SAN helper object - communication channel between the
  2456. switch and AFD in the process.
  2457. IoctlCode - operation IOCTL code (IOCTL_AFD_SWITCH_GET_PHYSICAL_ADDR)
  2458. RequestorMode - mode of the caller
  2459. InputBuffer - NULL, ignored
  2460. InputBufferLength - 0, ignored
  2461. OutputBuffer - NULL, ignored
  2462. OutputBufferLength - 0, ignored
  2463. Information - pointer to buffer to return pid of the SAN service process
  2464. Return Value:
  2465. STATUS_SUCCESS - operation succeeded
  2466. STATUS_INVALID_HANDLE - helper endpoint is of incorrect type
  2467. --*/
  2468. {
  2469. PAFD_ENDPOINT sanHlprEndpoint;
  2470. UNREFERENCED_PARAMETER (IoctlCode);
  2471. UNREFERENCED_PARAMETER (RequestorMode);
  2472. UNREFERENCED_PARAMETER (InputBuffer);
  2473. UNREFERENCED_PARAMETER (InputBufferLength);
  2474. UNREFERENCED_PARAMETER (OutputBuffer);
  2475. UNREFERENCED_PARAMETER (OutputBufferLength);
  2476. PAGED_CODE ();
  2477. *Information = 0;
  2478. sanHlprEndpoint = FileObject->FsContext;
  2479. if (!IS_SAN_HELPER(sanHlprEndpoint) ||
  2480. sanHlprEndpoint->OwningProcess!=IoGetCurrentProcess ()) {
  2481. return STATUS_INVALID_HANDLE;
  2482. }
  2483. *Information = (ULONG_PTR)AfdSanServicePid;
  2484. UPDATE_ENDPOINT2 (sanHlprEndpoint,
  2485. "AfdSanFastGetServicePid, pid: 0x%lX",
  2486. HandleToUlong (AfdSanServicePid));
  2487. return STATUS_SUCCESS;
  2488. }
  2489. NTSTATUS
  2490. AfdSanFastSetServiceProcess (
  2491. IN PFILE_OBJECT FileObject,
  2492. IN ULONG IoctlCode,
  2493. IN KPROCESSOR_MODE RequestorMode,
  2494. IN PVOID InputBuffer,
  2495. IN ULONG InputBufferLength,
  2496. IN PVOID OutputBuffer,
  2497. IN ULONG OutputBufferLength,
  2498. OUT PULONG_PTR Information
  2499. )
  2500. /*++
  2501. Routine Description:
  2502. Set the service helper endpoint
  2503. Arguments:
  2504. FileObject - SAN helper object - communication channel between the
  2505. switch and AFD in the process.
  2506. IoctlCode - operation IOCTL code (IOCTL_AFD_SWITCH_GET_PHYSICAL_ADDR)
  2507. RequestorMode - mode of the caller
  2508. InputBuffer - NULL, ignored
  2509. InputBufferLength - 0, ignored
  2510. OutputBuffer - NULL, ignored
  2511. OutputBufferLength - 0, ignored
  2512. Information - 0, ignored
  2513. Return Value:
  2514. STATUS_SUCCESS - operation succeeded
  2515. STATUS_INVALID_HANDLE - helper endpoint is of incorrect type
  2516. STATUS_ACCESS_DENIED - process is not priviliged enough to become service process.
  2517. STATUS_ADDRESS_ALREADY_EXISTS - service process has already registered.
  2518. --*/
  2519. {
  2520. NTSTATUS status;
  2521. PAFD_ENDPOINT sanHlprEndpoint;
  2522. UNREFERENCED_PARAMETER (IoctlCode);
  2523. UNREFERENCED_PARAMETER (RequestorMode);
  2524. UNREFERENCED_PARAMETER (InputBuffer);
  2525. UNREFERENCED_PARAMETER (InputBufferLength);
  2526. UNREFERENCED_PARAMETER (OutputBuffer);
  2527. UNREFERENCED_PARAMETER (OutputBufferLength);
  2528. PAGED_CODE ();
  2529. *Information = 0;
  2530. sanHlprEndpoint = FileObject->FsContext;
  2531. if (!IS_SAN_HELPER(sanHlprEndpoint) ||
  2532. sanHlprEndpoint->OwningProcess!=IoGetCurrentProcess ()) {
  2533. return STATUS_INVALID_HANDLE;
  2534. }
  2535. if (!sanHlprEndpoint->AdminAccessGranted) {
  2536. return STATUS_ACCESS_DENIED;
  2537. }
  2538. KeEnterCriticalRegion ();
  2539. ExAcquireResourceExclusiveLite( AfdResource, TRUE );
  2540. if (AfdSanServiceHelper==NULL) {
  2541. AfdSanServiceHelper = sanHlprEndpoint;
  2542. AfdSanServicePid = PsGetCurrentProcessId ();
  2543. status = STATUS_SUCCESS;
  2544. }
  2545. else if (AfdSanServiceHelper==sanHlprEndpoint) {
  2546. ASSERT (FileObject->LockOperation == TRUE);
  2547. status = STATUS_SUCCESS;
  2548. }
  2549. else {
  2550. status = STATUS_ADDRESS_ALREADY_EXISTS;
  2551. }
  2552. ExReleaseResourceLite (AfdResource);
  2553. KeLeaveCriticalRegion ();
  2554. UPDATE_ENDPOINT2 (sanHlprEndpoint, "AfdSanFastSetServiceProcess, status: 0x%lX", status);
  2555. return status;
  2556. }
  2557. NTSTATUS
  2558. AfdSanFastProviderChange (
  2559. IN PFILE_OBJECT FileObject,
  2560. IN ULONG IoctlCode,
  2561. IN KPROCESSOR_MODE RequestorMode,
  2562. IN PVOID InputBuffer,
  2563. IN ULONG InputBufferLength,
  2564. IN PVOID OutputBuffer,
  2565. IN ULONG OutputBufferLength,
  2566. OUT PULONG_PTR Information
  2567. )
  2568. /*++
  2569. Routine Description:
  2570. Notifies interested processes of SAN provider addition/deletion/change
  2571. Arguments:
  2572. FileObject - SAN helper object for the service process communication channel between the
  2573. switch and AFD in the process.
  2574. IoctlCode - operation IOCTL code (IOCTL_AFD_SWITCH_PROVIDER_CHANGE)
  2575. RequestorMode - mode of the caller
  2576. InputBuffer - NULL, ignored
  2577. InputBufferLength - 0, ignored
  2578. OutputBuffer - NULL, ignored
  2579. OutputBufferLength - 0, ignored
  2580. Information - 0, ignored
  2581. Return Value:
  2582. STATUS_SUCCESS - operation succeeded
  2583. STATUS_INVALID_HANDLE - helper endpoint is of incorrect type
  2584. STATUS_ACCESS_DENIED - helper endpoint is not for the service process.
  2585. --*/
  2586. {
  2587. PAFD_ENDPOINT sanHlprEndpoint;
  2588. UNREFERENCED_PARAMETER (IoctlCode);
  2589. UNREFERENCED_PARAMETER (RequestorMode);
  2590. UNREFERENCED_PARAMETER (InputBuffer);
  2591. UNREFERENCED_PARAMETER (InputBufferLength);
  2592. UNREFERENCED_PARAMETER (OutputBuffer);
  2593. UNREFERENCED_PARAMETER (OutputBufferLength);
  2594. *Information = 0;
  2595. sanHlprEndpoint = FileObject->FsContext;
  2596. if (!IS_SAN_HELPER(sanHlprEndpoint) ||
  2597. sanHlprEndpoint->OwningProcess!=IoGetCurrentProcess ()) {
  2598. return STATUS_INVALID_HANDLE;
  2599. }
  2600. if (sanHlprEndpoint!=AfdSanServiceHelper) {
  2601. return STATUS_ACCESS_DENIED;
  2602. }
  2603. UPDATE_ENDPOINT2 (sanHlprEndpoint,
  2604. "AfdSanFastProviderChange, seq num: 0x%lX",
  2605. AfdSanProviderListSeqNum);
  2606. AfdSanProcessAddrListForProviderChange (NULL);
  2607. return STATUS_SUCCESS;
  2608. }
  2609. NTSTATUS
  2610. FASTCALL
  2611. AfdSanAddrListChange (
  2612. IN PIRP Irp,
  2613. IN PIO_STACK_LOCATION IrpSp
  2614. )
  2615. /*++
  2616. Routine Description:
  2617. Processes address SAN list change IRP
  2618. Notifies both of address list changes and SAN
  2619. provider changes.
  2620. Arguments:
  2621. Irp - Pointer to I/O request packet.
  2622. IrpSp - pointer to the stack location to use for this request.
  2623. Return Value:
  2624. NTSTATUS -- Indicates whether the request was successfully queued.
  2625. --*/
  2626. {
  2627. PAFD_ENDPOINT sanHlprEndpoint;
  2628. NTSTATUS status;
  2629. sanHlprEndpoint = IrpSp->FileObject->FsContext;
  2630. if (IS_SAN_HELPER(sanHlprEndpoint) &&
  2631. sanHlprEndpoint->OwningProcess==IoGetCurrentProcess ()) {
  2632. if (AfdSanProviderListSeqNum==0 ||
  2633. sanHlprEndpoint->Common.SanHlpr.Plsn==AfdSanProviderListSeqNum) {
  2634. status = AfdAddressListChange (Irp, IrpSp);
  2635. if (AfdSanProviderListSeqNum==0 ||
  2636. sanHlprEndpoint->Common.SanHlpr.Plsn==AfdSanProviderListSeqNum) {
  2637. UPDATE_ENDPOINT (sanHlprEndpoint);
  2638. }
  2639. else {
  2640. AfdSanProcessAddrListForProviderChange (sanHlprEndpoint);
  2641. }
  2642. return status;
  2643. }
  2644. else {
  2645. sanHlprEndpoint->Common.SanHlpr.Plsn = AfdSanProviderListSeqNum;
  2646. status = STATUS_SUCCESS;
  2647. Irp->IoStatus.Information = sanHlprEndpoint->Common.SanHlpr.Plsn;
  2648. UPDATE_ENDPOINT2 (sanHlprEndpoint,
  2649. "AfdSanAddrListChange, new plsn: 0x%lX",
  2650. sanHlprEndpoint->Common.SanHlpr.Plsn);
  2651. }
  2652. }
  2653. else {
  2654. status = STATUS_INVALID_PARAMETER;
  2655. Irp->IoStatus.Information = 0;
  2656. UPDATE_ENDPOINT2 (sanHlprEndpoint, "AfdSanAddrListChange invalid helper: 0x%lX", status);
  2657. }
  2658. Irp->IoStatus.Status = status;
  2659. IoCompleteRequest (Irp, AfdPriorityBoost);
  2660. return status;
  2661. }
  2662. NTSTATUS
  2663. FASTCALL
  2664. AfdSanAcquireContext (
  2665. IN PIRP Irp,
  2666. IN PIO_STACK_LOCATION IrpSp
  2667. )
  2668. /*++
  2669. Routine Description:
  2670. Requests transfer of the socket context to the current process.
  2671. Arguments:
  2672. Irp - acquire conect IRP
  2673. IrpSp - current stack location
  2674. Return Value:
  2675. STATUS_PENDING - operation was successfully enqued
  2676. --*/
  2677. {
  2678. NTSTATUS status;
  2679. AFD_SWITCH_ACQUIRE_CTX_INFO ctxInfo;
  2680. PAFD_ENDPOINT sanHlprEndpoint, sanEndpoint;
  2681. PFILE_OBJECT sanFileObject = NULL;
  2682. PVOID requestCtx;
  2683. AFD_LOCK_QUEUE_HANDLE lockHandle;
  2684. BOOLEAN doTransfer;
  2685. PVOID context;
  2686. AFD_W4_INIT status = STATUS_SUCCESS;
  2687. try {
  2688. #ifdef _WIN64
  2689. if (IoIs32bitProcess (Irp)) {
  2690. PAFD_SWITCH_ACQUIRE_CTX_INFO ctxInfo32;
  2691. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength<sizeof (*ctxInfo32)) {
  2692. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  2693. }
  2694. if (Irp->RequestorMode!=KernelMode) {
  2695. ProbeForReadSmallStructure (IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  2696. sizeof (*ctxInfo32),
  2697. PROBE_ALIGNMENT32 (AFD_SWITCH_ACQUIRE_CTX_INFO32));
  2698. }
  2699. ctxInfo32 = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  2700. ctxInfo.SocketHandle = ctxInfo32->SocketHandle;
  2701. ctxInfo.SwitchContext = ctxInfo32->SwitchContext;
  2702. ctxInfo.SocketCtxBuf = ctxInfo32->SocketCtxBuf;
  2703. ctxInfo.SocketCtxBufSize = ctxInfo32->SocketCtxBufSize;
  2704. }
  2705. else
  2706. #endif //_WIN64
  2707. {
  2708. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength<sizeof (ctxInfo)) {
  2709. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  2710. }
  2711. if (Irp->RequestorMode!=KernelMode) {
  2712. ProbeForReadSmallStructure (IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  2713. sizeof (ctxInfo),
  2714. PROBE_ALIGNMENT (AFD_SWITCH_ACQUIRE_CTX_INFO));
  2715. }
  2716. ctxInfo = *((PAFD_SWITCH_ACQUIRE_CTX_INFO)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  2717. }
  2718. if (ctxInfo.SocketCtxBufSize < 1)
  2719. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  2720. Irp->MdlAddress = IoAllocateMdl (ctxInfo.SocketCtxBuf, // VirtualAddress
  2721. ctxInfo.SocketCtxBufSize, // Length
  2722. FALSE, // SecondaryBuffer
  2723. TRUE, // ChargeQuota
  2724. NULL); // Irp
  2725. if (Irp->MdlAddress==NULL) {
  2726. ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
  2727. }
  2728. MmProbeAndLockPages(
  2729. Irp->MdlAddress, // MemoryDescriptorList
  2730. Irp->RequestorMode, // AccessMode
  2731. IoWriteAccess // Operation
  2732. );
  2733. if (MmGetSystemAddressForMdlSafe(Irp->MdlAddress, LowPagePriority)==NULL) {
  2734. ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
  2735. }
  2736. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength>0) {
  2737. Irp->MdlAddress->Next = IoAllocateMdl (Irp->UserBuffer, // VirtualAddress
  2738. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,// Length
  2739. FALSE, // SecondaryBuffer
  2740. TRUE, // ChargeQuota
  2741. NULL); // Irp
  2742. if (Irp->MdlAddress->Next==NULL) {
  2743. ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
  2744. }
  2745. MmProbeAndLockPages(
  2746. Irp->MdlAddress->Next, // MemoryDescriptorList
  2747. Irp->RequestorMode, // AccessMode
  2748. IoWriteAccess // Operation
  2749. );
  2750. if (MmGetSystemAddressForMdlSafe(Irp->MdlAddress->Next, LowPagePriority)==NULL) {
  2751. ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
  2752. }
  2753. }
  2754. }
  2755. except (AFD_EXCEPTION_FILTER (status)) {
  2756. ASSERT (NT_ERROR (status));
  2757. //
  2758. // Cleanup partially processed MDLs since IO subsystem can't do it.
  2759. //
  2760. while (Irp->MdlAddress!=NULL) {
  2761. PMDL mdl = Irp->MdlAddress;
  2762. Irp->MdlAddress = mdl->Next;
  2763. mdl->Next = NULL;
  2764. if (mdl->MdlFlags & MDL_PAGES_LOCKED) {
  2765. MmUnlockPages (mdl);
  2766. }
  2767. IoFreeMdl (mdl);
  2768. }
  2769. goto complete;
  2770. }
  2771. status = ObReferenceObjectByHandle (
  2772. ctxInfo.SocketHandle,
  2773. (IrpSp->Parameters.DeviceIoControl.IoControlCode>>14)&3,
  2774. *IoFileObjectType,
  2775. Irp->RequestorMode,
  2776. (PVOID)&sanFileObject,
  2777. NULL
  2778. );
  2779. if (!NT_SUCCESS (status)) {
  2780. goto complete;
  2781. }
  2782. if (sanFileObject->DeviceObject!=AfdDeviceObject) {
  2783. status = STATUS_INVALID_HANDLE;
  2784. goto complete;
  2785. }
  2786. sanHlprEndpoint = IrpSp->FileObject->FsContext;
  2787. sanEndpoint = sanFileObject->FsContext;
  2788. IF_DEBUG(SAN_SWITCH) {
  2789. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2790. "AfdSanFastAcquireCtx: endp-%p.\n",
  2791. sanEndpoint));
  2792. }
  2793. //
  2794. // Just make sure that endpoints are of correct type
  2795. //
  2796. context = AfdLockEndpointContext (sanEndpoint); // To prevent refresh.
  2797. if (IS_SAN_HELPER(sanHlprEndpoint) &&
  2798. sanHlprEndpoint->OwningProcess==IoGetCurrentProcess () &&
  2799. IS_SAN_ENDPOINT(sanEndpoint)) {
  2800. if (sanEndpoint->Common.SanEndp.SanHlpr==AfdSanServiceHelper &&
  2801. sanHlprEndpoint==AfdSanServiceHelper) {
  2802. //
  2803. // This is an implicit duplication request from the service process.
  2804. // (we already received all the data from the owning process and
  2805. // associated sanEndpoint with the service process).
  2806. //
  2807. AfdAcquireSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  2808. //
  2809. // Make sure endpoint is still in transferring state
  2810. //
  2811. if (sanEndpoint->Common.SanEndp.CtxTransferStatus!=STATUS_MORE_PROCESSING_REQUIRED) {
  2812. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  2813. status = STATUS_CANCELLED;
  2814. }
  2815. else if (ctxInfo.SocketCtxBufSize > sanEndpoint->Common.SanEndp.SavedContextLength ||
  2816. ctxInfo.SocketCtxBufSize +
  2817. IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2818. sanEndpoint->Common.SanEndp.SavedContextLength) {
  2819. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  2820. //
  2821. // Switch should have queried the context size via AFD_GET_CONTEXT
  2822. //
  2823. status = STATUS_BUFFER_TOO_SMALL;
  2824. }
  2825. else {
  2826. PVOID savedContext = sanEndpoint->Common.SanEndp.SavedContext;
  2827. ULONG savedContextLength = sanEndpoint->Common.SanEndp.SavedContextLength;
  2828. sanEndpoint->Common.SanEndp.SavedContext = NULL;
  2829. sanEndpoint->Common.SanEndp.SavedContextLength = 0;
  2830. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  2831. RtlCopyMemory (
  2832. MmGetSystemAddressForMdl (Irp->MdlAddress),
  2833. savedContext,
  2834. ctxInfo.SocketCtxBufSize);
  2835. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength!=0) {
  2836. Irp->IoStatus.Information =
  2837. savedContextLength-
  2838. ctxInfo.SocketCtxBufSize;
  2839. RtlCopyMemory (
  2840. MmGetSystemAddressForMdl (Irp->MdlAddress->Next),
  2841. (PCHAR)savedContext+ctxInfo.SocketCtxBufSize,
  2842. Irp->IoStatus.Information);
  2843. }
  2844. else {
  2845. Irp->IoStatus.Information = 0;
  2846. }
  2847. AFD_FREE_POOL (savedContext, AFD_SAN_CONTEXT_POOL_TAG);
  2848. // sanEndpoint->Common.SanEndp.SavedContext = NULL;
  2849. sanEndpoint->Common.SanEndp.SwitchContext = ctxInfo.SwitchContext;
  2850. status = STATUS_SUCCESS;
  2851. //
  2852. // Note that we are not expecting a reply from service process
  2853. // anymore.
  2854. //
  2855. InterlockedExchangeAdd (&AfdSanServiceHelper->Common.SanHlpr.PendingRequests, -2);
  2856. }
  2857. AfdUnlockEndpointContext (sanEndpoint, context);
  2858. UPDATE_ENDPOINT2 (sanEndpoint,
  2859. "AfdSanAcquireContext, ctx bytes copied/status: 0x%lX",
  2860. NT_SUCCESS (status)
  2861. ? (ULONG)Irp->IoStatus.Information
  2862. : status);
  2863. //
  2864. // Complete the IRP
  2865. //
  2866. Irp->IoStatus.Status = status;
  2867. IoCompleteRequest (Irp, AfdPriorityBoost);
  2868. //
  2869. // Restart request processing.
  2870. //
  2871. AfdSanRestartRequestProcessing (sanEndpoint, status);
  2872. }
  2873. else {
  2874. AfdAcquireSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  2875. //
  2876. // Make sure Irp has not been cancelled meanwhile
  2877. //
  2878. IoSetCancelRoutine (Irp, AfdSanCancelRequest);
  2879. if (Irp->Cancel) {
  2880. //
  2881. // Oops, let it go
  2882. //
  2883. Irp->Tail.Overlay.ListEntry.Flink = NULL;
  2884. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  2885. if (IoSetCancelRoutine (Irp, NULL)==NULL) {
  2886. KIRQL cancelIrql;
  2887. //
  2888. // Cancel routine must be running, make sure
  2889. // it completes before we complete the IRP
  2890. //
  2891. IoAcquireCancelSpinLock (&cancelIrql);
  2892. IoReleaseCancelSpinLock (cancelIrql);
  2893. }
  2894. AfdUnlockEndpointContext (sanEndpoint, context);
  2895. status = STATUS_CANCELLED;
  2896. goto complete;
  2897. }
  2898. //
  2899. // Check if don't already have duplication in progress.
  2900. //
  2901. if (sanEndpoint->Common.SanEndp.CtxTransferStatus!=STATUS_PENDING &&
  2902. sanEndpoint->Common.SanEndp.CtxTransferStatus!=STATUS_MORE_PROCESSING_REQUIRED) {
  2903. if (!NT_SUCCESS (sanEndpoint->Common.SanEndp.CtxTransferStatus)) {
  2904. //
  2905. // Duplicaiton has failed previously, can't do another one.
  2906. //
  2907. status = sanEndpoint->Common.SanEndp.CtxTransferStatus;
  2908. Irp->Tail.Overlay.ListEntry.Flink = NULL;
  2909. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  2910. if (IoSetCancelRoutine (Irp, NULL)==NULL) {
  2911. KIRQL cancelIrql;
  2912. //
  2913. // Cancel routine must be running, make sure
  2914. // it completes before we complete the IRP
  2915. //
  2916. IoAcquireCancelSpinLock (&cancelIrql);
  2917. IoReleaseCancelSpinLock (cancelIrql);
  2918. }
  2919. AfdUnlockEndpointContext (sanEndpoint, context);
  2920. goto complete;
  2921. }
  2922. //
  2923. // Generate request context that uniquely identifies
  2924. // it among other requests on the same endpoint.
  2925. //
  2926. requestCtx = AFD_SWITCH_MAKE_REQUEST_CONTEXT(
  2927. sanEndpoint->Common.SanEndp.RequestId,
  2928. AFD_SWITCH_REQUEST_TFCTX);
  2929. sanEndpoint->Common.SanEndp.RequestId += 1;
  2930. //
  2931. // Store the request context in the Irp and insert it into
  2932. // the list
  2933. //
  2934. Irp->AfdSanRequestInfo.AfdSanRequestCtx = requestCtx;
  2935. sanEndpoint->Common.SanEndp.CtxTransferStatus = STATUS_PENDING;
  2936. doTransfer = TRUE;
  2937. }
  2938. else {
  2939. //
  2940. // Another duplication in progress, this one will have to wait.
  2941. //
  2942. Irp->AfdSanRequestInfo.AfdSanRequestCtx = NULL;
  2943. doTransfer = FALSE;
  2944. AFD_W4_INIT requestCtx = NULL; // Depends on variable above, but
  2945. // compiler does not see
  2946. // the connection.
  2947. }
  2948. Irp->AfdSanRequestInfo.AfdSanSwitchCtx = ctxInfo.SwitchContext;
  2949. Irp->AfdSanRequestInfo.AfdSanProcessId = PsGetCurrentProcessId();
  2950. Irp->AfdSanRequestInfo.AfdSanHelperEndp = sanHlprEndpoint;
  2951. //
  2952. // We are going to pend this IRP, mark it so
  2953. //
  2954. IoMarkIrpPending (Irp);
  2955. InsertTailList (&sanEndpoint->Common.SanEndp.IrpList,
  2956. &Irp->Tail.Overlay.ListEntry);
  2957. IoGetCurrentIrpStackLocation(Irp)->FileObject = sanFileObject;
  2958. UPDATE_ENDPOINT2 (sanEndpoint,
  2959. "AfdSanAcquireContext, request: 0x%lX",
  2960. PtrToUlong (Irp->AfdSanRequestInfo.AfdSanRequestCtx));
  2961. AfdReleaseSpinLock (&sanEndpoint->SpinLock, &lockHandle);
  2962. AfdUnlockEndpointContext (sanEndpoint, context);
  2963. IF_DEBUG(SAN_SWITCH) {
  2964. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2965. "AfdSanRedirectRequest: endp-%p, irp-%p, context-%p\n",
  2966. sanEndpoint, Irp, requestCtx));
  2967. }
  2968. if (doTransfer) {
  2969. status = AfdSanNotifyRequest (sanEndpoint,
  2970. requestCtx,
  2971. STATUS_SUCCESS,
  2972. (ULONG_PTR)PsGetCurrentProcessId());
  2973. if (!NT_SUCCESS (status)) {
  2974. PIRP irp;
  2975. //
  2976. // If notification failed, fail the request.
  2977. // Note that we cannot return the failure status directly
  2978. // as we already marked IRP as pending. Also, the IRP
  2979. // could have been cancelled, so we have to search for
  2980. // it in the list.
  2981. //
  2982. irp = AfdSanDequeueRequest (sanEndpoint, requestCtx);
  2983. if (irp!=NULL) {
  2984. ASSERT (irp==Irp);
  2985. irp->IoStatus.Status = status;
  2986. IoCompleteRequest (irp, AfdPriorityBoost);
  2987. }
  2988. //
  2989. // Restart other requests in the queue and reset context
  2990. // transfer status.
  2991. //
  2992. AfdSanRestartRequestProcessing (sanEndpoint, STATUS_SUCCESS);
  2993. }
  2994. }
  2995. //
  2996. // The request is in the queue or completed, we no longer need
  2997. // object reference.
  2998. //
  2999. status = STATUS_PENDING;
  3000. }
  3001. ObDereferenceObject (sanFileObject);
  3002. return status;
  3003. }
  3004. else {
  3005. AfdUnlockEndpointContext (sanEndpoint, context);
  3006. status = STATUS_INVALID_HANDLE;
  3007. }
  3008. UPDATE_ENDPOINT2 (sanEndpoint, "AfdSanAcquireContext, status: 0x%lX", status);
  3009. complete:
  3010. if (sanFileObject!=NULL)
  3011. ObDereferenceObject (sanFileObject);
  3012. Irp->IoStatus.Status = status;
  3013. IoCompleteRequest (Irp, AfdPriorityBoost);
  3014. return status;
  3015. }
  3016. NTSTATUS
  3017. AfdSanFastTransferCtx (
  3018. IN PFILE_OBJECT FileObject,
  3019. IN ULONG IoctlCode,
  3020. IN KPROCESSOR_MODE RequestorMode,
  3021. IN PVOID InputBuffer,
  3022. IN ULONG InputBufferLength,
  3023. IN PVOID OutputBuffer,
  3024. IN ULONG OutputBufferLength,
  3025. OUT PULONG_PTR Information
  3026. )
  3027. /*++
  3028. Routine Description:
  3029. Requests AFD to transfer endpoint into another process context
  3030. Arguments:
  3031. FileObject - SAN helper object - communication channel between the
  3032. switch and AFD in the process.
  3033. IoctlCode - operation IOCTL code (IOCTL_AFD_SWITCH_TRANSFER_CTX)
  3034. RequestorMode - mode of the caller
  3035. InputBuffer - input parameters for the operation (AFD_SWITCH_TRANSFER_CTX_INFO)
  3036. SocketHandle - SAN endpoint to be transferred
  3037. RequestContext - value that identifies corresponding acquire request.
  3038. SocketCtxBuf - endpoint context buffer to copy destination process
  3039. acquire request
  3040. SocketCtxSize - size of the buffer to copy
  3041. RcvBufferArray - array of buffered data to transfer to
  3042. destination process acquire request
  3043. RcvBufferCount - number of elements in the array.
  3044. InputBufferLength - sizeof (AFD_SWITCH_TRANSFER_CTX_INFO)
  3045. OutputBuffer - unused
  3046. OutputBufferLength - unused
  3047. Information - pointer to buffer to return number of bytes copied
  3048. Return Value:
  3049. STATUS_SUCCESS - operation succeeded
  3050. STATUS_INVALID_HANDLE - helper endpoint or switch endpoint is of incorrect type
  3051. STATUS_INVALID_PARAMETER - invalid input buffer size.
  3052. other - failed when attempting to access san endpoint or input buffer(s).
  3053. --*/
  3054. {
  3055. NTSTATUS status;
  3056. AFD_SWITCH_TRANSFER_CTX_INFO ctxInfo;
  3057. PVOID context;
  3058. PAFD_ENDPOINT sanHlprEndpoint, sanEndpoint;
  3059. PFILE_OBJECT sanFileObject;
  3060. PIRP irp;
  3061. PIO_STACK_LOCATION irpSp;
  3062. #ifdef _WIN64
  3063. WSABUF localArray[8];
  3064. LPWSABUF pArray = localArray;
  3065. #endif
  3066. PAGED_CODE ();
  3067. *Information = 0;
  3068. UNREFERENCED_PARAMETER (OutputBuffer);
  3069. UNREFERENCED_PARAMETER (OutputBufferLength);
  3070. AFD_W4_INIT status = STATUS_SUCCESS;
  3071. try {
  3072. #ifdef _WIN64
  3073. if (IoIs32bitProcess (NULL)) {
  3074. PAFD_SWITCH_TRANSFER_CTX_INFO ctxInfo32;
  3075. ULONG i;
  3076. if (InputBufferLength<sizeof (*ctxInfo32)) {
  3077. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  3078. }
  3079. if (RequestorMode!=KernelMode) {
  3080. ProbeForReadSmallStructure (InputBuffer,
  3081. sizeof (*ctxInfo32),
  3082. PROBE_ALIGNMENT32 (AFD_SWITCH_TRANSFER_CTX_INFO32));
  3083. }
  3084. ctxInfo32 = InputBuffer;
  3085. ctxInfo.SocketHandle = ctxInfo32->SocketHandle;
  3086. ctxInfo.SwitchContext = ctxInfo32->SwitchContext;
  3087. ctxInfo.RequestContext = ctxInfo32->RequestContext;
  3088. ctxInfo.SocketCtxBuf = ctxInfo32->SocketCtxBuf;
  3089. ctxInfo.SocketCtxBufSize = ctxInfo32->SocketCtxBufSize;
  3090. ctxInfo.RcvBufferArray = ctxInfo32->RcvBufferArray;
  3091. ctxInfo.RcvBufferCount = ctxInfo32->RcvBufferCount;
  3092. ctxInfo.Status = ctxInfo32->Status;
  3093. if (RequestorMode!=KernelMode) {
  3094. if (ctxInfo.SocketCtxBufSize==0 ||
  3095. ctxInfo.RcvBufferCount>(MAXULONG/sizeof (WSABUF32))) {
  3096. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  3097. }
  3098. ProbeForRead (ctxInfo.SocketCtxBuf,
  3099. ctxInfo.SocketCtxBufSize,
  3100. sizeof (UCHAR));
  3101. ProbeForRead (ctxInfo.RcvBufferArray,
  3102. sizeof (WSABUF32)*ctxInfo.RcvBufferCount,
  3103. PROBE_ALIGNMENT32 (WSABUF32));
  3104. }
  3105. if (ctxInfo.RcvBufferCount>sizeof(localArray)/sizeof(localArray[0])) {
  3106. pArray = AFD_ALLOCATE_POOL_WITH_QUOTA (
  3107. NonPagedPool,
  3108. sizeof (WSABUF)*ctxInfo.RcvBufferCount,
  3109. AFD_TEMPORARY_POOL_TAG);
  3110. // AFD_ALLOCATE_POOL_WITH_QUOTA macro sets
  3111. // POOL_RAISE_IF_ALLOCATION_FAILURE flag
  3112. ASSERT (pArray!=NULL);
  3113. }
  3114. for (i=0; i<ctxInfo.RcvBufferCount; i++) {
  3115. pArray[i].buf = ctxInfo.RcvBufferArray[i].buf;
  3116. pArray[i].len = ctxInfo.RcvBufferArray[i].len;
  3117. }
  3118. ctxInfo.RcvBufferArray = pArray;
  3119. }
  3120. else
  3121. #endif //_WIN64
  3122. {
  3123. if (InputBufferLength<sizeof (ctxInfo)) {
  3124. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  3125. }
  3126. if (RequestorMode!=KernelMode) {
  3127. ProbeForReadSmallStructure (InputBuffer,
  3128. sizeof (ctxInfo),
  3129. PROBE_ALIGNMENT (AFD_SWITCH_TRANSFER_CTX_INFO));
  3130. }
  3131. ctxInfo = *((PAFD_SWITCH_TRANSFER_CTX_INFO)InputBuffer);
  3132. if (RequestorMode!=KernelMode) {
  3133. if (ctxInfo.SocketCtxBufSize==0 ||
  3134. ctxInfo.RcvBufferCount>(MAXULONG/sizeof (WSABUF))) {
  3135. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  3136. }
  3137. ProbeForRead (ctxInfo.SocketCtxBuf,
  3138. ctxInfo.SocketCtxBufSize,
  3139. sizeof (UCHAR));
  3140. ProbeForRead (ctxInfo.RcvBufferArray,
  3141. sizeof (ctxInfo.RcvBufferArray)*ctxInfo.RcvBufferCount,
  3142. PROBE_ALIGNMENT (WSABUF));
  3143. }
  3144. }
  3145. if (ctxInfo.SwitchContext==NULL) {
  3146. IF_DEBUG(SAN_SWITCH) {
  3147. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3148. "AFD: Switch context is NULL in AfdSanFastTransferCtx\n"));
  3149. }
  3150. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  3151. }
  3152. }
  3153. except (AFD_EXCEPTION_FILTER (status)) {
  3154. ASSERT (NT_ERROR (status));
  3155. goto complete;
  3156. }
  3157. ctxInfo.Status = AfdValidateStatus (ctxInfo.Status);
  3158. sanHlprEndpoint = FileObject->FsContext;
  3159. ASSERT (IS_SAN_HELPER (sanHlprEndpoint));
  3160. status = AfdSanReferenceSwitchSocketByHandle (
  3161. ctxInfo.SocketHandle,
  3162. (IoctlCode>>14)&3,
  3163. RequestorMode,
  3164. sanHlprEndpoint,
  3165. ctxInfo.SwitchContext,
  3166. &sanFileObject
  3167. );
  3168. if (!NT_SUCCESS (status)) {
  3169. goto complete;
  3170. }
  3171. sanEndpoint = sanFileObject->FsContext;
  3172. IF_DEBUG(SAN_SWITCH) {
  3173. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3174. "AfdSanFastTransferCtx: endp-%p.\n",
  3175. sanEndpoint));
  3176. }
  3177. if (ctxInfo.RequestContext==AFD_SWITCH_MAKE_REQUEST_CONTEXT (0, AFD_SWITCH_REQUEST_TFCTX)) {
  3178. //
  3179. // This is unsolicited request to transfer endpoint into
  3180. // the service process.
  3181. //
  3182. PVOID savedContext = NULL;
  3183. ULONG ctxLength;
  3184. if (NT_SUCCESS (ctxInfo.Status)) {
  3185. //
  3186. // Save the user mode data.
  3187. //
  3188. ctxLength = ctxInfo.SocketCtxBufSize;
  3189. AFD_W4_INIT ASSERT (status == STATUS_SUCCESS);
  3190. try {
  3191. if (ctxInfo.RcvBufferCount>0)
  3192. ctxLength += AfdCalcBufferArrayByteLength(
  3193. ctxInfo.RcvBufferArray,
  3194. ctxInfo.RcvBufferCount);
  3195. savedContext = AFD_ALLOCATE_POOL_WITH_QUOTA (PagedPool,
  3196. ctxLength,
  3197. AFD_SAN_CONTEXT_POOL_TAG);
  3198. ASSERT (savedContext!=NULL);
  3199. RtlCopyMemory (
  3200. savedContext,
  3201. ctxInfo.SocketCtxBuf,
  3202. ctxInfo.SocketCtxBufSize);
  3203. if (ctxInfo.RcvBufferCount>0) {
  3204. AfdCopyBufferArrayToBuffer (
  3205. (PUCHAR)savedContext+ctxInfo.SocketCtxBufSize,
  3206. ctxLength-ctxInfo.SocketCtxBufSize,
  3207. ctxInfo.RcvBufferArray,
  3208. ctxInfo.RcvBufferCount);
  3209. }
  3210. }
  3211. except (AFD_EXCEPTION_FILTER (status)) {
  3212. ASSERT (NT_ERROR (status));
  3213. goto CleanupSavedContext;
  3214. }
  3215. status = AfdSanDupEndpointIntoServiceProcess (sanFileObject, savedContext, ctxLength);
  3216. if (NT_SUCCESS (status)) {
  3217. *Information = ctxLength;
  3218. goto complete_deref;
  3219. }
  3220. CleanupSavedContext:
  3221. //
  3222. // Something failed, free the context
  3223. //
  3224. if (savedContext!=NULL) {
  3225. AFD_FREE_POOL (savedContext, AFD_SAN_CONTEXT_POOL_TAG);
  3226. }
  3227. }
  3228. else {
  3229. //
  3230. // The process could not satisfy implicit transfer context request
  3231. //
  3232. status = ctxInfo.Status;
  3233. }
  3234. }
  3235. else {
  3236. //
  3237. // The process satisfied another process acquire request
  3238. // Find it first.
  3239. //
  3240. irp = AfdSanDequeueRequest (sanEndpoint, ctxInfo.RequestContext);
  3241. if (irp!=NULL) {
  3242. //
  3243. // Get IRP stack location and perform data copy
  3244. //
  3245. irpSp = IoGetCurrentIrpStackLocation (irp);
  3246. if (NT_SUCCESS (ctxInfo.Status)) {
  3247. AFD_SWITCH_CONTEXT localContext;
  3248. //
  3249. // Set the initial status to success since the process
  3250. // agreed to satisfy the transfer.
  3251. //
  3252. AFD_W4_INIT ASSERT (status == STATUS_SUCCESS);
  3253. try {
  3254. if ( MmGetMdlByteCount(irp->MdlAddress)!=ctxInfo.SocketCtxBufSize ||
  3255. (ctxInfo.RcvBufferCount!=0 &&
  3256. irpSp->Parameters.DeviceIoControl.OutputBufferLength<
  3257. AfdCalcBufferArrayByteLength(
  3258. ctxInfo.RcvBufferArray,
  3259. ctxInfo.RcvBufferCount)) ){
  3260. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  3261. }
  3262. RtlCopyMemory (
  3263. MmGetSystemAddressForMdl (irp->MdlAddress),
  3264. ctxInfo.SocketCtxBuf,
  3265. ctxInfo.SocketCtxBufSize);
  3266. if (ctxInfo.RcvBufferCount>0) {
  3267. irp->IoStatus.Information =
  3268. AfdCopyBufferArrayToBuffer (
  3269. MmGetSystemAddressForMdl (irp->MdlAddress->Next),
  3270. irpSp->Parameters.DeviceIoControl.OutputBufferLength,
  3271. ctxInfo.RcvBufferArray,
  3272. ctxInfo.RcvBufferCount);
  3273. }
  3274. else {
  3275. irp->IoStatus.Information = 0;
  3276. }
  3277. }
  3278. except (AFD_EXCEPTION_FILTER (status)) {
  3279. goto CopyException;
  3280. }
  3281. //
  3282. // Now change sanEndpoint's SanHlpr and SwitchContext to point
  3283. // to the new address space and switch socket
  3284. //
  3285. context = AfdLockEndpointContext (sanEndpoint);
  3286. if (!IS_SAN_ENDPOINT (sanEndpoint ) ||
  3287. sanEndpoint->Common.SanEndp.CtxTransferStatus!=STATUS_PENDING) {
  3288. status = STATUS_INVALID_HANDLE;
  3289. goto UnlockContext;
  3290. }
  3291. try {
  3292. localContext = *sanEndpoint->Common.SanEndp.SwitchContext;
  3293. }
  3294. except (AFD_EXCEPTION_FILTER (status)) {
  3295. ASSERT (NT_ERROR (status));
  3296. goto UnlockContext;
  3297. }
  3298. KeAttachProcess (PsGetProcessPcb(((PAFD_ENDPOINT)irp->AfdSanRequestInfo.AfdSanHelperEndp)->OwningProcess));
  3299. try {
  3300. //
  3301. // Place info regarding select/eventselect events in SwitchContext
  3302. // of the new switch socket
  3303. //
  3304. *((PAFD_SWITCH_CONTEXT)irp->AfdSanRequestInfo.AfdSanSwitchCtx) = localContext;
  3305. }
  3306. except (AFD_EXCEPTION_FILTER (status)) {
  3307. ASSERT (NT_ERROR (status));
  3308. KeDetachProcess ();
  3309. goto UnlockContext;
  3310. }
  3311. KeDetachProcess ();
  3312. sanEndpoint->Common.SanEndp.SanHlpr = irp->AfdSanRequestInfo.AfdSanHelperEndp;
  3313. REFERENCE_ENDPOINT2 (sanEndpoint->Common.SanEndp.SanHlpr,
  3314. "Transfer TO 0x%lX",
  3315. HandleToUlong (ctxInfo.SocketHandle) );
  3316. sanEndpoint->Common.SanEndp.SwitchContext = irp->AfdSanRequestInfo.AfdSanSwitchCtx;
  3317. //
  3318. // Reset implicit dup flag if it was set.
  3319. // We are satisfying explicit request for
  3320. // duplication.
  3321. //
  3322. sanEndpoint->Common.SanEndp.ImplicitDup = FALSE;
  3323. DEREFERENCE_ENDPOINT2 (sanHlprEndpoint,
  3324. "Transfer FROM 0x%lX",
  3325. HandleToUlong (ctxInfo.SocketHandle));
  3326. UnlockContext:
  3327. AfdUnlockEndpointContext (sanEndpoint, context);
  3328. CopyException:
  3329. //
  3330. // Report the final status to the process
  3331. // that wanted duplication
  3332. //
  3333. irp->IoStatus.Status = status;
  3334. }
  3335. else {
  3336. //
  3337. // This process could not satisfy transfer request
  3338. // Tell other process about this.
  3339. //
  3340. irp->IoStatus.Status = ctxInfo.Status;
  3341. //
  3342. // We succeeded this process refuse to dup request
  3343. // we should report it as success and continue processing
  3344. // of other redirected request. It is possible that we
  3345. // can still succeed other duplication requests.
  3346. //
  3347. status = STATUS_SUCCESS;
  3348. }
  3349. //
  3350. // Complete the acquuire request from another process.
  3351. //
  3352. IoCompleteRequest (irp, AfdPriorityBoost);
  3353. }
  3354. else {
  3355. status = STATUS_INVALID_PARAMETER;
  3356. }
  3357. }
  3358. //
  3359. // Restart request processing that were pended while
  3360. // we were processing duplication request.
  3361. //
  3362. AfdSanRestartRequestProcessing (sanEndpoint, status);
  3363. complete_deref:
  3364. UPDATE_ENDPOINT2 (sanEndpoint, "AfdSanFastTransferCtx, status: 0x%lX", status);
  3365. ObDereferenceObject (sanFileObject);
  3366. complete:
  3367. #ifdef _WIN64
  3368. if (pArray!=localArray) {
  3369. AFD_FREE_POOL (pArray, AFD_TEMPORARY_POOL_TAG);
  3370. }
  3371. #endif //_WIN64
  3372. return status;
  3373. }
  3374. BOOLEAN
  3375. AfdSanFastUnlockAll (
  3376. IN PFILE_OBJECT FileObject,
  3377. IN PEPROCESS Process,
  3378. OUT PIO_STATUS_BLOCK IoStatus,
  3379. IN PDEVICE_OBJECT DeviceObject
  3380. )
  3381. /*++
  3382. Routine Description:
  3383. Called by the system when last handle to the file object in closed
  3384. in some process while other processes still have handles opened
  3385. This is only called on files that were marked as locked at some point of time.
  3386. Arguments:
  3387. FileObject - file object of interest
  3388. Process - process which has last handle being closed
  3389. IoStatus - buffer to return operation status and information
  3390. DeviceObject - device object with which file object is associated
  3391. Return Value:
  3392. TRUE - operation completed OK.
  3393. --*/
  3394. {
  3395. PAFD_ENDPOINT sanEndpoint;
  3396. PVOID context;
  3397. PAGED_CODE ();
  3398. UNREFERENCED_PARAMETER (DeviceObject);
  3399. PAGED_CODE ();
  3400. sanEndpoint = FileObject->FsContext;
  3401. context = AfdLockEndpointContext (sanEndpoint);
  3402. if (IS_SAN_ENDPOINT (sanEndpoint)) {
  3403. ASSERT (sanEndpoint->Common.SanEndp.SanHlpr!=NULL);
  3404. if (sanEndpoint->Common.SanEndp.SanHlpr->OwningProcess==Process) {
  3405. NTSTATUS status = STATUS_CANCELLED;
  3406. //
  3407. // Owner process is closing it.
  3408. //
  3409. if (sanEndpoint->Common.SanEndp.SanHlpr!=AfdSanServiceHelper) {
  3410. NTSTATUS dupStatus;
  3411. dupStatus = AfdSanSetAskDupeToServiceState (sanEndpoint);
  3412. if (dupStatus == STATUS_PENDING ||
  3413. dupStatus == STATUS_MORE_PROCESSING_REQUIRED) {
  3414. //
  3415. // Some other process is already trying to import this socket. Let
  3416. // that complete
  3417. //
  3418. AfdUnlockEndpointContext (sanEndpoint, context);
  3419. goto Exit;
  3420. }
  3421. if (NT_SUCCESS (dupStatus)) {
  3422. PAFD_ENDPOINT sanHlprEndpoint = sanEndpoint->Common.SanEndp.SanHlpr;
  3423. //
  3424. // Last handle in the process that owns the socket is being
  3425. // closed while there are handles to it in other processes.
  3426. // Need to transfer the context to the service process
  3427. //
  3428. if ((InterlockedExchangeAdd (&sanHlprEndpoint->Common.SanHlpr.PendingRequests, 2) & 1)==0) {
  3429. status = IoSetIoCompletion (
  3430. sanHlprEndpoint->Common.SanHlpr.IoCompletionPort,
  3431. sanEndpoint->Common.SanEndp.SwitchContext,
  3432. AFD_SWITCH_MAKE_REQUEST_CONTEXT (0, AFD_SWITCH_REQUEST_TFCTX),
  3433. STATUS_SUCCESS,
  3434. (ULONG_PTR)AfdSanServicePid,
  3435. FALSE // ChargeQuota - Don't, handle is going away, no
  3436. // way for the run-away app to mount an attack
  3437. );
  3438. UPDATE_ENDPOINT2 (sanEndpoint, "Implicit TFCTX request, status: 0x%lX", status);
  3439. if (NT_SUCCESS (status)) {
  3440. AfdUnlockEndpointContext (sanEndpoint, context);
  3441. goto Exit;
  3442. }
  3443. }
  3444. else {
  3445. //
  3446. // Process has already exited, not much we can do.
  3447. //
  3448. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
  3449. "AFD: Process %p has exited before SAN context could be transferred out.\n",
  3450. Process));
  3451. }
  3452. InterlockedExchangeAdd (&sanHlprEndpoint->Common.SanHlpr.PendingRequests, -2);
  3453. }
  3454. }
  3455. AfdUnlockEndpointContext (sanEndpoint, context);
  3456. AfdSanRestartRequestProcessing (sanEndpoint, status);
  3457. }
  3458. else {
  3459. if (sanEndpoint->Common.SanEndp.ImplicitDup) {
  3460. AfdUnlockEndpointContext (sanEndpoint, context);
  3461. //
  3462. // Process is exiting and the only handle is in the
  3463. // other process where the handle was duplicated
  3464. // impilictly (without application request, e.g.
  3465. // cross proceess accepting socket duplicated into
  3466. // listening process to complete the accept or socket
  3467. // duplication into service process while waiting on
  3468. // other process to request ownership).
  3469. //
  3470. if (ObReferenceObject (FileObject)==3) {
  3471. NTSTATUS oldStatus;
  3472. // Why are we checking for refcount of 3?
  3473. // 1 - Handle in the implicit process
  3474. // 1 - IO manager for this call
  3475. // 1 - we just added
  3476. oldStatus = AfdSanRestartRequestProcessing (sanEndpoint, STATUS_CANCELLED);
  3477. if (NT_SUCCESS (oldStatus)) {
  3478. ASSERT (oldStatus!=STATUS_PENDING);
  3479. ASSERT ((ULONG_PTR)sanEndpoint->Common.SanEndp.SwitchContext<MM_USER_PROBE_ADDRESS);
  3480. //
  3481. // Notify the service process only if duplication has already
  3482. // completed
  3483. //
  3484. UPDATE_ENDPOINT2 (sanEndpoint, "AfdSanFastUnlockAll, posting CLSOCK", 0);
  3485. IoSetIoCompletion (
  3486. sanEndpoint->Common.SanEndp.SanHlpr->Common.SanHlpr.IoCompletionPort,
  3487. sanEndpoint->Common.SanEndp.SwitchContext,
  3488. AFD_SWITCH_MAKE_REQUEST_CONTEXT (0, AFD_SWITCH_REQUEST_CLSOC),
  3489. STATUS_SUCCESS,
  3490. (ULONG_PTR)0,
  3491. FALSE); // ChargeQuota - Don't, handle is going away, no
  3492. // way for the run-away app to mount an attack
  3493. }
  3494. }
  3495. ObDereferenceObject (FileObject);
  3496. }
  3497. else {
  3498. AfdUnlockEndpointContext (sanEndpoint, context);
  3499. }
  3500. }
  3501. }
  3502. else if (IS_SAN_HELPER (sanEndpoint)) {
  3503. //
  3504. // Helper never change to it safe to release the lock.
  3505. //
  3506. AfdUnlockEndpointContext (sanEndpoint, context);
  3507. //
  3508. // The process for which helper was created is exiting
  3509. // we need to cleanup all the endpoint that refer to this helper.
  3510. //
  3511. if (sanEndpoint->OwningProcess==Process) {
  3512. AfdSanHelperCleanup (sanEndpoint);
  3513. }
  3514. }
  3515. else {
  3516. //
  3517. // non-SAN endpoint. Someone else called NtLockFile on endpoint
  3518. // file object ...
  3519. //
  3520. AfdUnlockEndpointContext (sanEndpoint, context);
  3521. }
  3522. Exit:
  3523. IoStatus->Status = STATUS_SUCCESS;
  3524. IoStatus->Information = 0;
  3525. return TRUE;
  3526. }
  3527. //
  3528. // Internal routines.
  3529. //
  3530. NTSTATUS
  3531. AfdSanAcceptCore (
  3532. PIRP AcceptIrp,
  3533. PFILE_OBJECT AcceptFileObject,
  3534. PAFD_CONNECTION Connection,
  3535. PAFD_LOCK_QUEUE_HANDLE LockHandle
  3536. )
  3537. /*++
  3538. Routine Description:
  3539. Accept the incoming SAN connection on endpoint provided
  3540. Arguments:
  3541. AcceptIrp - accept IRP to complete
  3542. AcceptFileObject - file object of accepting endpoint
  3543. Connection - pointer to connection object that represents the incoming connection
  3544. LockHandle - IRQL at which listening endpoint spinlock was taken on entry to this routine.
  3545. Return Value:
  3546. STATUS_PENDING - accept operation started OK
  3547. STATUS_REMOTE_DISCONNECT - connection being accepted was aborted by the remote.
  3548. STATUS_CANCELLED - accepting endpoint was closed or accept IRP cancelled
  3549. --*/
  3550. {
  3551. PIRP connectIrp;
  3552. PIO_STACK_LOCATION irpSp;
  3553. PAFD_SWITCH_CONNECT_INFO connectInfo;
  3554. PAFD_ENDPOINT listenEndpoint, acceptEndpoint;
  3555. HANDLE acceptHandle;
  3556. ULONG receiveLength;
  3557. PKPROCESS listenProcess;
  3558. ASSERT (LockHandle->LockHandle.OldIrql < DISPATCH_LEVEL);
  3559. irpSp = IoGetCurrentIrpStackLocation (AcceptIrp);
  3560. listenEndpoint = irpSp->FileObject->FsContext;
  3561. acceptEndpoint = AcceptFileObject->FsContext;
  3562. ASSERT (Connection->SanConnection);
  3563. //
  3564. // Snag the connect indication IRP
  3565. //
  3566. connectIrp = Connection->ConnectIrp;
  3567. ASSERT (connectIrp!=NULL);
  3568. Connection->ConnectIrp = NULL;
  3569. //
  3570. // Handle EventSelect signalling
  3571. //
  3572. listenEndpoint->EventsActive &= ~AFD_POLL_ACCEPT;
  3573. IF_DEBUG(EVENT_SELECT) {
  3574. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3575. "AfdSanAcceptCore: Endp %p, Active %lx\n",
  3576. listenEndpoint,
  3577. listenEndpoint->EventsActive
  3578. ));
  3579. }
  3580. if (!IsListEmpty (&listenEndpoint->Common.VcListening.UnacceptedConnectionListHead ) ) {
  3581. AfdIndicateEventSelectEvent(
  3582. listenEndpoint,
  3583. AFD_POLL_ACCEPT,
  3584. STATUS_SUCCESS
  3585. );
  3586. }
  3587. //
  3588. // We no longer need the connection object for SAN
  3589. // endpoint, return it
  3590. //
  3591. Connection->Endpoint = NULL;
  3592. Connection->SanConnection = FALSE;
  3593. AfdSanReleaseConnection (listenEndpoint, Connection, FALSE);
  3594. DEREFERENCE_ENDPOINT (listenEndpoint);
  3595. if (IoSetCancelRoutine (connectIrp, NULL)==NULL) {
  3596. AfdReleaseSpinLock (&listenEndpoint->SpinLock, LockHandle);
  3597. connectIrp->IoStatus.Status = STATUS_CANCELLED;
  3598. connectIrp->IoStatus.Information = 0;
  3599. IoCompleteRequest (connectIrp, AfdPriorityBoost);
  3600. return STATUS_REMOTE_DISCONNECT;
  3601. }
  3602. AfdReleaseSpinLock (&listenEndpoint->SpinLock, LockHandle);
  3603. //
  3604. // Check that accept IRP and SAN connection IRP belong to the same process
  3605. //
  3606. if (IoThreadToProcess (AcceptIrp->Tail.Overlay.Thread)!=
  3607. IoThreadToProcess (connectIrp->Tail.Overlay.Thread)) {
  3608. //
  3609. // Listen process is different than the accepting one.
  3610. // We need to duplicate accepting handle into the listening
  3611. // process so that accept can take place there and the accepting
  3612. // socket will later get dup-ed into the accepting process when
  3613. // that process performs an IO operation on it.
  3614. //
  3615. NTSTATUS status;
  3616. listenProcess = PsGetProcessPcb(IoThreadToProcess (connectIrp->Tail.Overlay.Thread));
  3617. KeAttachProcess (listenProcess);
  3618. status = ObOpenObjectByPointer (
  3619. AcceptFileObject,
  3620. OBJ_CASE_INSENSITIVE,
  3621. NULL,
  3622. MAXIMUM_ALLOWED,
  3623. *IoFileObjectType,
  3624. KernelMode,
  3625. &acceptHandle);
  3626. KeDetachProcess ();
  3627. if (!NT_SUCCESS (status)) {
  3628. connectIrp->IoStatus.Status = STATUS_INVALID_HANDLE;
  3629. connectIrp->IoStatus.Information = 0;
  3630. IoCompleteRequest (connectIrp, AfdPriorityBoost);
  3631. return STATUS_REMOTE_DISCONNECT;
  3632. }
  3633. }
  3634. else {
  3635. acceptHandle = AcceptIrp->Tail.Overlay.DriverContext[3];
  3636. listenProcess = NULL;
  3637. }
  3638. //
  3639. // Now take care of the accept endpoint
  3640. //
  3641. AfdAcquireSpinLock (&acceptEndpoint->SpinLock, LockHandle);
  3642. IoSetCancelRoutine (AcceptIrp, AfdSanCancelAccept);
  3643. if (acceptEndpoint->EndpointCleanedUp || AcceptIrp->Cancel) {
  3644. //
  3645. // Endpoint was closed or IRP cancelled,
  3646. // reset accept irp pointer and return error
  3647. // to both application and SAN provider (to refuse
  3648. // the connection)
  3649. //
  3650. AcceptIrp->Tail.Overlay.ListEntry.Flink = NULL;
  3651. AfdReleaseSpinLock (&acceptEndpoint->SpinLock, LockHandle);
  3652. if (listenProcess!=NULL) {
  3653. #if DBG
  3654. NTSTATUS status;
  3655. #endif
  3656. //
  3657. // Destroy the handle that we created for
  3658. // accepting socket duplication.
  3659. //
  3660. KeAttachProcess (listenProcess);
  3661. #if DBG
  3662. status =
  3663. #endif
  3664. NtClose (acceptHandle);
  3665. KeDetachProcess ();
  3666. ASSERT (NT_SUCCESS (status));
  3667. }
  3668. connectIrp->IoStatus.Status = STATUS_CANCELLED;
  3669. connectIrp->IoStatus.Information = 0;
  3670. IoCompleteRequest (connectIrp, AfdPriorityBoost);
  3671. //
  3672. // If AcceptIrp's Cancel routine is running, let it finish.
  3673. // Once we return, caller will complete the AcceptIrp
  3674. //
  3675. if (IoSetCancelRoutine (AcceptIrp, NULL)==NULL) {
  3676. KIRQL cancelIrql;
  3677. IoAcquireCancelSpinLock (&cancelIrql);
  3678. IoReleaseCancelSpinLock (cancelIrql);
  3679. }
  3680. return STATUS_CANCELLED;
  3681. }
  3682. //
  3683. // Pend the accept IRP till provider
  3684. // completes it. This may take quite a while,
  3685. // which is not expected by the msafd and application,
  3686. // but we have no choice here
  3687. //
  3688. IoMarkIrpPending (AcceptIrp);
  3689. irpSp = IoGetCurrentIrpStackLocation (AcceptIrp);
  3690. receiveLength = irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength;
  3691. connectInfo = connectIrp->AssociatedIrp.SystemBuffer;
  3692. //
  3693. // Remove super accept IRP from the endpoint
  3694. //
  3695. acceptEndpoint->Irp = NULL;
  3696. //
  3697. // Convert endpoint to SAN
  3698. //
  3699. AfdSanInitEndpoint (IoGetCurrentIrpStackLocation (connectIrp)->FileObject->FsContext,
  3700. AcceptFileObject,
  3701. connectInfo->SwitchContext);
  3702. if (listenProcess!=NULL) {
  3703. //
  3704. // Note that socket was duplicated implicitly, without application request
  3705. //
  3706. acceptEndpoint->Common.SanEndp.ImplicitDup = TRUE;
  3707. }
  3708. UPDATE_ENDPOINT2 (acceptEndpoint, "AfdSanAcceptCore, accepted with bytes: 0x%lX", receiveLength);
  3709. InsertTailList (&acceptEndpoint->Common.SanEndp.IrpList,
  3710. &AcceptIrp->Tail.Overlay.ListEntry);
  3711. if (irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdRemoteAddressLength>0) {
  3712. ULONG remoteAddressLength =
  3713. FIELD_OFFSET (
  3714. TRANSPORT_ADDRESS,
  3715. Address[0].Address[
  3716. connectInfo->RemoteAddress.Address[0].AddressLength]);
  3717. #ifndef i386
  3718. if (acceptEndpoint->Common.VcConnecting.FixAddressAlignment) {
  3719. USHORT addressLength =
  3720. connectInfo->RemoteAddress.Address[0].AddressLength
  3721. + sizeof (USHORT);
  3722. USHORT UNALIGNED *pAddrLength = (PVOID)
  3723. ((PUCHAR)MmGetSystemAddressForMdl (AcceptIrp->MdlAddress)
  3724. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength
  3725. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength
  3726. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdRemoteAddressLength
  3727. - sizeof (USHORT));
  3728. RtlMoveMemory (
  3729. (PUCHAR)MmGetSystemAddressForMdl (AcceptIrp->MdlAddress)
  3730. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength
  3731. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength,
  3732. &connectInfo->RemoteAddress.Address[0].AddressType,
  3733. addressLength);
  3734. *pAddrLength = addressLength;
  3735. }
  3736. else
  3737. #endif
  3738. {
  3739. RtlMoveMemory (
  3740. (PUCHAR)MmGetSystemAddressForMdl (AcceptIrp->MdlAddress)
  3741. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength
  3742. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength,
  3743. &connectInfo->RemoteAddress,
  3744. remoteAddressLength);
  3745. }
  3746. if (irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength>0) {
  3747. PTA_ADDRESS localAddress = (PTA_ADDRESS)
  3748. &(connectInfo->RemoteAddress.Address[0].Address[
  3749. connectInfo->RemoteAddress.Address[0].AddressLength]);
  3750. TDI_ADDRESS_INFO UNALIGNED *addressInfo = (PVOID)
  3751. ((PUCHAR)MmGetSystemAddressForMdl(AcceptIrp->MdlAddress)
  3752. + irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdReceiveDataLength);
  3753. #ifndef i386
  3754. if (acceptEndpoint->Common.VcConnecting.FixAddressAlignment) {
  3755. USHORT UNALIGNED * pAddrLength = (PVOID)
  3756. ((PUCHAR)addressInfo
  3757. +irpSp->Parameters.AfdRestartSuperAcceptInfo.AfdLocalAddressLength
  3758. -sizeof(USHORT));
  3759. RtlMoveMemory (
  3760. addressInfo,
  3761. &localAddress->AddressType,
  3762. localAddress->AddressLength+sizeof (USHORT));
  3763. *pAddrLength = localAddress->AddressLength+sizeof (USHORT);
  3764. }
  3765. else
  3766. #endif
  3767. {
  3768. addressInfo->ActivityCount = 0;
  3769. addressInfo->Address.TAAddressCount = 1;
  3770. RtlMoveMemory (
  3771. &addressInfo->Address.Address,
  3772. localAddress,
  3773. FIELD_OFFSET (TA_ADDRESS, Address[localAddress->AddressLength]));
  3774. }
  3775. }
  3776. }
  3777. AfdReleaseSpinLock (&acceptEndpoint->SpinLock, LockHandle);
  3778. //
  3779. // Setup the accept info for the provider
  3780. //
  3781. //
  3782. // Do this under protection of exception handler since application
  3783. // can change protection attributes of the virtual address range
  3784. // or even deallocate it. Make sure to attach to the listening
  3785. // process if necessary.
  3786. //
  3787. if (listenProcess!=NULL) {
  3788. KeAttachProcess (listenProcess);
  3789. }
  3790. else {
  3791. ASSERT (IoGetCurrentProcess ()==IoThreadToProcess (connectIrp->Tail.Overlay.Thread));
  3792. }
  3793. try {
  3794. #ifdef _WIN64
  3795. if (IoIs32bitProcess (connectIrp)) {
  3796. PAFD_SWITCH_ACCEPT_INFO32 acceptInfo32;
  3797. acceptInfo32 = MmGetMdlVirtualAddress (connectIrp->MdlAddress);
  3798. ASSERT (acceptInfo32!=NULL);
  3799. ASSERT (MmGetMdlByteCount (connectIrp->MdlAddress)>=sizeof (*acceptInfo32));
  3800. acceptInfo32->AcceptHandle = (VOID * POINTER_32)acceptHandle;
  3801. acceptInfo32->ReceiveLength = receiveLength;
  3802. connectIrp->IoStatus.Information = sizeof (*acceptInfo32);
  3803. }
  3804. else
  3805. #endif _WIN64
  3806. {
  3807. PAFD_SWITCH_ACCEPT_INFO acceptInfo;
  3808. acceptInfo = MmGetMdlVirtualAddress (connectIrp->MdlAddress);
  3809. ASSERT (acceptInfo!=NULL);
  3810. ASSERT (MmGetMdlByteCount (connectIrp->MdlAddress)>=sizeof (*acceptInfo));
  3811. acceptInfo->AcceptHandle = acceptHandle;
  3812. acceptInfo->ReceiveLength = receiveLength;
  3813. connectIrp->IoStatus.Information = sizeof (*acceptInfo);
  3814. }
  3815. connectIrp->IoStatus.Status = (listenProcess==NULL) ? STATUS_SUCCESS : STATUS_MORE_ENTRIES;
  3816. }
  3817. except (AFD_EXCEPTION_FILTER (connectIrp->IoStatus.Status)) {
  3818. //
  3819. // If the app is playing with switch's virtual addresses
  3820. // we can't help much - it's accept IRP will probably
  3821. // just hang since the switch is not going to follow
  3822. // the failed connect IRP with accept completion.
  3823. //
  3824. }
  3825. if (listenProcess!=NULL) {
  3826. KeDetachProcess ();
  3827. }
  3828. //
  3829. // Complete the provider IRP.
  3830. //
  3831. IoCompleteRequest (connectIrp, AfdPriorityBoost);
  3832. return STATUS_PENDING;
  3833. }
  3834. VOID
  3835. AfdSanReleaseConnection (
  3836. PAFD_ENDPOINT ListenEndpoint,
  3837. PAFD_CONNECTION Connection,
  3838. BOOLEAN CheckBacklog
  3839. )
  3840. {
  3841. LONG failedAdds;
  3842. failedAdds = InterlockedDecrement (
  3843. &ListenEndpoint->Common.VcListening.FailedConnectionAdds);
  3844. if (CheckBacklog || failedAdds>=0) {
  3845. if (!IS_DELAYED_ACCEPTANCE_ENDPOINT (ListenEndpoint)) {
  3846. InterlockedPushEntrySList (
  3847. &ListenEndpoint->Common.VcListening.FreeConnectionListHead,
  3848. &Connection->SListEntry
  3849. );
  3850. return;
  3851. }
  3852. else {
  3853. NTSTATUS status;
  3854. status = AfdDelayedAcceptListen (ListenEndpoint, Connection);
  3855. if (NT_SUCCESS (status)) {
  3856. return;
  3857. }
  3858. }
  3859. }
  3860. InterlockedIncrement(
  3861. &ListenEndpoint->Common.VcListening.FailedConnectionAdds
  3862. );
  3863. DEREFERENCE_CONNECTION (Connection);
  3864. }
  3865. VOID
  3866. AfdSanCancelConnect (
  3867. IN PDEVICE_OBJECT DeviceObject,
  3868. IN PIRP Irp
  3869. )
  3870. /*++
  3871. Routine Description:
  3872. Cancels a connection indication IRP from SAN provider
  3873. Arguments:
  3874. DeviceObject - not used.
  3875. Irp - the IRP to cancel.
  3876. Return Value:
  3877. None.
  3878. --*/
  3879. {
  3880. PIO_STACK_LOCATION irpSp;
  3881. PAFD_CONNECTION connection;
  3882. PAFD_ENDPOINT endpoint;
  3883. AFD_LOCK_QUEUE_HANDLE lockHandle;
  3884. UNREFERENCED_PARAMETER (DeviceObject);
  3885. irpSp = IoGetCurrentIrpStackLocation (Irp);
  3886. connection = irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  3887. ASSERT (connection->Type==AfdBlockTypeConnection);
  3888. ASSERT (connection->SanConnection);
  3889. endpoint = connection->Endpoint;
  3890. ASSERT (IS_AFD_ENDPOINT_TYPE (endpoint));
  3891. ASSERT (endpoint->Listening);
  3892. ASSERT (KeGetCurrentIrql ()==DISPATCH_LEVEL);
  3893. AfdAcquireSpinLockAtDpcLevel (&endpoint->SpinLock, &lockHandle);
  3894. //
  3895. // If IRP still there, cancel it.
  3896. // Otherwise, it is being completed anyway.
  3897. //
  3898. if (connection->ConnectIrp!=NULL) {
  3899. IF_DEBUG(SAN_SWITCH) {
  3900. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3901. "AfdSanCancelConnect: endp-%p, irp-%p\n",
  3902. endpoint, Irp));
  3903. }
  3904. ASSERT (connection->ConnectIrp == Irp);
  3905. connection->ConnectIrp = NULL;
  3906. ASSERT (connection->Endpoint == endpoint);
  3907. connection->Endpoint = NULL;
  3908. connection->SanConnection = FALSE;
  3909. ASSERT (connection->State == AfdConnectionStateUnaccepted ||
  3910. connection->State==AfdConnectionStateReturned);
  3911. RemoveEntryList (&connection->ListEntry);
  3912. AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &lockHandle);
  3913. IoReleaseCancelSpinLock (Irp->CancelIrql);
  3914. ASSERT ((endpoint->Type&AfdBlockTypeVcListening)==AfdBlockTypeVcListening);
  3915. AfdSanReleaseConnection (endpoint, connection, TRUE);
  3916. DEREFERENCE_ENDPOINT (endpoint);
  3917. Irp->IoStatus.Status = STATUS_CANCELLED;
  3918. Irp->IoStatus.Information = 0;
  3919. IoCompleteRequest (Irp, AfdPriorityBoost);
  3920. }
  3921. else {
  3922. //
  3923. // Irp is about to be completed.
  3924. //
  3925. AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &lockHandle);
  3926. IoReleaseCancelSpinLock (Irp->CancelIrql);
  3927. }
  3928. }
  3929. VOID
  3930. AfdSanCancelAccept (
  3931. IN PDEVICE_OBJECT DeviceObject,
  3932. IN PIRP Irp
  3933. )
  3934. /*++
  3935. Routine Description:
  3936. Cancels an accept IRP from application waiting on accept
  3937. completion from SAN
  3938. Arguments:
  3939. DeviceObject - not used.
  3940. Irp - the IRP to cancel.
  3941. Return Value:
  3942. None.
  3943. --*/
  3944. {
  3945. PIO_STACK_LOCATION irpSp;
  3946. PFILE_OBJECT acceptFileObject;
  3947. PAFD_ENDPOINT acceptEndpoint;
  3948. AFD_LOCK_QUEUE_HANDLE lockHandle;
  3949. UNREFERENCED_PARAMETER (DeviceObject);
  3950. irpSp = IoGetCurrentIrpStackLocation (Irp);
  3951. acceptFileObject = irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  3952. acceptEndpoint = acceptFileObject->FsContext;
  3953. ASSERT (acceptEndpoint->Type==AfdBlockTypeSanEndpoint);
  3954. ASSERT (KeGetCurrentIrql()==DISPATCH_LEVEL);
  3955. AfdAcquireSpinLockAtDpcLevel (&acceptEndpoint->SpinLock, &lockHandle);
  3956. //
  3957. // If IRP still there, cancel it.
  3958. // Otherwise, it is being completed anyway.
  3959. //
  3960. if (Irp->Tail.Overlay.ListEntry.Flink!=NULL) {
  3961. RemoveEntryList (&Irp->Tail.Overlay.ListEntry);
  3962. IF_DEBUG(SAN_SWITCH) {
  3963. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3964. "AfdSanCancelAccept: endp-%p, irp-%p\n",
  3965. acceptEndpoint, Irp));
  3966. }
  3967. if (!acceptEndpoint->EndpointCleanedUp) {
  3968. ASSERT (acceptEndpoint->Common.SanEndp.SanHlpr!=NULL);
  3969. DEREFERENCE_ENDPOINT (acceptEndpoint->Common.SanEndp.SanHlpr);
  3970. //
  3971. // Make sure we cleanup all the fields since they will be
  3972. // treated as other part (VC) of the endpoint union.
  3973. //
  3974. RtlZeroMemory (&acceptEndpoint->Common.SanEndp,
  3975. sizeof (acceptEndpoint->Common.SanEndp));
  3976. //
  3977. // Reinitialize the endpoint structure.
  3978. //
  3979. acceptEndpoint->Type = AfdBlockTypeEndpoint;
  3980. acceptEndpoint->State = AfdEndpointStateOpen;
  3981. acceptEndpoint->DisconnectMode = 0;
  3982. acceptEndpoint->EndpointStateFlags = 0;
  3983. }
  3984. AfdReleaseSpinLockFromDpcLevel (&acceptEndpoint->SpinLock, &lockHandle);
  3985. IoReleaseCancelSpinLock (Irp->CancelIrql);
  3986. AFD_END_STATE_CHANGE (acceptEndpoint);
  3987. //
  3988. // Dereference accept file object and complete the IRP.
  3989. //
  3990. ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
  3991. ObDereferenceObject (acceptFileObject);
  3992. Irp->IoStatus.Status = STATUS_CANCELLED;
  3993. Irp->IoStatus.Information = 0;
  3994. IoCompleteRequest (Irp, AfdPriorityBoost);
  3995. }
  3996. else {
  3997. //
  3998. // Irp is about to be completed.
  3999. //
  4000. AfdReleaseSpinLockFromDpcLevel (&acceptEndpoint->SpinLock, &lockHandle);
  4001. IoReleaseCancelSpinLock (Irp->CancelIrql);
  4002. }
  4003. }
  4004. VOID
  4005. AfdSanCancelRequest (
  4006. IN PDEVICE_OBJECT DeviceObject,
  4007. IN PIRP Irp
  4008. )
  4009. /*++
  4010. Routine Description:
  4011. Cancels a redirected IRP
  4012. Arguments:
  4013. DeviceObject - not used.
  4014. Irp - the IRP to cancel.
  4015. Return Value:
  4016. None.
  4017. --*/
  4018. {
  4019. PIO_STACK_LOCATION irpSp;
  4020. PAFD_ENDPOINT endpoint;
  4021. AFD_LOCK_QUEUE_HANDLE lockHandle;
  4022. UNREFERENCED_PARAMETER (DeviceObject);
  4023. irpSp = IoGetCurrentIrpStackLocation (Irp);
  4024. endpoint = irpSp->FileObject->FsContext;
  4025. ASSERT (endpoint->Type==AfdBlockTypeSanEndpoint);
  4026. ASSERT (KeGetCurrentIrql ()==DISPATCH_LEVEL);
  4027. AfdAcquireSpinLockAtDpcLevel (&endpoint->SpinLock, &lockHandle);
  4028. //
  4029. // If IRP still there, cancel it.
  4030. // Otherwise, it is being completed anyway.
  4031. //
  4032. if (Irp->Tail.Overlay.ListEntry.Flink!=NULL) {
  4033. BOOLEAN needRestartProcessing = FALSE;
  4034. RemoveEntryList (&Irp->Tail.Overlay.ListEntry);
  4035. if (AFD_SWITCH_REQUEST_TYPE (Irp->AfdSanRequestInfo.AfdSanRequestCtx)
  4036. == AFD_SWITCH_REQUEST_TFCTX) {
  4037. //
  4038. // Request being cancelled is transfer request. We are suspending
  4039. // other requests while processing this one, so we need to reset
  4040. // the transfer status to allow further requests to proceed and
  4041. // if there are some requests pending already, we need to initiate
  4042. // them but only AFTER we informed the switch that transfer request
  4043. // was cancelled.
  4044. //
  4045. ASSERT (endpoint->Common.SanEndp.CtxTransferStatus==STATUS_PENDING);
  4046. if (!IsListEmpty (&endpoint->Common.SanEndp.IrpList)) {
  4047. needRestartProcessing = TRUE;
  4048. }
  4049. else {
  4050. endpoint->Common.SanEndp.CtxTransferStatus = STATUS_SUCCESS;
  4051. }
  4052. }
  4053. AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &lockHandle);
  4054. IoReleaseCancelSpinLock (Irp->CancelIrql);
  4055. IF_DEBUG(SAN_SWITCH) {
  4056. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  4057. "AfdSanCancelRequest: endp-%p, irp-%p, context-%p\n",
  4058. endpoint, Irp, Irp->AfdSanRequestInfo.AfdSanRequestCtx));
  4059. }
  4060. Irp->IoStatus.Status = STATUS_CANCELLED;
  4061. Irp->IoStatus.Information = 0;
  4062. if (Irp->AfdSanRequestInfo.AfdSanRequestCtx!=NULL) {
  4063. //
  4064. // Notify the switch that request was cancelled
  4065. //
  4066. AfdSanNotifyRequest (endpoint, Irp->AfdSanRequestInfo.AfdSanRequestCtx,
  4067. STATUS_CANCELLED,
  4068. 0);
  4069. if (needRestartProcessing) {
  4070. AfdSanRestartRequestProcessing (endpoint, STATUS_SUCCESS);
  4071. }
  4072. }
  4073. else {
  4074. ASSERT (needRestartProcessing==FALSE);
  4075. }
  4076. IoCompleteRequest (Irp, AfdPriorityBoost);
  4077. }
  4078. else {
  4079. //
  4080. // Irp is about to be completed.
  4081. //
  4082. AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &lockHandle);
  4083. IoReleaseCancelSpinLock (Irp->CancelIrql);
  4084. }
  4085. }
  4086. NTSTATUS
  4087. AfdSanRestartRequestProcessing (
  4088. PAFD_ENDPOINT Endpoint,
  4089. NTSTATUS Status
  4090. )
  4091. /*++
  4092. Routine Description:
  4093. Restarts request processing after completion of the
  4094. transfer context request.
  4095. Arguments:
  4096. Endpoint - endpoint on which to restart request processing
  4097. Status - new context transfer status
  4098. Return Value:
  4099. NTSTATUS previous transfer status
  4100. --*/
  4101. {
  4102. AFD_LOCK_QUEUE_HANDLE lockHandle;
  4103. NTSTATUS oldStatus;
  4104. Again:
  4105. AfdAcquireSpinLock (&Endpoint->SpinLock, &lockHandle);
  4106. if (!IS_SAN_ENDPOINT (Endpoint)) {
  4107. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  4108. return STATUS_INVALID_HANDLE;
  4109. }
  4110. oldStatus = Endpoint->Common.SanEndp.CtxTransferStatus;
  4111. ASSERT (Status!=STATUS_PENDING && Status!=STATUS_MORE_PROCESSING_REQUIRED);
  4112. //
  4113. // The enpoint should have just finished transferring context
  4114. // from one process to another. The CtxTransferStatus
  4115. // should still be pending or failure (e.g. if we jumped with
  4116. // goto below while another thread produced a failure).
  4117. //
  4118. ASSERT (Endpoint->Common.SanEndp.CtxTransferStatus==STATUS_PENDING ||
  4119. Endpoint->Common.SanEndp.CtxTransferStatus==STATUS_MORE_PROCESSING_REQUIRED ||
  4120. !NT_SUCCESS (Endpoint->Common.SanEndp.CtxTransferStatus) ||
  4121. !NT_SUCCESS (Status));
  4122. if (!NT_SUCCESS (Status)) {
  4123. PLIST_ENTRY irpList = NULL;
  4124. PVOID savedContext = NULL;
  4125. //
  4126. // Cleanup paged pool context that we saved for the switch.
  4127. //
  4128. if (Endpoint->Common.SanEndp.CtxTransferStatus==STATUS_MORE_PROCESSING_REQUIRED &&
  4129. Endpoint->Common.SanEndp.SavedContext!=NULL) {
  4130. //
  4131. // Save it to free when we release the spinlock - can free
  4132. // paged pool at DPC.
  4133. //
  4134. ASSERT (IS_SYSTEM_ADDRESS (Endpoint->Common.SanEndp.SavedContext));
  4135. savedContext = Endpoint->Common.SanEndp.SavedContext;
  4136. Endpoint->Common.SanEndp.SavedContext = NULL;
  4137. Endpoint->Common.SanEndp.SavedContextLength = 0;
  4138. }
  4139. //
  4140. // Reset the status to failure and get rid of all the requests
  4141. // after spinlock is released.
  4142. //
  4143. Endpoint->Common.SanEndp.CtxTransferStatus = Status;
  4144. while (!IsListEmpty (&Endpoint->Common.SanEndp.IrpList)) {
  4145. PLIST_ENTRY listEntry;
  4146. listEntry = RemoveHeadList (&Endpoint->Common.SanEndp.IrpList);
  4147. //
  4148. // Mark Flink so that cancel routine knows that request is being completed.
  4149. // Use Blink to create a singly-linked list of IRPs to complete.
  4150. //
  4151. listEntry->Flink = NULL;
  4152. listEntry->Blink = irpList;
  4153. irpList = listEntry;
  4154. }
  4155. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  4156. if (savedContext!=NULL) {
  4157. InterlockedExchangeAdd (&Endpoint->Common.SanEndp.SanHlpr->Common.SanHlpr.PendingRequests, -2);
  4158. AFD_FREE_POOL (savedContext, AFD_SAN_CONTEXT_POOL_TAG);
  4159. }
  4160. while (irpList!=NULL) {
  4161. PIRP irp;
  4162. irp = CONTAINING_RECORD (irpList, IRP, Tail.Overlay.ListEntry);
  4163. irpList = irp->Tail.Overlay.ListEntry.Blink;
  4164. if (irp->AfdSanRequestInfo.AfdSanRequestCtx!=NULL) {
  4165. InterlockedExchangeAdd (&Endpoint->Common.SanEndp.SanHlpr->Common.SanHlpr.PendingRequests, -2);
  4166. }
  4167. //
  4168. // Check if request is being cancelled and synchronize
  4169. // with the cancel routine if so.
  4170. //
  4171. if (IoSetCancelRoutine (irp, NULL)==NULL) {
  4172. KIRQL cancelIrql;
  4173. IoAcquireCancelSpinLock (&cancelIrql);
  4174. IoReleaseCancelSpinLock (cancelIrql);
  4175. }
  4176. irp->IoStatus.Status = Status;
  4177. irp->IoStatus.Information = 0;
  4178. IoCompleteRequest (irp, AfdPriorityBoost);
  4179. }
  4180. }
  4181. else if (Endpoint->Common.SanEndp.CtxTransferStatus==STATUS_PENDING ||
  4182. Endpoint->Common.SanEndp.CtxTransferStatus==STATUS_MORE_PROCESSING_REQUIRED)
  4183. {
  4184. PLIST_ENTRY listEntry;
  4185. NTSTATUS status;
  4186. //
  4187. // Scan the list for the request that have not been comminicated
  4188. // to the switch.
  4189. //
  4190. listEntry = Endpoint->Common.SanEndp.IrpList.Flink;
  4191. while (listEntry!=&Endpoint->Common.SanEndp.IrpList) {
  4192. ULONG_PTR requestInfo;
  4193. ULONG requestType;
  4194. PVOID requestCtx;
  4195. PIRP irp = CONTAINING_RECORD (listEntry,
  4196. IRP,
  4197. Tail.Overlay.ListEntry);
  4198. listEntry = listEntry->Flink;
  4199. //
  4200. // The transfer was successfull, continue processing requests
  4201. //
  4202. if (irp->AfdSanRequestInfo.AfdSanRequestCtx==NULL) {
  4203. //
  4204. // This request has not been communicated to the switch.
  4205. //
  4206. PIO_STACK_LOCATION irpSp;
  4207. //
  4208. // Create request context based on request type.
  4209. //
  4210. irpSp = IoGetCurrentIrpStackLocation (irp);
  4211. switch (irpSp->MajorFunction) {
  4212. case IRP_MJ_READ:
  4213. requestType = AFD_SWITCH_REQUEST_READ;
  4214. requestInfo = irpSp->Parameters.Read.Length;
  4215. break;
  4216. case IRP_MJ_WRITE:
  4217. requestType = AFD_SWITCH_REQUEST_WRITE;
  4218. requestInfo = irpSp->Parameters.Write.Length;
  4219. break;
  4220. case IRP_MJ_DEVICE_CONTROL:
  4221. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  4222. case IOCTL_AFD_SWITCH_ACQUIRE_CTX:
  4223. requestType = AFD_SWITCH_REQUEST_TFCTX;
  4224. requestInfo = (ULONG_PTR)irp->AfdSanRequestInfo.AfdSanProcessId;
  4225. break;
  4226. default:
  4227. ASSERT (!"Unsupported IOCTL");
  4228. __assume (0);
  4229. }
  4230. break;
  4231. default:
  4232. ASSERT (!"Unsupported IRP Major Function");
  4233. __assume (0);
  4234. }
  4235. requestCtx = AFD_SWITCH_MAKE_REQUEST_CONTEXT(
  4236. Endpoint->Common.SanEndp.RequestId,
  4237. requestType);
  4238. irp->AfdSanRequestInfo.AfdSanRequestCtx = requestCtx;
  4239. Endpoint->Common.SanEndp.RequestId += 1;
  4240. UPDATE_ENDPOINT2 (Endpoint,
  4241. "AfdSanRestartRequestProcessing, restarting req: 0x%lX",
  4242. PtrToUlong (requestCtx));
  4243. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  4244. status = AfdSanNotifyRequest (Endpoint, requestCtx, STATUS_SUCCESS, requestInfo);
  4245. if (NT_SUCCESS (status)) {
  4246. if (requestType==AFD_SWITCH_REQUEST_TFCTX) {
  4247. //
  4248. // If we successfully sent another context transfer request, we should
  4249. // stop processing until this request is completed. The context transfer
  4250. // flag should remain set.
  4251. //
  4252. return oldStatus;
  4253. }
  4254. }
  4255. else {
  4256. PIRP irp1;
  4257. //
  4258. // If notification failed, fail the request. The IRP
  4259. // could have been cancelled, so we have to search for
  4260. // it in the list.
  4261. //
  4262. irp1 = AfdSanDequeueRequest (Endpoint, requestCtx);
  4263. if (irp1!=NULL) {
  4264. ASSERT (irp1==irp);
  4265. irp1->IoStatus.Status = status;
  4266. IoCompleteRequest (irp1, AfdPriorityBoost);
  4267. }
  4268. }
  4269. //
  4270. // Reacquire the lock and continue processing from the beginning
  4271. // as the list could have changed while spinlock was released.
  4272. //
  4273. goto Again;
  4274. }
  4275. else {
  4276. //
  4277. // IRP has already been forwarded to the switch, leave it alone
  4278. //
  4279. }
  4280. }
  4281. //
  4282. // Ran till the end of the list and did not find another transfer request.
  4283. // We can reset the flag now.
  4284. //
  4285. Endpoint->Common.SanEndp.CtxTransferStatus = Status;
  4286. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  4287. }
  4288. else {
  4289. //
  4290. // This can only occur if we have already failed before and
  4291. // there are thus should be no irps in the list.
  4292. //
  4293. ASSERT (IsListEmpty (&Endpoint->Common.SanEndp.IrpList));
  4294. ASSERT (!NT_SUCCESS (Endpoint->Common.SanEndp.CtxTransferStatus));
  4295. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  4296. }
  4297. return oldStatus;
  4298. }
  4299. PIRP
  4300. AfdSanDequeueRequest (
  4301. PAFD_ENDPOINT SanEndpoint,
  4302. PVOID RequestCtx
  4303. )
  4304. /*++
  4305. Routine Description:
  4306. Removes the request from the san endpoint list
  4307. Arguments:
  4308. SanEndpoint - endpoint from which to remove the request
  4309. RequestCtx - context that identifies the request
  4310. Return Value:
  4311. The request or NULL is not found.
  4312. --*/
  4313. {
  4314. AFD_LOCK_QUEUE_HANDLE lockHandle;
  4315. PLIST_ENTRY listEntry;
  4316. ASSERT (RequestCtx!=NULL);
  4317. AfdAcquireSpinLock (&SanEndpoint->SpinLock, &lockHandle);
  4318. if (!IS_SAN_ENDPOINT (SanEndpoint)) {
  4319. AfdReleaseSpinLock (&SanEndpoint->SpinLock, &lockHandle);
  4320. return NULL;
  4321. }
  4322. listEntry = SanEndpoint->Common.SanEndp.IrpList.Flink;
  4323. //
  4324. // Walk the list till we find the request
  4325. //
  4326. while (listEntry!=&SanEndpoint->Common.SanEndp.IrpList) {
  4327. PIRP irp = CONTAINING_RECORD (listEntry,
  4328. IRP,
  4329. Tail.Overlay.ListEntry);
  4330. listEntry = listEntry->Flink;
  4331. if (irp->AfdSanRequestInfo.AfdSanRequestCtx==RequestCtx) {
  4332. RemoveEntryList (&irp->Tail.Overlay.ListEntry);
  4333. irp->Tail.Overlay.ListEntry.Flink = NULL;
  4334. AfdReleaseSpinLock (&SanEndpoint->SpinLock, &lockHandle);
  4335. //
  4336. // Check if request is being cancelled and synchronize
  4337. // with the cancel routine if so.
  4338. //
  4339. if (IoSetCancelRoutine (irp, NULL)==NULL) {
  4340. KIRQL cancelIrql;
  4341. IoAcquireCancelSpinLock (&cancelIrql);
  4342. IoReleaseCancelSpinLock (cancelIrql);
  4343. }
  4344. InterlockedExchangeAdd (&SanEndpoint->Common.SanEndp.SanHlpr->Common.SanHlpr.PendingRequests, -2);
  4345. return irp;
  4346. }
  4347. else if (irp->AfdSanRequestInfo.AfdSanRequestCtx==NULL) {
  4348. break;
  4349. }
  4350. }
  4351. AfdReleaseSpinLock (&SanEndpoint->SpinLock, &lockHandle);
  4352. return NULL;
  4353. }
  4354. NTSTATUS
  4355. AfdSanNotifyRequest (
  4356. PAFD_ENDPOINT SanEndpoint,
  4357. PVOID RequestCtx,
  4358. NTSTATUS Status,
  4359. ULONG_PTR Information
  4360. )
  4361. {
  4362. PVOID context;
  4363. PAFD_ENDPOINT sanHlprEndpoint;
  4364. NTSTATUS status;
  4365. PAGED_CODE ();
  4366. context = AfdLockEndpointContext (SanEndpoint);
  4367. if (IS_SAN_ENDPOINT (SanEndpoint)) {
  4368. //
  4369. // Get the san helper endpoint which we use to communicate
  4370. // with the switch
  4371. //
  4372. sanHlprEndpoint = SanEndpoint->Common.SanEndp.SanHlpr;
  4373. ASSERT (IS_SAN_HELPER (sanHlprEndpoint));
  4374. //
  4375. // Increment the count of outstanding requests and verify that
  4376. // helper endpoint is still active and thus the process can
  4377. // accept the requests.
  4378. //
  4379. if ((InterlockedExchangeAdd (&sanHlprEndpoint->Common.SanHlpr.PendingRequests, 2) & 1)==0) {
  4380. ASSERT ((ULONG_PTR)SanEndpoint->Common.SanEndp.SwitchContext<MM_USER_PROBE_ADDRESS); //
  4381. // Notify the switch about the request.
  4382. //
  4383. status = IoSetIoCompletion (
  4384. sanHlprEndpoint->Common.SanHlpr.IoCompletionPort,// Port
  4385. SanEndpoint->Common.SanEndp.SwitchContext, // Key
  4386. RequestCtx, // ApcContext
  4387. Status, // Status
  4388. Information, // Information
  4389. TRUE // ChargeQuota
  4390. );
  4391. }
  4392. else {
  4393. status = STATUS_CANCELLED;
  4394. }
  4395. }
  4396. else {
  4397. status = STATUS_INVALID_HANDLE;
  4398. }
  4399. AfdUnlockEndpointContext (SanEndpoint, context);
  4400. return status;
  4401. }
  4402. NTSTATUS
  4403. AfdSanPollBegin (
  4404. PAFD_ENDPOINT Endpoint,
  4405. ULONG EventMask
  4406. )
  4407. /*++
  4408. Routine Description:
  4409. Records poll call so that switch knows to notify AFD to complete
  4410. select/AsyncSelect/EventSelect requests
  4411. Arguments:
  4412. Endpoint - endpoint to record
  4413. EventMask - events that needs to be notified
  4414. Return Value:
  4415. NTSTATUS - may fail to access user mode address
  4416. Note:
  4417. This routine must be called in the context of user mode process
  4418. that owns the endpoint
  4419. --*/
  4420. {
  4421. LONG currentEvents, newEvents;
  4422. PVOID context;
  4423. BOOLEAN attached = FALSE;
  4424. NTSTATUS status = STATUS_SUCCESS;
  4425. PAGED_CODE ();
  4426. context = AfdLockEndpointContext (Endpoint);
  4427. if (IS_SAN_ENDPOINT (Endpoint)) {
  4428. if (IoGetCurrentProcess()!=Endpoint->Common.SanEndp.SanHlpr->OwningProcess) {
  4429. KeAttachProcess (PsGetProcessPcb(Endpoint->Common.SanEndp.SanHlpr->OwningProcess));
  4430. attached = TRUE;
  4431. }
  4432. try {
  4433. //
  4434. // Increment appropriate counts to inform the switch that we are interested
  4435. // in the event.
  4436. //
  4437. if (EventMask & AFD_POLL_RECEIVE) {
  4438. InterlockedIncrement (&Endpoint->Common.SanEndp.SwitchContext->RcvCount);
  4439. //
  4440. // Inform switch that select has happened on this endpoint
  4441. //
  4442. Endpoint->Common.SanEndp.SwitchContext->SelectFlag = TRUE;
  4443. }
  4444. if (EventMask & AFD_POLL_RECEIVE_EXPEDITED) {
  4445. InterlockedIncrement (&Endpoint->Common.SanEndp.SwitchContext->ExpCount);
  4446. }
  4447. if (EventMask & AFD_POLL_SEND) {
  4448. InterlockedIncrement (&Endpoint->Common.SanEndp.SwitchContext->SndCount);
  4449. }
  4450. //
  4451. // Update our event record.
  4452. //
  4453. do {
  4454. currentEvents = *((LONG volatile *)&Endpoint->Common.SanEndp.SelectEventsActive);
  4455. newEvents = *((LONG volatile *)&Endpoint->Common.SanEndp.SwitchContext->EventsActive);
  4456. }
  4457. while (InterlockedCompareExchange (
  4458. (PLONG)&Endpoint->Common.SanEndp.SelectEventsActive,
  4459. newEvents,
  4460. currentEvents)!=currentEvents);
  4461. }
  4462. except (AFD_EXCEPTION_FILTER (status)) {
  4463. ASSERT (NT_ERROR (status));
  4464. }
  4465. if (attached) {
  4466. KeDetachProcess ();
  4467. }
  4468. }
  4469. AfdUnlockEndpointContext (Endpoint, context);
  4470. return status;
  4471. }
  4472. VOID
  4473. AfdSanPollEnd (
  4474. PAFD_ENDPOINT Endpoint,
  4475. ULONG EventMask
  4476. )
  4477. /*++
  4478. Routine Description:
  4479. Records poll call completion, so that switch can avoild expensive calls to notify AFD
  4480. to complete select/AsyncSelect/EventSelect requests
  4481. Arguments:
  4482. Endpoint - endpoint to record
  4483. EventMask - events that needs to be dereferenced
  4484. Return Value:
  4485. NTSTATUS - may fail to access user mode address
  4486. Note:
  4487. This routine must be called in the context of user mode process
  4488. that owns the endpoint
  4489. --*/
  4490. {
  4491. BOOLEAN attached = FALSE;
  4492. PVOID context;
  4493. PAGED_CODE ();
  4494. context = AfdLockEndpointContext (Endpoint);
  4495. if (IS_SAN_ENDPOINT (Endpoint)) {
  4496. if (IoGetCurrentProcess()!=Endpoint->Common.SanEndp.SanHlpr->OwningProcess) {
  4497. KeAttachProcess (PsGetProcessPcb(Endpoint->Common.SanEndp.SanHlpr->OwningProcess));
  4498. attached = TRUE;
  4499. }
  4500. try {
  4501. //
  4502. // Decrement appropriate counts to inform the switch that we are no longer interested
  4503. // in the event.
  4504. //
  4505. if (EventMask & AFD_POLL_RECEIVE) {
  4506. InterlockedDecrement (&Endpoint->Common.SanEndp.SwitchContext->RcvCount);
  4507. }
  4508. if (EventMask & AFD_POLL_RECEIVE_EXPEDITED) {
  4509. InterlockedDecrement (&Endpoint->Common.SanEndp.SwitchContext->ExpCount);
  4510. }
  4511. if (EventMask & AFD_POLL_SEND) {
  4512. InterlockedDecrement (&Endpoint->Common.SanEndp.SwitchContext->SndCount);
  4513. }
  4514. }
  4515. except (AFD_EXCEPTION_FILTER_NO_STATUS()) {
  4516. //
  4517. // Not much we can do. The switch will have to call us with all the events.
  4518. //
  4519. }
  4520. if (attached) {
  4521. KeDetachProcess ();
  4522. }
  4523. }
  4524. AfdUnlockEndpointContext (Endpoint, context);
  4525. }
  4526. VOID
  4527. AfdSanPollUpdate (
  4528. PAFD_ENDPOINT Endpoint,
  4529. ULONG EventMask
  4530. )
  4531. /*++
  4532. Routine Description:
  4533. Updates local kernel information currently outstanding polls on the
  4534. endpoint to be later merged into information maitained by the switch
  4535. Arguments:
  4536. Endpoint - endpoint to record
  4537. EventMask - events that needs to be recorded
  4538. Return Value:
  4539. None
  4540. --*/
  4541. {
  4542. ASSERT (IS_SAN_ENDPOINT (Endpoint));
  4543. ASSERT (KeGetCurrentIrql()==DISPATCH_LEVEL);
  4544. ASSERT (Endpoint->Common.SanEndp.LocalContext!=NULL);
  4545. if (EventMask & AFD_POLL_RECEIVE) {
  4546. InterlockedIncrement (&Endpoint->Common.SanEndp.LocalContext->RcvCount);
  4547. }
  4548. if (EventMask & AFD_POLL_RECEIVE_EXPEDITED) {
  4549. InterlockedIncrement (&Endpoint->Common.SanEndp.LocalContext->ExpCount);
  4550. }
  4551. if (EventMask & AFD_POLL_SEND) {
  4552. InterlockedIncrement (&Endpoint->Common.SanEndp.LocalContext->SndCount);
  4553. }
  4554. }
  4555. NTSTATUS
  4556. AfdSanPollMerge (
  4557. PAFD_ENDPOINT Endpoint,
  4558. PAFD_SWITCH_CONTEXT Context
  4559. )
  4560. /*++
  4561. Routine Description:
  4562. Merges information about outstanding poll calls into switch counts.
  4563. Arguments:
  4564. Endpoint - endpoint to record
  4565. Context - outstanding select info merge in
  4566. Return Value:
  4567. NTSTATUS - may fail to access user mode address
  4568. Note:
  4569. This routine must be called in the context of user mode process
  4570. that owns the endpoint
  4571. --*/
  4572. {
  4573. NTSTATUS status = STATUS_SUCCESS;
  4574. PAGED_CODE ();
  4575. ASSERT (IoGetCurrentProcess()==Endpoint->Common.SanEndp.SanHlpr->OwningProcess);
  4576. ASSERT (Endpoint->Common.SanEndp.LocalContext == Context);
  4577. try {
  4578. InterlockedExchangeAdd (&Endpoint->Common.SanEndp.SwitchContext->RcvCount,
  4579. Context->RcvCount);
  4580. InterlockedExchangeAdd (&Endpoint->Common.SanEndp.SwitchContext->SndCount,
  4581. Context->SndCount);
  4582. InterlockedExchangeAdd (&Endpoint->Common.SanEndp.SwitchContext->ExpCount,
  4583. Context->ExpCount);
  4584. }
  4585. except (AFD_EXCEPTION_FILTER (status)) {
  4586. ASSERT (NT_ERROR (status));
  4587. }
  4588. return status;
  4589. }
  4590. VOID
  4591. AfdSanInitEndpoint (
  4592. PAFD_ENDPOINT SanHlprEndpoint,
  4593. PFILE_OBJECT SanFileObject,
  4594. PAFD_SWITCH_CONTEXT SwitchContext
  4595. )
  4596. /*++
  4597. Routine Description:
  4598. Initializes SAN endpoint structure
  4599. Arguments:
  4600. SanHlprEndpoint - switch helper endpoint - communication channel
  4601. between the switch and AFD for the owner process.
  4602. SanFile - file object for the endpoint to be initialized.
  4603. Return Value:
  4604. None
  4605. --*/
  4606. {
  4607. PAFD_ENDPOINT sanEndpoint = SanFileObject->FsContext;
  4608. ASSERT (IS_SAN_HELPER(SanHlprEndpoint));
  4609. REFERENCE_ENDPOINT (SanHlprEndpoint);
  4610. sanEndpoint->Common.SanEndp.SanHlpr = SanHlprEndpoint;
  4611. sanEndpoint->Common.SanEndp.FileObject = SanFileObject;
  4612. sanEndpoint->Common.SanEndp.SwitchContext = SwitchContext;
  4613. // sanEndpoint->Common.SanEndp.SavedContext = NULL;
  4614. sanEndpoint->Common.SanEndp.LocalContext = NULL;
  4615. InitializeListHead (&sanEndpoint->Common.SanEndp.IrpList);
  4616. sanEndpoint->Common.SanEndp.SelectEventsActive = 0;
  4617. sanEndpoint->Common.SanEndp.RequestId = 1;
  4618. sanEndpoint->Common.SanEndp.CtxTransferStatus = STATUS_SUCCESS;
  4619. sanEndpoint->Common.SanEndp.ImplicitDup = FALSE;
  4620. //
  4621. // HACKHACK. Force IO subsystem to call us when last handle to the file is closed
  4622. // in any given process.
  4623. //
  4624. SanFileObject->LockOperation = TRUE;
  4625. sanEndpoint->Type = AfdBlockTypeSanEndpoint;
  4626. }
  4627. VOID
  4628. AfdSanAbortConnection (
  4629. PAFD_CONNECTION Connection
  4630. )
  4631. {
  4632. PIRP connectIrp;
  4633. PDRIVER_CANCEL cancelRoutine;
  4634. KIRQL cancelIrql;
  4635. AFD_LOCK_QUEUE_HANDLE lockHandle;
  4636. PAFD_ENDPOINT endpoint = Connection->Endpoint;
  4637. ASSERT (Connection->SanConnection==TRUE);
  4638. //
  4639. // Acquire cancel spinlock and endpoint spinlock in
  4640. // this order and recheck the accept IRP
  4641. //
  4642. IoAcquireCancelSpinLock (&cancelIrql);
  4643. AfdAcquireSpinLockAtDpcLevel (&endpoint->SpinLock, &lockHandle);
  4644. connectIrp = Connection->ConnectIrp;
  4645. if ((connectIrp!=NULL) &&
  4646. ((cancelRoutine=IoSetCancelRoutine (connectIrp, NULL))!=NULL)) {
  4647. //
  4648. // Accept IRP was still there and was not cancelled/completed
  4649. // cancel it
  4650. //
  4651. AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &lockHandle);
  4652. connectIrp->CancelIrql = cancelIrql;
  4653. connectIrp->Cancel = TRUE;
  4654. (*cancelRoutine) (AfdDeviceObject, connectIrp);
  4655. }
  4656. else {
  4657. AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &lockHandle);
  4658. IoReleaseCancelSpinLock (cancelIrql);
  4659. }
  4660. }
  4661. VOID
  4662. AfdSanCleanupEndpoint (
  4663. PAFD_ENDPOINT Endpoint
  4664. )
  4665. /*++
  4666. Routine Description:
  4667. Cleans up SAN specific fields in AFD_ENDPOINT
  4668. Arguments:
  4669. Endpoint - endpoint to cleanup
  4670. Return Value:
  4671. None
  4672. --*/
  4673. {
  4674. PAFD_ENDPOINT sanHlprEndpoint;
  4675. ASSERT (IsListEmpty (&Endpoint->Common.SanEndp.IrpList));
  4676. ASSERT (Endpoint->Common.SanEndp.LocalContext == NULL);
  4677. sanHlprEndpoint = Endpoint->Common.SanEndp.SanHlpr;
  4678. ASSERT (sanHlprEndpoint!=NULL);
  4679. ASSERT (IS_SAN_HELPER (sanHlprEndpoint));
  4680. DEREFERENCE_ENDPOINT (sanHlprEndpoint);
  4681. Endpoint->Common.SanEndp.SanHlpr = NULL;
  4682. }
  4683. VOID
  4684. AfdSanCleanupHelper (
  4685. PAFD_ENDPOINT Endpoint
  4686. )
  4687. /*++
  4688. Routine Description:
  4689. Cleans up SAN helper specific fields in AFD_ENDPOINT
  4690. Arguments:
  4691. Endpoint - endpoint to cleanup
  4692. Return Value:
  4693. None
  4694. --*/
  4695. {
  4696. ASSERT (Endpoint->Common.SanHlpr.IoCompletionPort!=NULL);
  4697. ObDereferenceObject (Endpoint->Common.SanHlpr.IoCompletionPort);
  4698. Endpoint->Common.SanHlpr.IoCompletionPort = NULL;
  4699. ASSERT (Endpoint->Common.SanHlpr.IoCompletionEvent!=NULL);
  4700. ObDereferenceObject (Endpoint->Common.SanHlpr.IoCompletionEvent);
  4701. Endpoint->Common.SanHlpr.IoCompletionEvent = NULL;
  4702. KeEnterCriticalRegion ();
  4703. ExAcquireResourceExclusiveLite( AfdResource, TRUE );
  4704. ASSERT (IS_SAN_HELPER (Endpoint));
  4705. ASSERT (AfdSanServiceHelper!=Endpoint); // Should have been removed in cleanup.
  4706. ASSERT (!IsListEmpty (&Endpoint->Common.SanHlpr.SanListLink));
  4707. RemoveEntryList (&Endpoint->Common.SanHlpr.SanListLink);
  4708. ExReleaseResourceLite( AfdResource );
  4709. KeLeaveCriticalRegion ();
  4710. }
  4711. VOID
  4712. AfdSanHelperCleanup (
  4713. PAFD_ENDPOINT SanHlprEndpoint
  4714. )
  4715. {
  4716. if (InterlockedIncrement (&SanHlprEndpoint->Common.SanHlpr.PendingRequests)!=1) {
  4717. PLIST_ENTRY listEntry;
  4718. //
  4719. // Scan the endpoint list and cleanup all requests in the san endpoints
  4720. // that refer to this helper endpoint.
  4721. //
  4722. KeEnterCriticalRegion ();
  4723. ExAcquireResourceSharedLite( AfdResource, TRUE );
  4724. listEntry = AfdEndpointListHead.Flink;
  4725. while (listEntry!=&AfdEndpointListHead) {
  4726. PAFD_ENDPOINT sanEndpoint;
  4727. sanEndpoint = CONTAINING_RECORD (listEntry, AFD_ENDPOINT, GlobalEndpointListEntry);
  4728. if (IS_SAN_ENDPOINT (sanEndpoint) &&
  4729. sanEndpoint->Common.SanEndp.SanHlpr==SanHlprEndpoint &&
  4730. !IsListEmpty (&sanEndpoint->Common.SanEndp.IrpList)) {
  4731. AfdSanRestartRequestProcessing (sanEndpoint, STATUS_CANCELLED);
  4732. }
  4733. listEntry = listEntry->Flink;
  4734. }
  4735. ExReleaseResourceLite( AfdResource );
  4736. KeLeaveCriticalRegion ();
  4737. }
  4738. if (SanHlprEndpoint==AfdSanServiceHelper) {
  4739. //
  4740. // Last handle to the service helper is being closed in
  4741. // the service process (there must be some duplicates around).
  4742. // We can no longer count on it, clear our global.
  4743. //
  4744. KeEnterCriticalRegion ();
  4745. ExAcquireResourceExclusiveLite( AfdResource, TRUE );
  4746. //
  4747. // Re-check under the lock.
  4748. //
  4749. if (SanHlprEndpoint==AfdSanServiceHelper) {
  4750. AfdSanServiceHelper = NULL;
  4751. }
  4752. ExReleaseResourceLite( AfdResource );
  4753. KeLeaveCriticalRegion ();
  4754. }
  4755. }
  4756. BOOLEAN
  4757. AfdSanReferenceEndpointObject (
  4758. PAFD_ENDPOINT Endpoint
  4759. )
  4760. /*++
  4761. Routine Description:
  4762. Reference file object with which san endpoint is associated
  4763. Arguments:
  4764. Endpoint - endpoint of interest
  4765. Return Value:
  4766. TRUE - reference successed
  4767. FALSE - endpoint has already been cleaned up and its file object
  4768. is about to be closed.
  4769. --*/
  4770. {
  4771. BOOLEAN res = TRUE;
  4772. AFD_LOCK_QUEUE_HANDLE lockHandle;
  4773. AfdAcquireSpinLock (&Endpoint->SpinLock, &lockHandle);
  4774. if (!Endpoint->EndpointCleanedUp) {
  4775. ObReferenceObject (Endpoint->Common.SanEndp.FileObject);
  4776. }
  4777. else {
  4778. res = FALSE;
  4779. }
  4780. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  4781. return res;
  4782. }
  4783. NTSTATUS
  4784. AfdSanReferenceSwitchSocketByHandle (
  4785. IN HANDLE SocketHandle,
  4786. IN ACCESS_MASK DesiredAccess,
  4787. IN KPROCESSOR_MODE RequestorMode,
  4788. IN PAFD_ENDPOINT SanHlprEndpoint,
  4789. IN PAFD_SWITCH_CONTEXT SwitchContext OPTIONAL,
  4790. OUT PFILE_OBJECT *FileObject
  4791. )
  4792. /*++
  4793. Routine Description:
  4794. Finds and validates AFD endpoint based on the handle/context combination passed in
  4795. by the switch.
  4796. Arguments:
  4797. SocketHandle - Socket handle being referenced
  4798. DesiredAccess - Required access to the object to perform operation
  4799. RequestorMode - Mode of the caller
  4800. SanHlprEndpoint - helper endpoint - communication channel between AFD and switch
  4801. SwitchContext - context associated by the switch with the socket being referenced
  4802. FileObject - file object corresponding to socket handle
  4803. Return Value:
  4804. STATUS_SUCCESS - operation succeeded
  4805. other - failed to find/access endpoint associated with the socket handle/context
  4806. --*/
  4807. {
  4808. NTSTATUS status;
  4809. if (IS_SAN_HELPER (SanHlprEndpoint) &&
  4810. SanHlprEndpoint->OwningProcess==IoGetCurrentProcess ()) {
  4811. status = ObReferenceObjectByHandle (
  4812. SocketHandle,
  4813. DesiredAccess,
  4814. *IoFileObjectType,
  4815. RequestorMode,
  4816. FileObject,
  4817. NULL
  4818. );
  4819. if (NT_SUCCESS (status) &&
  4820. (*FileObject)->DeviceObject==AfdDeviceObject &&
  4821. //
  4822. // Ether socket belongs to the current process and context matches
  4823. // the one supplied by the switch
  4824. //
  4825. ((IS_SAN_ENDPOINT((PAFD_ENDPOINT)(*FileObject)->FsContext) &&
  4826. ((PAFD_ENDPOINT)((*FileObject)->FsContext))->Common.SanEndp.SanHlpr==SanHlprEndpoint &&
  4827. ((PAFD_ENDPOINT)((*FileObject)->FsContext))->Common.SanEndp.SwitchContext==SwitchContext)
  4828. ||
  4829. //
  4830. // Or this is just a non-SAN socket being converted to one or just
  4831. // used for select signalling.
  4832. //
  4833. (SwitchContext==NULL &&
  4834. ((PAFD_ENDPOINT)(*FileObject)->FsContext)->Type==AfdBlockTypeEndpoint)) ){
  4835. NOTHING;
  4836. }
  4837. else {
  4838. if (NT_SUCCESS (status)) {
  4839. //
  4840. // Undo object referencing since it doesn't match the one that switch expects
  4841. //
  4842. ObDereferenceObject (*FileObject);
  4843. status = STATUS_INVALID_HANDLE;
  4844. }
  4845. //
  4846. // If switch supplied the context, try to find the socket
  4847. // in the current process that has the same one.
  4848. //
  4849. if (SwitchContext!=NULL) {
  4850. status = AfdSanFindSwitchSocketByProcessContext (
  4851. status,
  4852. SanHlprEndpoint,
  4853. SwitchContext,
  4854. FileObject);
  4855. }
  4856. }
  4857. }
  4858. else
  4859. status = STATUS_INVALID_HANDLE;
  4860. return status;
  4861. }
  4862. NTSTATUS
  4863. AfdSanFindSwitchSocketByProcessContext (
  4864. IN NTSTATUS Status,
  4865. IN PAFD_ENDPOINT SanHlprEndpoint,
  4866. IN PAFD_SWITCH_CONTEXT SwitchContext,
  4867. OUT PFILE_OBJECT *FileObject
  4868. )
  4869. /*++
  4870. Routine Description:
  4871. Find SAN endpoint given its process (helper endpoint) and switch context.
  4872. Arguments:
  4873. Status - status returned by the ob object reference operation
  4874. (to be propagated to the caller in case of failure).
  4875. SanHlprEndpoint - helper endpoint for the process to look in
  4876. SwitchContext - switch context associated with the endpoint
  4877. FileObject - returns endpont's file object if found
  4878. Return Value:
  4879. STATUS_SUCCESS - san endpoint was found
  4880. other - failed to find endpoint based on the switch context.
  4881. --*/
  4882. {
  4883. PLIST_ENTRY listEntry;
  4884. PAFD_ENDPOINT sanEndpoint = NULL;
  4885. HANDLE socketHandle;
  4886. PVOID context;
  4887. PAGED_CODE ();
  4888. //
  4889. // Walk the global endpoint list and try to find the entry
  4890. // that matches the switch context
  4891. //
  4892. KeEnterCriticalRegion ();
  4893. ExAcquireResourceSharedLite (AfdResource, TRUE);
  4894. listEntry = AfdEndpointListHead.Flink;
  4895. AFD_W4_INIT context = NULL; // Depends on variable above, but compiler does not see
  4896. // the connection.
  4897. while (listEntry!=&AfdEndpointListHead) {
  4898. sanEndpoint = CONTAINING_RECORD (listEntry, AFD_ENDPOINT, GlobalEndpointListEntry);
  4899. context = AfdLockEndpointContext (sanEndpoint);
  4900. if (IS_SAN_ENDPOINT (sanEndpoint) &&
  4901. sanEndpoint->Common.SanEndp.SanHlpr==SanHlprEndpoint &&
  4902. sanEndpoint->Common.SanEndp.SwitchContext==SwitchContext &&
  4903. AfdSanReferenceEndpointObject (sanEndpoint)) {
  4904. break;
  4905. }
  4906. AfdUnlockEndpointContext (sanEndpoint, context);
  4907. listEntry = listEntry->Flink;
  4908. }
  4909. ExReleaseResourceLite (AfdResource);
  4910. KeLeaveCriticalRegion ();
  4911. if (listEntry==&sanEndpoint->GlobalEndpointListEntry) {
  4912. //
  4913. // Try to find the real handle for the switch to use in the future
  4914. //
  4915. *FileObject = sanEndpoint->Common.SanEndp.FileObject;
  4916. if (ObFindHandleForObject (SanHlprEndpoint->OwningProcess,
  4917. sanEndpoint->Common.SanEndp.FileObject,
  4918. *IoFileObjectType,
  4919. NULL,
  4920. &socketHandle)) {
  4921. UPDATE_ENDPOINT2 (sanEndpoint,
  4922. "AfdSanFindSwitchSocketByProcessContext, handle: 0x%lX",
  4923. HandleToUlong (socketHandle));
  4924. //
  4925. // Notify switch of handle to be used.
  4926. // Ignore failure, the switch will still be able to communicate via
  4927. // slow lookup path.
  4928. //
  4929. IoSetIoCompletion (
  4930. SanHlprEndpoint->Common.SanHlpr.IoCompletionPort,
  4931. SwitchContext,
  4932. AFD_SWITCH_MAKE_REQUEST_CONTEXT (0, AFD_SWITCH_REQUEST_CHCTX),
  4933. STATUS_SUCCESS,
  4934. (ULONG_PTR)socketHandle,
  4935. TRUE // Charge quota
  4936. );
  4937. }
  4938. else {
  4939. UPDATE_ENDPOINT2 (sanEndpoint,
  4940. "AfdSanFindSwitchSocketByProcessContext, object not found from handle: 0x%lX",
  4941. HandleToUlong (socketHandle));
  4942. }
  4943. AfdUnlockEndpointContext (sanEndpoint, context);
  4944. Status = STATUS_SUCCESS;
  4945. }
  4946. return Status;
  4947. }
  4948. BOOLEAN
  4949. AfdSanSetDupingToServiceState (
  4950. PAFD_ENDPOINT SanEndpoint
  4951. )
  4952. /*++
  4953. Routine Description:
  4954. Reset request pending on SAN endpoint while transfering
  4955. context to service process.
  4956. Arguments:
  4957. SanEndpoint - endpoint on which to reset requests.
  4958. Return Value:
  4959. TRUE - successfully reset requests and set transfer status
  4960. FALSE - the transfer status could not be reset
  4961. --*/
  4962. {
  4963. AFD_LOCK_QUEUE_HANDLE lockHandle;
  4964. PLIST_ENTRY listEntry;
  4965. LONG count = 0;
  4966. BOOLEAN res;
  4967. AfdAcquireSpinLock (&SanEndpoint->SpinLock, &lockHandle);
  4968. listEntry = SanEndpoint->Common.SanEndp.IrpList.Flink;
  4969. while (listEntry!=&SanEndpoint->Common.SanEndp.IrpList) {
  4970. PIRP irp = CONTAINING_RECORD (listEntry, IRP, Tail.Overlay.ListEntry);
  4971. if (irp->AfdSanRequestInfo.AfdSanRequestCtx!=NULL) {
  4972. count += 2;
  4973. irp->AfdSanRequestInfo.AfdSanRequestCtx = NULL;
  4974. }
  4975. listEntry = listEntry->Flink;
  4976. }
  4977. if (NT_SUCCESS (SanEndpoint->Common.SanEndp.CtxTransferStatus)) {
  4978. if (SanEndpoint->Common.SanEndp.CtxTransferStatus==STATUS_PENDING)
  4979. count += 2;
  4980. SanEndpoint->Common.SanEndp.CtxTransferStatus = STATUS_MORE_PROCESSING_REQUIRED;
  4981. res = TRUE;
  4982. InterlockedExchangeAdd (
  4983. &SanEndpoint->Common.SanEndp.SanHlpr->Common.SanHlpr.PendingRequests,
  4984. -count);
  4985. }
  4986. else {
  4987. res = FALSE;
  4988. }
  4989. AfdReleaseSpinLock (&SanEndpoint->SpinLock, &lockHandle);
  4990. return res;
  4991. }
  4992. NTSTATUS
  4993. AfdSanSetAskDupeToServiceState (
  4994. PAFD_ENDPOINT SanEndpoint
  4995. )
  4996. /*++
  4997. Routine Description:
  4998. Initiates the duplication to service process by checking
  4999. current duplication state and setting it to STATUS_PENDING
  5000. Arguments:
  5001. SanEndpoint - endpoint on which to reset requests.
  5002. Return Value:
  5003. Original value of CtxTransferStatus
  5004. --*/
  5005. {
  5006. NTSTATUS status;
  5007. AFD_LOCK_QUEUE_HANDLE lockHandle;
  5008. AfdAcquireSpinLock (&SanEndpoint->SpinLock, &lockHandle);
  5009. status = SanEndpoint->Common.SanEndp.CtxTransferStatus;
  5010. if (SanEndpoint->Common.SanEndp.CtxTransferStatus==STATUS_SUCCESS) {
  5011. SanEndpoint->Common.SanEndp.CtxTransferStatus = STATUS_PENDING;
  5012. }
  5013. AfdReleaseSpinLock (&SanEndpoint->SpinLock, &lockHandle);
  5014. return status;
  5015. }
  5016. NTSTATUS
  5017. AfdSanDupEndpointIntoServiceProcess (
  5018. PFILE_OBJECT SanFileObject,
  5019. PVOID SavedContext,
  5020. ULONG ContextLength
  5021. )
  5022. /*++
  5023. Routine Description:
  5024. Duplicate endpoint into the context of the service process
  5025. and save switch context on it
  5026. Arguments:
  5027. SanFileObject - file object being duplicated
  5028. SaveContext - pointer to switch context data
  5029. ContextLength - length of the context
  5030. Return Value:
  5031. STATUS_SUCCESS - successfully duped
  5032. other - failed.
  5033. --*/
  5034. {
  5035. NTSTATUS status;
  5036. HANDLE handle;
  5037. PAFD_ENDPOINT sanEndpoint = SanFileObject->FsContext;
  5038. PVOID context;
  5039. //
  5040. // Take the lock to make sure that service helper won't
  5041. // exit on us and take the helper endpoint with it.
  5042. //
  5043. KeEnterCriticalRegion ();
  5044. ExAcquireResourceSharedLite (AfdResource, TRUE);
  5045. if (AfdSanServiceHelper!=NULL) {
  5046. //
  5047. // Attach to the process and create handle for the file object.
  5048. //
  5049. KeAttachProcess (PsGetProcessPcb(AfdSanServiceHelper->OwningProcess));
  5050. status = ObOpenObjectByPointer (
  5051. SanFileObject,
  5052. OBJ_CASE_INSENSITIVE,
  5053. NULL,
  5054. MAXIMUM_ALLOWED,
  5055. *IoFileObjectType,
  5056. KernelMode,
  5057. &handle);
  5058. KeDetachProcess ();
  5059. if (NT_SUCCESS (status)) {
  5060. context = AfdLockEndpointContext (sanEndpoint);
  5061. //
  5062. // Notify the service process that it needs to acquire endpoint context.
  5063. //
  5064. if (sanEndpoint->Common.SanEndp.SanHlpr!=AfdSanServiceHelper) {
  5065. if ((InterlockedExchangeAdd (
  5066. &AfdSanServiceHelper->Common.SanHlpr.PendingRequests,
  5067. 2) & 1)==0) {
  5068. status = IoSetIoCompletion (
  5069. AfdSanServiceHelper->Common.SanHlpr.IoCompletionPort,
  5070. NULL,
  5071. AFD_SWITCH_MAKE_REQUEST_CONTEXT (0,AFD_SWITCH_REQUEST_AQCTX),
  5072. STATUS_SUCCESS,
  5073. (ULONG_PTR)handle,
  5074. TRUE // Charge quota
  5075. );
  5076. if (NT_SUCCESS (status)) {
  5077. //
  5078. // Check and modify the transfer status state under the
  5079. // endpoint spinlock.
  5080. //
  5081. if (AfdSanSetDupingToServiceState (sanEndpoint)) {
  5082. UPDATE_ENDPOINT (sanEndpoint);
  5083. DEREFERENCE_ENDPOINT (sanEndpoint->Common.SanEndp.SanHlpr);
  5084. REFERENCE_ENDPOINT(AfdSanServiceHelper);
  5085. sanEndpoint->Common.SanEndp.SanHlpr = AfdSanServiceHelper;
  5086. //sanEndpoint->Common.SanEndp.SwitchContext = NULL;
  5087. sanEndpoint->Common.SanEndp.SavedContext = SavedContext;
  5088. sanEndpoint->Common.SanEndp.SavedContextLength = ContextLength;
  5089. //
  5090. // Note that socket was duplicated implicitly without
  5091. // application request.
  5092. //
  5093. sanEndpoint->Common.SanEndp.ImplicitDup = TRUE;
  5094. }
  5095. else {
  5096. //
  5097. // Somehow we failed since endpoint in the wrong state
  5098. // already. When service process comes back to pick
  5099. // it up, we will just fail the call
  5100. //
  5101. status = STATUS_CANCELLED;
  5102. }
  5103. AfdUnlockEndpointContext (sanEndpoint, context);
  5104. ExReleaseResourceLite (AfdResource);
  5105. KeLeaveCriticalRegion ();
  5106. return status;
  5107. }
  5108. }
  5109. else {
  5110. status = STATUS_CANCELLED;
  5111. }
  5112. InterlockedExchangeAdd (&AfdSanServiceHelper->Common.SanHlpr.PendingRequests, -2);
  5113. }
  5114. else {
  5115. //
  5116. // Endpoint is already in the service process.
  5117. //
  5118. status = STATUS_INVALID_PARAMETER;
  5119. }
  5120. AfdUnlockEndpointContext (sanEndpoint, context);
  5121. KeAttachProcess (PsGetProcessPcb(sanEndpoint->Common.SanEndp.SanHlpr->OwningProcess));
  5122. NtClose (handle);
  5123. KeDetachProcess ();
  5124. }
  5125. }
  5126. else {
  5127. status = STATUS_UNSUCCESSFUL;
  5128. }
  5129. ExReleaseResourceLite (AfdResource);
  5130. KeLeaveCriticalRegion ();
  5131. return status;
  5132. }
  5133. VOID
  5134. AfdSanProcessAddrListForProviderChange (
  5135. PAFD_ENDPOINT SpecificEndpoint OPTIONAL
  5136. )
  5137. /*++
  5138. Routine Description:
  5139. Fires address list notifications for SAN helper endpoints
  5140. to inform switch of Winsock provider list change.
  5141. Arguments:
  5142. SpecificEndpoint - optinally indentifies specific
  5143. helper endpoint to fire notifications for
  5144. Return Value:
  5145. None.
  5146. --*/
  5147. {
  5148. AFD_LOCK_QUEUE_HANDLE lockHandle;
  5149. PLIST_ENTRY listEntry;
  5150. LIST_ENTRY completedChangeList;
  5151. PAFD_ADDRESS_CHANGE change;
  5152. PAFD_REQUEST_CONTEXT requestCtx;
  5153. PIRP irp;
  5154. PIO_STACK_LOCATION irpSp;
  5155. PAFD_ENDPOINT endpoint;
  5156. LONG plsn;
  5157. ASSERT (SpecificEndpoint==NULL || IS_SAN_HELPER (SpecificEndpoint));
  5158. //
  5159. // Create local list to process notifications after spinlock is released
  5160. //
  5161. InitializeListHead (&completedChangeList);
  5162. //
  5163. // Walk the list and move matching notifications to the local list
  5164. //
  5165. AfdAcquireSpinLock (&AfdAddressChangeLock, &lockHandle);
  5166. if (SpecificEndpoint==NULL) {
  5167. //
  5168. // General notification, increment provider
  5169. // list change sequence number.
  5170. //
  5171. AfdSanProviderListSeqNum += 1;
  5172. if (AfdSanProviderListSeqNum==0) {
  5173. AfdSanProviderListSeqNum += 1;
  5174. }
  5175. }
  5176. plsn = AfdSanProviderListSeqNum;
  5177. listEntry = AfdAddressChangeList.Flink;
  5178. while (listEntry!=&AfdAddressChangeList) {
  5179. change = CONTAINING_RECORD (listEntry,
  5180. AFD_ADDRESS_CHANGE,
  5181. ChangeListLink);
  5182. listEntry = listEntry->Flink;
  5183. if (!change->NonBlocking) {
  5184. irp = change->Irp;
  5185. irpSp = IoGetCurrentIrpStackLocation (irp);
  5186. requestCtx = (PAFD_REQUEST_CONTEXT)&irpSp->Parameters.DeviceIoControl;
  5187. endpoint = irpSp->FileObject->FsContext;
  5188. ASSERT (change==(PAFD_ADDRESS_CHANGE)irp->Tail.Overlay.DriverContext);
  5189. if (IS_SAN_HELPER (endpoint) &&
  5190. (SpecificEndpoint==NULL ||
  5191. endpoint==SpecificEndpoint)) {
  5192. AFD_LOCK_QUEUE_HANDLE endpointLockHandle;
  5193. ASSERT (change->AddressType==TDI_ADDRESS_TYPE_IP||
  5194. change->AddressType==TDI_ADDRESS_TYPE_IP6);
  5195. RemoveEntryList (&change->ChangeListLink);
  5196. change->ChangeListLink.Flink = NULL;
  5197. //
  5198. // If request is already canceled, let cancel routine complete it
  5199. //
  5200. if (IoSetCancelRoutine (irp, NULL)==NULL) {
  5201. continue;
  5202. }
  5203. AfdAcquireSpinLockAtDpcLevel (&endpoint->SpinLock, &endpointLockHandle);
  5204. if (AfdIsRequestInQueue (requestCtx)) {
  5205. endpoint->Common.SanHlpr.Plsn = plsn;
  5206. UPDATE_ENDPOINT2 (endpoint,
  5207. "AfdSanProcessAddrListForProviderChange, new plsn: 0x%lX",
  5208. plsn);
  5209. //
  5210. // Context is still in the list, just remove it so
  5211. // no-one can see it anymore and complete
  5212. //
  5213. RemoveEntryList (&requestCtx->EndpointListLink);
  5214. InsertTailList (&completedChangeList,
  5215. &change->ChangeListLink);
  5216. }
  5217. else if (!AfdIsRequestCompleted (requestCtx)) {
  5218. //
  5219. // During endpoint cleanup, this context was removed from the
  5220. // list and cleanup routine is about to be called, don't
  5221. // free this IRP until cleanup routine is called
  5222. // Also, indicate to the cleanup routine that we are done
  5223. // with this IRP and it can free it.
  5224. //
  5225. AfdMarkRequestCompleted (requestCtx);
  5226. }
  5227. AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &endpointLockHandle);
  5228. }
  5229. }
  5230. }
  5231. AfdReleaseSpinLock (&AfdAddressChangeLock, &lockHandle);
  5232. //
  5233. // Signal interested clients and complete IRPs as necessary
  5234. //
  5235. while (!IsListEmpty (&completedChangeList)) {
  5236. listEntry = RemoveHeadList (&completedChangeList);
  5237. change = CONTAINING_RECORD (listEntry,
  5238. AFD_ADDRESS_CHANGE,
  5239. ChangeListLink);
  5240. irp = change->Irp;
  5241. irp->IoStatus.Status = STATUS_SUCCESS;
  5242. //
  5243. // Assigning plsn (can't be 0) distinguishes
  5244. // this from regular address list change
  5245. // notification.
  5246. //
  5247. irp->IoStatus.Information = plsn;
  5248. IF_DEBUG (ADDRESS_LIST) {
  5249. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  5250. "AfdProcessAddressChangeList: Completing change IRP: %p with status: 0 .\n",
  5251. irp));
  5252. }
  5253. IoCompleteRequest (irp, AfdPriorityBoost);
  5254. }
  5255. }
  5256. NTSTATUS
  5257. AfdSanGetCompletionObjectTypePointer (
  5258. VOID
  5259. )
  5260. /*++
  5261. Routine Description:
  5262. Obtains completion port object type pointer for
  5263. completion port handle validation purposes.
  5264. Note, that this type is not exported from kernel like
  5265. most other types that afd uses.
  5266. Arguments:
  5267. None.
  5268. Return Value:
  5269. 0 - success, other - could not obtain reference.
  5270. --*/
  5271. {
  5272. NTSTATUS status;
  5273. UNICODE_STRING obName;
  5274. OBJECT_ATTRIBUTES obAttr;
  5275. HANDLE obHandle;
  5276. PVOID obType;
  5277. RtlInitUnicodeString (&obName, L"\\ObjectTypes\\IoCompletion");
  5278. InitializeObjectAttributes(
  5279. &obAttr,
  5280. &obName, // name
  5281. OBJ_KERNEL_HANDLE, // attributes
  5282. NULL, // root
  5283. NULL // security descriptor
  5284. );
  5285. status = ObOpenObjectByName (
  5286. &obAttr, // ObjectAttributes
  5287. NULL, // ObjectType
  5288. KernelMode, // AccessMode
  5289. NULL, // PassedAccessState
  5290. 0, // DesiredAccess
  5291. NULL, // DesiredAccess
  5292. &obHandle // Handle
  5293. );
  5294. if (NT_SUCCESS (status)) {
  5295. status = ObReferenceObjectByHandle (
  5296. obHandle,
  5297. 0, // DesiredAccess
  5298. NULL, // ObjectType
  5299. KernelMode, // AccessMode
  5300. &obType, // Object
  5301. NULL // HandleInformation
  5302. );
  5303. ZwClose (obHandle);
  5304. if (NT_SUCCESS (status)) {
  5305. //
  5306. // Make sure we only keep one reference to the object type
  5307. //
  5308. if (InterlockedCompareExchangePointer (
  5309. (PVOID *)&IoCompletionObjectType,
  5310. obType,
  5311. NULL)!=NULL) {
  5312. //
  5313. // The reference we have already must be the same
  5314. // is we just obtained - there should be only one
  5315. // completion object type in the system!
  5316. //
  5317. ASSERT (obType==(PVOID)IoCompletionObjectType);
  5318. //
  5319. // Get rid of the extra reference
  5320. //
  5321. ObDereferenceObject (obType);
  5322. }
  5323. }
  5324. }
  5325. return status;
  5326. }
  5327. /*
  5328. SAN SOCKET DUPLICATION AND REDIRECTED REQUEST PROCESSING NOTE
  5329. 1. Controlling fields in SAN endpoint (AFD_ENDPOINT.Common.SanEndp).
  5330. CtxTransferStatus:
  5331. STATUS_SUCCESS - default, duplication never been done or succeeded;
  5332. STATUS_PENDING - duplication in progress:
  5333. a)some process submitted IOCTL_AFD_SWITCH_ACQUIRE_CTX request
  5334. and AFD queued AFD_SWITCH_REQUEST_TFCTX to the owner process
  5335. of the endpoint;
  5336. b)owner process is closing its handle while other processes have
  5337. handles opened, so AFD queued AFD_SWITCH_REQUEST_TFCTX
  5338. to the owner process;
  5339. STATUS_MORE_PROCESSING_REQUIRED - service process duplication
  5340. in progress - AFD queued AFD_SWITCH_REQUEST_AQCTX to the service
  5341. process after owner process requested duplication upon handle close;
  5342. OTHER (failure status) - duplication failed, all redirect and context
  5343. transfer request should failed as well.
  5344. ImplicitDup:
  5345. FALSE - default, duplication never been done or last successful
  5346. duplication was explicit.
  5347. TRUE - AFD made unsolicited handle duplication:
  5348. a)accept was called in the process that doesn't own listening
  5349. endpoint and AFD duplicated handle into the listening process,
  5350. b)owner process closed the endpoint and AFD queued
  5351. AFD_SWITCH_REQUEST_TFCTX to it, the owner process then
  5352. responded with IOCTL_AFD_SWITCH_TRANSFER_CTX and AFD
  5353. duplicated handle into the service process (and queued
  5354. AFD_SWITCH_REQUEST_AQCTX);
  5355. IrpList:
  5356. List of redirected or IOCTL_AFD_SWITCH_ACQUIRE_CTX requests.
  5357. RequestId:
  5358. Counter for generation of UNIQUE requests ID's
  5359. SavedContext:
  5360. Saved user mode context from IOCTL_AFD_SWITCH_TRANSFER_CTX from owner
  5361. process that closed its handle while switch negotiates with
  5362. the service process to acquire the context.
  5363. SavedContextLength:
  5364. Length of the context above.
  5365. CtxTransferStatus, IrpList, and RequestID are protected with endpoint spinlock
  5366. (since they control request queueing and IRP completion/cancellation).
  5367. Other fields are protected via the endpoint context lock.
  5368. 2. Controlling fields in SAN helper (AFD_ENDPOINT.Common.SanHlpr).
  5369. PendingRequsts: number of requests submitted to the process via helper
  5370. as well as status of the helper (bit 1 set when helper handle was
  5371. closed and no new requests can be submitted).
  5372. Interlocked operations are used to access this field. Low order bit is
  5373. initialized to 0 and set to 1 via InterlockedIncrement when handle
  5374. for the helper is closed in the owning process. For each request,
  5375. the field is incremented by 2, then the low order bit is checked
  5376. to see if handle was closed. If so, request is failed immediately
  5377. and counter is decremented back by 2. Upon request completion, counter
  5378. is decremented by 2 as well.
  5379. 3. Processing of redirected requests (AfdSanRedirectRequest).
  5380. a)CtxTransferStatus==STATUS_SUCCESS:
  5381. set request ID and enqueue it, notify owner process (AfdSanNotifyRequest),
  5382. if owner process is gone or notification failed, dequeue and fail
  5383. the request (AfdSanDequeueRequest, IoCompleteRequest);
  5384. b)CtxTransferStatus==STATUS_PENDING||STATUS_MORE_PROCESSING_REQUIRED
  5385. NULL request ID and enqueue it to be processed when outstanding
  5386. duplication completes;
  5387. c)CtxTransferStatus==OTHER (failure):
  5388. fail the request
  5389. 4. Processing of explicit IOCTL_AFD_SWITCH_ACQUIRE_CTX (generated
  5390. by the app when it performed socket call in the process other
  5391. than the current owner - AfdSanAcquireContext):
  5392. a)CtxTransferStatus==STATUS_SUCCESS:
  5393. set request ID, enqueue it, and change CtxTransferStatus
  5394. to STATUS_PENDING, notify owner process (AfdSanNotifyRequest),
  5395. if owner process is gone or notification failed, dequeue (AfdSanDequeueRequest)
  5396. and fail the request (IoCompleteRequest), and reset CtxTransferStatus back
  5397. to STATUS_SUCCESS if it is still STATUS_PENDING (AfdSanRestartRequestProcessing -
  5398. other transfer requests can still succeed);
  5399. b)CtxTransferStatus==STATUS_PENDING||STATUS_MORE_PROCESSING_REQUIRED
  5400. NULL request ID and enqueue it to be processed when outstanding
  5401. duplication completes;
  5402. c)CtxTransferStatus==OTHER:
  5403. fail the request
  5404. 5. Processing of implicit IOCTL_AFD_SWITCH_ACQUIRE_CTX (generated
  5405. by the service process on AFD_SWITCH_REQUEST_AQCTX notification):
  5406. a)CtxTransferStatus==STATUS_MORE_PROCESSING_REQUIRED:
  5407. copy the saved context and data to the request buffer,
  5408. complete the acquire request with success,
  5409. post all queued requests (AfdSanRestartRequestProcessing) resubmitting those
  5410. that have NULL id and reset CtxTransferStatus to STATUS_SUCCESS or
  5411. failure if we failed to resumit one of them,
  5412. b)CtxTransferStatus==OTHER:
  5413. fail the request and mark CtxTransferStatus as STATUS_CANCELLED
  5414. 6. Processing of solicited IOCTL_AFD_SWITCH_TRANSFER_CTX (generated
  5415. by the owner process on AFD_SWITCH_REQUEST_TFCTX notification
  5416. for a process that explicitly requested ownership)
  5417. a)CtxTransferStatus==STATUS_PENDING:
  5418. find corresponding IRP with AFD_SWITCH_REQUEST_TFCTX context,
  5419. reset CtxTransferStatus to STATUS_SUCCESS and resume request
  5420. processing (resubmit those that have NULL ID);
  5421. b)CtxTransferStatus==OTHER or IRP is not found:
  5422. fail the request and mark CtxTransferStatus as STATUS_CANCELLED.
  5423. 7. Processing of unsolicited IOCTL_AFD_SWITCH_TRANSFER_CTX (generated
  5424. by the owner process on AFD_SWITCH_REQUEST_TFCTX notification for
  5425. a temporary holding in service process):
  5426. a)CtxTransferStatus==STATUS_PENDING (or STATUS_SUCCESS-this is not possible
  5427. currently since switch does not generate transfers by itself, but in
  5428. theory we can do this for WSADuplicateHandle):
  5429. save the context, reset CtxTransferStatus to
  5430. STATUS_MORE_PROCESSING_REQUIRED, reset all pending request IDs to NULL
  5431. for re-processing, queue AFD_SWITCH_REQUEST_AQCTX to service process
  5432. to pick up the endpoint;
  5433. if anything fails, reset CtxTransferStatus to failure status and fail
  5434. all pending requests;
  5435. b)CtxTransferStatus==OTHER:
  5436. fail the request and mark CtxTransferStatus as STATUS_CANCELLED.
  5437. 8. Processing of accept from the process that doesn't own listening socket.
  5438. Duplicate the accept handle into listening process and mark the endpoint
  5439. with ImplicitDup flag. Listening process will then explicitly request
  5440. context transfer (e.g. issue IOCTL_AFD_SWITCH_ACQUIRE_CTX).
  5441. 9. Processing of owner process handle close notification while other
  5442. processes still have handles opened (UnlockAll):
  5443. a)CtxTransferStatus==STATUS_SUCCESS
  5444. Set CtxTransferStatus to STATUS_PENDING and notify owner process
  5445. to transfer endpoint to the service process, if notification fails,
  5446. reset CtxTransferStatus to STATUS_CANCELLED and fail all pending
  5447. requests.
  5448. b)CtxTransferStatus==STATUS_PENDING
  5449. Some other process (maybe just little while back) asked for the socket
  5450. by explicit IOCTL_AFD_SWITCH_ACQUIRE_CTX. Let that duplication proceed.
  5451. No need to duplicate to service process.
  5452. c)CtxTransferStatus==OTHER
  5453. ignore the call - endpoint is either in failed state or another
  5454. duplication request is already in progress.
  5455. */