/****************************************************************************** * * INTEL Corporation Proprietary Information * Copyright (c) 1994, 1995, 1996 Intel Corporation. * * This listing is supplied under the terms of a license agreement * with INTEL Corporation and may not be used, copied, nor disclosed * except in accordance with the terms of that agreement. * *****************************************************************************/ /****************************************************************************** * * $Workfile: api_up.c $ * $Revision: 1.33 $ * $Modtime: 06 Feb 1997 14:37:24 $ * $Log: S:\sturgeon\src\h245\src\vcs\api_up.c_v $ * * Rev 1.33 06 Feb 1997 18:14:22 SBELL1 * took out ossDecoding of returnFunction in FunctionNotSupported PDU. * * Rev 1.32 05 Feb 1997 16:46:42 EHOWARDX * Was allocating nLength bytes, not WCHARS, for UserInputIndication * ASCII to Unicode conversion. Changed to allocate nLength WCHARs. * * Rev 1.31 06 Jan 1997 20:38:18 EHOWARDX * * Changed H245_CONF_CLOSE and H245_CONF_REQ_CLOSE to fill in * AccRej with H245_REJ for any errors. * * Rev 1.30 19 Dec 1996 21:00:56 EHOWARDX * Oops! H245_IND_OPEN_CONF can occur from T103 timeout (it's unique among * indications; it's the only one that can happen in response to a timeout!) * * Rev 1.29 19 Dec 1996 17:18:22 EHOWARDX * Changed to use h245asn1.h definitions instead of _setof3 and _setof8. * * Rev 1.28 18 Dec 1996 16:33:18 EHOWARDX * * Fixed bug in Master Slave Determination Kludge. * * Rev 1.27 17 Dec 1996 17:13:20 EHOWARDX * Added pSeparateStack to IND_OPEN_T. * * Rev 1.26 12 Dec 1996 15:57:12 EHOWARDX * Master Slave Determination kludge. * * Rev 1.25 21 Oct 1996 16:07:38 EHOWARDX * Modified to make sure H245_INDETERMINATE is returned and Master/Slave * status if determination fails. * * Rev 1.24 17 Oct 1996 18:17:14 EHOWARDX * Changed general string to always be Unicode. * * Rev 1.23 14 Oct 1996 14:01:12 EHOWARDX * Unicode changes. * * Rev 1.22 27 Aug 1996 10:54:16 unknown * Deleted redundant lines. * * Rev 1.22 27 Aug 1996 10:52:28 unknown * Deleted redundant lines. * * Rev 1.22 27 Aug 1996 09:54:12 unknown * Deleted redundant lines. * * Rev 1.21 26 Aug 1996 14:19:18 EHOWARDX * Added code to send FunctionNotUnderstood indication to remote peer * if receive callback returns H245_ERROR_NOSUP. * * Rev 1.20 20 Aug 1996 14:44:40 EHOWARDX * Changed H245_IND_COMM_MODE_RESPONSE and H245_IND_COMM_MODE_COMMAND * callbacks to fill in DataType field in Cap as per Mike Andrews' request. * * Rev 1.19 15 Aug 1996 15:20:24 EHOWARDX * First pass at new H245_COMM_MODE_ENTRY_T requested by Mike Andrews. * Use at your own risk! * * Rev 1.18 15 Aug 1996 09:34:20 EHOWARDX * Made TOTCAP and MUX structure in process_open_ind static since we are * accessing pointers to them after return from the function. * * Rev 1.17 29 Jul 1996 19:33:00 EHOWARDX * * Fixed bug in flow control - missing break in restriction switch statement. * * Rev 1.16 19 Jul 1996 14:11:26 EHOWARDX * * Added indication callback structure for CommunicationModeResponse * and CommunicationModeCommand. * * Rev 1.15 19 Jul 1996 12:48:00 EHOWARDX * * Multipoint clean-up. * * Rev 1.14 09 Jul 1996 17:09:28 EHOWARDX * Fixed pointer offset bug in processing DataType from received * OpenLogicalChannel. * * Rev 1.13 01 Jul 1996 22:13:04 EHOWARDX * * Added Conference and CommunicationMode structures and functions. * * Rev 1.12 18 Jun 1996 14:50:28 EHOWARDX * * Changed MLSE confirm handling. * * Rev 1.11 14 Jun 1996 18:57:52 EHOWARDX * Geneva update. * * Rev 1.10 10 Jun 1996 16:55:34 EHOWARDX * Removed #include "h245init.x" * * Rev 1.9 06 Jun 1996 18:45:52 EHOWARDX * Added check for null dwTransId to Tracker routines; changed to use * tracker routines instead of PLOCK macros. * * Rev 1.8 04 Jun 1996 13:56:46 EHOWARDX * Fixed Release build warnings. * * Rev 1.7 30 May 1996 23:39:00 EHOWARDX * Cleanup. * * Rev 1.6 29 May 1996 15:20:06 EHOWARDX * Change to use HRESULT. * * Rev 1.5 28 May 1996 14:22:58 EHOWARDX * Tel Aviv update. * * Rev 1.4 20 May 1996 22:17:58 EHOWARDX * Completed NonStandard Message and H.225.0 Maximum Skew indication * implementation. Added ASN.1 validation to H245SetLocalCap and * H245SetCapDescriptor. Check-in from Microsoft drop on 17-May-96. * * Rev 1.3 16 May 1996 19:40:46 EHOWARDX * Fixed multiplex capability bug. * * Rev 1.2 16 May 1996 15:59:24 EHOWARDX * Fine-tuning H245SetLocalCap/H245DelLocalCap/H245SetCapDescriptor/ * H245DelCapDescriptor behaviour. * * Rev 1.1 13 May 1996 23:16:26 EHOWARDX * Fixed remote terminal capability handling. * * Rev 1.0 09 May 1996 21:06:08 EHOWARDX * Initial revision. * * Rev 1.23.1.11 09 May 1996 19:31:30 EHOWARDX * Redesigned thread locking logic. * Added new API functions. * * Rev 1.23.1.10 01 May 1996 19:30:32 EHOWARDX * Added H245CopyCap(), H245FreeCap(), H245CopyMux(), H245FreeMux(). * Changed H2250_xxx definitions for H.225.0 address types to H245_xxx. * * Rev 1.23.1.9 29 Apr 1996 16:02:58 EHOWARDX * Changed callback to give second parameters as pointer to specific message * instead of pointer to general PDU structure. * * Rev 1.23.1.8 27 Apr 1996 21:09:40 EHOWARDX * Changed Channel Numbers to words, added H.225.0 support. * * Rev 1.23.1.7 26 Apr 1996 15:54:34 EHOWARDX * Added H.225.0 Capability support; Changed Capability indication * to only callback once with PDU. * * Rev 1.23.1.6 24 Apr 1996 20:53:56 EHOWARDX * Added new OpenLogicalChannelAck/OpenLogicalChannelReject support. * * Rev 1.23.1.5 23 Apr 1996 14:45:28 EHOWARDX * Disabled Curt's "Conflict Resolution". * * Rev 1.23.1.4 19 Apr 1996 12:55:10 EHOWARDX * Updated to 1.29 * * Rev 1.23.1.3 17 Apr 1996 14:37:38 unknown * Added load_H222_param(), load_VGMUX_param(), and load_H2250_param() and * modified process_open_ind() to use them. * * Rev 1.23.1.2 15 Apr 1996 15:10:32 EHOWARDX * Updated to match Curt's current version. * * Rev 1.23.1.1 03 Apr 1996 17:15:00 EHOWARDX * No change. * * Rev 1.23.1.0 03 Apr 1996 15:54:04 cjutzi * Branched for H.323. * * Rev 1.23 01 Apr 1996 16:46:20 cjutzi * * - changed tracker structure * - Completed ENdConnection, and made asynch.. rather * than sync.. as before * Changed H245ShutDown to be sync rather than async.. * * Rev 1.22 29 Mar 1996 14:54:28 cjutzi * - added UserInput, * * Rev 1.21 28 Mar 1996 15:57:46 cjutzi * - removed ASSERT line 1290.. close can occur on any channel at any time * * Rev 1.20 27 Mar 1996 08:36:40 cjutzi * - removed PDU from stack.. made them dynamically allocated * * Rev 1.19 26 Mar 1996 13:48:30 cjutzi * * - dwPreserved in the callback routine was uninitialized.. * * Rev 1.18 18 Mar 1996 15:23:30 cjutzi * * * * Rev 1.17 13 Mar 1996 14:14:02 cjutzi * * - clean up and added ASSERTs .. * * Rev 1.16 13 Mar 1996 12:06:12 cjutzi * * - fixed .. CONFIRM open.. for hani.. It released the tracker.. * was supposed to simply update the state to IDLE.. * * Rev 1.15 13 Mar 1996 09:22:12 cjutzi * * - removed CRITICAL SECTIONS * * Rev 1.14 12 Mar 1996 15:52:32 cjutzi * * - fixed master slave (forgot a break) * - fixed callback bug w/ cleanup on termcaps. * - implemented End Session * - fixed shutdown * - Implemented Locking (big changes here.. ) * * Rev 1.13 08 Mar 1996 14:04:18 cjutzi * * - implemented the upcall for mux table entries.. * - implemented capabillity descriptor callback * * Rev 1.12 05 Mar 1996 17:36:28 cjutzi * * - added MasterSlave indication message * - remove bzero/bcopy and changed free call * - implemented Mux Table down.. (not up) * * Rev 1.11 01 Mar 1996 14:16:08 cjutzi * * - added hani's error messages.. MasterSlave_FAILED.. oppss.. Forgot.. * * Rev 1.10 01 Mar 1996 13:47:58 cjutzi * * - added hani's new fsm id's * * Rev 1.9 29 Feb 1996 17:26:16 cjutzi * - bi-directional channel open working * * Rev 1.8 27 Feb 1996 14:56:30 cjutzi * * - fixed termcap_ack.. pdu was not being zero'd out.. * - cleaned up the code alittle.. * * Rev 1.7 26 Feb 1996 17:22:40 cjutzi * * - Misc Command Indication added * * Rev 1.6 26 Feb 1996 11:05:48 cjutzi * * - lot's o-changes.. (sorry) * * Rev 1.5 16 Feb 1996 13:01:54 cjutzi * * - got open / close / request close working in both directions. * * Rev 1.4 15 Feb 1996 14:11:46 cjutzi * * - added muxt table to incoming open.. * * Rev 1.3 15 Feb 1996 10:51:56 cjutzi * * - termcaps working * - changed API interface for MUX_T * - changed callback for IND_OPEN * - changed constants IND_OPEN/IND_OPEN_NEEDSRSP * - cleaned up the open. * - modified H223 stuff * * Rev 1.2 09 Feb 1996 16:58:28 cjutzi * * - cleanup.. and some fixes.. * - added and or changed headers to reflect the log of changes * *****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /**** *****/ /**** NOTES TO THE READER *****/ /**** *****/ /**** This program has been put together using a a screen which is *****/ /**** wider than 80 characters.. It is best if a similar screen size is *****/ /**** used.. Of course emacs is my preference but 80 col screens will *****/ /**** cause you much frustration.. *****/ /**** *****/ /**** Tabs are set to 8 *****/ /**** *****/ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ #ifndef STRICT #define STRICT #endif #include "precomp.h" /***********************/ /* H245 INCLUDES */ /***********************/ #include "h245api.h" #include "h245com.h" #include "h245sys.x" #include "h245asn1.h" #include "fsmexpor.h" #include "api_util.x" #include "pdu.x" HRESULT LoadUnicastAddress (H245_TRANSPORT_ADDRESS_T *pOut, UnicastAddress *pIn) { switch (pIn->choice) { case UnicastAddress_iPAddress_chosen: pOut->type = H245_IP_UNICAST; memcpy(pOut->u.ip.network, pIn->u.UnicastAddress_iPAddress.network.value, 4); pOut->u.ip.tsapIdentifier = pIn->u.UnicastAddress_iPAddress.tsapIdentifier; break; case iPXAddress_chosen: pOut->type = H245_IPX_UNICAST; memcpy(pOut->u.ipx.node, pIn->u.iPXAddress.node.value, 6); memcpy(pOut->u.ipx.netnum, pIn->u.iPXAddress.netnum.value, 4); memcpy(pOut->u.ipx.tsapIdentifier, pIn->u.iPXAddress.tsapIdentifier.value, 2); break; case UncstAddrss_iP6Address_chosen: pOut->type = H245_IP6_UNICAST; memcpy(pOut->u.ip6.network, pIn->u.UncstAddrss_iP6Address.network.value, 16); pOut->u.ip6.tsapIdentifier = pIn->u.UncstAddrss_iP6Address.tsapIdentifier; break; case netBios_chosen: pOut->type = H245_NETBIOS_UNICAST; memcpy(pOut->u.netBios, pIn->u.netBios.value, 16); break; case iPSourceRouteAddress_chosen: switch (pIn->u.iPSourceRouteAddress.routing.choice) { case strict_chosen: pOut->type = H245_IPSSR_UNICAST; break; case loose_chosen: pOut->type = H245_IPLSR_UNICAST; break; default: return H245_ERROR_INVALID_DATA_FORMAT; } // switch memcpy(pOut->u.ipSourceRoute.network, pIn->u.iPSourceRouteAddress.network.value, 4); pOut->u.ipSourceRoute.tsapIdentifier = pIn->u.iPSourceRouteAddress.tsapIdentifier; // TBD - handle route break; default: return H245_ERROR_INVALID_DATA_FORMAT; } // switch return H245_ERROR_OK; } // LoadUnicastAddress() HRESULT LoadMulticastAddress(H245_TRANSPORT_ADDRESS_T *pOut, MulticastAddress *pIn) { switch (pIn->choice) { case MltcstAddrss_iPAddress_chosen: pOut->type = H245_IP_MULTICAST; memcpy(pOut->u.ip.network, pIn->u.MltcstAddrss_iPAddress.network.value, 4); pOut->u.ip.tsapIdentifier = pIn->u.MltcstAddrss_iPAddress.tsapIdentifier; break; case MltcstAddrss_iP6Address_chosen: pOut->type = H245_IP6_MULTICAST; memcpy(pOut->u.ip6.network, pIn->u.MltcstAddrss_iP6Address.network.value, 16); pOut->u.ip6.tsapIdentifier = pIn->u.MltcstAddrss_iP6Address.tsapIdentifier; break; default: return H245_ERROR_INVALID_DATA_FORMAT; } // switch return H245_ERROR_OK; } // LoadMulticastAddress() HRESULT LoadTransportAddress(H245_TRANSPORT_ADDRESS_T *pOut, H245TransportAddress *pIn) { switch (pIn->choice) { case unicastAddress_chosen: return LoadUnicastAddress (pOut, &pIn->u.unicastAddress); case multicastAddress_chosen: return LoadMulticastAddress(pOut, &pIn->u.multicastAddress); default: return H245_ERROR_INVALID_DATA_FORMAT; } // switch } // LoadTransportAddress() HRESULT LoadCommModeEntry(H245_COMM_MODE_ENTRY_T *pOut, CommunicationModeTableEntry *pIn) { HRESULT lResult; memset(pOut, 0, sizeof(*pOut)); if (pIn->bit_mask & CMTEy_nnStndrd_present) { pOut->pNonStandard = pIn->CMTEy_nnStndrd; } pOut->sessionID = (unsigned char)pIn->sessionID; if (pIn->bit_mask & CMTEy_assctdSssnID_present) { pOut->associatedSessionID = (unsigned char)pIn->CMTEy_assctdSssnID; pOut->associatedSessionIDPresent = TRUE; } if (pIn->bit_mask & CommunicationModeTableEntry_terminalLabel_present) { pOut->terminalLabel = pIn->terminalLabel; pOut->terminalLabelPresent = TRUE; } pOut->pSessionDescription = pIn->sessionDescription.value; pOut->wSessionDescriptionLength = (WORD) pIn->sessionDescription.length; switch (pIn->dataType.choice) { case dataType_videoData_chosen: pOut->dataType.DataType = H245_DATA_VIDEO; break; case dataType_audioData_chosen: pOut->dataType.DataType = H245_DATA_AUDIO; break; case dataType_data_chosen: pOut->dataType.DataType = H245_DATA_DATA; break; default: return H245_ERROR_INVALID_DATA_FORMAT; } // switch lResult = build_totcap_cap_n_client_from_capability ((struct Capability *)&pIn->dataType, pOut->dataType.DataType, pIn->dataType.u.dataType_videoData.choice, &pOut->dataType); if (lResult != H245_ERROR_OK) return lResult; if (pIn->bit_mask & CMTEy_mdChnnl_present) { lResult = LoadTransportAddress(&pOut->mediaChannel, &pIn->CMTEy_mdChnnl); if (lResult != H245_ERROR_OK) return lResult; pOut->mediaChannelPresent = TRUE; } if (pIn->bit_mask & CMTEy_mdGrntdDlvry_present) { pOut->mediaGuaranteed = pIn->CMTEy_mdGrntdDlvry; pOut->mediaGuaranteedPresent = TRUE; } if (pIn->bit_mask & CMTEy_mdCntrlChnnl_present) { lResult = LoadTransportAddress(&pOut->mediaControlChannel, &pIn->CMTEy_mdCntrlChnnl); if (lResult != H245_ERROR_OK) return lResult; pOut->mediaControlChannelPresent = TRUE; } if (pIn->bit_mask & CMTEy_mdCntrlGrntdDlvry_present) { pOut->mediaControlGuaranteed = pIn->CMTEy_mdCntrlGrntdDlvry; pOut->mediaControlGuaranteedPresent = TRUE; } return H245_ERROR_OK; } // LoadCommModeEntry() /***************************************************************************** * * TYPE: Local * * PROCEDURE: load_H222_param * load_H223_param * load_VGMUX_param * load_H2250_param * load_H2250ACK_param * * DESCRIPTION * * This routine builds local API-style Logical Parameters out of ASN.1 * structure passed to it * * * RETURN: * *****************************************************************************/ static HRESULT load_H222_param (H245_H222_LOGICAL_PARAM_T * pOut, /* output */ H222LogicalChannelParameters * pIn) /* input */ { /* See setup_H220_mux() for inverse function */ memset(pOut, 0, sizeof(*pOut)); pOut->resourceID = pIn->resourceID; pOut->subChannelID = pIn->subChannelID; if (pIn->bit_mask & pcr_pid_present) { pOut->pcr_pidPresent = TRUE; pOut->pcr_pid = pIn->pcr_pid; } if (pIn->bit_mask & programDescriptors_present) { pOut->programDescriptors.length = pIn->programDescriptors.length; pOut->programDescriptors.value = pIn->programDescriptors.value; } if (pIn->bit_mask & streamDescriptors_present) { pOut->streamDescriptors.length = pIn->streamDescriptors.length; pOut->streamDescriptors.value = pIn->streamDescriptors.value; } return H245_ERROR_OK; } // load_H222_param() static HRESULT load_H223_param (H245_H223_LOGICAL_PARAM_T * pOut, /* output */ H223LogicalChannelParameters * pIn) /* input */ { HRESULT lError = H245_ERROR_OK; /* See setup_H223_mux() for inverse function */ memset(pOut, 0, sizeof(*pOut)); pOut->SegmentFlag = pIn->segmentableFlag; switch (pIn->adaptationLayerType.choice) { case H223LCPs_aLTp_nnStndrd_chosen: lError = CopyNonStandardParameter(&pOut->H223_NONSTD, &pIn->adaptationLayerType.u.H223LCPs_aLTp_nnStndrd); pOut->AlType = H245_H223_AL_NONSTD; break; case H223LCPs_aLTp_al1Frmd_chosen: pOut->AlType = H245_H223_AL_AL1FRAMED; break; case H223LCPs_aLTp_al1NtFrmd_chosen: pOut->AlType = H245_H223_AL_AL1NOTFRAMED; break; case H223LCPs_aLTp_a2WSNs_1_chosen: pOut->AlType = H245_H223_AL_AL2NOSEQ; break; case H223LCPs_aLTp_a2WSNs_2_chosen: pOut->AlType = H245_H223_AL_AL2SEQ; break; case H223LCPs_aLTp_al3_chosen: pOut->AlType = H245_H223_AL_AL3; pOut->CtlFldOctet = (unsigned char)pIn->adaptationLayerType.u.H223LCPs_aLTp_al3.controlFieldOctets; pOut->SndBufSize = pIn->adaptationLayerType.u.H223LCPs_aLTp_al3.sendBufferSize; break; } /* switch */ return lError; } // load_H223_param() static HRESULT load_VGMUX_param(H245_VGMUX_LOGICAL_PARAM_T *pOut, /* output */ V76LogicalChannelParameters *pIn) /* input */ { /* See setup_VGMUX_mux() for inverse function */ memset(pOut, 0, sizeof(*pOut)); pOut->crcLength = pIn->hdlcParameters.crcLength.choice; pOut->n401 = pIn->hdlcParameters.n401; pOut->loopbackTestProcedure = pIn->hdlcParameters.loopbackTestProcedure; pOut->suspendResume = pIn->suspendResume.choice; pOut->uIH = pIn->uIH; pOut->mode = pIn->mode.choice; switch (pIn->mode.choice) { case eRM_chosen: pOut->windowSize = pIn->mode.u.eRM.windowSize; pOut->recovery = pIn->mode.u.eRM.recovery.choice; break; } // switch pOut->audioHeaderPresent = pIn->v75Parameters.audioHeaderPresent; return H245_ERROR_OK; } // load_VGMUX_param() static HRESULT load_H2250_param(H245_H2250_LOGICAL_PARAM_T * pOut, /* output */ H2250LogicalChannelParameters *pIn) /* input */ { HRESULT lError = H245_ERROR_OK; /* See setup_H2250_mux() for inverse function */ memset(pOut, 0, sizeof(*pOut)); if (pIn->bit_mask & H2250LCPs_nnStndrd_present) { pOut->nonStandardList = pIn->H2250LCPs_nnStndrd; } pOut->sessionID = (unsigned char) pIn->sessionID; if (pIn->bit_mask & H2250LCPs_assctdSssnID_present) { pOut->associatedSessionID = (unsigned char)pIn->H2250LCPs_assctdSssnID; pOut->associatedSessionIDPresent = TRUE; } if (pIn->bit_mask & H2250LCPs_mdChnnl_present) { if (lError == H245_ERROR_OK) { lError = LoadTransportAddress(&pOut->mediaChannel, &pIn->H2250LCPs_mdChnnl); if (lError == H245_ERROR_OK) { pOut->mediaChannelPresent = TRUE; } } } if (pIn->bit_mask & H2250LCPs_mdGrntdDlvry_present) { pOut->mediaGuaranteed = pIn->H2250LCPs_mdGrntdDlvry; pOut->mediaGuaranteedPresent = TRUE; } if (pIn->bit_mask & H2250LCPs_mdCntrlChnnl_present) { if (lError == H245_ERROR_OK) { lError = LoadTransportAddress(&pOut->mediaControlChannel, &pIn->H2250LCPs_mdCntrlChnnl); if (lError == H245_ERROR_OK) { pOut->mediaControlChannelPresent = TRUE; } } } if (pIn->bit_mask & H2250LCPs_mCGDy_present) { pOut->mediaControlGuaranteed = pIn->H2250LCPs_mCGDy; pOut->mediaControlGuaranteedPresent = TRUE; } if (pIn->bit_mask & silenceSuppression_present) { pOut->silenceSuppression = pIn->silenceSuppression; pOut->silenceSuppressionPresent = TRUE; } if (pIn->bit_mask & H2250LogicalChannelParameters_destination_present) { pOut->destination = pIn->destination; pOut->destinationPresent = TRUE; } if (pIn->bit_mask & H2250LCPs_dRTPPTp_present) { pOut->dynamicRTPPayloadType = (unsigned char)pIn->H2250LCPs_dRTPPTp; pOut->dynamicRTPPayloadTypePresent = TRUE; } if (pIn->bit_mask & mediaPacketization_present) { switch (pIn->mediaPacketization.choice) { case h261aVideoPacketization_chosen: pOut->h261aVideoPacketization = TRUE; break; default: return H245_ERROR_INVALID_DATA_FORMAT; } // switch } return lError; } // load_H2250_param() static HRESULT load_H2250ACK_param(H245_H2250ACK_LOGICAL_PARAM_T * pOut, H2250LgclChnnlAckPrmtrs * pIn) { HRESULT lError = H245_ERROR_OK; /* See setup_H2250ACK_mux() for inverse function */ memset(pOut, 0, sizeof(*pOut)); if (pIn->bit_mask & H2250LCAPs_nnStndrd_present) { pOut->nonStandardList = pIn->H2250LCAPs_nnStndrd; } if (pIn->bit_mask & sessionID_present) { pOut->sessionID = (unsigned char) pIn->sessionID; pOut->sessionIDPresent = TRUE; } if (pIn->bit_mask & H2250LCAPs_mdChnnl_present) { if (lError == H245_ERROR_OK) { lError = LoadTransportAddress(&pOut->mediaChannel, &pIn->H2250LCAPs_mdChnnl); if (lError == H245_ERROR_OK) { pOut->mediaChannelPresent = TRUE; } } } if (pIn->bit_mask & H2250LCAPs_mdCntrlChnnl_present) { if (lError == H245_ERROR_OK) { lError = LoadTransportAddress(&pOut->mediaControlChannel, &pIn->H2250LCAPs_mdCntrlChnnl); if (lError == H245_ERROR_OK) { pOut->mediaControlChannelPresent = TRUE; } } } if (pIn->bit_mask & H2250LCAPs_dRTPPTp_present) { pOut->dynamicRTPPayloadType = (unsigned char)pIn->H2250LCAPs_dRTPPTp; pOut->dynamicRTPPayloadTypePresent = TRUE; } return lError; } // load_H2250ACK_param() /***************************************************************************** * * TYPE: Local * * PROCEDURE: build_element_list_from_mux - * * DESCRIPTION * recursively build H245_MUX_ENTRY_ELEMENT_T list from * ASN1 mux table descriptor entrys. * * RETURN: * *****************************************************************************/ static H245_MUX_ENTRY_ELEMENT_T * build_element_list_from_mux (MultiplexElement *p_ASN_mux_el, H245_ACC_REJ_T *p_acc_rej) { DWORD ii; H245_MUX_ENTRY_ELEMENT_T *p_mux_el; H245_MUX_ENTRY_ELEMENT_T *p_mux_el_tmp = NULL; H245_MUX_ENTRY_ELEMENT_T *p_mux_el_lst = NULL; if (!(p_mux_el = (H245_MUX_ENTRY_ELEMENT_T *)MemAlloc(sizeof(H245_MUX_ENTRY_ELEMENT_T)))) { /* too complicated.. ran out of memory */ H245TRACE(0,1,"build_element_list_from_mux : H245_ERROR_NOMEM"); *p_acc_rej = H245_REJ_MUX_COMPLICATED; return NULL; } /* zero it out */ memset (p_mux_el, 0, sizeof(H245_MUX_ENTRY_ELEMENT_T)); switch (p_ASN_mux_el->type.choice) { case typ_logicalChannelNumber_chosen: /* assign as a logical channel */ p_mux_el->Kind = H245_MUX_LOGICAL_CHANNEL; p_mux_el->u.Channel = p_ASN_mux_el->type.u.typ_logicalChannelNumber; break; case subElementList_chosen: { /* if the sub element list doesn't exist .. no go */ /* if the sub element list has less than 2 entries.. no go. */ if ((!p_ASN_mux_el->type.u.subElementList) || (p_ASN_mux_el->type.u.subElementList->count < 2)) { /* invalid Element list.. */ H245TRACE(0,1,"build_element_list_from_mux : << ERROR >> Element Count < 2"); *p_acc_rej = H245_REJ; free_mux_el_list (p_mux_el); return NULL; } /* assign as entry element */ p_mux_el->Kind = H245_MUX_ENTRY_ELEMENT; /* ok.. for every sub element in the list */ for (ii=0;iitype.u.subElementList->count;ii++) { if (!(p_mux_el_tmp = build_element_list_from_mux (&p_ASN_mux_el->type.u.subElementList->value[ii], p_acc_rej))) { /* *p_acc_rej is set from below */ free_mux_el_list (p_mux_el); return NULL; } /* if first on the down sub element list.. assign to sub */ /* element portion of mux_el */ if (!p_mux_el_lst) p_mux_el->u.pMuxTblEntryElem = p_mux_el_tmp; /* otherwise.. just a list.. add it on.. */ else p_mux_el_lst->pNext = p_mux_el_tmp; p_mux_el_lst = p_mux_el_tmp; } } break; default: /* Un supported structure */ H245TRACE(0,1,"build_element_list_from_mux : INVALID MUX TABLE ENTRY PDU 'type.choice' unknown"); *p_acc_rej = H245_REJ; free_mux_el_list (p_mux_el); return NULL; } switch (p_ASN_mux_el->repeatCount.choice) { case repeatCount_finite_chosen: p_mux_el->RepeatCount = p_ASN_mux_el->repeatCount.u.repeatCount_finite; break; case untilClosingFlag_chosen: p_mux_el->RepeatCount = 0; break; default: /* Un supported structure */ H245TRACE(0,1,"build_element_list_from_mux : INVALID MUX TABLE ENTRY PDU 'repeatCount.choice' unknown"); *p_acc_rej = H245_REJ; free_mux_el_list (p_mux_el); return NULL; break; } return p_mux_el; } /***************************************************************************** * * TYPE: Local * * PROCEDURE: process_mux_table_ind * * DESCRIPTION * * * RETURN: * *****************************************************************************/ static H245_MUX_TABLE_T * process_mux_table_ind (MltmdSystmCntrlMssg *p_pdu_ind, unsigned short *p_seq, H245_ACC_REJ_MUX_T rej_mux, DWORD *p_rej_cnt, DWORD *p_acc_cnt) { UINT ii; /* generic counter */ MultiplexEntrySend *p_ASN_mux; /* ans1 mux entry */ MultiplexEntryDescriptorLink p_ASN_med_desc_lnk; /* asn1 mux entry descriptor */ int mux_entry; /* current mux entry descc */ H245_MUX_TABLE_T *p_mux_table_list = NULL; ASSERT(p_pdu_ind->choice == MltmdSystmCntrlMssg_rqst_chosen); ASSERT(p_pdu_ind->u.MltmdSystmCntrlMssg_rqst.choice == multiplexEntrySend_chosen); /* initialize rej_mux */ for (ii=0;ii<15;ii++) { rej_mux[ii].AccRej = H245_ACC; rej_mux[ii].MuxEntryId = 0; } *p_rej_cnt = 0; *p_acc_cnt = 0; p_ASN_mux = &(p_pdu_ind->u.MltmdSystmCntrlMssg_rqst.u.multiplexEntrySend); /* get sequence number */ *p_seq = p_ASN_mux->sequenceNumber; /* this should never happen.. */ if (!(p_ASN_mux->multiplexEntryDescriptors)) return NULL; /* for each descriptor.. ie mux table entry */ for (p_ASN_med_desc_lnk = p_ASN_mux->multiplexEntryDescriptors, mux_entry=0; p_ASN_med_desc_lnk; p_ASN_med_desc_lnk = p_ASN_med_desc_lnk->next, mux_entry++) { /* remove descriptor from table */ H245_MUX_TABLE_T *p_mux_table; H245_MUX_TABLE_T *p_mux_table_lst = NULL; if (!(p_mux_table = (H245_MUX_TABLE_T *)MemAlloc(sizeof(H245_MUX_TABLE_T)))) { /* houston.. we have a problem !!!!!!!! */ /* rejet this one.. */ /* and move on.. */ rej_mux[mux_entry].MuxEntryId = p_ASN_med_desc_lnk->value.multiplexTableEntryNumber; rej_mux[mux_entry].AccRej = H245_REJ; (*p_rej_cnt)++; continue; } /* zero it out */ memset (p_mux_table, 0, sizeof(H245_MUX_TABLE_T)); /* assign mux table entry */ rej_mux[mux_entry].MuxEntryId = (DWORD) p_mux_table->MuxEntryId = p_ASN_med_desc_lnk->value.multiplexTableEntryNumber; /* if element is not present */ if (p_ASN_med_desc_lnk->value.bit_mask != elementList_present) { p_mux_table->pMuxTblEntryElem = NULL; rej_mux[mux_entry].AccRej = H245_ACC; (*p_acc_cnt)++; } /* if element list present */ else { H245_MUX_ENTRY_ELEMENT_T *p_mux_el_lst = NULL; H245_MUX_ENTRY_ELEMENT_T *p_mux_el_tmp = NULL; /* start if off.. w/ ok */ rej_mux[mux_entry].AccRej = H245_ACC; /* for each element in the element list.. */ /* build the subelements.. if error .. free */ /* what youve done so far.. and break out */ for (ii=0; ii < p_ASN_med_desc_lnk->value.elementList.count; ii++) { /* if any of the elements fail.. flag the entry w/ reject reason */ /* (this is done inside the build_element_list..) */ /* and break out.. continue on with the next descriptor */ if (!(p_mux_el_tmp = build_element_list_from_mux (&(p_ASN_med_desc_lnk->value.elementList.value[ii]),&(rej_mux[mux_entry].AccRej)))) { /* free the list.. */ free_mux_el_list (p_mux_table->pMuxTblEntryElem); break; } /* ***************************** */ /* LINK IN THE MUX ENTRY ELEMENT */ /* ***************************** */ /* if first time through */ if (!p_mux_el_lst) p_mux_table->pMuxTblEntryElem = p_mux_el_tmp; /* otherwize .. just tag on the end */ else p_mux_el_lst->pNext = p_mux_el_tmp; p_mux_el_lst = p_mux_el_tmp; } /* for each element in descriptor list */ } /* if element list present */ /* if you've accepted the mux table entry descriptor */ if (rej_mux[mux_entry].AccRej == H245_ACC) { /* indicate an accept */ (*p_acc_cnt)++; /* ******************************** */ /* LINK IN THE MUX TABLE DESCRIPTOR */ /* ******************************** */ /* first table entry on the list.. (first time through) */ if (!p_mux_table_list) p_mux_table_list = p_mux_table; else p_mux_table_lst->pNext = p_mux_table; p_mux_table_lst = p_mux_table; } else { /* indicate a reject */ (*p_rej_cnt)++; /* otherwise.. free it and move on to something better */ MemFree(p_mux_table); } } /* for each desriptor in the list */ return p_mux_table_list; } /* procedure */ /***************************************************************************** * * TYPE: Local * * PROCEDURE: process_term_cap_set_ind__cap_table * * DESCRIPTION allocates a new cap link and copies the capabiliites. * links into the tiven capabilityTableLink, and if * Parameters are NONSTANDARD does some gymnastics to copy * data so it can be used.. * * NOTE: Copied data must be freed when capability is deleted. * see where the capability is deleted for exceptions * for "NONSTD" parameter sets .. (this is not pretty) * * RETURN: * *****************************************************************************/ static HRESULT process_term_cap_set_ind__cap_table ( struct InstanceStruct *pInstance, struct TerminalCapabilitySet *pTermCapSet, CapabilityTableLink pCapLink, MltmdSystmCntrlMssg *p_pdu_rsp) { H245_TOTCAP_T totcap; CapabilityTableLink pNewLink; HRESULT lError; while (pCapLink) { if (build_totcap_from_captbl (&totcap, pCapLink, H245_REMOTE) == H245_ERROR_OK) { /* ok.. assume the CapId is set.. find it in the remote table */ /* if it exists, delete it so we can add new one in it's place */ pNewLink = find_capid_by_entrynumber( pTermCapSet, totcap.CapId); if (pNewLink) { del_cap_link ( pTermCapSet, pNewLink ); } /* ok.. if you've deleted the cap.. now see if there is a new one to take it's place */ if (pCapLink->value.bit_mask & capability_present) { /* load and link into remote table entry */ pNewLink = alloc_link_cap_entry (pTermCapSet); if (!pNewLink) { return H245_ERROR_NORESOURCE; } /* copy the cap over to the remote entry */ pNewLink->value = pCapLink->value; // If it's nonstandard, the above didn't work, so fix it up... lError = H245_ERROR_OK; switch (pCapLink->value.capability.choice) { case Capability_nonStandard_chosen: lError = CopyNonStandardParameter(&pNewLink->value.capability.u.Capability_nonStandard, &pCapLink->value.capability.u.Capability_nonStandard); break; case receiveVideoCapability_chosen: case transmitVideoCapability_chosen: case rcvAndTrnsmtVdCpblty_chosen: if (pCapLink->value.capability.u.receiveVideoCapability.choice == VdCpblty_nonStandard_chosen) { lError = CopyNonStandardParameter(&pNewLink->value.capability.u.receiveVideoCapability.u.VdCpblty_nonStandard, &pCapLink->value.capability.u.receiveVideoCapability.u.VdCpblty_nonStandard); } break; case receiveAudioCapability_chosen: case transmitAudioCapability_chosen: case rcvAndTrnsmtAdCpblty_chosen: if (pCapLink->value.capability.u.receiveAudioCapability.choice == AdCpblty_nonStandard_chosen) { lError = CopyNonStandardParameter(&pNewLink->value.capability.u.receiveAudioCapability.u.AdCpblty_nonStandard, &pCapLink->value.capability.u.receiveAudioCapability.u.AdCpblty_nonStandard); } break; case rcvDtApplctnCpblty_chosen: case trnsmtDtApplctnCpblty_chosen: case rATDACy_chosen : if (pCapLink->value.capability.u.rcvDtApplctnCpblty.application.choice == DACy_applctn_nnStndrd_chosen) { lError = CopyNonStandardParameter(&pNewLink->value.capability.u.rcvDtApplctnCpblty.application.u.DACy_applctn_nnStndrd, &pCapLink->value.capability.u.rcvDtApplctnCpblty.application.u.DACy_applctn_nnStndrd); } break; } // switch if (lError != H245_ERROR_OK) return lError; } /* if capability_present */ } /* if build_totcap_from_captbl succeeded */ pCapLink = pCapLink->next; } /* for all entries in link */ return H245_ERROR_OK; } /***************************************************************************** * * TYPE: Local * * PROCEDURE: process_term_cap_set_ind__cap_desc * * DESCRIPTION * * * RETURN: * *****************************************************************************/ static HRESULT process_term_cap_set_ind__cap_desc (struct InstanceStruct *pInstance, struct TerminalCapabilitySet *pTermCapSet, CapabilityDescriptor *pReqCapDesc, MltmdSystmCntrlMssg *p_pdu_rsp) { unsigned int uCapDescNumber; CapabilityDescriptor *pCapDesc; unsigned int uCapDesc; SmltnsCpbltsLink pSimCap; SmltnsCpbltsLink pReqSimCap; CapabilityDescriptor TempCapDesc; unsigned int uSimCount; unsigned int uReqAltCount; unsigned int uReqAltCap; unsigned int uAltCap; HRESULT lError = H245_ERROR_OK; uCapDescNumber = pReqCapDesc->capabilityDescriptorNumber & 255; H245TRACE(pInstance->dwInst,20,"API:process_term_cap_set_ind - Remote Capability Descriptor #%d", uCapDescNumber); // Find corresponding capability descriptor pCapDesc = NULL; for (uCapDesc = 0; uCapDesc < pTermCapSet->capabilityDescriptors.count; ++uCapDesc) { if (pTermCapSet->capabilityDescriptors.value[uCapDesc].capabilityDescriptorNumber == uCapDescNumber) { // Deallocate old simultaneous capabilities pCapDesc = &pTermCapSet->capabilityDescriptors.value[uCapDesc]; if (pCapDesc->smltnsCpblts) dealloc_simultaneous_cap(pCapDesc); break; } // if } // for if (pCapDesc == NULL) { // Allocate a new terminal capability descriptor ASSERT(pTermCapSet->capabilityDescriptors.count < 256); pCapDesc = &pTermCapSet->capabilityDescriptors.value[pTermCapSet->capabilityDescriptors.count++]; } ASSERT(pCapDesc->smltnsCpblts == NULL); if (!(pReqCapDesc->bit_mask & smltnsCpblts_present)) { // Delete the terminal capability descriptor pTermCapSet->capabilityDescriptors.count--; *pCapDesc = pTermCapSet->capabilityDescriptors.value[pTermCapSet->capabilityDescriptors.count]; return H245_ERROR_OK; } // Make a copy of the (volatile) new capability descriptor pCapDesc->bit_mask = 0; pCapDesc->capabilityDescriptorNumber = (CapabilityDescriptorNumber)uCapDescNumber; pCapDesc->smltnsCpblts = NULL; // We copy the linked list to a temporary so that it // gets reversed twice and ends up in same order TempCapDesc.smltnsCpblts = NULL; uSimCount = 0; pReqSimCap = pReqCapDesc->smltnsCpblts; while (pReqSimCap) { // Allocate a new simultaneous capability list element pSimCap = MemAlloc(sizeof(*pSimCap)); if (pSimCap == NULL) { H245TRACE(pInstance->dwInst, 1, "API:process_term_cap_set_ind: malloc failed"); lError = H245_ERROR_NOMEM; break; } // Verify that each alternative capability in the request // simultaneous capability is valid // if so, copy it uAltCap = 0; uReqAltCount = pReqSimCap->value.count; for (uReqAltCap = 0; uReqAltCap < uReqAltCount; ++uReqAltCap) { // Is the Capability in the remote Capability Table? if (find_capid_by_entrynumber (pTermCapSet, pReqSimCap->value.value[uReqAltCap]) == NULL) { // can't find the Capability H245TRACE(pInstance->dwInst,1,"API:process_term_cap_set_ind - Remote Capability Table Entry #%d not found", pReqSimCap->value.value[uReqAltCap]); lError = H245_ERROR_UNKNOWN; } else if (uAltCap >= H245_MAX_ALTCAPS) { // Exceeded arbitrary limit H245TRACE(pInstance->dwInst,1, "API:process_term_cap_set_ind - Too many alternative capabilities (%d)", uAltCap); lError = H245_ERROR_NORESOURCE; break; } else { // Copy the capability number pSimCap->value.value[uAltCap++] = pReqSimCap->value.value[uReqAltCap]; } } /* for alternative capbilities */ if (uAltCap) { // Verify that we have not exceeded arbitrary limit if (++uSimCount > H245_MAX_SIMCAPS) { // Exceeded arbitrary limit H245TRACE(pInstance->dwInst, 1, "API:process_term_cap_set_ind - Too many simultaneous capabilities (%d)", uSimCount); MemFree(pSimCap); lError = H245_ERROR_NORESOURCE; } else { // Add new simultaneous capability to the temporary list pSimCap->value.count = (unsigned short)uAltCap; pSimCap->next = TempCapDesc.smltnsCpblts; TempCapDesc.smltnsCpblts = pSimCap; } } else { H245TRACE(pInstance->dwInst, 1, "API:process_term_cap_set_ind - No valid alternative capabilities found"); MemFree(pSimCap); lError = H245_ERROR_UNKNOWN; } pReqSimCap = pReqSimCap->next; } // while while (TempCapDesc.smltnsCpblts) { // Move elements from temporary to final linked list pSimCap = TempCapDesc.smltnsCpblts; TempCapDesc.smltnsCpblts = pSimCap->next; pSimCap->next = pCapDesc->smltnsCpblts; pCapDesc->smltnsCpblts = pSimCap; } // Error if no simultaneous capabilities found if (pCapDesc->smltnsCpblts) { pCapDesc->bit_mask |= smltnsCpblts_present; } else { H245TRACE(pInstance->dwInst, 1, "API:process_term_cap_set_ind - No simultaneous capabilities found"); lError = H245_ERROR_UNKNOWN; } return lError; } /***************************************************************************** * * TYPE: Local * * PROCEDURE: process_term_cap_set_ind__mux_cap * * DESCRIPTION * * * RETURN: * * NOTES: * We do a copy to set up a capability structure, then do another copy via * H245CopyCap() to create a copy of the capability because the structure * given to us by the ASN.1 decoded may contain pointers to data which will * be deallocated upon return. * *****************************************************************************/ static HRESULT process_term_cap_set_ind__mux_cap (struct InstanceStruct *pInstance, struct TerminalCapabilitySet *pTermCapSet, MultiplexCapability * pReqMuxCap, MltmdSystmCntrlMssg *p_pdu_rsp) { H245_TOTCAP_T TotCap; // Initialize temporary capability structure memset(&TotCap, 0, sizeof(TotCap)); TotCap.Dir = H245_CAPDIR_RMTRXTX; TotCap.DataType = H245_DATA_MUX; // Get rid of old remote multiplex capability, if any if (pTermCapSet->bit_mask & multiplexCapability_present) { del_mux_cap(pTermCapSet); } switch (pReqMuxCap->choice) { case MltplxCpblty_nonStandard_chosen: // Save a copy of the multiplex capability TotCap.Cap.H245Mux_NONSTD = pReqMuxCap->u.MltplxCpblty_nonStandard; TotCap.ClientType = H245_CLIENT_MUX_NONSTD; H245TRACE(pInstance->dwInst,1,"API:process_term_cap_set_ind__mux_cap - Nonstandard Mux not yet supported"); break; case h222Capability_chosen: // Save a copy of the multiplex capability TotCap.Cap.H245Mux_H222 = pReqMuxCap->u.h222Capability; TotCap.ClientType = H245_CLIENT_MUX_H222; break; case h223Capability_chosen: // Save a copy of the multiplex capability TotCap.Cap.H245Mux_H223 = pReqMuxCap->u.h223Capability; TotCap.ClientType = H245_CLIENT_MUX_H223; break; case v76Capability_chosen: // Save a copy of the multiplex capability TotCap.Cap.H245Mux_VGMUX = pReqMuxCap->u.v76Capability; TotCap.ClientType = H245_CLIENT_MUX_VGMUX; break; case h2250Capability_chosen: // Save a copy of the multiplex capability TotCap.Cap.H245Mux_H2250 = pReqMuxCap->u.h2250Capability; TotCap.ClientType = H245_CLIENT_MUX_H2250; break; default: H245TRACE(pInstance->dwInst,1,"API:process_term_cap_set_ind__mux_cap - invalid mux cap type %d", &pReqMuxCap->choice); return H245_ERROR_NOSUP; } return set_mux_cap(pInstance, pTermCapSet, &TotCap); } /***************************************************************************** * * TYPE: Local * * PROCEDURE: process_term_cap_set_ind * * DESCRIPTION * ************************************************************** * * (TBD) .. this module will ack all terminal capbilities * need to build reject.. (maybe later??) * * THIS IS A BIG TBD * ************************************************************** * * RETURN: * *****************************************************************************/ static HRESULT process_term_cap_set_ind (struct InstanceStruct *pInstance, MltmdSystmCntrlMssg *p_pdu_req, MltmdSystmCntrlMssg *p_pdu_rsp) { HRESULT lError = H245_ERROR_OK; TerminalCapabilitySet *pTermCapSet; ASSERT (p_pdu_req->choice == MltmdSystmCntrlMssg_rqst_chosen); ASSERT (p_pdu_req->u.MltmdSystmCntrlMssg_rqst.choice == terminalCapabilitySet_chosen); H245TRACE(pInstance->dwInst,10,"API:process_term_cap_set_ind <-"); /* build ack response */ p_pdu_rsp->choice = MSCMg_rspns_chosen; p_pdu_rsp->u.MSCMg_rspns.choice = terminalCapabilitySetAck_chosen; p_pdu_rsp->u.MSCMg_rspns.u.terminalCapabilitySetAck.sequenceNumber = p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.terminalCapabilitySet.sequenceNumber; pTermCapSet = &pInstance->API.PDU_RemoteTermCap.u.MltmdSystmCntrlMssg_rqst.u.terminalCapabilitySet; //*************************** // Deal with Capability Table //*************************** if (p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.terminalCapabilitySet.bit_mask & capabilityTable_present) { CapabilityTableLink pCapTable = p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.terminalCapabilitySet.capabilityTable; if (pCapTable->value.capability.choice == Capability_nonStandard_chosen && pCapTable->value.capability.u.Capability_nonStandard.nonStandardIdentifier.choice == h221NonStandard_chosen && pCapTable->value.capability.u.Capability_nonStandard.nonStandardIdentifier.u.h221NonStandard.t35CountryCode == 0xB5 && pCapTable->value.capability.u.Capability_nonStandard.nonStandardIdentifier.u.h221NonStandard.t35Extension == 0x42 && pCapTable->value.capability.u.Capability_nonStandard.nonStandardIdentifier.u.h221NonStandard.manufacturerCode == 0x8080) { pInstance->bMasterSlaveKludge = TRUE; pCapTable = pCapTable->next; } lError = process_term_cap_set_ind__cap_table(pInstance, pTermCapSet, pCapTable, p_pdu_rsp); if (lError != H245_ERROR_OK) { H245TRACE(pInstance->dwInst,1,"API:process_term_cap_set_ind - cap table error %s",map_api_error(lError)); /* (TBC) need to reject somehow */ } } /* if Capability Table Present */ //************************************** // Deal with Capability Descriptor Table // i.e. simultaneous capabilities // NOTE: these are not held in the remote terminal capbility set //************************************** if (p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.terminalCapabilitySet.bit_mask & capabilityDescriptors_present) { int des_cnt; int ii; des_cnt = p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.terminalCapabilitySet.capabilityDescriptors.count; H245TRACE(pInstance->dwInst,20,"API:process_term_cap_set_ind - %d Simultaneous Capabilities",des_cnt); for (ii = 0; ii < des_cnt; ++ii) { lError = process_term_cap_set_ind__cap_desc (pInstance, pTermCapSet, &p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u. terminalCapabilitySet.capabilityDescriptors.value[ii], p_pdu_rsp); if (lError != H245_ERROR_OK) { H245TRACE(pInstance->dwInst,1,"API:process_term_cap_set_ind - cap desc error %s",map_api_error(lError)); /* (TBC) need to reject somehow */ } } /* for each descriptor */ } /* if capability descriptor present */ /**************************************/ /* Deal with Multiplex Capability set */ /**************************************/ /* NOTE: these are not held in the remote terminal capability set */ if (p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.terminalCapabilitySet.bit_mask & multiplexCapability_present) { /* send up the indication to the client for each new entry */ lError = process_term_cap_set_ind__mux_cap(pInstance, pTermCapSet, &p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u. terminalCapabilitySet.multiplexCapability, p_pdu_rsp); if (lError != H245_ERROR_OK) { H245TRACE(pInstance->dwInst,1,"API:process_term_cap_set_ind - mux cap error %s",map_api_error(lError)); /* (TBC) need to reject somehow */ } } H245TRACE(pInstance->dwInst,10,"API:process_term_cap_set_ind -> OK"); return H245_ERROR_OK; } /***************************************************************************** * * TYPE: Local * * PROCEDURE: process_open_ind * * DESCRIPTION * * RETURN: * * ASSUME: * Callback must happen inside this routine since the * datastructures passed back to the application are allocated * in this moudle. * * Application will <<>> the needed data structures when * callback occurs.. * *****************************************************************************/ static HRESULT process_open_ind (struct InstanceStruct *pInstance, MltmdSystmCntrlMssg *p_pdu_req, unsigned short *p_FwdChan, /* for return on error */ H245_ACC_REJ_T *p_AccRej, /* for return error */ H245_CONF_IND_T *p_conf_ind) /* out */ { static H245_TOTCAP_T rx_totcap; /* for receive caps */ static H245_TOTCAP_T tx_totcap; /* for transmit caps */ static H245_MUX_T RxMux; static H245_MUX_T TxMux; unsigned short choice; /* tmp for type of cap to routine */ HRESULT lError; Tracker_T *p_tracker; H245TRACE(pInstance->dwInst,10,"API:process_open_ind <-"); *p_AccRej = H245_ACC; /********************************/ /* check for forward parameters */ /********************************/ /* get forward Rx channel id */ p_conf_ind->u.Indication.u.IndOpen.RxChannel = *p_FwdChan = p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel.forwardLogicalChannelNumber; H245TRACE(pInstance->dwInst,20,"API:process_open_ind - channel = %d",p_conf_ind->u.Indication.u.IndOpen.RxChannel); /* get port number */ if (p_pdu_req->u.MltmdSystmCntrlMssg_rqst. u.openLogicalChannel.forwardLogicalChannelParameters.bit_mask & fLCPs_prtNmbr_present) { p_conf_ind->u.Indication.u.IndOpen.RxPort = p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel.forwardLogicalChannelParameters.fLCPs_prtNmbr; } else p_conf_ind->u.Indication.u.IndOpen.RxPort = H245_INVALID_PORT_NUMBER; /* ok.. forward data type selection */ switch (p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel.forwardLogicalChannelParameters.dataType.choice) { case DataType_nonStandard_chosen: H245TRACE(pInstance->dwInst,20,"API:process_open_ind - Rx nonStandard"); /* (TBD) what do I do here ?? */ *p_AccRej = H245_REJ_TYPE_NOTSUPPORT; return H245_ERROR_NOSUP; case nullData_chosen: H245TRACE(pInstance->dwInst,20,"API:process_open_ind - Rx nullData"); /* (TBD) what do I do here ?? */ *p_AccRej = H245_REJ_TYPE_NOTSUPPORT; return H245_ERROR_NOSUP; break; case DataType_videoData_chosen: H245TRACE(pInstance->dwInst,20,"API:process_open_ind - Rx videoData"); p_conf_ind->u.Indication.u.IndOpen.RxDataType = H245_DATA_VIDEO; choice = p_pdu_req->u.MltmdSystmCntrlMssg_rqst. u.openLogicalChannel.forwardLogicalChannelParameters.dataType. u.DataType_videoData.choice; break; case DataType_audioData_chosen: H245TRACE(pInstance->dwInst,20,"API:process_open_ind - Rx audioData"); p_conf_ind->u.Indication.u.IndOpen.RxDataType = H245_DATA_AUDIO; choice = p_pdu_req->u.MltmdSystmCntrlMssg_rqst. u.openLogicalChannel.forwardLogicalChannelParameters.dataType. u.DataType_audioData.choice; break; case DataType_data_chosen: H245TRACE(pInstance->dwInst,20,"API:process_open_ind - Rx dataData"); p_conf_ind->u.Indication.u.IndOpen.RxDataType = H245_DATA_DATA; choice = p_pdu_req->u.MltmdSystmCntrlMssg_rqst. u.openLogicalChannel.forwardLogicalChannelParameters.dataType. u.DataType_data.application.choice; break; case encryptionData_chosen: H245TRACE(pInstance->dwInst,20,"API:process_open_ind - Rx encryptionData"); /* (TBC) what do I do here ?? */ *p_AccRej = H245_REJ_TYPE_NOTSUPPORT; return H245_ERROR_NOSUP; break; default: H245TRACE(pInstance->dwInst,20,"API:process_open_ind - Rx encryptionData"); /* (TBC) what do I do here ?? */ *p_AccRej = H245_REJ_TYPE_UNKNOWN; return H245_ERROR_NOSUP; break; } /* load the tot cap's capability and client from capability */ /* this will give us the client type and the Capability for the indication */ if ((lError = build_totcap_cap_n_client_from_capability ((struct Capability *) &(p_pdu_req->u.MltmdSystmCntrlMssg_rqst. u.openLogicalChannel.forwardLogicalChannelParameters.dataType), p_conf_ind->u.Indication.u.IndOpen.RxDataType, choice, &rx_totcap)) != H245_ERROR_OK) { *p_AccRej = H245_REJ_TYPE_NOTSUPPORT; return lError; } /* load it from the totcap you just built.. then toss it aside.. like an empty can of soda.. */ p_conf_ind->u.Indication.u.IndOpen.RxClientType = rx_totcap.ClientType; p_conf_ind->u.Indication.u.IndOpen.pRxCap = &(rx_totcap.Cap); /* H.223/H.222 Mux table parameters for forward channel */ p_conf_ind->u.Indication.u.IndOpen.pRxMux = &RxMux; switch (p_pdu_req->u.MltmdSystmCntrlMssg_rqst. u.openLogicalChannel.forwardLogicalChannelParameters.multiplexParameters.choice) { case fLCPs_mPs_h223LCPs_chosen: /* H.223 Logical Parameters */ p_conf_ind->u.Indication.u.IndOpen.pRxMux->Kind = H245_H223; lError = load_H223_param(&RxMux.u.H223, &p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel.forwardLogicalChannelParameters.multiplexParameters.u.fLCPs_mPs_h223LCPs); if (lError != H245_ERROR_OK) { *p_AccRej = H245_REJ_AL_COMB; return lError; } break; case fLCPs_mPs_h222LCPs_chosen: /* H.222 Logical Parameters */ p_conf_ind->u.Indication.u.IndOpen.pRxMux->Kind = H245_H222; lError = load_H222_param(&RxMux.u.H222, &p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel.forwardLogicalChannelParameters.multiplexParameters.u.fLCPs_mPs_h222LCPs); break; case fLCPs_mPs_v76LCPs_chosen: /* VGMUX Logical Parameters */ p_conf_ind->u.Indication.u.IndOpen.pRxMux->Kind = H245_VGMUX; lError =load_VGMUX_param(&RxMux.u.VGMUX, &p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel.forwardLogicalChannelParameters.multiplexParameters.u.fLCPs_mPs_v76LCPs); break; case fLCPs_mPs_h2250LCPs_chosen: /* H.225.0 Logical Parameters */ p_conf_ind->u.Indication.u.IndOpen.pRxMux->Kind = H245_H2250; lError = load_H2250_param(&RxMux.u.H2250, &p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel.forwardLogicalChannelParameters.multiplexParameters.u.fLCPs_mPs_h2250LCPs); break; default: lError = H245_ERROR_NOSUP; } // switch if (lError != H245_ERROR_OK) { *p_AccRej = H245_REJ; return lError; } /********************************/ /* check for reverse parameters */ /********************************/ if (p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel.bit_mask & OLCl_rLCPs_present) { switch (p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel.OLCl_rLCPs.dataType.choice) { case DataType_nonStandard_chosen: H245TRACE(pInstance->dwInst,20,"API:process_open_ind - Tx nonStandard"); /* (TBC) what do I do here ?? */ *p_AccRej = H245_REJ_TYPE_NOTSUPPORT; return H245_ERROR_NOSUP; case nullData_chosen: H245TRACE(pInstance->dwInst,20,"API:process_open_ind - Tx nullData"); /* (TBC) what do I do here ?? */ *p_AccRej = H245_REJ_TYPE_NOTSUPPORT; return H245_ERROR_NOSUP; break; case DataType_videoData_chosen: H245TRACE(pInstance->dwInst,20,"API:process_open_ind - Tx videoData"); p_conf_ind->u.Indication.u.IndOpen.TxDataType = H245_DATA_VIDEO; choice = p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel.OLCl_rLCPs.dataType.u.DataType_videoData.choice; break; case DataType_audioData_chosen: H245TRACE(pInstance->dwInst,20,"API:process_open_ind - Tx audioData"); p_conf_ind->u.Indication.u.IndOpen.TxDataType = H245_DATA_AUDIO; choice = p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel.OLCl_rLCPs.dataType.u.DataType_audioData.choice; break; case DataType_data_chosen: H245TRACE(pInstance->dwInst,20,"API:process_open_ind - Tx dataData"); p_conf_ind->u.Indication.u.IndOpen.TxDataType = H245_DATA_DATA; choice = p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel.OLCl_rLCPs.dataType.u.DataType_data.application.choice; break; case encryptionData_chosen: H245TRACE(pInstance->dwInst,20,"API:process_open_ind - Tx encryptionData"); /* (TBC) what do I do here ?? */ *p_AccRej = H245_REJ_TYPE_NOTSUPPORT; return H245_ERROR_NOSUP; break; default: /* (TBC) what do I do here ?? */ *p_AccRej = H245_REJ_TYPE_UNKNOWN; H245TRACE(pInstance->dwInst,1,"API:process_open_ind - unknown choice %d", p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel.OLCl_rLCPs.dataType.choice); return H245_ERROR_NOSUP; } /* load the tot cap's capability and client from capability */ if ((lError = build_totcap_cap_n_client_from_capability ((struct Capability *) &(p_pdu_req->u.MltmdSystmCntrlMssg_rqst. u.openLogicalChannel.OLCl_rLCPs.dataType), p_conf_ind->u.Indication.u.IndOpen.TxDataType, choice, &tx_totcap)) != H245_ERROR_OK) { *p_AccRej = H245_REJ_TYPE_NOTSUPPORT; return lError; } p_conf_ind->u.Indication.u.IndOpen.TxClientType = tx_totcap.ClientType; p_conf_ind->u.Indication.u.IndOpen.pTxCap = &(tx_totcap.Cap); /* if H223/H222 Mux table parameters for reverse channel availalbe */ if (p_pdu_req->u.MltmdSystmCntrlMssg_rqst. u.openLogicalChannel.OLCl_rLCPs.bit_mask & OLCl_rLCPs_mltplxPrmtrs_present) { switch (p_pdu_req->u.MltmdSystmCntrlMssg_rqst. u.openLogicalChannel.OLCl_rLCPs.OLCl_rLCPs_mltplxPrmtrs.choice) { case rLCPs_mPs_h223LCPs_chosen: p_conf_ind->u.Indication.u.IndOpen.pTxMux = &TxMux; p_conf_ind->u.Indication.u.IndOpen.pTxMux->Kind = H245_H223; lError = load_H223_param(&TxMux.u.H223, &p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel. OLCl_rLCPs.OLCl_rLCPs_mltplxPrmtrs.u.rLCPs_mPs_h223LCPs); if (lError != H245_ERROR_OK) { *p_AccRej = H245_REJ_AL_COMB; return H245_ERROR_NOSUP; } break; case rLCPs_mPs_v76LCPs_chosen: p_conf_ind->u.Indication.u.IndOpen.pTxMux = &TxMux; p_conf_ind->u.Indication.u.IndOpen.pTxMux->Kind = H245_VGMUX; lError = load_VGMUX_param(&TxMux.u.VGMUX, &p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel. OLCl_rLCPs.OLCl_rLCPs_mltplxPrmtrs.u.rLCPs_mPs_v76LCPs); break; case rLCPs_mPs_h2250LCPs_chosen: p_conf_ind->u.Indication.u.IndOpen.pTxMux = &TxMux; p_conf_ind->u.Indication.u.IndOpen.pTxMux->Kind = H245_H2250; lError = load_H2250_param(&TxMux.u.H2250, &p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel. OLCl_rLCPs.OLCl_rLCPs_mltplxPrmtrs.u.rLCPs_mPs_h2250LCPs); break; default: lError = H245_ERROR_NOSUP; } if (lError != H245_ERROR_OK) { *p_AccRej = H245_REJ; return lError; } } /* if H223/H222 mux table reverse parameters */ } /* if reverse parameters present */ if (p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel.bit_mask & OpnLgclChnnl_sprtStck_present) { p_conf_ind->u.Indication.u.IndOpen.pSeparateStack = &p_pdu_req->u.MltmdSystmCntrlMssg_rqst.u.openLogicalChannel.OpnLgclChnnl_sprtStck; } /* conflict resolution .. just do it now.. */ /* only on opens.. of same data type .. */ #if 0 #ifndef LOOPBACK /* if master */ if (pInstance->API.MasterSlave == APIMS_Master) { p_tracker = NULL; while (p_tracker = find_tracker_by_type (dwInst, API_OPEN_CHANNEL_T, p_tracker)) { /* if allocated locally .. and incoming */ /* data type == outstanding incoming */ /* there is a conflict */ if ((p_tracker->u.Channel.ChannelAlloc == API_CH_ALLOC_LCL) && (p_tracker->u.Channel.DataType == p_conf_ind->u.Indication.u.IndOpen.RxDataType)) { *p_AccRej = H245_REJ; return H245_ERROR_INVALID_OP; } /* if conflict */ } /* while */ } /* if master */ #endif /* LOOPBACK */ #endif /* setup a tracker for this guy. */ p_tracker = alloc_link_tracker (pInstance, API_OPEN_CHANNEL_T, 0, API_ST_WAIT_LCLACK, API_CH_ALLOC_RMT, (p_pdu_req->u.MltmdSystmCntrlMssg_rqst. u.openLogicalChannel.bit_mask & OLCl_rLCPs_present)?API_CH_TYPE_BI:API_CH_TYPE_UNI, p_conf_ind->u.Indication.u.IndOpen.RxDataType, H245_INVALID_CHANNEL, p_conf_ind->u.Indication.u.IndOpen.RxChannel, 0); if (!(p_tracker)) { H245TRACE(pInstance->dwInst,1,"API:process_open_ind -> %s",map_api_error(H245_ERROR_NOMEM)); *p_AccRej = H245_REJ; return H245_ERROR_NOMEM; } H245TRACE(pInstance->dwInst,10,"API:process_open_ind -> OK"); return H245_ERROR_OK; } /***************************************************************************** * * TYPE: Local * * PROCEDURE: process_bi_open_rsp * * DESCRIPTION * * RETURN: * * ASSUME: * Callback must happen inside this routine since the * datastructures passed back to the application are allocated * in this moudle. * * Application will <<>> the needed data structures when * callback occurs.. * *****************************************************************************/ static HRESULT process_bi_open_rsp (struct InstanceStruct * pInstance, /* in */ MltmdSystmCntrlMssg *p_pdu_rsp, /* in */ H245_MUX_T *p_RxMux, /* in */ DWORD *p_RxChannel, /* out */ H245_CONF_IND_T *p_conf_ind /* out */ ) { H245TRACE(pInstance->dwInst,10,"API:process_bi_open_rsp <-"); p_conf_ind->u.Confirm.Error = H245_ERROR_OK; // Get Reverse Logical Channel Number *p_RxChannel = p_conf_ind->u.Confirm.u.ConfOpenNeedRsp.RxChannel = p_pdu_rsp->u.MSCMg_rspns.u.openLogicalChannelAck.OLCAk_rLCPs.reverseLogicalChannelNumber; // Get Reverse Port Number if (p_pdu_rsp->u.MSCMg_rspns.u.openLogicalChannelAck.OLCAk_rLCPs.bit_mask & rLCPs_prtNmbr_present) { p_conf_ind->u.Confirm.u.ConfOpenNeedRsp.RxPort = p_pdu_rsp->u.MSCMg_rspns.u.openLogicalChannelAck.OLCAk_rLCPs.rLCPs_prtNmbr; } if (p_pdu_rsp->u.MSCMg_rspns.u.openLogicalChannelAck.OLCAk_rLCPs.bit_mask & OLCAk_rLCPs_mPs_present) { // Get Reverse Logical Channel ACK Parameters switch (p_pdu_rsp->u.MSCMg_rspns.u.openLogicalChannelAck.OLCAk_rLCPs.OLCAk_rLCPs_mPs.choice) { case rLCPs_mPs_h222LCPs_chosen: p_RxMux->Kind = H245_H222; p_conf_ind->u.Confirm.Error = load_H222_param(&p_RxMux->u.H222, &p_pdu_rsp->u.MSCMg_rspns.u.openLogicalChannelAck.OLCAk_rLCPs.OLCAk_rLCPs_mPs.u.rLCPs_mPs_h222LCPs); p_conf_ind->u.Confirm.u.ConfOpenNeedRsp.pRxMux = p_RxMux; break; case mPs_h2250LgclChnnlPrmtrs_chosen: p_RxMux->Kind = H245_H2250ACK; p_conf_ind->u.Confirm.Error = load_H2250_param(&p_RxMux->u.H2250, &p_pdu_rsp->u.MSCMg_rspns.u.openLogicalChannelAck.OLCAk_rLCPs.OLCAk_rLCPs_mPs.u. mPs_h2250LgclChnnlPrmtrs); p_conf_ind->u.Confirm.u.ConfOpenNeedRsp.pRxMux = p_RxMux; break; default: H245TRACE(pInstance->dwInst,1,"API:process_bi_open_rsp - unknown choice %d", p_pdu_rsp->u.MSCMg_rspns.u.openLogicalChannelAck.OLCAk_rLCPs.OLCAk_rLCPs_mPs.choice); p_conf_ind->u.Confirm.Error = H245_ERROR_NOSUP; } // switch } H245TRACE(pInstance->dwInst,10,"API:process_bi_open_rsp -> OK"); return H245_ERROR_OK; } WORD awObject[64]; unsigned int ArrayFromObject(WORD *pwObject, unsigned uSize, POBJECTID pObject) { register unsigned int uLength = 0; while (pObject) { if (uLength >= uSize) { H245TRACE(0,1,"API:ArrayFromObject Object ID too long"); return uLength; } pwObject[uLength++] = (WORD) pObject->value; pObject = pObject->next; } return uLength; } // ArrayFromObject() /***************************************************************************** * * TYPE: Callback * * PROCEDURE: * * DESCRIPTION * * * RETURN: * *****************************************************************************/ static Tracker_T * TrackerValidate(struct InstanceStruct *pInstance, DWORD_PTR dwTransId) { register Tracker_T *pTracker = (Tracker_T *)dwTransId; if (find_tracker_by_pointer (pInstance, pTracker) != pTracker) { H245TRACE(pInstance->dwInst,1,"API:ValidateTracker -> Tracker Not Found"); return NULL; } return pTracker; } static DWORD_PTR TranslateTransId(struct InstanceStruct *pInstance, DWORD_PTR dwTransId) { register Tracker_T *pTracker = (Tracker_T *)dwTransId; if (pTracker == NULL) { H245TRACE(pInstance->dwInst,1,"API:TranslateTransId -> NULL Tracker"); return 0; } if (find_tracker_by_pointer (pInstance, pTracker) != pTracker) { H245TRACE(pInstance->dwInst,1,"API:TranslateTransId -> Tracker Not Found"); return 0; } return pTracker->TransId; } static void TrackerFree(struct InstanceStruct *pInstance, DWORD_PTR dwTransId) { register Tracker_T *pTracker = (Tracker_T *)dwTransId; if (pTracker == NULL) { H245TRACE(pInstance->dwInst,1,"API:TrackerFree -> NULL Tracker"); return; } if (find_tracker_by_pointer (pInstance, pTracker) != pTracker) { H245TRACE(pInstance->dwInst,1,"API:TrackerFree -> Tracker Not Found"); return; } unlink_dealloc_tracker (pInstance, pTracker); } static DWORD_PTR TranslateAndFree(struct InstanceStruct *pInstance, DWORD_PTR dwTransId) { register Tracker_T *pTracker = (Tracker_T *)dwTransId; if (pTracker == NULL) { H245TRACE(pInstance->dwInst,1,"API:TranslateAndFree -> NULL Tracker"); return 0; } if (find_tracker_by_pointer (pInstance, pTracker) != pTracker) { H245TRACE(pInstance->dwInst,1,"API:TranslateAndFree -> Tracker Not Found"); return 0; } dwTransId = pTracker->TransId; unlink_dealloc_tracker (pInstance, pTracker); return dwTransId; } static void TrackerNewState(struct InstanceStruct *pInstance, DWORD_PTR dwTransId, int nNewState) { register Tracker_T *pTracker = (Tracker_T *)dwTransId; if (pTracker == NULL) { H245TRACE(pInstance->dwInst,1,"API:TrackerNewState -> NULL Tracker"); return; } if (find_tracker_by_pointer (pInstance, pTracker) != pTracker) { H245TRACE(pInstance->dwInst,1,"API:TrackerNewState -> Tracker Not Found"); return; } pTracker->State = nNewState; } static WORD GetRxChannel(struct InstanceStruct *pInstance, DWORD_PTR dwTransId) { register Tracker_T *pTracker = (Tracker_T *)dwTransId; if (pTracker == NULL) { H245TRACE(pInstance->dwInst,1,"API:GetRxChannel -> NULL Tracker"); return 0; } if (find_tracker_by_pointer (pInstance, pTracker) != pTracker) { H245TRACE(pInstance->dwInst,1,"API:GetRxChannel -> Tracker Not Found"); return 0; } return (WORD)pTracker->u.Channel.RxChannel; } static WORD GetTxChannel(struct InstanceStruct *pInstance, DWORD_PTR dwTransId) { register Tracker_T *pTracker = (Tracker_T *)dwTransId; if (pTracker == NULL) { H245TRACE(pInstance->dwInst,1,"API:GetTxChannel -> NULL Tracker"); return 0; } if (find_tracker_by_pointer (pInstance, pTracker) != pTracker) { H245TRACE(pInstance->dwInst,1,"API:GetTxChannel -> Tracker Not Found"); return 0; } return (WORD)pTracker->u.Channel.TxChannel; } HRESULT H245FunctionNotUnderstood(struct InstanceStruct *pInstance, PDU_T *pPdu) { HRESULT hr = H245_ERROR_OK; MltmdSystmCntrlMssg *pMmPdu = NULL; pMmPdu = (MltmdSystmCntrlMssg *) MemAlloc(sizeof(MltmdSystmCntrlMssg)); if(NULL == pMmPdu) { return H245_ERROR_NOMEM; } memset(pMmPdu, 0, sizeof(MltmdSystmCntrlMssg)); pMmPdu->choice = indication_chosen; pMmPdu->u.indication.choice = functionNotUnderstood_chosen; pMmPdu->u.indication.u.functionNotUnderstood.choice = pPdu->choice; switch (pPdu->choice) { case FnctnNtUndrstd_request_chosen: pMmPdu->u.indication.u.functionNotUnderstood.u.FnctnNtUndrstd_request = pPdu->u.MltmdSystmCntrlMssg_rqst; break; case FnctnNtUndrstd_response_chosen: pMmPdu->u.indication.u.functionNotUnderstood.u.FnctnNtUndrstd_response = pPdu->u.MSCMg_rspns; break; case FnctnNtUndrstd_command_chosen: pMmPdu->u.indication.u.functionNotUnderstood.u.FnctnNtUndrstd_command = pPdu->u.MSCMg_cmmnd; default: MemFree(pMmPdu); return H245_ERROR_OK; } hr = sendPDU(pInstance, pMmPdu); MemFree(pMmPdu); return hr; } // H245FunctionNotUnderstood() HRESULT H245FsmConfirm (PDU_t * pPdu, DWORD dwEvent, struct InstanceStruct * pInstance, DWORD_PTR dwTransId, HRESULT lError) { H245_CONF_IND_T ConfInd; DWORD dwIndex; H245_MUX_T TxMux; H245_MUX_T RxMux; HRESULT lResult = H245_ERROR_OK; ASSERT(pInstance != NULL); ASSERT(pInstance->API.ConfIndCallBack != NULL); H245TRACE(pInstance->dwInst,4,"H245FsmConfirm <- Event=%s (%d)", map_fsm_event(dwEvent),dwEvent); memset (&ConfInd, 0, sizeof(ConfInd)); ConfInd.Kind = H245_CONF; ConfInd.u.Confirm.Confirm = dwEvent; ConfInd.u.Confirm.dwPreserved = pInstance->API.dwPreserved; ConfInd.u.Confirm.dwTransId = dwTransId; ConfInd.u.Confirm.Error = lError; switch (dwEvent) { /******************************/ /* */ /* master slave determination */ /* */ /******************************/ case H245_CONF_INIT_MSTSLV: ConfInd.u.Confirm.dwTransId = TranslateAndFree(pInstance, dwTransId); /* handle errors */ switch (lError) { case H245_ERROR_OK: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == mstrSlvDtrmntnAck_chosen); pInstance->API.SystemState = APIST_Connected; if (pPdu->u.MSCMg_rspns.u.mstrSlvDtrmntnAck.decision.choice == master_chosen) { pInstance->API.MasterSlave = APIMS_Master; ConfInd.u.Confirm.u.ConfMstSlv = H245_MASTER; } else { pInstance->API.MasterSlave = APIMS_Slave; ConfInd.u.Confirm.u.ConfMstSlv = H245_SLAVE; } break; case REJECT: H245TRACE(pInstance->dwInst,1,"H245FsmConfirm - Master Slave Reject"); ConfInd.u.Confirm.Error = H245_ERROR_UNKNOWN; ConfInd.u.Confirm.u.ConfMstSlv = H245_INDETERMINATE; break; case TIMER_EXPIRY: case ERROR_D_TIMEOUT: case ERROR_F_TIMEOUT: ConfInd.u.Confirm.Error = H245_ERROR_TIMEOUT; ConfInd.u.Confirm.u.ConfMstSlv = H245_INDETERMINATE; break; // case FUNCT_NOT_SUP: // case ERROR_A_INAPPROPRIATE: // case ERROR_B_INAPPROPRIATE: // case ERROR_C_INAPPROPRIATE: // case MS_FAILED: default: H245TRACE(pInstance->dwInst,1,"H245FsmConfirm - Master Slave Error %d", lError); ConfInd.u.Confirm.Error = H245_ERROR_UNKNOWN; ConfInd.u.Confirm.u.ConfMstSlv = H245_INDETERMINATE; break; } break; /****************************************/ /* */ /* Terminal Capability exchange confirm */ /* */ /****************************************/ case H245_CONF_SEND_TERMCAP: ConfInd.u.Confirm.dwTransId = TranslateAndFree(pInstance, dwTransId); /* determine errors */ switch (lError) { case H245_ERROR_OK: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == terminalCapabilitySetAck_chosen); ConfInd.u.Confirm.u.ConfSndTcap.AccRej = H245_ACC; clean_cap_table(&pInstance->API.PDU_LocalTermCap.u.MltmdSystmCntrlMssg_rqst.u.terminalCapabilitySet); break; case REJECT: ConfInd.u.Confirm.Error = H245_ERROR_OK; ConfInd.u.Confirm.u.ConfSndTcap.AccRej = H245_REJ; break; case TIMER_EXPIRY: case ERROR_D_TIMEOUT: case ERROR_F_TIMEOUT: ConfInd.u.Confirm.Error = H245_ERROR_TIMEOUT; break; // case FUNCT_NOT_SUP: // case ERROR_A_INAPPROPRIATE: // case ERROR_B_INAPPROPRIATE: // case ERROR_C_INAPPROPRIATE: default: H245TRACE(pInstance->dwInst,1,"H245FsmConfirm - Term Cap Error %d", lError); ConfInd.u.Confirm.Error = H245_ERROR_UNKNOWN; break; } break; /***************************************/ /* */ /* unidirectional logical channel open */ /* */ /***************************************/ case H245_CONF_OPEN: ConfInd.u.Confirm.dwTransId = TranslateTransId(pInstance, dwTransId); ConfInd.u.Confirm.u.ConfOpen.TxChannel = GetTxChannel(pInstance, dwTransId); ConfInd.u.Confirm.u.ConfOpen.RxPort = H245_INVALID_PORT_NUMBER; /* determine errors */ switch (lError) { case H245_ERROR_OK: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == openLogicalChannelAck_chosen); ASSERT((pPdu->u.MSCMg_rspns.u.openLogicalChannelAck.bit_mask & OLCAk_rLCPs_present) == 0); if (pPdu->u.MSCMg_rspns.u.openLogicalChannelAck.bit_mask & OLCAk_sprtStck_present) { ConfInd.u.Confirm.u.ConfOpen.pSeparateStack = &pPdu->u.MSCMg_rspns.u.openLogicalChannelAck.OLCAk_sprtStck; } if (pPdu->u.MSCMg_rspns.u.openLogicalChannelAck.bit_mask & frwrdMltplxAckPrmtrs_present) { switch (pPdu->u.MSCMg_rspns.u.openLogicalChannelAck.frwrdMltplxAckPrmtrs.choice) { case h2250LgclChnnlAckPrmtrs_chosen: TxMux.Kind = H245_H2250ACK; load_H2250ACK_param(&TxMux.u.H2250ACK, &pPdu->u.MSCMg_rspns.u.openLogicalChannelAck.frwrdMltplxAckPrmtrs.u.h2250LgclChnnlAckPrmtrs); ConfInd.u.Confirm.u.ConfOpen.pTxMux = &TxMux; break; } // switch } ConfInd.u.Confirm.u.ConfOpen.AccRej = H245_ACC; TrackerNewState(pInstance,dwTransId,API_ST_IDLE); break; case REJECT: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == openLogicalChannelReject_chosen); ConfInd.u.Confirm.Error = H245_ERROR_OK; ConfInd.u.Confirm.u.ConfOpen.AccRej = pPdu->u.MSCMg_rspns.u.openLogicalChannelReject.cause.choice; TrackerFree(pInstance,dwTransId); break; case TIMER_EXPIRY: case ERROR_D_TIMEOUT: case ERROR_F_TIMEOUT: ConfInd.u.Confirm.Error = H245_ERROR_TIMEOUT; ConfInd.u.Confirm.u.ConfOpen.AccRej = H245_REJ; TrackerFree(pInstance,dwTransId); break; // case FUNCT_NOT_SUP: // case ERROR_A_INAPPROPRIATE: // case ERROR_B_INAPPROPRIATE: // case ERROR_C_INAPPROPRIATE: default: H245TRACE(pInstance->dwInst,1,"H245FsmConfirm - Open Channel Error %d", lError); ConfInd.u.Confirm.Error = H245_ERROR_UNKNOWN; ConfInd.u.Confirm.u.ConfOpen.AccRej = H245_REJ; TrackerFree(pInstance,dwTransId); } break; /***********************************************/ /* */ /* bidirectional logical channel open (TBD)??? */ /* */ /***********************************************/ case H245_CONF_NEEDRSP_OPEN: { Tracker_T *pTracker; pTracker = TrackerValidate(pInstance, dwTransId); if (pTracker == NULL) return H245_ERROR_OK; ConfInd.u.Confirm.dwTransId = pTracker->TransId; ConfInd.u.Confirm.u.ConfOpenNeedRsp.TxChannel = (WORD)pTracker->u.Channel.TxChannel; ConfInd.u.Confirm.u.ConfOpenNeedRsp.RxPort = H245_INVALID_PORT_NUMBER; /* determine errors */ switch (lError) { case H245_ERROR_OK: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == openLogicalChannelAck_chosen); ASSERT((pPdu->u.MSCMg_rspns.u.openLogicalChannelAck.bit_mask & OLCAk_rLCPs_present) != 0); ConfInd.u.Confirm.u.ConfOpenNeedRsp.AccRej = H245_ACC; if (pPdu->u.MSCMg_rspns.u.openLogicalChannelAck.bit_mask & OLCAk_sprtStck_present) { ConfInd.u.Confirm.u.ConfOpenNeedRsp.pSeparateStack = &pPdu->u.MSCMg_rspns.u.openLogicalChannelAck.OLCAk_sprtStck; } if (pPdu->u.MSCMg_rspns.u.openLogicalChannelAck.bit_mask & frwrdMltplxAckPrmtrs_present) { switch (pPdu->u.MSCMg_rspns.u.openLogicalChannelAck.frwrdMltplxAckPrmtrs.choice) { case h2250LgclChnnlAckPrmtrs_chosen: TxMux.Kind = H245_H2250ACK; load_H2250ACK_param(&TxMux.u.H2250ACK, &pPdu->u.MSCMg_rspns.u.openLogicalChannelAck.frwrdMltplxAckPrmtrs.u.h2250LgclChnnlAckPrmtrs); ConfInd.u.Confirm.u.ConfOpenNeedRsp.pTxMux = &TxMux; break; } // switch } /* NOTE Receive Channel is assigned in this call */ process_bi_open_rsp (pInstance, pPdu, &RxMux, &(pTracker->u.Channel.RxChannel), &ConfInd); /* NOTE: this is a special case since we have to assign */ /* the receive channel to the tracker.. otherwise we */ /* will not be able to find it later.. */ /* Here we have to update both the state, and the channel */ pTracker->State = API_ST_WAIT_CONF; break; case REJECT: ConfInd.u.Confirm.Confirm = H245_CONF_OPEN; ConfInd.u.Confirm.u.ConfOpen.TxChannel = (WORD)pTracker->u.Channel.TxChannel; ConfInd.u.Confirm.Error = H245_ERROR_OK; ConfInd.u.Confirm.u.ConfOpen.AccRej = pPdu->u.MSCMg_rspns.u.openLogicalChannelReject.cause.choice; unlink_dealloc_tracker (pInstance, pTracker); break; case TIMER_EXPIRY: case ERROR_D_TIMEOUT: case ERROR_F_TIMEOUT: ConfInd.u.Confirm.Confirm = H245_CONF_OPEN; ConfInd.u.Confirm.u.ConfOpen.TxChannel = (WORD)pTracker->u.Channel.TxChannel; ConfInd.u.Confirm.Error = H245_ERROR_TIMEOUT; ConfInd.u.Confirm.u.ConfOpen.AccRej = H245_REJ; unlink_dealloc_tracker (pInstance, pTracker); break; // case FUNCT_NOT_SUP: // case ERROR_A_INAPPROPRIATE: // case ERROR_B_INAPPROPRIATE: // case ERROR_C_INAPPROPRIATE: default: H245TRACE(pInstance->dwInst,1,"H245FsmConfirm - Open Channel Error %d", lError); ConfInd.u.Confirm.Confirm = H245_CONF_OPEN; ConfInd.u.Confirm.u.ConfOpen.TxChannel = (WORD)pTracker->u.Channel.TxChannel; ConfInd.u.Confirm.Error = H245_ERROR_UNKNOWN; ConfInd.u.Confirm.u.ConfOpen.AccRej = H245_REJ; unlink_dealloc_tracker (pInstance, pTracker); } } break; /************************************************/ /* */ /* unidirectional logical channel close */ /* */ /* bidirection logical channel close */ /* */ /************************************************/ case H245_CONF_CLOSE: ConfInd.u.Confirm.dwTransId = TranslateTransId(pInstance, dwTransId); ConfInd.u.Confirm.u.ConfClose.Channel = GetTxChannel(pInstance, dwTransId); ConfInd.u.Confirm.u.ConfClose.AccRej = H245_ACC; /* determine errors */ switch (lError) { case H245_ERROR_OK: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == closeLogicalChannelAck_chosen); ConfInd.u.Confirm.u.ConfClose.AccRej = H245_ACC; TrackerFree(pInstance,dwTransId); break; case REJECT: /* should never be rejected */ H245TRACE(pInstance->dwInst,1,"H245FsmConfirm - Close Channel Rejected"); TrackerNewState(pInstance,dwTransId,API_ST_IDLE); ConfInd.u.Confirm.Error = H245_ERROR_UNKNOWN; ConfInd.u.Confirm.u.ConfClose.AccRej = H245_REJ; break; case TIMER_EXPIRY: case ERROR_D_TIMEOUT: case ERROR_F_TIMEOUT: TrackerNewState(pInstance,dwTransId,API_ST_IDLE); ConfInd.u.Confirm.Error = H245_ERROR_TIMEOUT; ConfInd.u.Confirm.u.ConfClose.AccRej = H245_REJ; break; // case FUNCT_NOT_SUP: // case ERROR_A_INAPPROPRIATE: // case ERROR_B_INAPPROPRIATE: // case ERROR_C_INAPPROPRIATE: default: H245TRACE(pInstance->dwInst,1,"H245FsmConfirm - Close Channel Error %d", lError); TrackerNewState(pInstance,dwTransId,API_ST_IDLE); ConfInd.u.Confirm.Error = H245_ERROR_UNKNOWN; ConfInd.u.Confirm.u.ConfClose.AccRej = H245_REJ; } break; /***************************/ /* */ /* request channel close */ /* */ /***************************/ case H245_CONF_REQ_CLOSE: ConfInd.u.Confirm.dwTransId = TranslateTransId(pInstance, dwTransId); ConfInd.u.Confirm.u.ConfReqClose.Channel = GetRxChannel(pInstance, dwTransId); TrackerNewState(pInstance,dwTransId,API_ST_IDLE); /* determine errors */ switch (lError) { case H245_ERROR_OK: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == requestChannelCloseAck_chosen); ConfInd.u.Confirm.u.ConfReqClose.AccRej = H245_ACC; break; case REJECT: ConfInd.u.Confirm.Error = H245_ERROR_OK; ConfInd.u.Confirm.u.ConfReqClose.AccRej = H245_REJ; break; case TIMER_EXPIRY: case ERROR_D_TIMEOUT: case ERROR_F_TIMEOUT: ConfInd.u.Confirm.Error = H245_ERROR_TIMEOUT; ConfInd.u.Confirm.u.ConfReqClose.AccRej = H245_REJ; break; // case FUNCT_NOT_SUP: // case ERROR_A_INAPPROPRIATE: // case ERROR_B_INAPPROPRIATE: // case ERROR_C_INAPPROPRIATE: default: H245TRACE(pInstance->dwInst,1,"H245FsmConfirm - Request Channel Close Error %d", lError); ConfInd.u.Confirm.Error = H245_ERROR_UNKNOWN; ConfInd.u.Confirm.u.ConfReqClose.AccRej = H245_REJ; } break; /*******************/ /* */ /* mux table entry */ /* */ /*******************/ case H245_CONF_MUXTBL_SND: { UINT ii; Tracker_T *pTracker; pTracker = TrackerValidate(pInstance, dwTransId); if (pTracker == NULL) return H245_ERROR_OK; ConfInd.u.Confirm.dwTransId = pTracker->TransId; switch (lError) { case H245_ERROR_OK: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == multiplexEntrySendAck_chosen); for (ii = 0; ii < pPdu->u.MSCMg_rspns.u.multiplexEntrySendAck.multiplexTableEntryNumber.count; ii ++) { pTracker->u.MuxEntryCount--; ConfInd.u.Confirm.u.ConfMuxSnd.MuxEntryId = pPdu->u.MSCMg_rspns.u.multiplexEntrySendAck.multiplexTableEntryNumber.value[ii]; ConfInd.u.Confirm.u.ConfMuxSnd.AccRej = H245_ACC; if ((*pInstance->API.ConfIndCallBack)(&ConfInd, &pPdu->u.MSCMg_rspns.u.multiplexEntrySendAck) == H245_ERROR_NOSUP) { H245FunctionNotUnderstood(pInstance, pPdu); } pTracker = TrackerValidate(pInstance, dwTransId); if (pTracker == NULL) return H245_ERROR_OK; } if (pTracker->u.MuxEntryCount == 0) { unlink_dealloc_tracker (pInstance, pTracker); } pPdu = NULL; // Don't do callback again! break; case REJECT: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == multiplexEntrySendReject_chosen); ConfInd.u.Confirm.Error = H245_ERROR_OK; for (ii = 0; ii < pPdu->u.MSCMg_rspns.u.multiplexEntrySendReject.rejectionDescriptions.count; ++ii) { pTracker->u.MuxEntryCount--; ConfInd.u.Confirm.u.ConfMuxSnd.MuxEntryId = pPdu->u.MSCMg_rspns.u.multiplexEntrySendReject.rejectionDescriptions.value[ii].multiplexTableEntryNumber; switch (pPdu->u.MSCMg_rspns.u.multiplexEntrySendReject.rejectionDescriptions.value[ii].cause.choice) { default: H245PANIC(); case MERDs_cs_unspcfdCs_chosen: ConfInd.u.Confirm.u.ConfMuxSnd.AccRej = H245_REJ; /* unspecified */ break; case descriptorTooComplex_chosen: ConfInd.u.Confirm.u.ConfMuxSnd.AccRej = H245_REJ_MUX_COMPLICATED; break; } if ((*pInstance->API.ConfIndCallBack)(&ConfInd, &pPdu->u.MSCMg_rspns.u.multiplexEntrySendReject) == H245_ERROR_NOSUP) { H245FunctionNotUnderstood(pInstance, pPdu); } pTracker = TrackerValidate(pInstance, dwTransId); if (pTracker == NULL) return H245_ERROR_OK; } if (pTracker->u.MuxEntryCount == 0) { unlink_dealloc_tracker (pInstance, pTracker); } pPdu = NULL; // Don't do callback again! break; case TIMER_EXPIRY: case ERROR_D_TIMEOUT: case ERROR_F_TIMEOUT: unlink_dealloc_tracker (pInstance, pTracker); ConfInd.u.Confirm.Error = H245_ERROR_TIMEOUT; break; // case FUNCT_NOT_SUP: // case ERROR_A_INAPPROPRIATE: // case ERROR_B_INAPPROPRIATE: // case ERROR_C_INAPPROPRIATE: default: H245TRACE(pInstance->dwInst,1,"H245FsmConfirm - Mux Table Send Error %d", lError); unlink_dealloc_tracker (pInstance, pTracker); ConfInd.u.Confirm.Error = H245_ERROR_UNKNOWN; } // switch } break; case H245_CONF_RMESE: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == requestMultiplexEntryAck_chosen); ConfInd.u.Confirm.u.ConfRmese.dwCount = pPdu->u.MSCMg_rspns.u.requestMultiplexEntryAck.entryNumbers.count; for (dwIndex = 0; dwIndex < ConfInd.u.Confirm.u.ConfRmese.dwCount; ++dwIndex) { ConfInd.u.Confirm.u.ConfRmese.awMultiplexTableEntryNumbers[dwIndex] = pPdu->u.MSCMg_rspns.u.requestMultiplexEntryAck.entryNumbers.value[dwIndex]; } break; case H245_CONF_RMESE_REJECT: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == rqstMltplxEntryRjct_chosen); ConfInd.u.Confirm.u.ConfRmeseReject.dwCount = pPdu->u.MSCMg_rspns.u.rqstMltplxEntryRjct.rejectionDescriptions.count; for (dwIndex = 0; dwIndex < ConfInd.u.Confirm.u.ConfRmeseReject.dwCount; ++dwIndex) { ConfInd.u.Confirm.u.ConfRmeseReject.awMultiplexTableEntryNumbers[dwIndex] = pPdu->u.MSCMg_rspns.u.rqstMltplxEntryRjct.rejectionDescriptions.value[dwIndex].multiplexTableEntryNumber; } break; case H245_CONF_RMESE_EXPIRED: ASSERT(pPdu == NULL); break; case H245_CONF_MRSE: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == requestModeAck_chosen); ConfInd.u.Confirm.u.ConfMrse = pPdu->u.MSCMg_rspns.u.requestModeAck.response.choice; break; case H245_CONF_MRSE_REJECT: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == requestModeReject_chosen); ConfInd.u.Confirm.u.ConfMrseReject = pPdu->u.MSCMg_rspns.u.requestModeReject.cause.choice; break; case H245_CONF_MRSE_EXPIRED: ASSERT(pPdu == NULL); break; case H245_CONF_MLSE: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == maintenanceLoopAck_chosen); ConfInd.u.Confirm.u.ConfMlse.LoopType = pPdu->u.MSCMg_rspns.u.maintenanceLoopAck.type.choice; switch (pPdu->u.MSCMg_rspns.u.maintenanceLoopAck.type.choice) { case systemLoop_chosen: ConfInd.u.Confirm.u.ConfMlse.Channel = 0; break; case mediaLoop_chosen: case logicalChannelLoop_chosen: ConfInd.u.Confirm.u.ConfMlse.Channel = pPdu->u.MSCMg_rspns.u.maintenanceLoopAck.type.u.mediaLoop; break; default: H245TRACE(pInstance->dwInst,1, "H245FsmConfirm: Invalid Maintenance Loop Ack type %d", pPdu->u.MSCMg_rspns.u.maintenanceLoopAck.type.choice); lResult = H245_ERROR_NOSUP; } // switch break; case H245_CONF_MLSE_REJECT: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == maintenanceLoopReject_chosen); ConfInd.u.Confirm.u.ConfMlseReject.LoopType = pPdu->u.MSCMg_rspns.u.maintenanceLoopReject.type.choice; switch (pPdu->u.MSCMg_rspns.u.maintenanceLoopReject.type.choice) { case systemLoop_chosen: ConfInd.u.Confirm.u.ConfMlseReject.Channel = 0; break; case mediaLoop_chosen: case logicalChannelLoop_chosen: ConfInd.u.Confirm.u.ConfMlseReject.Channel = pPdu->u.MSCMg_rspns.u.maintenanceLoopReject.type.u.mediaLoop; break; default: H245TRACE(pInstance->dwInst,1, "H245FsmConfirm: Invalid Maintenance Loop Reject type %d", pPdu->u.MSCMg_rspns.u.maintenanceLoopReject.type.choice); lResult = H245_ERROR_NOSUP; } // switch break; case H245_CONF_MLSE_EXPIRED: ASSERT(pPdu == NULL); break; case H245_CONF_RTDSE: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == roundTripDelayResponse_chosen); break; case H245_CONF_RTDSE_EXPIRED: ASSERT(pPdu == NULL); break; default: /* Possible Error */ H245TRACE(pInstance->dwInst, 1, "H245FsmConfirm -> Invalid Confirm Event %d", dwEvent); return H245_ERROR_SUBSYS; } // switch if (lResult == H245_ERROR_OK) { if (pPdu) { if ((*pInstance->API.ConfIndCallBack)(&ConfInd, &pPdu->u.MSCMg_rspns.u) == H245_ERROR_NOSUP) { H245FunctionNotUnderstood(pInstance, pPdu); } } else { (*pInstance->API.ConfIndCallBack)(&ConfInd, NULL); } H245TRACE(pInstance->dwInst,4,"H245FsmConfirm -> OK"); } else { H245TRACE(pInstance->dwInst,1,"H245FsmConfirm -> %s", map_api_error(lResult)); } return lResult; } // H245FsmConfirm() HRESULT H245FsmIndication (PDU_t * pPdu, DWORD dwEvent, struct InstanceStruct * pInstance, DWORD_PTR dwTransId, HRESULT lError) { H245_CONF_IND_T ConfInd; DWORD dwIndex; MltmdSystmCntrlMssg *pRsp; HRESULT lResult = H245_ERROR_OK; #if 1 int nLength; WCHAR * pwchar = NULL; #endif ASSERT(dwEvent == H245_IND_OPEN_CONF || pPdu != NULL); ASSERT(pInstance != NULL); ASSERT(pInstance->API.ConfIndCallBack != NULL); H245TRACE(pInstance->dwInst,4,"H245FsmIndication <- Event=%s (%d)", map_fsm_event(dwEvent),dwEvent); memset (&ConfInd, 0, sizeof(ConfInd)); ConfInd.Kind = H245_IND; ConfInd.u.Indication.Indicator = dwEvent; ConfInd.u.Indication.dwPreserved = pInstance->API.dwPreserved; switch (dwEvent) { /******************************/ /* */ /* master slave determination */ /* */ /******************************/ case H245_IND_MSTSLV: /* handle errors */ switch (lError) { case H245_ERROR_OK: ASSERT(pPdu != NULL); ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == mstrSlvDtrmntnAck_chosen); pInstance->API.SystemState = APIST_Connected; if (pPdu->u.MSCMg_rspns.u.mstrSlvDtrmntnAck.decision.choice == master_chosen) { pInstance->API.MasterSlave = APIMS_Master; ConfInd.u.Indication.u.IndMstSlv = H245_MASTER; } else { pInstance->API.MasterSlave = APIMS_Slave; ConfInd.u.Indication.u.IndMstSlv = H245_SLAVE; } break; case MS_FAILED: case REJECT: case TIMER_EXPIRY: ConfInd.u.Indication.u.IndMstSlv = H245_INDETERMINATE; break; // case ERROR_D_TIMEOUT: // case ERROR_F_TIMEOUT: // case FUNCT_NOT_SUP: // case ERROR_A_INAPPROPRIATE: // case ERROR_B_INAPPROPRIATE: // case ERROR_C_INAPPROPRIATE: default: H245PANIC(); /* (TBC) */ return H245_ERROR_OK; } break; /****************************************/ /* */ /* Terminal Capability exchange */ /* */ /****************************************/ /* decode_termcapset breaks the termcap set up and sends up */ /* a single indication to the client */ case H245_IND_CAP: ASSERT(pPdu->choice == MltmdSystmCntrlMssg_rqst_chosen); ASSERT(pPdu->u.MltmdSystmCntrlMssg_rqst.choice == terminalCapabilitySet_chosen); pRsp = (PDU_t *)MemAlloc(sizeof(*pPdu)); if (pRsp == NULL) { H245TRACE(pInstance->dwInst,1,"H245FsmIndication TermCap: no memory for response"); return H245_ERROR_NOMEM; } memset(pRsp, 0, sizeof(*pRsp)); process_term_cap_set_ind (pInstance, pPdu, pRsp); FsmOutgoing(pInstance, pRsp, 0); MemFree (pRsp); break; case H245_IND_CESE_RELEASE: break; /************************************************/ /* */ /* unidirectional logical channel open */ /* */ /* bidirectional logical channel open */ /* */ /************************************************/ case H245_IND_OPEN: ASSERT(pPdu->choice == MltmdSystmCntrlMssg_rqst_chosen); ASSERT(pPdu->u.MltmdSystmCntrlMssg_rqst.choice == openLogicalChannel_chosen); { unsigned short forward_channel; H245_ACC_REJ_T acc_rej; /* if error, process_open_ind will tell us what to send for reject */ if (process_open_ind(pInstance,pPdu,&forward_channel,&acc_rej,&ConfInd) != H245_ERROR_OK) { // Reject the open pRsp = (PDU_t *)MemAlloc(sizeof(*pPdu)); if (pRsp == NULL) { H245TRACE(pInstance->dwInst,1,"H245FsmIndication TermCap: no memory for response"); return H245_ERROR_NOMEM; } memset(pRsp, 0, sizeof(*pRsp)); pdu_rsp_open_logical_channel_rej(pRsp, forward_channel, (WORD)acc_rej); FsmOutgoing(pInstance, pRsp, 0); MemFree (pRsp); } } break; /************************************************/ /* */ /* Confirm bi-directional open */ /* */ /************************************************/ case H245_IND_OPEN_CONF: #if defined(_DEBUG) if (lError == H245_ERROR_OK) { ASSERT(pPdu != NULL); ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == opnLgclChnnlCnfrm_chosen); } #endif { Tracker_T *pTracker; pTracker = TrackerValidate(pInstance, dwTransId); if (pTracker == NULL) return H245_ERROR_OK; /* confirm processing */ ASSERT(pTracker->State == API_ST_WAIT_CONF); ASSERT(pTracker->TrackerType == API_OPEN_CHANNEL_T); ASSERT(pTracker->u.Channel.ChannelAlloc == API_CH_ALLOC_RMT); ASSERT(pTracker->u.Channel.ChannelType == API_CH_TYPE_BI); ConfInd.u.Indication.u.IndOpenConf.RxChannel = (WORD)pTracker->u.Channel.RxChannel; ConfInd.u.Indication.u.IndOpenConf.TxChannel = (WORD)pTracker->u.Channel.TxChannel; pTracker->State = API_ST_IDLE; } break; /************************************************/ /* */ /* unidirectional logical channel close */ /* */ /* bidirectional logical channel close */ /* */ /************************************************/ case H245_IND_CLOSE: ASSERT(pPdu->choice == MltmdSystmCntrlMssg_rqst_chosen); ASSERT(pPdu->u.MltmdSystmCntrlMssg_rqst.choice == closeLogicalChannel_chosen); { Tracker_T *pTracker; ConfInd.u.Indication.u.IndClose.Channel = pPdu->u.MltmdSystmCntrlMssg_rqst.u.closeLogicalChannel.forwardLogicalChannelNumber; ConfInd.u.Indication.u.IndClose.Reason = (pPdu->u.MltmdSystmCntrlMssg_rqst.u.closeLogicalChannel.source.choice==user_chosen)?H245_USER:H245_LCSE; /* find the tracker */ pTracker = find_tracker_by_rxchannel (pInstance, ConfInd.u.Indication.u.IndClose.Channel, API_CH_ALLOC_RMT); if (!pTracker) { H245TRACE(pInstance->dwInst,4,"H245FsmIndication -> close indication - Tracker not found"); return H245_ERROR_OK; } unlink_dealloc_tracker (pInstance, pTracker); } break; /************************************************/ /* */ /* request channel close */ /* */ /************************************************/ case H245_IND_REQ_CLOSE: ASSERT(pPdu->choice == MltmdSystmCntrlMssg_rqst_chosen); ASSERT(pPdu->u.MltmdSystmCntrlMssg_rqst.choice == requestChannelClose_chosen); { Tracker_T *pTracker; ConfInd.u.Indication.u.IndReqClose = pPdu->u.MltmdSystmCntrlMssg_rqst.u.requestChannelClose.forwardLogicalChannelNumber; /* find the tracker */ pTracker = find_tracker_by_txchannel (pInstance, ConfInd.u.Indication.u.IndReqClose, API_CH_ALLOC_LCL); if (!pTracker) { H245TRACE(pInstance->dwInst,4,"H245FsmIndication Request Channel Close: Tracker not found"); pRsp = (PDU_t *)MemAlloc(sizeof(*pPdu)); if (pRsp == NULL) { H245TRACE(pInstance->dwInst,1,"H245FsmIndication Request Channel Close: no memory for response"); return H245_ERROR_NOMEM; } memset(pRsp, 0, sizeof(*pRsp)); /* can't find it.. must be closed.. respond anyway */ pdu_rsp_request_channel_close_rej(pRsp, (WORD)ConfInd.u.Indication.u.IndReqClose,H245_REJ); FsmOutgoing(pInstance, pRsp, 0); MemFree(pRsp); /* Possible Error.. could have been removed from list or */ /* could have been allocated remotely... and this is a protocol */ /* error */ return H245_ERROR_OK; } ASSERT(pTracker->State == API_ST_IDLE); pTracker->State = API_ST_WAIT_LCLACK; pTracker->TrackerType = API_CLOSE_CHANNEL_T; } break; /************************************************/ /* */ /* Release Close Request */ /* */ /************************************************/ case H245_IND_CLCSE_RELEASE: ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == rqstChnnlClsRls_chosen); { Tracker_T *pTracker; /* find tracker.. and set to LCLACK_CANCEL */ /* this will tell api to notify user */ pTracker = find_tracker_by_txchannel (pInstance, pPdu->u.indication.u.rqstChnnlClsRls.forwardLogicalChannelNumber, API_CH_ALLOC_LCL); if (pTracker) { if (pTracker->State != API_ST_WAIT_LCLACK) { return H245_ERROR_INVALID_INST; } pTracker->State = API_ST_WAIT_LCLACK_CANCEL; } else { H245TRACE(pInstance->dwInst,1,"H245FsmIndication -> IND_REL_CLSE: Cancel.. NO TRACKER FOUND"); } } break; /************************************************/ /* */ /* mux table entry */ /* */ /************************************************/ case H245_IND_MUX_TBL: ASSERT(pPdu->choice == MltmdSystmCntrlMssg_rqst_chosen); ASSERT(pPdu->u.MltmdSystmCntrlMssg_rqst.choice == multiplexEntrySend_chosen); { unsigned short seq_num; H245_ACC_REJ_MUX_T rej_mux; H245_MUX_TABLE_T *p_mux_tbl; DWORD rej_cnt; DWORD acc_cnt; Tracker_T *pTracker; /* process the mux table entry */ p_mux_tbl = process_mux_table_ind(pPdu,&seq_num,rej_mux,&rej_cnt,&acc_cnt); if (rej_cnt) { /* build the reject pdu from the rej_mux table */ if (!(pRsp = (MltmdSystmCntrlMssg *)MemAlloc(sizeof(MltmdSystmCntrlMssg)))) return H245_ERROR_NOMEM; memset(pRsp, 0, sizeof(MltmdSystmCntrlMssg)); pdu_rsp_mux_table_rej (pRsp,seq_num,rej_mux,(rej_cnt+acc_cnt)); FsmOutgoing(pInstance, pRsp, 0); MemFree(pRsp); } /* if there are any left to send up. */ if (p_mux_tbl) { if (!(pTracker = alloc_link_tracker (pInstance, API_RECV_MUX_T, /* use the TransId.. for the sequence number */ seq_num, API_ST_WAIT_LCLACK, API_CH_ALLOC_UNDEF, API_CH_TYPE_UNDEF, 0, H245_INVALID_CHANNEL, H245_INVALID_CHANNEL, 0))) { free_mux_table_list (p_mux_tbl); H245TRACE(pInstance->dwInst,1,"API:process_open_ind -> %s",map_api_error(H245_ERROR_NOMEM)); /* (TBC) this should be a fatal error */ H245PANIC(); break; } pTracker->u.MuxEntryCount = acc_cnt; ConfInd.u.Indication.u.IndMuxTbl.Count = acc_cnt; ConfInd.u.Indication.u.IndMuxTbl.pMuxTbl = p_mux_tbl; if ((*pInstance->API.ConfIndCallBack)(&ConfInd, &pPdu->u.MltmdSystmCntrlMssg_rqst.u) == H245_ERROR_NOSUP) { H245FunctionNotUnderstood(pInstance, pPdu); } free_mux_table_list (p_mux_tbl); return H245_ERROR_OK; } } break; case H245_IND_MTSE_RELEASE: ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == mltplxEntrySndRls_chosen); break; case H245_IND_RMESE: ASSERT(pPdu->choice == MltmdSystmCntrlMssg_rqst_chosen); ASSERT(pPdu->u.MltmdSystmCntrlMssg_rqst.choice == requestMultiplexEntry_chosen); ConfInd.u.Indication.u.IndRmese.dwCount = pPdu->u.MltmdSystmCntrlMssg_rqst.u.requestMultiplexEntry.entryNumbers.count; for (dwIndex = 0; dwIndex < ConfInd.u.Indication.u.IndRmese.dwCount; ++dwIndex) { ConfInd.u.Indication.u.IndRmese.awMultiplexTableEntryNumbers[dwIndex] = pPdu->u.MltmdSystmCntrlMssg_rqst.u.requestMultiplexEntry.entryNumbers.value[dwIndex]; } break; case H245_IND_RMESE_RELEASE: ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == rqstMltplxEntryRls_chosen); break; case H245_IND_MRSE: ASSERT(pPdu->choice == MltmdSystmCntrlMssg_rqst_chosen); ASSERT(pPdu->u.MltmdSystmCntrlMssg_rqst.choice == requestMode_chosen); ConfInd.u.Indication.u.IndMrse.pRequestedModes = pPdu->u.MltmdSystmCntrlMssg_rqst.u.requestMode.requestedModes; break; case H245_IND_MRSE_RELEASE: ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == requestModeRelease_chosen); break; case H245_IND_MLSE: ASSERT(pPdu->choice == MltmdSystmCntrlMssg_rqst_chosen); ASSERT(pPdu->u.MltmdSystmCntrlMssg_rqst.choice == maintenanceLoopRequest_chosen); ConfInd.u.Indication.u.IndMlse.LoopType = pPdu->u.MltmdSystmCntrlMssg_rqst.u.maintenanceLoopRequest.type.choice; if (ConfInd.u.Indication.u.IndMlse.LoopType == systemLoop_chosen) ConfInd.u.Indication.u.IndMlse.Channel = 0; else ConfInd.u.Indication.u.IndMlse.Channel = pPdu->u.MltmdSystmCntrlMssg_rqst.u.maintenanceLoopRequest.type.u.mediaLoop; break; case H245_IND_MLSE_RELEASE: ASSERT(pPdu->choice == MSCMg_cmmnd_chosen); ASSERT(pPdu->u.MSCMg_cmmnd.choice == mntnncLpOffCmmnd_chosen); break; case H245_IND_NONSTANDARD_REQUEST: case H245_IND_NONSTANDARD_RESPONSE: case H245_IND_NONSTANDARD_COMMAND: case H245_IND_NONSTANDARD: ConfInd.u.Indication.u.IndNonstandard.pData = pPdu->u.indication.u.IndctnMssg_nonStandard.nonStandardData.data.value; ConfInd.u.Indication.u.IndNonstandard.dwDataLength = pPdu->u.indication.u.IndctnMssg_nonStandard.nonStandardData.data.length; switch (pPdu->u.indication.u.IndctnMssg_nonStandard.nonStandardData.nonStandardIdentifier.choice) { case object_chosen: ConfInd.u.Indication.u.IndNonstandard.pwObjectId = awObject; ConfInd.u.Indication.u.IndNonstandard.dwObjectIdLength = ArrayFromObject(&awObject[0], sizeof(awObject)/sizeof(awObject[0]), pPdu->u.indication.u.IndctnMssg_nonStandard.nonStandardData.nonStandardIdentifier.u.object); ConfInd.u.Indication.u.IndNonstandard.byCountryCode = 0; ConfInd.u.Indication.u.IndNonstandard.byExtension = 0; ConfInd.u.Indication.u.IndNonstandard.wManufacturerCode = 0; break; case h221NonStandard_chosen: ConfInd.u.Indication.u.IndNonstandard.pwObjectId = NULL; ConfInd.u.Indication.u.IndNonstandard.dwObjectIdLength = 0; ConfInd.u.Indication.u.IndNonstandard.byCountryCode = (BYTE) pPdu->u.indication.u.IndctnMssg_nonStandard.nonStandardData.nonStandardIdentifier.u.h221NonStandard.t35CountryCode; ConfInd.u.Indication.u.IndNonstandard.byExtension = (BYTE) pPdu->u.indication.u.IndctnMssg_nonStandard.nonStandardData.nonStandardIdentifier.u.h221NonStandard.t35Extension; ConfInd.u.Indication.u.IndNonstandard.wManufacturerCode = pPdu->u.indication.u.IndctnMssg_nonStandard.nonStandardData.nonStandardIdentifier.u.h221NonStandard.manufacturerCode; break; default: H245TRACE(pInstance->dwInst,1, "H245FsmIndication: unrecognized nonstandard identifier type %d", pPdu->u.indication.u.IndctnMssg_nonStandard.nonStandardData.nonStandardIdentifier.choice); lResult = H245_ERROR_NOSUP; } // switch break; case H245_IND_MISC_COMMAND: ASSERT(pPdu->choice == MSCMg_cmmnd_chosen); ASSERT(pPdu->u.MSCMg_cmmnd.choice == miscellaneousCommand_chosen); break; case H245_IND_MISC: ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == miscellaneousIndication_chosen); break; case H245_IND_COMM_MODE_REQUEST: ASSERT(pPdu->choice == MltmdSystmCntrlMssg_rqst_chosen); ASSERT(pPdu->u.MltmdSystmCntrlMssg_rqst.choice == communicationModeRequest_chosen); break; case H245_IND_COMM_MODE_RESPONSE: ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == cmmnctnMdRspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.u.cmmnctnMdRspns.choice == communicationModeTable_chosen); { unsigned int uCount; CommunicationModeTableLink pLink; H245_COMM_MODE_ENTRY_T * pTable; uCount = 0; pLink = pPdu->u.MSCMg_rspns.u.cmmnctnMdRspns.u.communicationModeTable; while (pLink) { ++uCount; pLink = pLink->next; } pTable = MemAlloc(uCount * sizeof(*pTable)); if (pTable) { ConfInd.u.Indication.u.IndCommRsp.pTable = pTable; ConfInd.u.Indication.u.IndCommRsp.byTableCount = (BYTE)uCount; pLink = pPdu->u.MSCMg_rspns.u.cmmnctnMdRspns.u.communicationModeTable; while (pLink) { lResult = LoadCommModeEntry(pTable, &pLink->value); if (lResult != H245_ERROR_OK) { MemFree(pTable); return lResult; } ++pTable; pLink = pLink->next; } if ((*pInstance->API.ConfIndCallBack)(&ConfInd, &pPdu->u.MltmdSystmCntrlMssg_rqst.u) == H245_ERROR_NOSUP) { H245FunctionNotUnderstood(pInstance, pPdu); } MemFree(pTable); H245TRACE(pInstance->dwInst,4,"H245FsmIndication -> OK"); return H245_ERROR_OK; } lResult = H245_ERROR_NOMEM; } break; case H245_IND_COMM_MODE_COMMAND: ASSERT(pPdu->choice == MSCMg_cmmnd_chosen); ASSERT(pPdu->u.MSCMg_cmmnd.choice == communicationModeCommand_chosen); { unsigned int uCount; CommunicationModeCommandLink pLink; H245_COMM_MODE_ENTRY_T * pTable; uCount = 0; pLink = pPdu->u.MSCMg_cmmnd.u.communicationModeCommand.communicationModeTable; while (pLink) { ++uCount; pLink = pLink->next; } pTable = MemAlloc(uCount * sizeof(*pTable)); if (pTable) { ConfInd.u.Indication.u.IndCommCmd.pTable = pTable; ConfInd.u.Indication.u.IndCommCmd.byTableCount = (BYTE)uCount; pLink = pPdu->u.MSCMg_cmmnd.u.communicationModeCommand.communicationModeTable; while (pLink) { lResult = LoadCommModeEntry(pTable, &pLink->value); if (lResult != H245_ERROR_OK) { MemFree(pTable); return lResult; } ++pTable; pLink = pLink->next; } { H245FunctionNotUnderstood(pInstance, pPdu); } if ((*pInstance->API.ConfIndCallBack)(&ConfInd, &pPdu->u.MltmdSystmCntrlMssg_rqst.u) == H245_ERROR_NOSUP) { H245FunctionNotUnderstood(pInstance, pPdu); } MemFree(pTable); H245TRACE(pInstance->dwInst,4,"H245FsmIndication -> OK"); return H245_ERROR_OK; } lResult = H245_ERROR_NOMEM; } break; case H245_IND_CONFERENCE_REQUEST: ASSERT(pPdu->choice == MltmdSystmCntrlMssg_rqst_chosen); ASSERT(pPdu->u.MltmdSystmCntrlMssg_rqst.choice == conferenceRequest_chosen); ConfInd.u.Indication.u.IndConferReq.RequestType = pPdu->u.MltmdSystmCntrlMssg_rqst.u.conferenceRequest.choice; ConfInd.u.Indication.u.IndConferReq.byMcuNumber = (BYTE) pPdu->u.MltmdSystmCntrlMssg_rqst.u.conferenceRequest.u.dropTerminal.mcuNumber; ConfInd.u.Indication.u.IndConferReq.byTerminalNumber = (BYTE) pPdu->u.MltmdSystmCntrlMssg_rqst.u.conferenceRequest.u.dropTerminal.terminalNumber; break; case H245_IND_CONFERENCE_RESPONSE: ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == conferenceResponse_chosen); ConfInd.u.Indication.u.IndConferRsp.ResponseType = pPdu->u.MSCMg_rspns.u.conferenceResponse.choice; switch (pPdu->u.MSCMg_rspns.u.conferenceResponse.choice) { case mCTerminalIDResponse_chosen: case terminalIDResponse_chosen: case conferenceIDResponse_chosen: case passwordResponse_chosen: ConfInd.u.Indication.u.IndConferRsp.byMcuNumber = (BYTE) pPdu->u.MSCMg_rspns.u.conferenceResponse.u.mCTerminalIDResponse.terminalLabel.mcuNumber; ConfInd.u.Indication.u.IndConferRsp.byTerminalNumber = (BYTE) pPdu->u.MSCMg_rspns.u.conferenceResponse.u.mCTerminalIDResponse.terminalLabel.terminalNumber; ConfInd.u.Indication.u.IndConferRsp.pOctetString = pPdu->u.MSCMg_rspns.u.conferenceResponse.u.mCTerminalIDResponse.terminalID.value; ConfInd.u.Indication.u.IndConferRsp.byOctetStringLength = (BYTE) pPdu->u.MSCMg_rspns.u.conferenceResponse.u.mCTerminalIDResponse.terminalID.length; break; case terminalListResponse_chosen: ConfInd.u.Indication.u.IndConferRsp.pTerminalList = pPdu->u.MSCMg_rspns.u.conferenceResponse.u.terminalListResponse.value; ConfInd.u.Indication.u.IndConferRsp.wTerminalListCount = (WORD) pPdu->u.MSCMg_rspns.u.conferenceResponse.u.terminalListResponse.count; break; case videoCommandReject_chosen: case terminalDropReject_chosen: break; case makeMeChairResponse_chosen: switch (pPdu->u.MSCMg_rspns.u.conferenceResponse.u.makeMeChairResponse.choice) { case grantedChairToken_chosen: ConfInd.u.Indication.u.IndConferRsp.ResponseType = H245_RSP_GRANTED_CHAIR_TOKEN; break; default: H245TRACE(pInstance->dwInst, 1, "H245FsmIndication: Invalid make me chair response %d", pPdu->u.MSCMg_rspns.u.conferenceResponse.u.makeMeChairResponse.choice); // Fall-through to next case case deniedChairToken_chosen: ConfInd.u.Indication.u.IndConferRsp.ResponseType = H245_RSP_DENIED_CHAIR_TOKEN; } // switch break; default: H245TRACE(pInstance->dwInst, 1, "H245FsmIndication: Invalid Conference Response type %d", pPdu->u.MSCMg_rspns.u.conferenceResponse.choice); lResult = H245_ERROR_NOSUP; } // switch break; case H245_IND_CONFERENCE_COMMAND: ASSERT(pPdu->choice == MSCMg_cmmnd_chosen); ASSERT(pPdu->u.MSCMg_cmmnd.choice == conferenceCommand_chosen); ConfInd.u.Indication.u.IndConferCmd.CommandType = pPdu->u.MSCMg_cmmnd.u.conferenceCommand.choice; ConfInd.u.Indication.u.IndConferCmd.Channel = pPdu->u.MSCMg_cmmnd.u.conferenceCommand.u.brdcstMyLgclChnnl; ConfInd.u.Indication.u.IndConferCmd.byMcuNumber = (BYTE) pPdu->u.MSCMg_cmmnd.u.conferenceCommand.u.sendThisSource.mcuNumber; ConfInd.u.Indication.u.IndConferCmd.byTerminalNumber = (BYTE) pPdu->u.MSCMg_cmmnd.u.conferenceCommand.u.sendThisSource.terminalNumber; break; case H245_IND_CONFERENCE: ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == conferenceIndication_chosen); ConfInd.u.Indication.u.IndConfer.IndicationType = pPdu->u.indication.u.conferenceIndication.choice; ConfInd.u.Indication.u.IndConfer.bySbeNumber = (BYTE) pPdu->u.indication.u.conferenceIndication.u.sbeNumber; ConfInd.u.Indication.u.IndConfer.byMcuNumber = (BYTE) pPdu->u.indication.u.conferenceIndication.u.terminalNumberAssign.mcuNumber; ConfInd.u.Indication.u.IndConfer.byTerminalNumber = (BYTE) pPdu->u.indication.u.conferenceIndication.u.terminalNumberAssign.terminalNumber; break; case H245_IND_SEND_TERMCAP: ASSERT(pPdu->choice == MSCMg_cmmnd_chosen); ASSERT(pPdu->u.MSCMg_cmmnd.choice == sndTrmnlCpbltySt_chosen); break; case H245_IND_ENCRYPTION: ASSERT(pPdu->choice == MSCMg_cmmnd_chosen); ASSERT(pPdu->u.MSCMg_cmmnd.choice == encryptionCommand_chosen); break; case H245_IND_FLOW_CONTROL: ASSERT(pPdu->choice == MSCMg_cmmnd_chosen); ASSERT(pPdu->u.MSCMg_cmmnd.choice == flowControlCommand_chosen); ConfInd.u.Indication.u.IndFlowControl.Scope = pPdu->u.MSCMg_cmmnd.u.flowControlCommand.scope.choice; switch (pPdu->u.MSCMg_cmmnd.u.flowControlCommand.scope.choice) { case FCCd_scp_lgclChnnlNmbr_chosen: ConfInd.u.Indication.u.IndFlowControl.Channel = pPdu->u.MSCMg_cmmnd.u.flowControlCommand.scope.u.FCCd_scp_lgclChnnlNmbr; break; case FlwCntrlCmmnd_scp_rsrcID_chosen: ConfInd.u.Indication.u.IndFlowControl.wResourceID = pPdu->u.MSCMg_cmmnd.u.flowControlCommand.scope.u.FlwCntrlCmmnd_scp_rsrcID; break; case FCCd_scp_whlMltplx_chosen: break; default: H245TRACE(pInstance->dwInst, 1, "H245FsmIndication: Invalid Flow Control restriction %d", pPdu->u.MSCMg_cmmnd.u.flowControlCommand.restriction.choice); lResult = H245_ERROR_NOSUP; } // switch switch (pPdu->u.MSCMg_cmmnd.u.flowControlCommand.restriction.choice) { case maximumBitRate_chosen: ConfInd.u.Indication.u.IndFlowControl.dwRestriction = pPdu->u.MSCMg_cmmnd.u.flowControlCommand.restriction.u.maximumBitRate; break; case noRestriction_chosen: ConfInd.u.Indication.u.IndFlowControl.dwRestriction = H245_NO_RESTRICTION; break; default: H245TRACE(pInstance->dwInst, 1, "H245FsmIndication: Invalid Flow Control restriction %d", pPdu->u.MSCMg_cmmnd.u.flowControlCommand.restriction.choice); lResult = H245_ERROR_NOSUP; } // switch break; case H245_IND_ENDSESSION: ASSERT(pPdu->choice == MSCMg_cmmnd_chosen); ASSERT(pPdu->u.MSCMg_cmmnd.choice == endSessionCommand_chosen); ConfInd.u.Indication.u.IndEndSession.SessionMode = H245_ENDSESSION_DISCONNECT; switch (pPdu->u.MSCMg_cmmnd.u.endSessionCommand.choice) { case EndSssnCmmnd_nonStandard_chosen: ConfInd.u.Indication.u.IndEndSession.SessionMode = H245_ENDSESSION_NONSTD, ConfInd.u.Indication.u.IndEndSession.SessionNonStd = pPdu->u.MSCMg_cmmnd.u.endSessionCommand.u.EndSssnCmmnd_nonStandard; break; case disconnect_chosen: break; case gstnOptions_chosen: switch (pPdu->u.MSCMg_cmmnd.u.endSessionCommand.u.gstnOptions.choice) { case EndSessionCommand_gstnOptions_telephonyMode_chosen: ConfInd.u.Indication.u.IndEndSession.SessionMode = H245_ENDSESSION_TELEPHONY; break; case v8bis_chosen: ConfInd.u.Indication.u.IndEndSession.SessionMode = H245_ENDSESSION_V8BIS; break; case v34DSVD_chosen: ConfInd.u.Indication.u.IndEndSession.SessionMode = H245_ENDSESSION_V34DSVD; break; case v34DuplexFAX_chosen: ConfInd.u.Indication.u.IndEndSession.SessionMode = H245_ENDSESSION_V34DUPFAX; break; case v34H324_chosen: ConfInd.u.Indication.u.IndEndSession.SessionMode = H245_ENDSESSION_V34H324; break; default: H245TRACE(pInstance->dwInst, 1, "H245FsmIndication: Invalid End Session GSTN options %d", pPdu->u.MSCMg_cmmnd.u.endSessionCommand.u.gstnOptions.choice); } // switch break; default: H245TRACE(pInstance->dwInst, 1, "H245FsmIndication: Invalid End Session type %d", pPdu->u.MSCMg_cmmnd.u.endSessionCommand.choice); } // switch break; case H245_IND_FUNCTION_NOT_UNDERSTOOD: ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == functionNotUnderstood_chosen); break; case H245_IND_JITTER: ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == jitterIndication_chosen); break; case H245_IND_H223_SKEW: ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == h223SkewIndication_chosen); ConfInd.u.Indication.u.IndH223Skew.LogicalChannelNumber1 = pPdu->u.indication.u.h223SkewIndication.logicalChannelNumber1; ConfInd.u.Indication.u.IndH223Skew.LogicalChannelNumber2 = pPdu->u.indication.u.h223SkewIndication.logicalChannelNumber2; ConfInd.u.Indication.u.IndH223Skew.wSkew = pPdu->u.indication.u.h223SkewIndication.skew; break; case H245_IND_NEW_ATM_VC: ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == newATMVCIndication_chosen); break; case H245_IND_USERINPUT: ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == userInput_chosen); ConfInd.u.Indication.u.IndUserInput.Kind = pPdu->u.indication.u.userInput.choice; switch (pPdu->u.indication.u.userInput.choice) { case UsrInptIndctn_nnStndrd_chosen: ConfInd.u.Indication.u.IndUserInput.u.NonStd = pPdu->u.indication.u.userInput.u.UsrInptIndctn_nnStndrd; break; case alphanumeric_chosen: #if 1 nLength = MultiByteToWideChar(CP_ACP, // code page 0, // dwFlags pPdu->u.indication.u.userInput.u.alphanumeric, -1, // ASCII string length (in bytes) NULL, // Unicode string 0); // max Unicode string length pwchar = MemAlloc(nLength * sizeof(WCHAR)); if (pwchar == NULL) { H245TRACE(pInstance->dwInst, 1, "H245FsmIndication: no memory for user input", 0); lResult = H245_ERROR_NOMEM; } else { nLength = MultiByteToWideChar(CP_ACP, // code page 0, // dwFlags pPdu->u.indication.u.userInput.u.alphanumeric, -1, // ASCII string length (in bytes) pwchar, // Unicode string nLength); // max Unicode string length ConfInd.u.Indication.u.IndUserInput.u.pGenString = pwchar; } #else ConfInd.u.Indication.u.IndUserInput.u.pGenString = pPdu->u.indication.u.userInput.u.alphanumeric; #endif break; default: H245TRACE(pInstance->dwInst, 1, "H245FsmIndication: unrecognized user input type %d", pPdu->u.indication.u.userInput.choice); lResult = H245_ERROR_NOSUP; } // switch break; case H245_IND_H2250_MAX_SKEW: ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == h2250MxmmSkwIndctn_chosen); ConfInd.u.Indication.u.IndH2250MaxSkew.LogicalChannelNumber1 = pPdu->u.indication.u.h2250MxmmSkwIndctn.logicalChannelNumber1; ConfInd.u.Indication.u.IndH2250MaxSkew.LogicalChannelNumber2 = pPdu->u.indication.u.h2250MxmmSkwIndctn.logicalChannelNumber2; ConfInd.u.Indication.u.IndH2250MaxSkew.wSkew = pPdu->u.indication.u.h2250MxmmSkwIndctn.maximumSkew; break; case H245_IND_MC_LOCATION: ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == mcLocationIndication_chosen); lResult = LoadTransportAddress(&ConfInd.u.Indication.u.IndMcLocation, &pPdu->u.indication.u.mcLocationIndication.signalAddress); break; case H245_IND_VENDOR_ID: ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == vendorIdentification_chosen); ConfInd.u.Indication.u.IndVendorId.Identifier = pPdu->u.indication.u.vendorIdentification.vendor; if (pPdu->u.indication.u.vendorIdentification.bit_mask & productNumber_present) { ConfInd.u.Indication.u.IndVendorId.pProductNumber = pPdu->u.indication.u.vendorIdentification.productNumber.value; ConfInd.u.Indication.u.IndVendorId.byProductNumberLength = (BYTE) pPdu->u.indication.u.vendorIdentification.productNumber.length; } if (pPdu->u.indication.u.vendorIdentification.bit_mask & versionNumber_present) { ConfInd.u.Indication.u.IndVendorId.pVersionNumber = pPdu->u.indication.u.vendorIdentification.versionNumber.value; ConfInd.u.Indication.u.IndVendorId.byVersionNumberLength = (BYTE) pPdu->u.indication.u.vendorIdentification.versionNumber.length; } break; case H245_IND_FUNCTION_NOT_SUPPORTED: ASSERT(pPdu->choice == indication_chosen); ASSERT(pPdu->u.indication.choice == IndicationMessage_functionNotSupported_chosen); ConfInd.u.Indication.u.IndFns.Cause = pPdu->u.indication.u.functionNotSupported.cause.choice; ConfInd.u.Indication.u.IndFns.Type = UNKNOWN; /*if (pPdu->u.indication.u.functionNotSupported.bit_mask & returnedFunction_present) { int pduNum = MltmdSystmCntrlMssg_PDU; OssBuf ossBuf; MltmdSystmCntrlMssg *pPduReturned; ossBuf.value = pPdu->u.indication.u.functionNotSupported.returnedFunction.value; ossBuf.length = pPdu->u.indication.u.functionNotSupported.returnedFunction.length; if (ossDecode(pInstance->p_ossWorld, &pduNum, &ossBuf, (void * *)&pPduReturned) == PDU_DECODED) { switch (pPduReturned->choice) { case MltmdSystmCntrlMssg_rqst_chosen: ConfInd.u.Indication.u.IndFns.Type = pPduReturned->u.MltmdSystmCntrlMssg_rqst.choice - RqstMssg_nonStandard_chosen + REQ_NONSTANDARD; break; case MSCMg_rspns_chosen: ConfInd.u.Indication.u.IndFns.Type = pPduReturned->u.MSCMg_rspns.choice - RspnsMssg_nonStandard_chosen + RSP_NONSTANDARD; break; case MSCMg_cmmnd_chosen: ConfInd.u.Indication.u.IndFns.Type = pPduReturned->u.MSCMg_cmmnd.choice - CmmndMssg_nonStandard_chosen + CMD_NONSTANDARD; break; case indication_chosen: ConfInd.u.Indication.u.IndFns.Type = pPduReturned->u.indication.choice - IndctnMssg_nonStandard_chosen + IND_NONSTANDARD; break; default: H245TRACE(pInstance->dwInst, 1, "H245FsmIndication: unrecognized FunctionNotSupported message type %d", pPduReturned->choice); lResult = H245_ERROR_NOSUP; } // switch // Free the PDU if (ossFreePDU(pInstance->p_ossWorld, pduNum, pPduReturned)) { H245TRACE(pInstance->dwInst, 1, "H245FsmIndication: FREE FAILURE"); } } } */ break; #if(0) // this isn't in H245 Version 3. and this code did nothing with it anyway case H245_IND_H223_RECONFIG: ASSERT(pPdu->choice == MltmdSystmCntrlMssg_rqst_chosen); ASSERT(pPdu->u.MltmdSystmCntrlMssg_rqst.choice == h223AnnxARcnfgrtn_chosen); break; case H245_IND_H223_RECONFIG_ACK: ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == h223AnnxARcnfgrtnAck_chosen); break; case H245_IND_H223_RECONFIG_REJECT: ASSERT(pPdu->choice == MSCMg_rspns_chosen); ASSERT(pPdu->u.MSCMg_rspns.choice == h223AnnxARcnfgrtnRjct_chosen); break; #endif // if(0) default: /* Possible Error */ H245TRACE(pInstance->dwInst, 1, "H245FsmIndication -> Invalid Indication Event %d", dwEvent); lResult = H245_ERROR_SUBSYS; } // switch #if 1 if (pwchar) MemFree(pwchar); #endif if (lResult == H245_ERROR_OK) { if ((*pInstance->API.ConfIndCallBack)(&ConfInd, &pPdu->u.MltmdSystmCntrlMssg_rqst.u) == H245_ERROR_NOSUP) { H245FunctionNotUnderstood(pInstance, pPdu); } H245TRACE(pInstance->dwInst,4,"H245FsmIndication -> OK"); } else { H245TRACE(pInstance->dwInst,1,"H245FsmIndication -> %s", map_api_error(lResult)); } return lResult; } // H245FsmIndication()