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.

638 lines
23 KiB

  1. /* (C) 1997-2000 Microsoft Corp.
  2. *
  3. * file : MCSIoctl.c
  4. * author : Erik Mavrinac
  5. *
  6. * description: MCS API calls received from MCSMUX through ICA stack IOCTLs
  7. * and returned through ICA virtual channel inputs. These entry points
  8. * simply provide an IOCTL translation layer for the kernel-mode API.
  9. * ONLY MCSMUX should make these calls.
  10. */
  11. #include "PreComp.h"
  12. #pragma hdrstop
  13. #include <MCSImpl.h>
  14. /*
  15. * Prototypes for forward references for locally-defined functions.
  16. */
  17. NTSTATUS AttachUserRequestFunc(PDomain, PSD_IOCTL);
  18. NTSTATUS DetachUserRequestFunc(PDomain, PSD_IOCTL);
  19. NTSTATUS ChannelJoinRequestFunc(PDomain, PSD_IOCTL);
  20. NTSTATUS ChannelLeaveRequestFunc(PDomain, PSD_IOCTL);
  21. NTSTATUS SendDataRequestFunc(PDomain, PSD_IOCTL);
  22. NTSTATUS ConnectProviderResponseFunc(PDomain, PSD_IOCTL);
  23. NTSTATUS DisconnectProviderRequestFunc(PDomain, PSD_IOCTL);
  24. NTSTATUS T120StartFunc(PDomain, PSD_IOCTL);
  25. /*
  26. * Globals
  27. */
  28. // Table of function entry points for ChannelWrite() request calls.
  29. // These entry points correspond to request defines in MCSIOCTL.h.
  30. // NULL means unsupported, which will be handled by dispatch code in
  31. // PdChannelWrite() in PDAPI.c.
  32. const PT120RequestFunc g_T120RequestDispatch[] =
  33. {
  34. AttachUserRequestFunc,
  35. DetachUserRequestFunc,
  36. ChannelJoinRequestFunc,
  37. ChannelLeaveRequestFunc,
  38. SendDataRequestFunc, // Handles both uniform and regular.
  39. SendDataRequestFunc, // Handles both uniform and regular.
  40. NULL, // MCS_CHANNEL_CONVENE_REQUEST unsupported.
  41. NULL, // MCS_CHANNEL_DISBAND_REQUEST unsupported.
  42. NULL, // MCS_CHANNEL_ADMIT_REQUEST unsupported.
  43. NULL, // MCS_CHANNEL_EXPEL_REQUEST unsupported.
  44. NULL, // MCS_TOKEN_GRAB_REQUEST unsupported.
  45. NULL, // MCS_TOKEN_INHIBIT_REQUEST unsupported.
  46. NULL, // MCS_TOKEN_GIVE_REQUEST unsupported.
  47. NULL, // MCS_TOKEN_GIVE_RESPONSE unsupported.
  48. NULL, // MCS_TOKEN_PLEASE_REQUEST unsupported.
  49. NULL, // MCS_TOKEN_RELEASE_REQUEST unsupported.
  50. NULL, // MCS_TOKEN_TEST_REQUEST unsupported.
  51. NULL, // MCS_CONNECT_PROVIDER_REQUEST unsupported.
  52. ConnectProviderResponseFunc,
  53. DisconnectProviderRequestFunc,
  54. T120StartFunc,
  55. };
  56. /*
  57. * Main callback for user attachment indications/confirms from kernel mode API.
  58. * Translate and send to user mode.
  59. */
  60. void __stdcall UserModeUserCallback(
  61. UserHandle hUser,
  62. unsigned Message,
  63. void *Params,
  64. void *UserDefined)
  65. {
  66. BYTE *pData;
  67. unsigned DataLength;
  68. NTSTATUS Status;
  69. UserAttachment *pUA;
  70. pUA = (UserAttachment *)hUser;
  71. //MCS FUTURE: Handle all callbacks. Right now we support only those
  72. // we know are going to pass by.
  73. switch (Message) {
  74. case MCS_DETACH_USER_INDICATION: {
  75. DetachUserIndication *pDUin;
  76. DetachUserIndicationIoctl DUinIoctl;
  77. pDUin = (DetachUserIndication *)Params;
  78. DUinIoctl.Header.Type = Message;
  79. DUinIoctl.Header.hUser = hUser;
  80. DUinIoctl.UserDefined = UserDefined;
  81. DUinIoctl.DUin = *pDUin;
  82. pData = (BYTE *)&DUinIoctl;
  83. DataLength = sizeof(DetachUserIndicationIoctl);
  84. // Send data below.
  85. break;
  86. }
  87. default:
  88. ErrOut1(pUA->pDomain->pContext, "UserModeUserCallback: "
  89. "Unsupported callback %d received", Message);
  90. return;
  91. }
  92. // Send the data to user mode.
  93. ASSERT(pUA->pDomain->bChannelBound);
  94. Status = IcaChannelInput(pUA->pDomain->pContext, Channel_Virtual,
  95. Virtual_T120ChannelNum, NULL, pData, DataLength);
  96. if (!NT_SUCCESS(Status)) {
  97. ErrOut2(pUA->pDomain->pContext, "UserModeUserCallback: "
  98. "Error %X on IcaChannelInput() for callback %d",
  99. Status, Message);
  100. // Ignore errors here. This should not happen unless the stack is
  101. // going down.
  102. }
  103. }
  104. /*
  105. * Handles MCS kernel API callbacks for MCS send-data indications.
  106. * Translates into user mode call.
  107. */
  108. BOOLEAN __fastcall UserModeSendDataCallback(
  109. BYTE *pData,
  110. unsigned DataLength,
  111. void *UserDefined,
  112. UserHandle hUser,
  113. BOOLEAN bUniform,
  114. ChannelHandle hChannel,
  115. MCSPriority Priority,
  116. UserID SenderID,
  117. Segmentation Segmentation)
  118. {
  119. BOOLEAN result = TRUE;
  120. NTSTATUS Status;
  121. UserAttachment *pUA;
  122. SendDataIndicationIoctl SDinIoctl;
  123. pUA = (UserAttachment *)hUser;
  124. //MCS FUTURE: Need to alloc data and copy or, better yet,
  125. // utilize a header at the beginning of the input buffer
  126. // to send this upward.
  127. #if 0
  128. SDinIoctl.Header.Type = bUniform ? MCS_UNIFORM_SEND_DATA_INDICATION :
  129. MCS_SEND_DATA_INDICATION;
  130. SDinIoctl.Header.hUser = hUser;
  131. SDinIoctl.UserDefined = UserDefined;
  132. SDinIoctl.hChannel = hChannel;
  133. SDinIoctl.SenderID = SenderID;
  134. SDinIoctl.Priority = Priority;
  135. SDinIoctl.Segmentation = Segmentation;
  136. SDinIoctl.DataLength = DataLength;
  137. // Send the data to user mode.
  138. ASSERT(pUA->pDomain->bChannelBound);
  139. Status = IcaChannelInput(pUA->pDomain->pContext, Channel_Virtual,
  140. Virtual_T120ChannelNum, NULL, pData, DataLength);
  141. if (!NT_SUCCESS(Status)) {
  142. ErrOut2(pUA->pDomain->pContext, "UserModeUserCallback: "
  143. "Error %X on IcaChannelInput() for callback %d",
  144. Status, Message);
  145. // Ignore errors here. This should not happen unless the stack is
  146. // going down.
  147. }
  148. #endif
  149. ErrOut(pUA->pDomain->pContext, "UserModeUserCallback: "
  150. "Unsupported send-data indication received, code incomplete");
  151. ASSERT(FALSE);
  152. return result;
  153. }
  154. /*
  155. * Handles an MCS attach-user request from user mode. Translates the ioctl
  156. * into a kernel-mode MCS API call.
  157. */
  158. NTSTATUS AttachUserRequestFunc(Domain *pDomain, PSD_IOCTL pSdIoctl)
  159. {
  160. AttachUserReturnIoctl *pAUrt;
  161. AttachUserRequestIoctl *pAUrq;
  162. ASSERT(pSdIoctl->InputBufferLength == sizeof(AttachUserRequestIoctl));
  163. ASSERT(pSdIoctl->OutputBufferLength == sizeof(AttachUserReturnIoctl));
  164. pAUrq = (AttachUserRequestIoctl *) pSdIoctl->InputBuffer;
  165. pAUrt = (AttachUserReturnIoctl *) pSdIoctl->OutputBuffer;
  166. ASSERT(pAUrq->Header.Type == MCS_ATTACH_USER_REQUEST);
  167. // Call kernel-mode API which will handle creating local data and,
  168. // if necessary, will forward the request to the top provider.
  169. // Provide a kernel-mode callback that will package the data and send it
  170. // to the appropriate user.
  171. pAUrt->MCSErr = MCSAttachUserRequest((DomainHandle)pDomain,
  172. UserModeUserCallback, UserModeSendDataCallback,
  173. pAUrq->UserDefined, &pAUrt->hUser, &pAUrt->MaxSendSize,
  174. &pAUrt->bCompleted);
  175. pAUrt->UserID = ((UserAttachment *)pAUrt->hUser)->UserID;
  176. pSdIoctl->BytesReturned = sizeof(AttachUserReturnIoctl);
  177. // Return STATUS_SUCCESS even if there was an error code returned --
  178. // the MCSError code is returned above too.
  179. return STATUS_SUCCESS;
  180. }
  181. /*
  182. * Handles an MCS detach-user request channel write. There is no callback for
  183. * this request, the user attachment is considered destroyed upon return.
  184. */
  185. NTSTATUS DetachUserRequestFunc(PDomain pDomain, PSD_IOCTL pSdIoctl)
  186. {
  187. MCSError *pMCSErr;
  188. DetachUserRequestIoctl *pDUrq;
  189. ASSERT(pSdIoctl->InputBufferLength == sizeof(DetachUserRequestIoctl));
  190. ASSERT(pSdIoctl->OutputBufferLength == sizeof(MCSError));
  191. pDUrq = (DetachUserRequestIoctl *)pSdIoctl->InputBuffer;
  192. pMCSErr = (MCSError *)pSdIoctl->OutputBuffer;
  193. ASSERT(pDUrq->Header.Type == MCS_DETACH_USER_REQUEST);
  194. // Call the kernel-mode API.
  195. *pMCSErr = MCSDetachUserRequest(pDUrq->Header.hUser);
  196. pSdIoctl->BytesReturned = sizeof(MCSError);
  197. // Always return STATUS_SUCCESS.
  198. return STATUS_SUCCESS;
  199. }
  200. /*
  201. * Channel join - ChannelWrite() request.
  202. */
  203. NTSTATUS ChannelJoinRequestFunc(PDomain pDomain, PSD_IOCTL pSdIoctl)
  204. {
  205. ChannelJoinRequestIoctl *pCJrq;
  206. ChannelJoinReturnIoctl *pCJrt;
  207. ASSERT(pSdIoctl->InputBufferLength == sizeof(ChannelJoinRequestIoctl));
  208. ASSERT(pSdIoctl->OutputBufferLength == sizeof(ChannelJoinReturnIoctl));
  209. pCJrq = (ChannelJoinRequestIoctl *) pSdIoctl->InputBuffer;
  210. pCJrt = (ChannelJoinReturnIoctl *) pSdIoctl->OutputBuffer;
  211. ASSERT(pCJrq->Header.Type == MCS_CHANNEL_JOIN_REQUEST);
  212. // Make the call to the kernel mode API.
  213. pCJrt->MCSErr = MCSChannelJoinRequest(pCJrq->Header.hUser,
  214. pCJrq->ChannelID, &pCJrt->hChannel, &pCJrt->bCompleted);
  215. pCJrt->ChannelID = ((MCSChannel *)pCJrt->hChannel)->ID;
  216. pSdIoctl->BytesReturned = sizeof(ChannelJoinReturnIoctl);
  217. // Always return STATUS_SUCCESS.
  218. return STATUS_SUCCESS;
  219. }
  220. /*
  221. * Channel leave - ChannelWrite() request.
  222. */
  223. NTSTATUS ChannelLeaveRequestFunc(PDomain pDomain, PSD_IOCTL pSdIoctl)
  224. {
  225. MCSError *pMCSErr;
  226. ChannelLeaveRequestIoctl *pCLrq;
  227. ASSERT(pSdIoctl->InputBufferLength == sizeof(ChannelLeaveRequestIoctl));
  228. ASSERT(pSdIoctl->OutputBufferLength == sizeof(MCSError));
  229. pCLrq = (ChannelLeaveRequestIoctl *)pSdIoctl->InputBuffer;
  230. pMCSErr = (MCSError *)pSdIoctl->OutputBuffer;
  231. ASSERT(pCLrq->Header.Type == MCS_CHANNEL_LEAVE_REQUEST);
  232. *pMCSErr = MCSChannelLeaveRequest(pCLrq->Header.hUser, pCLrq->hChannel);
  233. pSdIoctl->BytesReturned = sizeof(MCSError);
  234. // Always return STATUS_SUCCESS.
  235. return STATUS_SUCCESS;
  236. }
  237. /*
  238. * Send data - handles both uniform and regular sends.
  239. * Data is packed immediately after the SendDataRequestIoctl struct.
  240. * No profixes or suffixes are needed.
  241. */
  242. NTSTATUS SendDataRequestFunc(PDomain pDomain, PSD_IOCTL pSdIoctl)
  243. {
  244. POUTBUF pOutBuf;
  245. MCSError *pMCSErr;
  246. NTSTATUS Status;
  247. UserAttachment *pUA;
  248. SendDataRequestIoctl *pSDrq;
  249. ASSERT(pSdIoctl->InputBufferLength >= sizeof(SendDataRequestIoctl));
  250. ASSERT(pSdIoctl->OutputBufferLength == sizeof(MCSError));
  251. pSDrq = (SendDataRequestIoctl *)pSdIoctl->InputBuffer;
  252. pMCSErr = (MCSError *)pSdIoctl->OutputBuffer;
  253. ASSERT(pSDrq->Header.Type == MCS_SEND_DATA_REQUEST ||
  254. pSDrq->Header.Type == MCS_UNIFORM_SEND_DATA_REQUEST);
  255. ASSERT(pSdIoctl->InputBufferLength == (sizeof(SendDataRequestIoctl) +
  256. pSDrq->DataLength));
  257. #if DBG
  258. // Get pUA for tracing.
  259. pUA = (UserAttachment *)pSDrq->Header.hUser;
  260. #endif
  261. // Allocate an OutBuf to emulate a kernel-mode caller.
  262. Status = IcaBufferAlloc(pDomain->pContext, TRUE, TRUE,
  263. (SendDataReqPrefixBytes + pSDrq->DataLength +
  264. SendDataReqSuffixBytes), NULL, &pOutBuf);
  265. if (Status != STATUS_SUCCESS) {
  266. ErrOut(pUA->pDomain->pContext, "Could not allocate an OutBuf for a "
  267. "send-data request sent from user mode");
  268. return Status;
  269. }
  270. // Copy the user-mode memory to the kernel outbuf.
  271. memcpy(pOutBuf->pBuffer + SendDataReqPrefixBytes,
  272. &pSdIoctl->InputBuffer + sizeof(SendDataRequestIoctl),
  273. pSDrq->DataLength);
  274. // Set OutBuf params according to needs of API.
  275. pOutBuf->ByteCount = pSDrq->DataLength;
  276. pOutBuf->pBuffer += SendDataReqPrefixBytes;
  277. // Call the kernel-mode API.
  278. *pMCSErr = MCSSendDataRequest(pSDrq->Header.hUser, pSDrq->hChannel,
  279. pSDrq->RequestType, 0, pSDrq->Priority, pSDrq->Segmentation,
  280. pOutBuf);
  281. pSdIoctl->BytesReturned = sizeof(MCSError);
  282. // Always return STATUS_SUCCESS.
  283. return STATUS_SUCCESS;
  284. }
  285. /*
  286. * Connect provider response - ChannelWrite() request. Requires filler bytes
  287. * in MCSConnectProviderResponseIoctl to make sure we use at least 54 bytes
  288. * for the struct so we can reuse the OutBuf here. User data must start
  289. * at (pSdIoctl->pBuffer + sizeof(MCSConnectProviderResponseIoctl)).
  290. */
  291. NTSTATUS ConnectProviderResponseFunc(
  292. PDomain pDomain,
  293. PSD_IOCTL pSdIoctl)
  294. {
  295. POUTBUF pOutBuf;
  296. NTSTATUS Status;
  297. ConnectProviderResponseIoctl *pCPrs;
  298. ASSERT(pSdIoctl->InputBufferLength ==
  299. sizeof(ConnectProviderResponseIoctl));
  300. pCPrs = (ConnectProviderResponseIoctl *)pSdIoctl->InputBuffer;
  301. ASSERT(pCPrs->Header.Type == MCS_CONNECT_PROVIDER_RESPONSE);
  302. // Verify that we are actually waiting for a CP response.
  303. if (pDomain->State != State_ConnectProvIndPending) {
  304. ErrOut(pDomain->pContext, "Connect-provider response call received, "
  305. "we are in wrong state, ignoring");
  306. return STATUS_INVALID_DOMAIN_STATE;
  307. }
  308. // Alloc OutBuf for sending PDU.
  309. // This allocation is vital to the session and must succeed.
  310. do {
  311. Status = IcaBufferAlloc(pDomain->pContext, FALSE, TRUE,
  312. ConnectResponseHeaderSize + pCPrs->UserDataLength, NULL,
  313. &pOutBuf);
  314. if (Status != STATUS_SUCCESS)
  315. ErrOut(pDomain->pContext, "Could not allocate an OutBuf for a "
  316. "connect-response PDU, retrying");
  317. } while (Status != STATUS_SUCCESS);
  318. // Encode PDU header. Param 2, the called connect ID, does not need to be
  319. // anything special because we do not allow extra sockets to be opened
  320. // for other data priorities.
  321. CreateConnectResponseHeader(pDomain->pContext, pCPrs->Result, 0,
  322. &pDomain->DomParams, pCPrs->UserDataLength, pOutBuf->pBuffer,
  323. &pOutBuf->ByteCount);
  324. // Copy the user data after the header.
  325. RtlCopyMemory(pOutBuf->pBuffer + pOutBuf->ByteCount, pCPrs->pUserData,
  326. pCPrs->UserDataLength);
  327. pOutBuf->ByteCount += pCPrs->UserDataLength;
  328. // Send the new PDU OutBuf down to the TD for sending out.
  329. //MCS FUTURE: Needs to change for multiple connections.
  330. Status = SendOutBuf(pDomain, pOutBuf);
  331. if (!NT_SUCCESS(Status)) {
  332. ErrOut(pDomain->pContext, "Could not send connect-response PDU OutBuf "
  333. "to TD");
  334. // Ignore errors here -- this should only occur if stack is going down.
  335. return Status;
  336. }
  337. // Transition state depending on Result.
  338. if (pCPrs->Result == RESULT_SUCCESSFUL) {
  339. pDomain->State = State_MCS_Connected;
  340. }
  341. else {
  342. TraceOut(pDomain->pContext, "ConnectProviderRespFunc(): Node "
  343. "controller returned error in response, destroying call "
  344. "data");
  345. pDomain->State = State_Disconnected;
  346. // Detach any users that attached during domain setup.
  347. DisconnectProvider(pDomain, TRUE, REASON_PROVIDER_INITIATED);
  348. }
  349. return STATUS_SUCCESS;
  350. }
  351. /*
  352. * Disconnect provider - ChannelWrite() request.
  353. * This handles both the case where a disconnect is performed on the local
  354. * "connection" (i.e. pDPrq->hConn == NULL), and a specific remote
  355. * connection (pDPrq->hConn != NULL)/
  356. * MCS FUTURE: Change for multiple connections.
  357. */
  358. NTSTATUS DisconnectProviderRequestFunc(
  359. PDomain pDomain,
  360. PSD_IOCTL pSdIoctl)
  361. {
  362. NTSTATUS Status;
  363. DisconnectProviderRequestIoctl *pDPrq;
  364. LONG refs;
  365. TraceOut1(pDomain->pContext, "DisconnectProviderRequestFunc(): Entry, "
  366. "pDomain=%X", pDomain);
  367. ASSERT(pSdIoctl->InputBufferLength ==
  368. sizeof(DisconnectProviderRequestIoctl));
  369. pDPrq = (DisconnectProviderRequestIoctl *)pSdIoctl->InputBuffer;
  370. ASSERT(pDPrq->Header.hUser == NULL);
  371. ASSERT(pDPrq->Header.Type == MCS_DISCONNECT_PROVIDER_REQUEST);
  372. // Send DPum PDU if we can still send data.
  373. if ((pDomain->State == State_MCS_Connected) && pDomain->bCanSendData) {
  374. POUTBUF pOutBuf;
  375. // Alloc OutBuf for sending DPum PDU.
  376. Status = IcaBufferAlloc(pDomain->pContext, FALSE, TRUE, DPumPDUSize,
  377. NULL, &pOutBuf);
  378. if (Status != STATUS_SUCCESS) {
  379. ErrOut(pDomain->pContext, "Could not allocate an OutBuf for a "
  380. "DPum PDU, cannot send");
  381. // We ignore problems sending the DPum PDU since we are going down
  382. // anyway.
  383. }
  384. else {
  385. SD_SYNCWRITE SdSyncWrite;
  386. CreateDisconnectProviderUlt(pDPrq->Reason, pOutBuf->pBuffer);
  387. pOutBuf->ByteCount = DPumPDUSize;
  388. TraceOut(pDomain->pContext, "DisconnectProviderRequestFunc(): "
  389. "Sending DPum PDU");
  390. // Send the PDU to the transport.
  391. // MCS FUTURE: Assuming only one transport and only one
  392. // connection.
  393. Status = SendOutBuf(pDomain, pOutBuf);
  394. if (!NT_SUCCESS(Status))
  395. // We ignore problems sending the DPum PDU since we are going
  396. // down anyway.
  397. WarnOut(pDomain->pContext, "Could not send DPum PDU OutBuf "
  398. "downward");
  399. // The call to IcaCallNextDriver unlocks our stack, allowing a WD_Close to
  400. // go through. WD_Close can call MCSCleanup which will free pDomain,
  401. // and NULL out pTSWd->hDomainKernel. Because pDomain may no longer be valid,
  402. // it is not good enough to check pDomain->StatusDead here! To keep this
  403. // fix localized, we created a pseudo-RefCount to protect the exact cases
  404. // we saw this bug hit in stress. A bug will be opened for Longhorn to
  405. // make this RefCount generic so that ALL calls to IcaWaitForSingleObject (etc)
  406. // are protected.
  407. PDomainAddRef(pDomain);
  408. // Flush the transport driver. Note that this call can block and
  409. // release the stack lock
  410. Status = IcaCallNextDriver(pDomain->pContext, SD$SYNCWRITE,
  411. &SdSyncWrite);
  412. refs = PDomainRelease(pDomain);
  413. if (0 == refs)
  414. {
  415. // We ignore problems since we are going down anyway.
  416. Status = STATUS_SUCCESS;
  417. goto DC_EXIT_POINT;
  418. }
  419. if (!NT_SUCCESS(Status))
  420. // We ignore problems since we are going down anyway.
  421. WarnOut(pDomain->pContext, "Could not sync transport after "
  422. "DPum");
  423. // If the client has not already responded with a FIN (while we
  424. // were blocked on the synchronous write) wait until we see it or time
  425. // out trying
  426. if (pDomain->bCanSendData) {
  427. pDomain->pBrokenEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
  428. if (pDomain->pBrokenEvent) {
  429. KeInitializeEvent(pDomain->pBrokenEvent, NotificationEvent, FALSE);
  430. PDomainAddRef(pDomain);
  431. IcaWaitForSingleObject(pDomain->pContext,
  432. pDomain->pBrokenEvent,
  433. 5000);
  434. refs = PDomainRelease(pDomain);
  435. if (0 == refs)
  436. {
  437. // We ignore problems since we are going down anyway.
  438. Status = STATUS_SUCCESS;
  439. goto DC_EXIT_POINT;
  440. }
  441. ExFreePool(pDomain->pBrokenEvent);
  442. pDomain->pBrokenEvent = NULL;
  443. }
  444. }
  445. }
  446. }
  447. // Internal disconnection code.
  448. DisconnectProvider(pDomain, (BOOLEAN)(pDPrq->hConn == NULL),
  449. pDPrq->Reason);
  450. Status = STATUS_SUCCESS;
  451. // Different behavior for different connections.
  452. if (pDPrq->hConn == NULL) {
  453. // This call should only come in when the stack is going away.
  454. // So, prevent further data sends to transport and further channel
  455. // inputs to user mode.
  456. pDomain->bCanSendData = FALSE;
  457. pDomain->bChannelBound = FALSE;
  458. // The domain is considered dead now. Domain struct cleanup will
  459. // occur during stack driver cleanup at MCSCleanup().
  460. // Status = IcaChannelInput(pDomain->pContext, Channel_Virtual,
  461. // Virtual_T120ChannelNum, NULL, "F", 1);
  462. }
  463. DC_EXIT_POINT:
  464. return Status;
  465. }
  466. NTSTATUS T120StartFunc(Domain *pDomain, PSD_IOCTL pSdIoctl)
  467. {
  468. NTSTATUS Status;
  469. DisconnectProviderIndicationIoctl DPin;
  470. pDomain->bT120StartReceived = TRUE;
  471. // This is to handle a timing window where the stack has just come up
  472. // but a DPum from a quickly-disconnected client has already arrived.
  473. if (pDomain->bDPumReceivedNotInput) {
  474. // We should have received a QUERY_VIRTUAL_BINDINGS ioctl by this time.
  475. ASSERT(pDomain->bChannelBound);
  476. // Fill out disconnect-provider indication for the node controller.
  477. DPin.Header.hUser = NULL; // Node controller.
  478. DPin.Header.Type = MCS_DISCONNECT_PROVIDER_INDICATION;
  479. DPin.hConn = NULL;
  480. // Reason is a 3-bit field starting at bit 1 of the 1st byte.
  481. DPin.Reason = pDomain->DelayedDPumReason;
  482. // Send the DPin to the node controller channel.
  483. TraceOut(pDomain->pContext, "HandleDisconnProvUlt(): Sending "
  484. "DISCONNECT_PROV_IND upward");
  485. Status = IcaChannelInput(pDomain->pContext, Channel_Virtual,
  486. Virtual_T120ChannelNum, NULL, (BYTE *)&DPin, sizeof(DPin));
  487. if (!NT_SUCCESS(Status)) {
  488. // We ignore the error -- if the stack is coming down, the link
  489. // may have been broken, so this is not a major concern.
  490. WarnOut1(pDomain->pContext, "T120StartFunc(): "
  491. "Could not send DISCONN_PROV_IND to user mode, "
  492. "status=%X, ignoring error", Status);
  493. }
  494. // In this case we have to ignore the fact that we may have a
  495. // X.224 connect already pending.
  496. return STATUS_SUCCESS;
  497. }
  498. pDomain->bCanSendData = TRUE;
  499. // If an X.224 connect has already been processed, and we have bound the
  500. // virtual channels, send the X.224 response.
  501. if (pDomain->bChannelBound && pDomain->State == State_X224_Requesting) {
  502. TraceOut(pDomain->pContext, "T120StartFunc(): Sending X.224 response");
  503. Status = SendX224Confirm(pDomain);
  504. // Ignore errors. Failure to send should occur only when the stack is
  505. // going down.
  506. }
  507. else {
  508. WarnOut(pDomain->pContext,
  509. "T120StartFunc(): Domain state not State_X224_Requesting, "
  510. "awaiting X.224 connect");
  511. }
  512. return STATUS_SUCCESS;
  513. }