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.

625 lines
29 KiB

  1. /**MOD+**********************************************************************/
  2. /* Module: nccb.cpp */
  3. /* */
  4. /* Purpose: NC callbacks from MCS */
  5. /* */
  6. /* Copyright(C) Microsoft Corporation 1997 */
  7. /* */
  8. /****************************************************************************/
  9. #include <adcg.h>
  10. extern "C" {
  11. #define TRC_GROUP TRC_GROUP_NETWORK
  12. #define TRC_FILE "anccb"
  13. #include <atrcapi.h>
  14. }
  15. #include "autil.h"
  16. #include "wui.h"
  17. #include "nc.h"
  18. #include "mcs.h"
  19. #include "nl.h"
  20. #include "cchan.h"
  21. /**PROC+*********************************************************************/
  22. /* Name: NC_OnMCSConnected */
  23. /* */
  24. /* Purpose: Connected callback from MCS */
  25. /* */
  26. /* Returns: None */
  27. /* */
  28. /* Params: IN result - result code */
  29. /* IN pUserData - user data */
  30. /* IN userDataLen - user data length */
  31. /* */
  32. /* Operation: Validate the GCC PDU and userdata supplied in the MCS */
  33. /* userdata. If invalid, then disconnect. */
  34. /* The GCC PDU is encoded as follows: */
  35. /* */
  36. /* number of bytes value */
  37. /* =============== ===== */
  38. /* NC_MCS_HDRLEN MCS header */
  39. /* 1 or 2 Total GCC PDU length */
  40. /* NC_GCC_RSPLEN GCC CreateConferenceConfirm PDU body */
  41. /* 4 H221 key */
  42. /* 1 or 2 length of GCC user data */
  43. /* ? GCC user data */
  44. /* */
  45. /* */
  46. /**PROC-*********************************************************************/
  47. DCVOID DCCALLBACK CNC::NC_OnMCSConnected(DCUINT result,
  48. PDCUINT8 pUserData,
  49. DCUINT userDataLen)
  50. {
  51. PRNS_UD_HEADER pHdr;
  52. PDCUINT8 ptr;
  53. DCUINT16 udLen;
  54. PDCUINT16 pMCSChannel;
  55. DC_BEGIN_FN("NC_OnMCSConnected");
  56. if (result != MCS_RESULT_SUCCESSFUL)
  57. {
  58. /********************************************************************/
  59. /* Something's wrong. Trace and set the disconnect error code. */
  60. /********************************************************************/
  61. TRC_ERR((TB, _T("ConnectResponse error %u"), result));
  62. TRC_ASSERT((0 == _NC.disconnectReason),
  63. (TB, _T("Disconnect reason has already been set!")));
  64. _NC.disconnectReason = NL_MAKE_DISCONNECT_ERR(NL_ERR_NCBADMCSRESULT);
  65. /********************************************************************/
  66. /* Begin the disconnection process. */
  67. /********************************************************************/
  68. _pMcs->MCS_Disconnect();
  69. DC_QUIT;
  70. }
  71. TRC_NRM((TB, _T("Connected OK")));
  72. TRC_DATA_DBG("UserData", pUserData, userDataLen);
  73. /************************************************************************/
  74. /* First, skip the MCS header bytes */
  75. /************************************************************************/
  76. ptr = pUserData + NC_MCS_HDRLEN;
  77. /************************************************************************/
  78. /* SECURITY: The GCC PDU length read below is a length encoded within */
  79. /* a PDU (Usually, this is bad). However, in this case, the client */
  80. /* ignores this value (note the length is skipped over below). */
  81. /* ALSO, the server has this size HARDCODED as 0x2a. See */
  82. /* tgccdata.c!gccEncodeUserData which uses hardcoded values to fill in */
  83. /* parts of the GCC table. Thus, it's not a security bug. */
  84. /************************************************************************/
  85. /************************************************************************/
  86. /* Allow for length > 128. In PER this is encoded as 10xxxxxx xxxxxxxx */
  87. /************************************************************************/
  88. TRC_DBG((TB, _T("GCC PDU length byte %#x"), *ptr));
  89. if (*ptr++ & 0x80)
  90. {
  91. ptr++;
  92. TRC_DBG((TB, _T("GCC PDU length byte 2 %#x"), *ptr));
  93. }
  94. /************************************************************************/
  95. /* The GCC PDU bytes don't contain any useful information, so just skip */
  96. /* over them. */
  97. /************************************************************************/
  98. ptr += NC_GCC_RSPLEN;
  99. if (ptr >= pUserData + userDataLen)
  100. {
  101. TRC_ERR((TB, _T("No UserData")));
  102. TRC_ASSERT((0 == _NC.disconnectReason),
  103. (TB, _T("Disconnect reason has already been set!")));
  104. _NC.disconnectReason = NL_MAKE_DISCONNECT_ERR(NL_ERR_NCNOUSERDATA);
  105. _pMcs->MCS_Disconnect();
  106. DC_QUIT;
  107. }
  108. if (DC_MEMCMP(ptr, SERVER_H221_KEY, H221_KEY_LEN))
  109. {
  110. TRC_ERR((TB, _T("Invalid H221 key from server")));
  111. TRC_ASSERT((0 == _NC.disconnectReason),
  112. (TB, _T("Disconnect reason has already been set!")));
  113. _NC.disconnectReason = NL_MAKE_DISCONNECT_ERR(NL_ERR_NCINVALIDH221KEY);
  114. _pMcs->MCS_Disconnect();
  115. DC_QUIT;
  116. }
  117. /************************************************************************/
  118. /* Skip H221 key; read the GCC userdata length. */
  119. /************************************************************************/
  120. ptr += H221_KEY_LEN;
  121. /************************************************************************/
  122. /* Length is PER encoded: either 0xxxxxxx or 10xxxxxx xxxxxxxx. */
  123. /************************************************************************/
  124. udLen = (DCUINT16)*ptr++;
  125. if (udLen & 0x0080)
  126. {
  127. udLen = (DCUINT16)(*ptr++ | ((udLen & 0x3F) << 8));
  128. }
  129. TRC_DBG((TB, _T("Length of GCC userdata %hu"), udLen));
  130. /************************************************************************/
  131. /* Save the user data to return on the onConnected callback. */
  132. /* Note: pass _NC.userDataRNS (aligned) to UT_ParseUserData(), not ptr */
  133. /* (unaligned). */
  134. /************************************************************************/
  135. _NC.userDataLenRNS = udLen;
  136. if( _NC.pUserDataRNS )
  137. {
  138. UT_Free( _pUt, _NC.pUserDataRNS );
  139. }
  140. /************************************************************************/
  141. /* Verify that the udLen size that came out of the packet is less than */
  142. /* the packet size itself, since we're going to do a MEMCPY from the */
  143. /* packet. Also, because the size of udLen is limited to the size of */
  144. /* the packet, the Malloc below is not unbounded. */
  145. /************************************************************************/
  146. if (!IsContainedMemory(pUserData, userDataLen, ptr, udLen))
  147. {
  148. TRC_ABORT((TB, _T("Bad UserData size")));
  149. TRC_ASSERT((0 == _NC.disconnectReason),
  150. (TB, _T("Disconnect reason has already been set!")));
  151. _NC.disconnectReason = NL_MAKE_DISCONNECT_ERR(NL_ERR_NCNOCOREDATA);
  152. _pMcs->MCS_Disconnect();
  153. DC_QUIT;
  154. }
  155. _NC.pUserDataRNS = (PDCUINT8)UT_Malloc( _pUt, udLen );
  156. if( NULL == _NC.pUserDataRNS )
  157. {
  158. TRC_ERR( ( TB, _T("Failed to allocate %u bytes for core user data"), udLen ) );
  159. DC_QUIT;
  160. }
  161. DC_MEMCPY(_NC.pUserDataRNS, ptr, udLen);
  162. /************************************************************************/
  163. /* Get the server version number from the CORE user data. */
  164. /************************************************************************/
  165. pHdr = _pUt->UT_ParseUserData((PRNS_UD_HEADER)_NC.pUserDataRNS,
  166. _NC.userDataLenRNS,
  167. RNS_UD_SC_CORE_ID);
  168. if (pHdr == NULL)
  169. {
  170. /********************************************************************/
  171. /* No core user data, disconnect. */
  172. /********************************************************************/
  173. TRC_ERR((TB, _T("No CORE user data")));
  174. TRC_ASSERT((0 == _NC.disconnectReason),
  175. (TB, _T("Disconnect reason has already been set!")));
  176. _NC.disconnectReason = NL_MAKE_DISCONNECT_ERR(NL_ERR_NCNOCOREDATA);
  177. _pMcs->MCS_Disconnect();
  178. DC_QUIT;
  179. }
  180. _NC.serverVersion = ((PRNS_UD_SC_CORE)pHdr)->version;
  181. if (_RNS_MAJOR_VERSION(_NC.serverVersion) != RNS_UD_MAJOR_VERSION)
  182. {
  183. /********************************************************************/
  184. /* The server version data doesn't match the client, so disconnect.*/
  185. /********************************************************************/
  186. TRC_ERR((TB, _T("Version mismatch, client: %#lx server: %#lx"),
  187. RNS_UD_VERSION,
  188. ((PRNS_UD_SC_CORE)pHdr)->version));
  189. TRC_ASSERT((0 == _NC.disconnectReason),
  190. (TB, _T("Disconnect reason has already been set!")));
  191. _NC.disconnectReason = NL_MAKE_DISCONNECT_ERR(NL_ERR_NCVERSIONMISMATCH);
  192. _pMcs->MCS_Disconnect();
  193. DC_QUIT;
  194. }
  195. /************************************************************************/
  196. /* Extract the T.128 channel from the user data */
  197. /************************************************************************/
  198. pHdr = _pUt->UT_ParseUserData((PRNS_UD_HEADER)_NC.pUserDataRNS,
  199. _NC.userDataLenRNS,
  200. RNS_UD_SC_NET_ID);
  201. /************************************************************************/
  202. /* Disconnect if no NET user data. */
  203. /************************************************************************/
  204. if (pHdr == NULL)
  205. {
  206. TRC_ERR((TB, _T("No NET data: cannot join share")));
  207. TRC_ASSERT((0 == _NC.disconnectReason),
  208. (TB, _T("Disconnect reason has already been set!")));
  209. _NC.disconnectReason = NL_MAKE_DISCONNECT_ERR(NL_ERR_NCNONETDATA);
  210. _pMcs->MCS_Disconnect();
  211. DC_QUIT;
  212. }
  213. _NC.pNetData = (PRNS_UD_SC_NET)pHdr;
  214. //
  215. // Validate the share channel ID - the invalid channel ID is reserved
  216. // to prevent re-joining all channels (see #479976)
  217. //
  218. if (MCS_INVALID_CHANNEL_ID == _NC.pNetData->MCSChannelID) {
  219. TRC_ERR((TB, _T("Got invalid channel ID")));
  220. TRC_ASSERT((0 == _NC.disconnectReason),
  221. (TB, _T("Disconnect reason has already been set!")));
  222. _NC.disconnectReason = NL_MAKE_DISCONNECT_ERR(NL_ERR_NCJOINBADCHANNEL);
  223. _pMcs->MCS_Disconnect();
  224. DC_QUIT;
  225. }
  226. _NC.shareChannel = _NC.pNetData->MCSChannelID;
  227. TRC_NRM((TB, _T("Share Channel from userData %#hx"), _NC.shareChannel));
  228. /************************************************************************/
  229. /* The length of .pNetData has already been checked to make sure that */
  230. /* it fits in our source packet: */
  231. /* a) userDataLenRNS was bounds-checked above, within the packet */
  232. /* passed into this function. */
  233. /* b) pNetData->header.length was verified to be within */
  234. /* userDataLenRNS in the call to UT_ParseUserData above. */
  235. /* */
  236. /* Thus, pNetData sits within the packet passed into this function. We */
  237. /* can assert this here, but the retail check was already done. */
  238. /************************************************************************/
  239. TRC_ASSERT((IsContainedMemory(_NC.pUserDataRNS, _NC.userDataLenRNS, _NC.pNetData, _NC.pNetData->header.length)),
  240. (TB, _T("Invalid pNetData size in packet; Retail check failed to catch it.")));
  241. /************************************************************************/
  242. /* Extract virtual channel numbers */
  243. /************************************************************************/
  244. TRC_NRM((TB, _T("%d virtual channels returned"), _NC.pNetData->channelCount));
  245. if (_RNS_MINOR_VERSION(_NC.serverVersion) >= 3)
  246. {
  247. _NC.MCSChannelCount = _NC.pNetData->channelCount;
  248. if (_NC.pNetData->channelCount != 0 &&
  249. _NC.pNetData->channelCount < CHANNEL_MAX_COUNT)
  250. {
  251. pMCSChannel = (PDCUINT16)(_NC.pNetData + 1);
  252. DC_MEMCPY(&(_NC.MCSChannel),
  253. pMCSChannel,
  254. _NC.pNetData->channelCount * sizeof(DCUINT16));
  255. }
  256. else
  257. {
  258. TRC_ALT((TB,_T("Invalid or zero channel count.")));
  259. _NC.MCSChannelCount = 0;
  260. }
  261. }
  262. else
  263. {
  264. TRC_ALT((TB, _T("Server minor ver %hd doesn't support 4-byte lengths"),
  265. _RNS_MINOR_VERSION(_NC.serverVersion)));
  266. _NC.MCSChannelCount = 0;
  267. }
  268. /************************************************************************/
  269. /* Issue AttachUser to continue connection establishment. */
  270. /************************************************************************/
  271. _pMcs->MCS_AttachUser();
  272. //
  273. // Flag we're waiting for a confirm to validate that we
  274. // only receive confirms in response to our requests
  275. //
  276. _NC.fPendingAttachUserConfirm = TRUE;
  277. DC_EXIT_POINT:
  278. DC_END_FN();
  279. return;
  280. } /* NC_OnMCSConnected */
  281. /**PROC+*********************************************************************/
  282. /* Name: NC_OnMCSAttachUserConfirm */
  283. /* */
  284. /* Purpose: AttachUserConfirm callback from MCS */
  285. /* */
  286. /* Returns: None */
  287. /* */
  288. /* Params: IN result - result code */
  289. /* IN userID - MCS User ID */
  290. /* */
  291. /**PROC-*********************************************************************/
  292. DCVOID DCCALLBACK CNC::NC_OnMCSAttachUserConfirm(DCUINT result, DCUINT16 userID)
  293. {
  294. DC_BEGIN_FN("NC_OnMCSAttachUserConfirm");
  295. if (result == MCS_RESULT_SUCCESSFUL && _NC.fPendingAttachUserConfirm)
  296. {
  297. TRC_NRM((TB, _T("AttachUser OK - user %#hx"), userID));
  298. _pUi->UI_SetClientMCSID(userID);
  299. /********************************************************************/
  300. /* Join the channels */
  301. /********************************************************************/
  302. _pMcs->MCS_JoinChannel(userID, userID);
  303. }
  304. else
  305. {
  306. TRC_NRM((TB, _T("AttachUser Failed - result %u fPending: %d"),
  307. result, _NC.fPendingAttachUserConfirm));
  308. TRC_ASSERT((0 == _NC.disconnectReason),
  309. (TB, _T("Disconnect reason has already been set!")));
  310. _NC.disconnectReason =
  311. NL_MAKE_DISCONNECT_ERR(NL_ERR_NCATTACHUSERFAILED);
  312. _pMcs->MCS_Disconnect();
  313. }
  314. //
  315. // Only allow confirms in response to our requests
  316. //
  317. _NC.fPendingAttachUserConfirm = FALSE;
  318. DC_END_FN();
  319. return;
  320. } /* NC_OnMCSAttachUserConfirm */
  321. /**PROC+*********************************************************************/
  322. /* Name: NC_OnMCSChannelJoinConfirm */
  323. /* */
  324. /* Purpose: ChannelJoinConfirm callback from MCS */
  325. /* */
  326. /* Returns: None */
  327. /* */
  328. /* Params: IN result - result code */
  329. /* IN channel - MCS Channel */
  330. /* */
  331. /* Operation: Join the other channel, or notify SL of connection */
  332. /* */
  333. /**PROC-*********************************************************************/
  334. DCVOID DCCALLBACK CNC::NC_OnMCSChannelJoinConfirm(DCUINT result, DCUINT16 channel)
  335. {
  336. DCBOOL callOnConnected = FALSE;
  337. DC_BEGIN_FN("NC_OnMCSChannelJoinConfirm");
  338. /************************************************************************/
  339. /* Ensure that we joined the channel successfully. */
  340. /************************************************************************/
  341. if (result != MCS_RESULT_SUCCESSFUL)
  342. {
  343. /********************************************************************/
  344. /* We failed to join the channel so set the correct error reason */
  345. /* and then disconnect. */
  346. /********************************************************************/
  347. TRC_ALT((TB, _T("Channel join failed channel:%#hx result:%u"),
  348. channel,
  349. result));
  350. TRC_ASSERT((0 == _NC.disconnectReason),
  351. (TB, _T("Disconnect reason has already been set!")));
  352. _NC.disconnectReason =
  353. NL_MAKE_DISCONNECT_ERR(NL_ERR_NCCHANNELJOINFAILED);
  354. _pMcs->MCS_Disconnect();
  355. DC_QUIT;
  356. }
  357. TRC_NRM((TB, _T("Channel Join %#hx OK"), channel));
  358. //
  359. // Validate that we receive the confirm for the last channel
  360. // we requested.
  361. //
  362. if (_pMcs->MCS_GetPendingChannelJoin() != channel) {
  363. TRC_ERR((TB,_T("Received unexpected channel join.")
  364. _T("Expecting: 0x%x received: 0x%x"),
  365. _pMcs->MCS_GetPendingChannelJoin(), channel));
  366. _NC.disconnectReason =
  367. NL_MAKE_DISCONNECT_ERR(NL_ERR_NCJOINBADCHANNEL);
  368. _pMcs->MCS_Disconnect();
  369. DC_QUIT;
  370. }
  371. /************************************************************************/
  372. /* Now determine which channel we joined. */
  373. /************************************************************************/
  374. if (channel == _pUi->UI_GetClientMCSID())
  375. {
  376. /********************************************************************/
  377. /* We've just successfully joined the single user channel, so now */
  378. /* go on and try to join the share channel. */
  379. /********************************************************************/
  380. TRC_NRM((TB, _T("Joined user chan OK - attempt to join share chan %#hx"),
  381. _NC.shareChannel));
  382. _pMcs->MCS_JoinChannel(_NC.shareChannel, _pUi->UI_GetClientMCSID());
  383. }
  384. else if (channel == _NC.shareChannel)
  385. {
  386. /********************************************************************/
  387. /* We've just joined the Share channel */
  388. /********************************************************************/
  389. if (_NC.MCSChannelCount != 0)
  390. {
  391. /****************************************************************/
  392. /* Start joining virtual channels */
  393. /****************************************************************/
  394. TRC_NRM((TB, _T("Joined Share channel - join first VC %d"),
  395. _NC.MCSChannel[0]));
  396. _NC.MCSChannelNumber = 0;
  397. _pMcs->MCS_JoinChannel(_NC.MCSChannel[0], _pUi->UI_GetClientMCSID());
  398. }
  399. else
  400. {
  401. /****************************************************************/
  402. /* No virtual channels - tell the Core that we are connected. */
  403. /****************************************************************/
  404. TRC_NRM((TB, _T("Joined share channel, no VCs - call OnConnected")));
  405. callOnConnected = TRUE;
  406. }
  407. }
  408. else if (channel == _NC.MCSChannel[_NC.MCSChannelNumber])
  409. {
  410. /********************************************************************/
  411. /* We've just joined a virtual channel */
  412. /********************************************************************/
  413. TRC_NRM((TB, _T("Joined Virtual channel #%d (%x)"),
  414. _NC.MCSChannelNumber, _NC.MCSChannel[_NC.MCSChannelNumber]));
  415. _NC.MCSChannelNumber++;
  416. if (_NC.MCSChannelNumber == _NC.MCSChannelCount)
  417. {
  418. /****************************************************************/
  419. /* That was the last virtual channel - tell the core */
  420. /****************************************************************/
  421. TRC_NRM((TB, _T("All done - call OnConnected callbacks")));
  422. callOnConnected = TRUE;
  423. }
  424. else
  425. {
  426. /****************************************************************/
  427. /* Join the next virtual channel */
  428. /****************************************************************/
  429. TRC_NRM((TB, _T("Join virtual channel #%d (%x)"),
  430. _NC.MCSChannelNumber, _NC.MCSChannel[_NC.MCSChannelNumber]));
  431. _pMcs->MCS_JoinChannel(_NC.MCSChannel[_NC.MCSChannelNumber],
  432. _pUi->UI_GetClientMCSID());
  433. }
  434. }
  435. else
  436. {
  437. /********************************************************************/
  438. /* We didn't expect to join this channel! Something bad must have */
  439. /* happened so disconnect now. */
  440. /********************************************************************/
  441. TRC_ABORT((TB, _T("Joined unexpected channel:%#hx"), channel));
  442. TRC_ASSERT((0 == _NC.disconnectReason),
  443. (TB, _T("Disconnect reason has already been set!")));
  444. _NC.disconnectReason = NL_MAKE_DISCONNECT_ERR(NL_ERR_NCJOINBADCHANNEL);
  445. _pMcs->MCS_Disconnect();
  446. DC_QUIT;
  447. }
  448. /************************************************************************/
  449. /* Call the onConnected callbacks if required */
  450. /************************************************************************/
  451. if (callOnConnected)
  452. {
  453. TRC_NRM((TB, _T("Call onConnected callbacks")));
  454. //
  455. // We don't expect to join any more channels
  456. //
  457. _pMcs->MCS_SetPendingChannelJoin(MCS_INVALID_CHANNEL_ID);
  458. _pNl->_NL.callbacks.onConnected(_pSl, _NC.shareChannel,
  459. _NC.pUserDataRNS,
  460. _NC.userDataLenRNS,
  461. _NC.serverVersion);
  462. /************************************************************************/
  463. /* Note that the length pNetData->header.length was already verified */
  464. /* in NC_OnMCSConnected (retail check). */
  465. /************************************************************************/
  466. _pChan->ChannelOnConnected(_NC.shareChannel,
  467. _NC.serverVersion,
  468. _NC.pNetData,
  469. _NC.pNetData->header.length);
  470. }
  471. DC_EXIT_POINT:
  472. DC_END_FN();
  473. return;
  474. } /* NC_OnMCSChannelJoinConfirm */
  475. /**PROC+*********************************************************************/
  476. /* Name: NC_OnMCSDisconnected */
  477. /* */
  478. /* Purpose: Disconnected callback from MCS. */
  479. /* */
  480. /* Params: IN reason - reason code */
  481. /* */
  482. /**PROC-*********************************************************************/
  483. DCVOID DCCALLBACK CNC::NC_OnMCSDisconnected(DCUINT reason)
  484. {
  485. DC_BEGIN_FN("NC_OnMCSDisconnected");
  486. /************************************************************************/
  487. /* Decide if we want to over-ride the disconnect reason code. */
  488. /************************************************************************/
  489. if (_NC.disconnectReason != 0)
  490. {
  491. TRC_ALT((TB, _T("Over-riding disconnection reason (%u->%u)"),
  492. reason,
  493. _NC.disconnectReason));
  494. /********************************************************************/
  495. /* Over-ride the error code and set the global variable to 0. */
  496. /********************************************************************/
  497. reason = _NC.disconnectReason;
  498. _NC.disconnectReason = 0;
  499. }
  500. /************************************************************************/
  501. /* Free the core user data. */
  502. /************************************************************************/
  503. if( _NC.pUserDataRNS )
  504. {
  505. UT_Free( _pUt, _NC.pUserDataRNS );
  506. _NC.pUserDataRNS = NULL;
  507. }
  508. /************************************************************************/
  509. /* Issue the callback to the layer above to let him know that we've */
  510. /* disconnected. */
  511. /************************************************************************/
  512. TRC_DBG((TB, _T("Disconnect reason:%u"), reason));
  513. _pNl->_NL.callbacks.onDisconnected(_pSl, reason);
  514. _pChan->ChannelOnDisconnected(reason);
  515. DC_END_FN();
  516. return;
  517. } /* NC_OnMCSDisconnected */
  518. /**PROC+*********************************************************************/
  519. /* Name: NC_OnMCSBufferAvailable */
  520. /* */
  521. /* Purpose: OnBufferAvailable callback from MCS */
  522. /* */
  523. /* Returns: none */
  524. /* */
  525. /* Params: none */
  526. /* */
  527. /**PROC-*********************************************************************/
  528. DCVOID DCCALLBACK CNC::NC_OnMCSBufferAvailable(DCVOID)
  529. {
  530. DC_BEGIN_FN("NC_OnMCSBufferAvailable");
  531. /************************************************************************/
  532. /* Call the core callback first to let the core have first shot at any */
  533. /* available buffers */
  534. /************************************************************************/
  535. TRC_NRM((TB, _T("Call Core OnBufferAvailable callback")));
  536. _pNl->_NL.callbacks.onBufferAvailable(_pSl);
  537. /************************************************************************/
  538. /* Now call the virtual channel callback */
  539. /************************************************************************/
  540. TRC_NRM((TB, _T("Call VC OnBufferAvailable callback")));
  541. _pChan->ChannelOnBufferAvailable();
  542. DC_END_FN();
  543. return;
  544. } /* NC_OnMCSBufferAvailable */