Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

747 lines
18 KiB

  1. #include "stdafx.h"
  2. #include "h323asn1.h"
  3. struct SAFE_ENCODER
  4. {
  5. public:
  6. CRITICAL_SECTION CriticalSection;
  7. ASN1encoding_t Encoder;
  8. private:
  9. void Lock (void) { EnterCriticalSection (&CriticalSection); }
  10. void Unlock (void) { LeaveCriticalSection (&CriticalSection); }
  11. public:
  12. SAFE_ENCODER (void);
  13. ~SAFE_ENCODER (void);
  14. BOOL Create (ASN1module_t);
  15. void Close (void);
  16. DWORD Encode (
  17. IN DWORD PduType,
  18. IN PVOID PduStructure,
  19. OUT PUCHAR * ReturnBuffer,
  20. OUT PDWORD ReturnBufferLength);
  21. void FreeBuffer (
  22. IN PUCHAR Buffer);
  23. };
  24. class SAFE_DECODER
  25. {
  26. public:
  27. CRITICAL_SECTION CriticalSection;
  28. ASN1decoding_t Decoder;
  29. private:
  30. void Lock (void) { EnterCriticalSection (&CriticalSection); }
  31. void Unlock (void) { LeaveCriticalSection (&CriticalSection); }
  32. public:
  33. SAFE_DECODER (void);
  34. ~SAFE_DECODER (void);
  35. BOOL Create (ASN1module_t Module);
  36. void Close (void);
  37. DWORD Decode (
  38. IN PUCHAR Buffer,
  39. IN DWORD BufferLength,
  40. IN DWORD PduType,
  41. OUT PVOID * PduStructure);
  42. void FreePdu (
  43. IN DWORD PduType,
  44. IN PVOID PduStructure);
  45. };
  46. static SAFE_ENCODER H225Encoder;
  47. static SAFE_DECODER H225Decoder;
  48. static SAFE_ENCODER H245Encoder;
  49. static SAFE_DECODER H245Decoder;
  50. void H323ASN1Initialize (void)
  51. {
  52. ASN1error_e Error;
  53. H225PP_Module_Startup();
  54. H245PP_Module_Startup();
  55. H225Encoder.Create (H225PP_Module);
  56. H225Decoder.Create (H225PP_Module);
  57. H245Encoder.Create (H245PP_Module);
  58. H245Decoder.Create (H245PP_Module);
  59. }
  60. void H323ASN1Shutdown (void)
  61. {
  62. H225Encoder.Close();
  63. H225Decoder.Close();
  64. H245Encoder.Close();
  65. H245Decoder.Close();
  66. H225PP_Module_Cleanup();
  67. H245PP_Module_Cleanup();
  68. }
  69. DWORD H225EncodePdu (
  70. IN DWORD PduType,
  71. IN PVOID PduStructure,
  72. OUT PUCHAR * ReturnBuffer,
  73. OUT PDWORD ReturnBufferLength)
  74. {
  75. return H225Encoder.Encode (PduType, PduStructure, ReturnBuffer, ReturnBufferLength);
  76. }
  77. DWORD H225DecodePdu (
  78. IN PUCHAR Buffer,
  79. IN DWORD BufferLength,
  80. IN DWORD PduType,
  81. OUT PVOID * ReturnPduStructure)
  82. {
  83. return H225Decoder.Decode (Buffer, BufferLength, PduType, ReturnPduStructure);
  84. }
  85. DWORD H225FreePdu (
  86. IN DWORD PduType,
  87. IN PVOID PduStructure)
  88. {
  89. H225Decoder.FreePdu (PduType, PduStructure);
  90. return ERROR_SUCCESS;
  91. }
  92. DWORD H225FreeBuffer (
  93. IN PUCHAR Buffer)
  94. {
  95. H225Encoder.FreeBuffer (Buffer);
  96. return ERROR_SUCCESS;
  97. }
  98. DWORD H245EncodePdu (
  99. IN DWORD PduType,
  100. IN PVOID PduStructure,
  101. OUT PUCHAR * ReturnBuffer,
  102. OUT PDWORD ReturnBufferLength)
  103. {
  104. return H245Encoder.Encode (PduType, PduStructure, ReturnBuffer, ReturnBufferLength);
  105. }
  106. DWORD H245DecodePdu (
  107. IN PUCHAR Buffer,
  108. IN DWORD BufferLength,
  109. IN DWORD PduType,
  110. OUT PVOID * ReturnPduStructure)
  111. {
  112. return H245Decoder.Decode (Buffer, BufferLength, PduType, ReturnPduStructure);
  113. }
  114. DWORD H245FreePdu (
  115. IN DWORD PduType,
  116. IN PVOID PduStructure)
  117. {
  118. H245Decoder.FreePdu (PduType, PduStructure);
  119. return ERROR_SUCCESS;
  120. }
  121. DWORD H245FreeBuffer (
  122. IN PUCHAR Buffer)
  123. {
  124. H245Encoder.FreeBuffer (Buffer);
  125. return ERROR_SUCCESS;
  126. }
  127. // SAFE_ENCODER ----------------------------------------------------------------------
  128. SAFE_ENCODER::SAFE_ENCODER (void)
  129. {
  130. InitializeCriticalSection (&CriticalSection);
  131. Encoder = NULL;
  132. }
  133. SAFE_ENCODER::~SAFE_ENCODER (void)
  134. {
  135. DeleteCriticalSection (&CriticalSection);
  136. assert (!Encoder);
  137. }
  138. BOOL SAFE_ENCODER::Create (ASN1module_t Module)
  139. {
  140. ASN1error_e Error;
  141. if (Encoder)
  142. return TRUE;
  143. Error = ASN1_CreateEncoder (Module, &Encoder, NULL, 0, NULL);
  144. if (ASN1_FAILED (Error))
  145. DebugF (_T("SAFE_ENCODER::Create: failed to create ASN.1 encoder, error %d\n"), Error);
  146. return ASN1_SUCCEEDED (Error);
  147. }
  148. void SAFE_ENCODER::Close (void)
  149. {
  150. if (Encoder) {
  151. ASN1_CloseEncoder (Encoder);
  152. Encoder = NULL;
  153. }
  154. }
  155. DWORD SAFE_ENCODER::Encode (
  156. IN DWORD PduType,
  157. IN PVOID PduStructure,
  158. OUT PUCHAR * ReturnBuffer,
  159. OUT PDWORD ReturnBufferLength)
  160. {
  161. ASN1error_e Error;
  162. Lock();
  163. Error = ASN1_Encode (Encoder, PduStructure, PduType, ASN1ENCODE_ALLOCATEBUFFER, NULL, 0);
  164. if (ASN1_SUCCEEDED (Error)) {
  165. *ReturnBuffer = Encoder -> buf;
  166. *ReturnBufferLength = Encoder -> len;
  167. }
  168. #if 0
  169. else
  170. DebugError (Error, _T("SAFE_ENCODER::Encode: failed to encode pdu\n"));
  171. #endif
  172. Unlock();
  173. return Error;
  174. }
  175. void SAFE_ENCODER::FreeBuffer (IN PUCHAR Buffer)
  176. {
  177. assert (Encoder);
  178. Lock();
  179. ASN1_FreeEncoded (Encoder, Buffer);
  180. Unlock();
  181. }
  182. // SAFE_DECODER -----------------------------------------------------------------------
  183. SAFE_DECODER::SAFE_DECODER (void)
  184. {
  185. InitializeCriticalSection (&CriticalSection);
  186. Decoder = NULL;
  187. }
  188. SAFE_DECODER::~SAFE_DECODER (void)
  189. {
  190. DeleteCriticalSection (&CriticalSection);
  191. assert (!Decoder);
  192. }
  193. BOOL SAFE_DECODER::Create (ASN1module_t Module)
  194. {
  195. ASN1error_e Error;
  196. if (Decoder)
  197. return TRUE;
  198. Error = ASN1_CreateDecoder (Module, &Decoder, NULL, 0, NULL);
  199. if (ASN1_FAILED (Error))
  200. DebugF (_T("SAFE_DECODER::Create: failed to create ASN.1 decoder, error %d\n"), Error);
  201. return ASN1_SUCCEEDED (Error);
  202. }
  203. void SAFE_DECODER::Close (void)
  204. {
  205. if (Decoder) {
  206. ASN1_CloseDecoder (Decoder);
  207. Decoder = NULL;
  208. }
  209. }
  210. void SAFE_DECODER::FreePdu (IN DWORD PduType, IN PVOID PduStructure)
  211. {
  212. assert (Decoder);
  213. Lock();
  214. ASN1_FreeDecoded (Decoder, PduStructure, PduType);
  215. Unlock();
  216. }
  217. DWORD SAFE_DECODER::Decode (
  218. IN PUCHAR Buffer,
  219. IN DWORD BufferLength,
  220. IN DWORD PduType,
  221. OUT PVOID * ReturnPduStructure)
  222. {
  223. ASN1error_e Error;
  224. Lock();
  225. Error = ASN1_Decode (Decoder, ReturnPduStructure, PduType, ASN1DECODE_SETBUFFER, Buffer, BufferLength);
  226. Unlock();
  227. #if 0
  228. if (ASN1_FAILED (Error))
  229. DebugError (Error, _T("SAFE_DECODER::Decode: failed to decode pdu\n"));
  230. #endif
  231. return Error;
  232. }
  233. // formerly from pdu.cpp -----------------------------------------------------------------
  234. ///////////////////////////////////////////////////////////////////////////////
  235. // //
  236. // Q.931 PDUs //
  237. // //
  238. ///////////////////////////////////////////////////////////////////////////////
  239. /*++
  240. Routine Description:
  241. Encodes the Non-ASN and ASN parts together into a buffer which
  242. is sent on the wire.
  243. Arguments:
  244. None.
  245. Return Values:
  246. Returns S_OK in case of success or an error in case of failure.
  247. --*/
  248. #define DEFAULT_Q931_BUF_SIZE 300
  249. HRESULT EncodeQ931PDU(
  250. IN Q931_MESSAGE *pQ931msg,
  251. IN H323_UserInformation *pUserInformation OPTIONAL,
  252. OUT BYTE **ppReturnEncodedData,
  253. OUT DWORD *pReturnEncodedDataLength)
  254. {
  255. HRESULT HResult;
  256. BYTE *Buffer;
  257. DWORD BufLen;
  258. _ASSERTE(pUserInformation);
  259. _ASSERTE(pQ931msg);
  260. _ASSERTE(ppReturnEncodedData);
  261. _ASSERTE(pReturnEncodedDataLength);
  262. *ppReturnEncodedData = NULL;
  263. *pReturnEncodedDataLength = 0;
  264. Buffer = (BYTE *) EM_MALLOC(sizeof(BYTE)*DEFAULT_Q931_BUF_SIZE);
  265. if (!Buffer) {
  266. return E_OUTOFMEMORY;
  267. }
  268. // 4 bytes for TPKT header
  269. BufLen = DEFAULT_Q931_BUF_SIZE - 4;
  270. // Encode the PDU
  271. HResult = pQ931msg->EncodePdu(Buffer + 4, &BufLen);
  272. if (HRESULT_FROM_WIN32 (ERROR_MORE_DATA) == HResult)
  273. {
  274. // CODEWORK: Use Realloc ??
  275. EM_FREE(Buffer);
  276. Buffer = (BYTE *) EM_MALLOC(sizeof(BYTE)*(BufLen + 4));
  277. if (!Buffer) {
  278. return E_OUTOFMEMORY;
  279. }
  280. HResult = pQ931msg->EncodePdu(Buffer + 4, &BufLen);
  281. if (FAILED(HResult))
  282. {
  283. EM_FREE(Buffer);
  284. return HResult;
  285. }
  286. }
  287. SetupTPKTHeader(Buffer, BufLen);
  288. *ppReturnEncodedData = Buffer;
  289. *pReturnEncodedDataLength = BufLen + 4;
  290. return S_OK;
  291. }
  292. HRESULT DecodeQ931PDU(
  293. IN BYTE * pbData,
  294. IN DWORD dwDataLen,
  295. OUT Q931_MESSAGE** ppReturnQ931msg,
  296. OUT H323_UserInformation ** ppReturnH323UserInfo
  297. )
  298. {
  299. Q931_MESSAGE *pQ931msg = NULL;
  300. H323_UserInformation *pDecodedH323UserInfo = NULL;
  301. HRESULT HResult;
  302. *ppReturnQ931msg = NULL;
  303. *ppReturnH323UserInfo = NULL;
  304. pQ931msg = new Q931_MESSAGE();
  305. if (pQ931msg == NULL)
  306. {
  307. DebugF( _T("HandleRecvCompletion(): allocating pQ931msg failed\n"));
  308. return E_OUTOFMEMORY;
  309. }
  310. // Decode the PDU
  311. // This call "attaches" pbData to pQ931msg
  312. HResult = pQ931msg->AttachDecodePdu(
  313. pbData, dwDataLen,
  314. FALSE // Q931_MESSAGE should not free this buffer
  315. );
  316. if (FAILED(HResult))
  317. {
  318. DebugF( _T("Decoding the Q.931 PDU Failed : 0x%x\n"), HResult);
  319. delete pQ931msg;
  320. return HResult;
  321. }
  322. // Get UUIE part
  323. Q931_IE *pInfoElement;
  324. // CODEWORK: We need a separate error to see if the UUIE element
  325. // is not present.
  326. HResult = pQ931msg->FindInfoElement(Q931_IE_USER_TO_USER, &pInfoElement);
  327. if (HResult != S_OK)
  328. {
  329. DebugF(_T("Decoding the Q.931 PDU Failed : 0x%x\n"), HResult);
  330. delete pQ931msg;
  331. return E_FAIL; // HResult;
  332. }
  333. _ASSERTE(pInfoElement != NULL);
  334. _ASSERTE(pInfoElement->Identifier == Q931_IE_USER_TO_USER);
  335. *ppReturnH323UserInfo = pInfoElement->Data.UserToUser.PduStructure;
  336. *ppReturnQ931msg = pQ931msg;
  337. return S_OK;
  338. } // DecodeQ931PDU()
  339. // CODEWORK: Move all the FreePDU functions into a
  340. // separate file and share it in both
  341. // emsend.cpp/emrecv.cpp
  342. void FreeQ931PDU(
  343. IN Q931_MESSAGE *pQ931msg,
  344. IN H323_UserInformation *pH323UserInformation
  345. )
  346. {
  347. HRESULT HResult;
  348. BYTE *Buffer = NULL;
  349. DWORD BufLen = 0;
  350. _ASSERTE(pQ931msg != NULL);
  351. // The buffer is attached to the Q931_MESSAGE structure and we
  352. // need to free it.
  353. HResult = pQ931msg->Detach(&Buffer, &BufLen);
  354. if (HResult == S_OK && Buffer != NULL)
  355. {
  356. EM_FREE(Buffer);
  357. }
  358. // pH323UserInformation is also freed by the destructor
  359. delete pQ931msg;
  360. }
  361. //////////////////////// CALL PROCEEDING PDU
  362. // Static members used in encoding the CallProceeding PDU
  363. // Note that the CallProceeding UUIE structure created holds
  364. // pointers to these structures and someone freeing the structure
  365. // should NEVER try free those pointers.
  366. #if 0 // 0 ******* Region Commented Out Begins *******
  367. const struct GatewayInfo_protocol GatewayProtocol = {
  368. NULL,
  369. };
  370. #endif // 0 ******* Region Commented Out Ends *******
  371. #define OID_ELEMENT_LAST(Value) { NULL, Value }
  372. #define OID_ELEMENT(Index,Value) { (ASN1objectidentifier_s *) &_OID_Q931ProtocolIdentifierV2 [Index], Value },
  373. // this stores an unrolled constant linked list
  374. const ASN1objectidentifier_s _OID_Q931ProtocolIdentifierV2 [] = {
  375. OID_ELEMENT(1, 0) // 0 = ITU-T
  376. OID_ELEMENT(2, 0) // 0 = Recommendation
  377. OID_ELEMENT(3, 8) // 8 = H Series
  378. OID_ELEMENT(4, 2250) // 2250 = H.225.0
  379. OID_ELEMENT(5, 0) // 0 = Version
  380. OID_ELEMENT_LAST(2) // 2 = V2
  381. };
  382. /*++
  383. The user of this function needs to pass in pReturnQ931msg and
  384. pReturnH323UserInfo (probably allocated on the stack.
  385. // OLD OLD
  386. pReturnH323UserInfo is already added as UUIE to pReturnQ931msg.
  387. It is returned from this function so as to enable the caller to
  388. free it after sending the PDU.
  389. The user of this function needs to call
  390. delete *ppReturnQ931msg; and EM_FREE *ppReturnH323UserInfo;
  391. to free the allocated data.
  392. --*/
  393. HRESULT Q931EncodeCallProceedingMessage(
  394. IN WORD CallRefVal,
  395. IN OUT Q931_MESSAGE *pReturnQ931msg,
  396. IN OUT H323_UserInformation *pReturnH323UserInfo
  397. )
  398. {
  399. HRESULT HResult;
  400. pReturnQ931msg->MessageType = Q931_MESSAGE_TYPE_CALL_PROCEEDING;
  401. pReturnQ931msg->CallReferenceValue = CallRefVal;
  402. // Fill in the ASN.1 UUIE part
  403. // This should zero out all the bit_masks and we set only what
  404. // are necessary.
  405. ZeroMemory(pReturnH323UserInfo, sizeof(H323_UserInformation));
  406. pReturnH323UserInfo->h323_uu_pdu.h323_message_body.choice =
  407. callProceeding_chosen;
  408. CallProceeding_UUIE *pCallProceedingPdu =
  409. &pReturnH323UserInfo->h323_uu_pdu.h323_message_body.u.callProceeding;
  410. pCallProceedingPdu->protocolIdentifier =
  411. const_cast <ASN1objectidentifier_t> (_OID_Q931ProtocolIdentifierV2);
  412. #if 0 // 0 ******* Region Commented Out Begins *******
  413. pCallProceedingPdu->destinationInfo.bit_mask = gateway_present;
  414. pCallProceedingPdu->destinationInfo.gateway.bit_mask = protocol_present;
  415. #endif // 0 ******* Region Commented Out Ends *******
  416. pCallProceedingPdu->destinationInfo.mc = FALSE;
  417. pCallProceedingPdu->destinationInfo.undefinedNode = FALSE;
  418. // Append the Information element.
  419. Q931_IE InfoElement;
  420. InfoElement.Identifier = Q931_IE_USER_TO_USER;
  421. InfoElement.Data.UserToUser.Type = Q931_UUIE_X208;
  422. InfoElement.Data.UserToUser.PduStructure = pReturnH323UserInfo;
  423. // Don't delete the PduStructure
  424. InfoElement.Data.UserToUser.IsOwner = FALSE;
  425. HResult = pReturnQ931msg->AppendInfoElement(&InfoElement);
  426. if (FAILED(HResult))
  427. {
  428. DebugF(_T("Failed to Append UUIE info element to CallProceeding PDU : 0x%x\n"),
  429. HResult);
  430. return HResult;
  431. }
  432. return S_OK;
  433. }
  434. /*++
  435. The user of this function needs to pass in pReturnQ931msg and
  436. pReturnH323UserInfo (probably allocated on the stack.
  437. // OLD OLD
  438. pReturnH323UserInfo is already added as UUIE to pReturnQ931msg.
  439. It is returned from this function so as to enable the caller to
  440. free it after sending the PDU.
  441. The user of this function needs to call
  442. delete *ppReturnQ931msg; and EM_FREE *ppReturnH323UserInfo;
  443. to free the allocated data.
  444. --*/
  445. HRESULT Q931EncodeReleaseCompleteMessage(
  446. IN WORD CallRefVal,
  447. IN OUT Q931_MESSAGE *pReturnQ931msg,
  448. IN OUT H323_UserInformation *pReturnH323UserInfo
  449. )
  450. {
  451. HRESULT HResult;
  452. pReturnQ931msg->MessageType = Q931_MESSAGE_TYPE_RELEASE_COMPLETE;
  453. pReturnQ931msg->CallReferenceValue = CallRefVal;
  454. // Fill in the ASN.1 UUIE part
  455. // This should zero out all the bit_masks and we set only what
  456. // are necessary.
  457. ZeroMemory(pReturnH323UserInfo, sizeof(H323_UserInformation));
  458. pReturnH323UserInfo->h323_uu_pdu.h323_message_body.choice =
  459. releaseComplete_chosen;
  460. ReleaseComplete_UUIE *pReleaseCompletePdu =
  461. &pReturnH323UserInfo->h323_uu_pdu.h323_message_body.u.releaseComplete;
  462. pReleaseCompletePdu->protocolIdentifier =
  463. const_cast <ASN1objectidentifier_t> (_OID_Q931ProtocolIdentifierV2);
  464. pReleaseCompletePdu->bit_mask |= ReleaseComplete_UUIE_reason_present;
  465. pReleaseCompletePdu->reason.choice =
  466. ReleaseCompleteReason_undefinedReason_chosen;
  467. // Append the Information element.
  468. Q931_IE InfoElement;
  469. InfoElement.Identifier = Q931_IE_USER_TO_USER;
  470. InfoElement.Data.UserToUser.Type = Q931_UUIE_X208;
  471. InfoElement.Data.UserToUser.PduStructure = pReturnH323UserInfo;
  472. // Don't delete the PduStructure
  473. InfoElement.Data.UserToUser.IsOwner = FALSE;
  474. HResult = pReturnQ931msg->AppendInfoElement(&InfoElement);
  475. if (FAILED(HResult))
  476. {
  477. DebugF(_T("Failed to Append UUIE info element to CallProceeding PDU : 0x%x\n"),
  478. HResult);
  479. return HResult;
  480. }
  481. return S_OK;
  482. }
  483. ///////////////////////////////////////////////////////////////////////////////
  484. // //
  485. // H.245 PDUs //
  486. // //
  487. ///////////////////////////////////////////////////////////////////////////////
  488. /*++
  489. Routine Description:
  490. Encodes the ASN part into a buffer which is sent on the wire.
  491. Arguments:
  492. None.
  493. Return Values:
  494. Returns S_OK in case of success or an error in case of failure.
  495. --*/
  496. HRESULT EncodeH245PDU(
  497. IN MultimediaSystemControlMessage &rH245pdu,
  498. OUT BYTE **ppReturnEncodedData,
  499. OUT DWORD *pReturnEncodedDataLength)
  500. {
  501. DWORD Status;
  502. BYTE *pH245Buf, *pBuf;
  503. DWORD BufLen;
  504. // Initialize default return values.
  505. *ppReturnEncodedData = NULL;
  506. *pReturnEncodedDataLength = 0;
  507. _ASSERTE(ppReturnEncodedData != NULL);
  508. _ASSERTE(pReturnEncodedDataLength != NULL);
  509. Status = H245EncodePdu_MultimediaSystemControlMessage(
  510. &rH245pdu,
  511. &pH245Buf,
  512. &BufLen);
  513. if (Status != NO_ERROR)
  514. {
  515. DebugF (_T("EncodeH245PDU: failed to encode H.245 pdu error: %d(0x%x)\n"),
  516. Status, Status);
  517. return HRESULT_FROM_WIN32(Status);
  518. }
  519. pBuf = (BYTE *) EM_MALLOC(BufLen + 4);
  520. if (pBuf == NULL)
  521. {
  522. DebugF (_T("EncodeH245PDU: failed to allocate buffer\n"));
  523. return E_OUTOFMEMORY;
  524. }
  525. CopyMemory(pBuf + 4, pH245Buf, BufLen);
  526. SetupTPKTHeader(pBuf, BufLen);
  527. H245FreeBuffer(pH245Buf);
  528. *ppReturnEncodedData = pBuf;
  529. *pReturnEncodedDataLength = BufLen + 4;
  530. return S_OK;
  531. }
  532. HRESULT DecodeH245PDU (
  533. IN LPBYTE Data,
  534. IN DWORD DataLength,
  535. OUT MultimediaSystemControlMessage **ppReturnH245pdu)
  536. {
  537. DWORD Status;
  538. MultimediaSystemControlMessage *pDecodedH245pdu = NULL;
  539. *ppReturnH245pdu = NULL;
  540. Status = H245DecodePdu_MultimediaSystemControlMessage(Data,
  541. DataLength,
  542. &pDecodedH245pdu
  543. );
  544. if (ASN1_FAILED (Status))
  545. {
  546. DebugF( _T("DecodeH245PDU: Failed to decode H.245 pdu length: ")
  547. _T("%d error: %d(0x%x)\n"),
  548. DataLength, Status, Status);
  549. DumpMemory (Data, DataLength);
  550. return HRESULT_FROM_WIN32(Status);
  551. }
  552. *ppReturnH245pdu = pDecodedH245pdu;
  553. return S_OK;
  554. }
  555. void FreeH245PDU(
  556. MultimediaSystemControlMessage *pH245pdu
  557. )
  558. {
  559. if (pH245pdu != NULL)
  560. {
  561. H245FreePdu_MultimediaSystemControlMessage(pH245pdu);
  562. }
  563. }