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.

998 lines
46 KiB

  1. /****************************************************************************/
  2. // xtapi.cpp
  3. //
  4. // XT layer - portable API
  5. //
  6. // Copyright (C) 1997-1999 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <adcg.h>
  9. extern "C" {
  10. #define TRC_FILE "xtapi"
  11. #define TRC_GROUP TRC_GROUP_NETWORK
  12. #include <atrcapi.h>
  13. }
  14. #include "autil.h"
  15. #include "xt.h"
  16. #include "cd.h"
  17. #include "nl.h"
  18. #include "sl.h"
  19. #include "mcs.h"
  20. CXT::CXT(CObjs* objs)
  21. {
  22. _pClientObjects = objs;
  23. }
  24. CXT::~CXT()
  25. {
  26. }
  27. /****************************************************************************/
  28. /* Name: XT_Init */
  29. /* */
  30. /* Purpose: Initializes _XT. Since XT is stateless, this just involves */
  31. /* initializing TD. */
  32. /****************************************************************************/
  33. DCVOID DCAPI CXT::XT_Init(DCVOID)
  34. {
  35. DC_BEGIN_FN("XT_Init");
  36. /************************************************************************/
  37. /* Initialize our global data. */
  38. /************************************************************************/
  39. DC_MEMSET(&_XT, 0, sizeof(_XT));
  40. _pCd = _pClientObjects->_pCdObject;
  41. _pSl = _pClientObjects->_pSlObject;
  42. _pTd = _pClientObjects->_pTDObject;
  43. _pMcs = _pClientObjects->_pMCSObject;
  44. _pUt = _pClientObjects->_pUtObject;
  45. _pUi = _pClientObjects->_pUiObject;
  46. _pClx = _pClientObjects->_pCLXObject;
  47. TRC_NRM((TB, _T("XT pkt max-size:%u min-size:%u"),
  48. XT_MAX_HEADER_SIZE,
  49. XT_MIN_HEADER_SIZE));
  50. _pTd->TD_Init();
  51. TRC_NRM((TB, _T("XT successfully initialized")));
  52. DC_END_FN();
  53. } /* XT_Init */
  54. /****************************************************************************/
  55. /* Name: XT_SendBuffer */
  56. /* */
  57. /* Purpose: Adds the XT data packet header and then sends the packet. */
  58. /* */
  59. /* Params: IN pData - pointer to the start of the data. */
  60. /* IN dataLength - amount of the buffer used. */
  61. /* IN bufHandle - handle to a buffer. */
  62. /****************************************************************************/
  63. DCVOID DCAPI CXT::XT_SendBuffer(PDCUINT8 pData,
  64. DCUINT dataLength,
  65. XT_BUFHND bufHandle)
  66. {
  67. DCUINT packetLength;
  68. XT_DT xtDT = XT_DT_DATA;
  69. DC_BEGIN_FN("XT_SendBuffer");
  70. /************************************************************************/
  71. /* Check that we're not being asked to send more data than we can. */
  72. /************************************************************************/
  73. TRC_ASSERT((dataLength <= XT_MAX_DATA_SIZE),
  74. (TB, _T("Data exceeds XT TSDU length of %u"), XT_MAX_DATA_SIZE));
  75. /************************************************************************/
  76. /* Add our XT data header. All the invariant fields are already */
  77. /* initialized, so all that remains to be filled in is the packet */
  78. /* length. */
  79. /************************************************************************/
  80. packetLength = dataLength + sizeof(XT_DT);
  81. xtDT.hdr.lengthHighPart = ((DCUINT16)packetLength) >> 8;
  82. xtDT.hdr.lengthLowPart = ((DCUINT16)packetLength) & 0xFF;
  83. TRC_DBG((TB, _T("XT pkt length:%u"), packetLength));
  84. /************************************************************************/
  85. /* Now update the data pointer to point to the include the XT data */
  86. /* header. */
  87. /************************************************************************/
  88. TRC_DBG((TB, _T("Move pData back from %p to %p"),
  89. pData,
  90. pData - sizeof(XT_DT)));
  91. pData -= sizeof(XT_DT);
  92. /************************************************************************/
  93. /* Copy in the header. */
  94. /************************************************************************/
  95. memcpy(pData, &xtDT, sizeof(XT_DT));
  96. /************************************************************************/
  97. /* Trace out the packet. */
  98. /************************************************************************/
  99. TRC_DATA_DBG("XT packet:", pData, packetLength);
  100. /************************************************************************/
  101. /* Now send the buffer. */
  102. /************************************************************************/
  103. _pTd->TD_SendBuffer(pData, packetLength, (TD_BUFHND)bufHandle);
  104. DC_END_FN();
  105. } /* XT_SendBuffer */
  106. /****************************************************************************/
  107. /* Name: XT_Recv */
  108. /* */
  109. /* Purpose: Attempts to retrieve the requested number of bytes into the */
  110. /* buffer pointed to by pBuffer. This function should only */
  111. /* be called in response to an MCS_OnXTDataAvailable callback. */
  112. /* */
  113. /* Returns: The number of bytes received. */
  114. /* */
  115. /* Params: IN pData - pointer to buffer to receive the data. */
  116. /* IN length - number of bytes to receive. */
  117. /****************************************************************************/
  118. DCUINT DCAPI CXT::XT_Recv(PDCUINT8 pData, DCUINT length)
  119. {
  120. DCUINT bytesRead;
  121. DCUINT numBytes;
  122. DC_BEGIN_FN("XT_Recv");
  123. TRC_ASSERT((length != 0), (TB, _T("Data length to receive is 0")));
  124. TRC_ASSERT((length < 65535),(TB,_T("Data length %u too large"), length));
  125. TRC_ASSERT((pData != 0), (TB, _T("Data pointer is NULL")));
  126. // We can only receive the minimum of the number of bytes in XT and
  127. // the requested length.
  128. numBytes = DC_MIN(length, _XT.dataBytesLeft);
  129. TRC_DBG((TB, _T("Receive %u bytes (length:%u dataBytesLeft:%u)"),
  130. numBytes, length, _XT.dataBytesLeft));
  131. // Try to read the bytes from TD.
  132. bytesRead = _pTd->TD_Recv(pData, numBytes);
  133. // Decrement the count of data bytes left in _XT.
  134. _XT.dataBytesLeft -= bytesRead;
  135. TRC_DBG((TB, _T("%u data bytes left in XT frame"), _XT.dataBytesLeft));
  136. if (!_pTd->TD_QueryDataAvailable() || (0 == _XT.dataBytesLeft)) {
  137. // TD has no more data or this XT frame is finished - so there is
  138. // no longer any data left in _XT.
  139. TRC_DBG((TB, _T("No data left in XT")));
  140. _XT.dataInXT = FALSE;
  141. }
  142. TRC_DATA_DBG("Data received:", pData, bytesRead);
  143. DC_END_FN();
  144. return bytesRead;
  145. } /* XT_Recv */
  146. /****************************************************************************/
  147. /* Name: XT_OnTDConnected */
  148. /* */
  149. /* Purpose: This is called by TD when it has successfully connected. */
  150. /****************************************************************************/
  151. DCVOID DCCALLBACK CXT::XT_OnTDConnected(DCVOID)
  152. {
  153. DC_BEGIN_FN("XT_OnTDConnected");
  154. TRC_NRM((TB, _T("TD connected: init states and decouple CR send")));
  155. // Initialize our state and count of bytes that we're waiting for.
  156. // Fast-path server output can send as small as 2 bytes for a header,
  157. // so we init the header receive size to get 2 bytes, which we'll expand
  158. // to X.224 or fast-path remainder as needed when receiving.
  159. //
  160. // Also reset the count of data bytes left and flag that there is
  161. // currently no data in _XT.
  162. XT_ResetDataState();
  163. // Decouple to the sender thread and send a XT CR.
  164. _pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
  165. CD_NOTIFICATION_FUNC(CXT,XTSendCR),
  166. 0);
  167. DC_END_FN();
  168. } /* XT_OnTDConnected */
  169. /****************************************************************************/
  170. /* Name: XT_OnTDDisconnected */
  171. /* */
  172. /* Purpose: This callback function is called by TD when it has */
  173. /* disconnected. */
  174. /* */
  175. /* Params: IN reason - reason for the disconnection. */
  176. /****************************************************************************/
  177. DCVOID DCCALLBACK CXT::XT_OnTDDisconnected(DCUINT reason)
  178. {
  179. DC_BEGIN_FN("XT_OnTDDisconnected");
  180. TRC_ASSERT((reason != 0), (TB, _T("Disconnect reason from TD is 0")));
  181. /************************************************************************/
  182. /* Decide if we want to over-ride the disconnect reason code. */
  183. /************************************************************************/
  184. if (_XT.disconnectErrorCode != 0)
  185. {
  186. TRC_ALT((TB, _T("Over-riding disconnection error code (%u->%u)"),
  187. reason,
  188. _XT.disconnectErrorCode));
  189. /********************************************************************/
  190. /* Over-ride the error code and set the global variable to 0. */
  191. /********************************************************************/
  192. reason = _XT.disconnectErrorCode;
  193. _XT.disconnectErrorCode = 0;
  194. }
  195. /************************************************************************/
  196. /* Just pass this up to MCS. */
  197. /************************************************************************/
  198. TRC_NRM((TB, _T("Disconnect reason:%u"), reason));
  199. _pMcs->MCS_OnXTDisconnected(reason);
  200. DC_END_FN();
  201. } /* XT_OnTDDisconnected */
  202. /****************************************************************************/
  203. // XTRecvToHdrBuf
  204. //
  205. // Receives data into the header buffer.
  206. // We use a macro to force cutting the function call overhead. Data-receive
  207. // must be as fast as possible, at the expense of a bit of code size.
  208. // Returns TRUE in bytesNeededZero if the receive bytes needed count is zero.
  209. // Returns FALSE in status if an invalid number of bytes is being read
  210. //
  211. /****************************************************************************/
  212. #define XTRecvToHdrBuf(bytesNeededZero,status) { \
  213. unsigned bytesRecv; \
  214. \
  215. /* Check that we're being asked to receive some data and that the */ \
  216. /* header buffer has space for it. */ \
  217. /* We also chech the unsigned overflow here. If we add to a trusted */ \
  218. /* size (_XT.hdrBytesRead) anything the result should not be smaller */ \
  219. /* then the trusted size. */ \
  220. TRC_ASSERT((0 != _XT.hdrBytesNeeded), (TB, _T("No data to receive"))); \
  221. TRC_ASSERT((_XT.hdrBytesRead + _XT.hdrBytesNeeded <= sizeof(_XT.pHdrBuf)), \
  222. (TB, _T("Header buffer size %u too small for %u read + %u needed"), \
  223. sizeof(_XT.pHdrBuf), \
  224. _XT.hdrBytesRead, \
  225. _XT.hdrBytesNeeded)); \
  226. TRC_ASSERT((_XT.hdrBytesRead + _XT.hdrBytesNeeded >= _XT.hdrBytesRead), \
  227. (TB, _T("Header size overflow caused by %u read + %u needed"), \
  228. sizeof(_XT.pHdrBuf), \
  229. _XT.hdrBytesRead, \
  230. _XT.hdrBytesNeeded)); \
  231. if ((_XT.hdrBytesRead + _XT.hdrBytesNeeded <= sizeof(_XT.pHdrBuf))) \
  232. { \
  233. bytesRecv = _pTd->TD_Recv(_XT.pHdrBuf + _XT.hdrBytesRead, _XT.hdrBytesNeeded); \
  234. _XT.hdrBytesNeeded -= bytesRecv; \
  235. _XT.hdrBytesRead += bytesRecv; \
  236. bytesNeededZero = (0 == _XT.hdrBytesNeeded); \
  237. status = TRUE; \
  238. } \
  239. else \
  240. { \
  241. status = FALSE; \
  242. } \
  243. \
  244. }
  245. /****************************************************************************/
  246. /* Name: XT_OnTDDataAvailable */
  247. /* */
  248. /* Purpose: This callback function is called by TD when it has received */
  249. /* data from the server. */
  250. /****************************************************************************/
  251. DCVOID DCCALLBACK CXT::XT_OnTDDataAvailable(DCVOID)
  252. {
  253. PXT_CMNHDR pCmnHdr = (PXT_CMNHDR)_XT.pHdrBuf;
  254. unsigned pktType;
  255. unsigned unreadPktBytes;
  256. DCBOOL fAllBytesRecvd = FALSE;
  257. DCBOOL rcvOk = TRUE;
  258. DC_BEGIN_FN("XT_OnTDDataAvailable");
  259. // Check for recursion.
  260. if (!_XT.inXTOnTDDataAvail) {
  261. _XT.inXTOnTDDataAvail = TRUE;
  262. // Loop round while there is data available in TD.
  263. while (_pTd->TD_QueryDataAvailable()) {
  264. TRC_DBG((TB, _T("Data available from TD, state:%u"), _XT.rcvState));
  265. switch (_XT.rcvState) {
  266. case XT_RCVST_HEADER:
  267. XTRecvToHdrBuf(fAllBytesRecvd, rcvOk);
  268. if (fAllBytesRecvd && rcvOk) {
  269. // We've read the first two bytes, and can now decide
  270. // what type of packet this is.
  271. if ((_XT.pHdrBuf[0] & TS_OUTPUT_FASTPATH_ACTION_MASK) ==
  272. TS_OUTPUT_FASTPATH_ACTION_FASTPATH) {
  273. // This is a fast-path output header. The length
  274. // is in the second and, maybe, third byte.
  275. if (!(_XT.pHdrBuf[1] & 0x80)) {
  276. // Length was in first byte only. Proceed to
  277. // the data state.
  278. _XT.hdrBytesNeeded =
  279. XT_FASTPATH_OUTPUT_BASE_HEADER_SIZE;
  280. _XT.hdrBytesRead = 0;
  281. _XT.rcvState =
  282. XT_RCVST_FASTPATH_OUTPUT_BEGIN_DATA;
  283. // Before updating the count of data bytes
  284. // left, assert that it is currently zero.
  285. TRC_ASSERT((0 == _XT.dataBytesLeft),
  286. (TB, _T("Data bytes left non-zero:%u"),
  287. _XT.dataBytesLeft));
  288. _XT.dataBytesLeft = _XT.pHdrBuf[1] - 2;
  289. if (_XT.dataBytesLeft >= 2) {
  290. TRC_DBG((TB,_T("Fast-path output pkt, ")
  291. _T("size=%u"), _XT.dataBytesLeft));
  292. MCS_SetDataLengthToReceive(_pMcs,
  293. _XT.dataBytesLeft);
  294. /************************************************************/
  295. /* There is a retail check for size in MCS_RecvToDataBuf, */
  296. /* but this helps us debug it before that point. */
  297. /************************************************************/
  298. TRC_ASSERT((_pMcs->_MCS.dataBytesNeeded < 65535),
  299. (TB,_T("Data recv size %u too large"), _pMcs->_MCS.dataBytesNeeded));
  300. }
  301. else {
  302. TRC_ABORT((TB, _T("Fast-path size byte %02X")
  303. _T("contains len < 2"),
  304. _XT.pHdrBuf[1]));
  305. TRC_ASSERT((0 == _XT.disconnectErrorCode),
  306. (TB, _T("Disconnect error code ")
  307. _T("already set!")));
  308. _XT.disconnectErrorCode =
  309. NL_MAKE_DISCONNECT_ERR(
  310. NL_ERR_XTBADHEADER);
  311. _pTd->TD_Disconnect();
  312. goto PostDataRead;
  313. }
  314. }
  315. else {
  316. _XT.hdrBytesNeeded = 1;
  317. _XT.rcvState = XT_RCVST_FASTPATH_OUTPUT_HEADER;
  318. }
  319. }
  320. else {
  321. // The first byte is standard X.224. Reset the
  322. // state to read a full X.224 header.
  323. _XT.hdrBytesNeeded = sizeof(XT_DT) -
  324. XT_FASTPATH_OUTPUT_BASE_HEADER_SIZE;
  325. _XT.rcvState = XT_RCVST_X224_HEADER;
  326. }
  327. }
  328. else if (!rcvOk)
  329. {
  330. TRC_ERR((TB,_T("Recv to hdrbuf failed bailing out")));
  331. _XT.disconnectErrorCode =
  332. NL_MAKE_DISCONNECT_ERR(
  333. NL_ERR_XTBADHEADER);
  334. _pTd->TD_Disconnect();
  335. goto PostDataRead;
  336. }
  337. break;
  338. case XT_RCVST_FASTPATH_OUTPUT_HEADER:
  339. XTRecvToHdrBuf(fAllBytesRecvd, rcvOk);
  340. if (fAllBytesRecvd && rcvOk) {
  341. // This is a long fast-path output header (3 bytes).
  342. // Get the size from the second and third bytes and
  343. // change to data state.
  344. _XT.hdrBytesNeeded =
  345. XT_FASTPATH_OUTPUT_BASE_HEADER_SIZE;
  346. _XT.hdrBytesRead = 0;
  347. _XT.rcvState = XT_RCVST_FASTPATH_OUTPUT_BEGIN_DATA;
  348. // Before updating the count of data bytes left,
  349. // assert that it is currently zero.
  350. TRC_ASSERT((0 == _XT.dataBytesLeft),
  351. (TB, _T("Data bytes left non-zero:%u"),
  352. _XT.dataBytesLeft));
  353. _XT.dataBytesLeft = (((_XT.pHdrBuf[1] & 0x7F) << 8) |
  354. _XT.pHdrBuf[2]) - 3;
  355. if (_XT.dataBytesLeft >= 3) {
  356. TRC_DBG((TB,_T("Fast-path output pkt, size=%u"),
  357. _XT.dataBytesLeft));
  358. MCS_SetDataLengthToReceive(_pMcs, _XT.dataBytesLeft);
  359. /************************************************************/
  360. /* There is a retail check for size in MCS_RecvToDataBuf, */
  361. /* but this helps us debug it before that point. */
  362. /************************************************************/
  363. TRC_ASSERT((_pMcs->_MCS.dataBytesNeeded < 65535),
  364. (TB,_T("Data recv size %u too large"), _pMcs->_MCS.dataBytesNeeded));
  365. }
  366. else {
  367. TRC_ABORT((TB, _T("Fast-path size bytes %02X %02X")
  368. _T("contain len < 3"),
  369. _XT.pHdrBuf[1], _XT.pHdrBuf[2]));
  370. TRC_ASSERT((0 == _XT.disconnectErrorCode),
  371. (TB, _T("Disconnect error code ")
  372. _T("already set!")));
  373. _XT.disconnectErrorCode =
  374. NL_MAKE_DISCONNECT_ERR(
  375. NL_ERR_XTBADHEADER);
  376. _pTd->TD_Disconnect();
  377. goto PostDataRead;
  378. }
  379. }
  380. else if (!rcvOk)
  381. {
  382. TRC_ERR((TB,_T("Recv to hdrbuf failed bailing out")));
  383. _XT.disconnectErrorCode =
  384. NL_MAKE_DISCONNECT_ERR(
  385. NL_ERR_XTBADHEADER);
  386. _pTd->TD_Disconnect();
  387. goto PostDataRead;
  388. }
  389. break;
  390. case XT_RCVST_FASTPATH_OUTPUT_BEGIN_DATA: {
  391. BYTE FAR *_pTdData;
  392. // If we can, use the fully-recv()'d data straight from
  393. // the TD buffer, since fast-path does not need to
  394. // copy to an aligned buffer. Since we're at state
  395. // BEGIN_DATA we know we've not yet read any post-header
  396. // output data. The most common implementation of recv()
  397. // copies into the target buffer the entire data for one
  398. // TCP sequence (i.e. one server OUTBUF) if the target
  399. // buffer is large enough. Which means that most often
  400. // we'll be able to use the data directly, since the TD
  401. // receive buffer size is tuned to accept an entire large
  402. // (~8K) server OUTBUF. If we can't get the full data,
  403. // copy into the MCS buffer and move to CONTINUE_DATA.
  404. TD_GetDataForLength(_pMcs->_MCS.dataBytesNeeded, &_pTdData, _pTd);
  405. if (_pTdData != NULL) {
  406. HRESULT hrTemp;
  407. // We've gotten all the data. Now we can fast-path
  408. // call past all the layering to SL for decryption.
  409. hrTemp = _pSl->SL_OnFastPathOutputReceived(_pTdData,
  410. _pMcs->_MCS.dataBytesNeeded,
  411. _XT.pHdrBuf[0] & TS_OUTPUT_FASTPATH_ENCRYPTED,
  412. _XT.pHdrBuf[0] & TS_OUTPUT_FASTPATH_SECURE_CHECKSUM);
  413. // Reset for the next header.
  414. _pMcs->_MCS.dataBytesRead = 0;
  415. _XT.dataBytesLeft = 0;
  416. _XT.rcvState = XT_RCVST_HEADER;
  417. if (!SUCCEEDED(hrTemp))
  418. {
  419. XT_IgnoreRestofPacket();
  420. goto PostDataRead;
  421. }
  422. }
  423. else {
  424. HRESULT hrTemp;
  425. // Copy for reassembly directly into the MCS data buffer.
  426. MCS_RecvToDataBuf(hrTemp, this, _pMcs);
  427. if (!SUCCEEDED(hrTemp))
  428. {
  429. TRC_ABORT((TB,_T("Recv to databuf failed bailing out")));
  430. _XT.disconnectErrorCode =
  431. NL_MAKE_DISCONNECT_ERR(
  432. NL_ERR_XTBADHEADER);
  433. _pTd->TD_Disconnect();
  434. goto PostDataRead;
  435. }
  436. fAllBytesRecvd = (S_OK == hrTemp);
  437. if (fAllBytesRecvd) {
  438. // We've gotten all the data. Now we can fast-path
  439. // call past all the layering to SL for decryption.
  440. hrTemp = _pSl->SL_OnFastPathOutputReceived(_pMcs->_MCS.pReceivedPacket,
  441. _pMcs->_MCS.dataBytesRead,
  442. _XT.pHdrBuf[0] & TS_OUTPUT_FASTPATH_ENCRYPTED,
  443. _XT.pHdrBuf[0] & TS_OUTPUT_FASTPATH_SECURE_CHECKSUM);
  444. // Reset for the next header.
  445. _pMcs->_MCS.dataBytesRead = 0;
  446. _XT.dataBytesLeft = 0;
  447. _XT.rcvState = XT_RCVST_HEADER;
  448. if (!SUCCEEDED(hrTemp))
  449. {
  450. goto PostDataRead;
  451. }
  452. }
  453. else {
  454. _XT.rcvState = XT_RCVST_FASTPATH_OUTPUT_CONTINUE_DATA;
  455. }
  456. }
  457. break;
  458. }
  459. case XT_RCVST_FASTPATH_OUTPUT_CONTINUE_DATA:
  460. {
  461. HRESULT hrTemp;
  462. // Copy for reassembly directly into the MCS data buffer.
  463. MCS_RecvToDataBuf(hrTemp, this, _pMcs);
  464. if (!SUCCEEDED(hrTemp))
  465. {
  466. TRC_ABORT((TB,_T("Recv to databuf failed bailing out")));
  467. _XT.disconnectErrorCode =
  468. NL_MAKE_DISCONNECT_ERR(
  469. NL_ERR_XTBADHEADER);
  470. _pTd->TD_Disconnect();
  471. goto PostDataRead;
  472. }
  473. fAllBytesRecvd = (S_OK == hrTemp);
  474. if (fAllBytesRecvd) {
  475. // We've gotten all the data. Now we can fast-path
  476. // call past all the layering to SL for decryption.
  477. hrTemp = _pSl->SL_OnFastPathOutputReceived(_pMcs->_MCS.pReceivedPacket,
  478. _pMcs->_MCS.dataBytesRead,
  479. _XT.pHdrBuf[0] & TS_OUTPUT_FASTPATH_ENCRYPTED,
  480. _XT.pHdrBuf[0] & TS_OUTPUT_FASTPATH_SECURE_CHECKSUM);
  481. // Reset for the next header.
  482. _pMcs->_MCS.dataBytesRead = 0;
  483. _XT.dataBytesLeft = 0;
  484. _XT.rcvState = XT_RCVST_HEADER;
  485. if (!SUCCEEDED(hrTemp))
  486. {
  487. goto PostDataRead;
  488. }
  489. }
  490. else {
  491. _XT.rcvState = XT_RCVST_FASTPATH_OUTPUT_CONTINUE_DATA;
  492. }
  493. break;
  494. }
  495. case XT_RCVST_X224_HEADER:
  496. XTRecvToHdrBuf(fAllBytesRecvd, rcvOk);
  497. if (fAllBytesRecvd && rcvOk) {
  498. // We've read a complete X.224 common header, so we
  499. // can now attempt to interpret it. First of all check
  500. // that the TPKT version is correct.
  501. if (pCmnHdr->vrsn != XT_TPKT_VERSION)
  502. {
  503. TRC_ABORT((TB, _T("Unknown TPKT version:%u"),
  504. (DCUINT)pCmnHdr->vrsn));
  505. TRC_ASSERT((0 == _XT.disconnectErrorCode),
  506. (TB, _T("Disconnect error code already set!")));
  507. _XT.disconnectErrorCode =
  508. NL_MAKE_DISCONNECT_ERR(
  509. NL_ERR_XTBADTPKTVERSION);
  510. // Something very bad has happened so just
  511. // disconnect.
  512. _pTd->TD_Disconnect();
  513. goto PostDataRead;
  514. }
  515. // Get the packet type - this is given by the top four
  516. // bits of the crcDt field.
  517. pktType = pCmnHdr->typeCredit >> 4;
  518. // Calculate the number of unread bytes in the packet.
  519. unreadPktBytes = ((pCmnHdr->lengthHighPart << 8) | pCmnHdr->lengthLowPart) -
  520. _XT.hdrBytesRead;
  521. TRC_DBG((TB, _T("Pkt type:%u read:%u unread:%u"),
  522. pktType,
  523. _XT.hdrBytesRead,
  524. unreadPktBytes));
  525. if (XT_PKT_DT == pktType) {
  526. // This is a data packet - we don't need to
  527. // receive any more header bytes. Update our
  528. // state variables.
  529. _XT.hdrBytesNeeded =
  530. XT_FASTPATH_OUTPUT_BASE_HEADER_SIZE;
  531. _XT.hdrBytesRead = 0;
  532. _XT.rcvState = XT_RCVST_X224_DATA;
  533. // Before updating the count of data bytes left,
  534. // assert that it is currently zero.
  535. TRC_ASSERT((0 == _XT.dataBytesLeft),
  536. (TB, _T("Data bytes left non-zero:%u"),
  537. _XT.dataBytesLeft));
  538. _XT.dataBytesLeft = unreadPktBytes;
  539. //
  540. // Here we don't have to check the unreadPktBytes
  541. // because this can't cause an overflow. The size
  542. // of the data in an XT packet can be as much as
  543. // XT_MAX_DATA_SIZE and it should be checked by
  544. // the protocols above.
  545. //
  546. TRC_ASSERT((XT_MAX_DATA_SIZE >= _XT.dataBytesLeft),
  547. (TB, _T("Data bytes left too big:%u"),
  548. _XT.dataBytesLeft));
  549. TRC_DBG((TB, _T("Data pkt(size:%u) state HDR->DATA"),
  550. _XT.dataBytesLeft));
  551. }
  552. else {
  553. // This is a control packet - we need to receive
  554. // some more bytes.
  555. // Here we have a real issue if we have an overflow.
  556. // We have to check that what we still have to read
  557. // is not going to overflow the buffer. We check
  558. // the overflow against the hdrBytesRead because
  559. // this is a trusted value.
  560. if ((_XT.hdrBytesRead + unreadPktBytes >
  561. sizeof(_XT.pHdrBuf)) ||
  562. (_XT.hdrBytesRead + unreadPktBytes <
  563. _XT.hdrBytesRead)) {
  564. TRC_ERR((TB,_T("The header length is too big.")));
  565. _XT.disconnectErrorCode =
  566. NL_MAKE_DISCONNECT_ERR(
  567. NL_ERR_XTBADHEADER);
  568. // TD_Disconnect doesn't have anything to
  569. // do with the XT state so we have to reset
  570. // the XT state in order to have a successful
  571. // disconnect
  572. _pTd->TD_Disconnect();
  573. XT_IgnoreRestofPacket();
  574. goto PostDataRead;
  575. }
  576. _XT.hdrBytesNeeded = unreadPktBytes;
  577. _XT.rcvState = XT_RCVST_X224_CONTROL;
  578. TRC_NRM((TB, _T("Ctrl pkt state HEADER->CONTROL")));
  579. }
  580. }
  581. else if (!rcvOk)
  582. {
  583. TRC_ERR((TB,_T("Recv to hdrbuf failed bailing out")));
  584. _XT.disconnectErrorCode =
  585. NL_MAKE_DISCONNECT_ERR(
  586. NL_ERR_XTBADHEADER);
  587. _pTd->TD_Disconnect();
  588. goto PostDataRead;
  589. }
  590. break;
  591. case XT_RCVST_X224_CONTROL:
  592. XTRecvToHdrBuf(fAllBytesRecvd, rcvOk);
  593. if (fAllBytesRecvd && rcvOk) {
  594. // We've now managed to get a whole packet, so try to
  595. // interpret it.
  596. XTHandleControlPkt();
  597. // Update our states.
  598. _XT.rcvState = XT_RCVST_HEADER;
  599. _XT.hdrBytesNeeded =
  600. XT_FASTPATH_OUTPUT_BASE_HEADER_SIZE;
  601. _XT.hdrBytesRead = 0;
  602. TRC_NRM((TB, _T("Processed ctrl pkt state CONTROL->HEADER")));
  603. }
  604. else if (!rcvOk)
  605. {
  606. TRC_ERR((TB,_T("Recv to hdrbuf failed bailing out")));
  607. _XT.disconnectErrorCode =
  608. NL_MAKE_DISCONNECT_ERR(
  609. NL_ERR_XTBADHEADER);
  610. _pTd->TD_Disconnect();
  611. goto PostDataRead;
  612. }
  613. break;
  614. case XT_RCVST_X224_DATA:
  615. // We now have some data available, so set our flag and
  616. // callback to MCS.
  617. _XT.dataInXT = TRUE;
  618. if (_pMcs->MCS_OnXTDataAvailable()) {
  619. // MCS has finished with this frame. This frame
  620. // should not have any remaining data in it!
  621. TRC_ASSERT((_XT.dataBytesLeft == 0),
  622. (TB, _T("Unexpected extra %u bytes in the frame"),
  623. _XT.dataBytesLeft));
  624. if (_XT.dataBytesLeft != 0)
  625. {
  626. _XT.disconnectErrorCode =
  627. NL_MAKE_DISCONNECT_ERR(
  628. NL_ERR_XTUNEXPECTEDDATA);
  629. _pTd->TD_Disconnect();
  630. goto PostDataRead;
  631. }
  632. // No data remaining so zip back to the expecting
  633. // header state.
  634. _XT.rcvState = XT_RCVST_HEADER;
  635. TRC_DBG((TB, _T("Munched data pkt state DATA->HEADER")));
  636. }
  637. break;
  638. default:
  639. TRC_ABORT((TB, _T("Unrecognized XT recv state:%u"),
  640. _XT.rcvState));
  641. goto PostDataRead;
  642. }
  643. }
  644. PostDataRead:
  645. _XT.inXTOnTDDataAvail = FALSE;
  646. if ( _XT.disconnectErrorCode == 0 ) {
  647. _pClx->CLX_ClxPktDrawn();
  648. }
  649. }
  650. else {
  651. TRC_ALT((TB, _T("Recursion!")));
  652. // Note we need to make sure not to reset _XT.inXTOnTDDataAvail.
  653. }
  654. DC_END_FN();
  655. } /* XT_OnTDDataAvailable */
  656. /****************************************************************************/
  657. /* Name: XTSendCR */
  658. /* */
  659. /* Purpose: Sends an X224 CR TPDU on the sender thread. */
  660. /* */
  661. /* Operation: This function gets a private buffer from TD, fills it with */
  662. /* an X224 CR and then sends it. */
  663. /****************************************************************************/
  664. DCVOID DCINTERNAL CXT::XTSendCR(ULONG_PTR unused)
  665. {
  666. PDCUINT8 pBuffer;
  667. TD_BUFHND bufHandle;
  668. DCBOOL intRC;
  669. XT_CR xtCR = XT_CR_DATA;
  670. PBYTE pLBInfo;
  671. BYTE HashModeCookie[HASHMODE_COOKIE_LENGTH];
  672. BYTE TruncatedUserName[USERNAME_TRUNCATED_LENGTH + 1];
  673. BOOL HashMode = FALSE;
  674. DCUINT8 LBInfoLen;
  675. HRESULT hr;
  676. DC_BEGIN_FN("XTSendCR");
  677. DC_IGNORE_PARAMETER(unused);
  678. // First set up the load balance information. The algorithm is as follows:
  679. // 1. If in the middle of a redirection and there is a redirection cookie,
  680. // use the redirection cookie.
  681. // 2. If in the middle of a redirection and there is no redirection cookie,
  682. // use no cookie at all.
  683. // Otherwise, non-redirection rules apply:
  684. // 3. If no scripted cookie is available, use the default built-in hash mode
  685. // cookie. ("Cookie: mstshash=<truncated username>" + CR + LF)
  686. // Only do this if there is something in the username field.
  687. // 4. If a scripted cookie is available, use it.
  688. if (_pUi->UI_IsClientRedirected()) {
  689. // Handles cases 1 and 2, above.
  690. pLBInfo = (PBYTE)_pUi->UI_GetRedirectedLBInfo();
  691. }
  692. else {
  693. pLBInfo = (PBYTE)_pUi->UI_GetLBInfo();
  694. // If pLBInfo is NULL then case 3. Otherwise, fall through--it's
  695. // case 4.
  696. if (pLBInfo == NULL && _pUi->_UI.UserName[0] != NULL) {
  697. // Take the 1st 10 ASCII bytes of the username.
  698. // NOT an error for this to fail as we intentionally truncate
  699. hr = StringCchPrintfA(
  700. (char *) TruncatedUserName,
  701. USERNAME_TRUNCATED_LENGTH,
  702. "%S", _pUi->_UI.UserName);
  703. TruncatedUserName[USERNAME_TRUNCATED_LENGTH] = '\0';
  704. // Create the cookie
  705. hr = StringCchPrintfA(
  706. (char *) HashModeCookie,
  707. HASHMODE_COOKIE_LENGTH - 1,
  708. "Cookie: mstshash=%s\r\n",
  709. TruncatedUserName);
  710. if (FAILED(hr)) {
  711. TRC_ERR((TB,_T("Printf hasmodecookie failed: 0x%x"),hr));
  712. }
  713. HashModeCookie[HASHMODE_COOKIE_LENGTH - 1] = NULL;
  714. pLBInfo = HashModeCookie;
  715. // Set hash mode to true to indicate pLBInfo is not a BSTR.
  716. HashMode = TRUE;
  717. }
  718. }
  719. if (pLBInfo) {
  720. DCUINT16 xtLen;
  721. // If HashMode is FALSE then pLBInfo is a BSTR. Otherwise it points to
  722. // bytes.
  723. if (HashMode == FALSE)
  724. LBInfoLen = (DCUINT8) SysStringByteLen((BSTR)pLBInfo);
  725. else
  726. LBInfoLen = strlen((char *) pLBInfo);
  727. xtLen = (xtCR.hdr.lengthHighPart << 8) + xtCR.hdr.lengthLowPart;
  728. xtLen += LBInfoLen;
  729. xtCR.hdr.lengthHighPart = xtLen >> 8;
  730. xtCR.hdr.lengthLowPart = xtLen & 0xFF;
  731. }
  732. else {
  733. LBInfoLen = 0;
  734. }
  735. xtCR.hdr.li += (DCUINT8)LBInfoLen;
  736. /************************************************************************/
  737. /* TD is now connected. */
  738. /************************************************************************/
  739. TRC_NRM((TB, _T("Send XT CR...")));
  740. /************************************************************************/
  741. /* Get a private buffer in which to send the TD connection request. */
  742. /************************************************************************/
  743. intRC = _pTd->TD_GetPrivateBuffer(sizeof(xtCR) + LBInfoLen,
  744. &pBuffer, &bufHandle);
  745. if (intRC) {
  746. // Fill in the buffer with the CR.
  747. DC_MEMCPY(pBuffer, &xtCR, sizeof(xtCR));
  748. if (pLBInfo) {
  749. DC_MEMCPY(pBuffer + sizeof(xtCR), pLBInfo, LBInfoLen);
  750. }
  751. TRC_DATA_NRM("CR data:", &xtCR, sizeof(xtCR));
  752. // Send the XT CR.
  753. _pTd->TD_SendBuffer(pBuffer, sizeof(xtCR) + LBInfoLen, bufHandle);
  754. TRC_NRM((TB, _T("Sent XT CR")));
  755. }
  756. else {
  757. TRC_NRM((TB, _T("Failed to get a private buffer - just quit")));
  758. }
  759. DC_END_FN();
  760. } /* XTSendCR */
  761. /****************************************************************************/
  762. /* Name: XTHandleControlPkt */
  763. /* */
  764. /* Purpose: This function is called after XT has received a control */
  765. /* packet. It is responsible for interpreting the control */
  766. /* packet and calling the appropriate functions. */
  767. /****************************************************************************/
  768. DCVOID DCINTERNAL CXT::XTHandleControlPkt(DCVOID)
  769. {
  770. PXT_CMNHDR pCmnHdr = (PXT_CMNHDR) _XT.pHdrBuf;
  771. DCUINT pktType;
  772. DC_BEGIN_FN("XTHandleControlPkt");
  773. /************************************************************************/
  774. /* Get the packet type - this is given by the top four bits of the */
  775. /* crcDt field. */
  776. /************************************************************************/
  777. pktType = pCmnHdr->typeCredit >> 4;
  778. TRC_NRM((TB, _T("Pkt type:%u"), pktType));
  779. /************************************************************************/
  780. /* Now check for the packet type. */
  781. /************************************************************************/
  782. switch (pktType)
  783. {
  784. case XT_PKT_CR:
  785. {
  786. /****************************************************************/
  787. /* We don't expect to receive one of these, so trace an alert. */
  788. /****************************************************************/
  789. TRC_ERR((TB, _T("Received unexpected XT CR pkt")));
  790. /****************************************************************/
  791. /* We could handle this case by sending a X224 ER or DR packet, */
  792. /* but instead we'll do the absolute minimum and just ignore */
  793. /* this packet (the other side should time-out its connection */
  794. /* request). */
  795. /****************************************************************/
  796. }
  797. break;
  798. case XT_PKT_CC:
  799. {
  800. TRC_NRM((TB, _T("XT CC received")));
  801. /****************************************************************/
  802. /* This is a connection confirm. We're not interested in the */
  803. /* contents of this packet - all we need to do is to tell MCS */
  804. /* that we're now connected. */
  805. /****************************************************************/
  806. _pMcs->MCS_OnXTConnected();
  807. }
  808. break;
  809. case XT_PKT_DR:
  810. case XT_PKT_ER:
  811. {
  812. TRC_NRM((TB, _T("XT DR/ER received")));
  813. /****************************************************************/
  814. /* This is a disconnect request or an error - we've either */
  815. /* failed to establish the connection or the other party is */
  816. /* wanting to disconnect from the existing connection. Note */
  817. /* that we don't need to respond to the DR TPDU (Class 0 X224 */
  818. /* doesn't provide any way to do so). Call _pTd->TD_Disconnect to */
  819. /* disconnect the layer below us. TD will call us (XT) back */
  820. /* when it has disconnected - at that point we'll tell the */
  821. /* layers above that we've disconnected. */
  822. /****************************************************************/
  823. _pTd->TD_Disconnect();
  824. }
  825. break;
  826. default:
  827. {
  828. /****************************************************************/
  829. /* Something very bad has happened so we'd better try to */
  830. /* disconnect. */
  831. /****************************************************************/
  832. TRC_ABORT((TB, _T("Unrecognized XT header - %u"), pktType));
  833. /****************************************************************/
  834. /* Set the disconnect error code. This will be used to */
  835. /* over-ride/ the reason code in the OnDisconnected callback. */
  836. /****************************************************************/
  837. TRC_ASSERT((0 == _XT.disconnectErrorCode),
  838. (TB, _T("Disconnect error code has already been set!")));
  839. _XT.disconnectErrorCode =
  840. NL_MAKE_DISCONNECT_ERR(NL_ERR_XTBADHEADER);
  841. /****************************************************************/
  842. /* Begin the disconnection. */
  843. /****************************************************************/
  844. _pTd->TD_Disconnect();
  845. }
  846. break;
  847. }
  848. DC_END_FN();
  849. } /* XTHandleControlPkt */