/* packet-mrcpv2.c * Routines for Media Resource Control Protocol Version 2 (MRCPv2) dissection * Copyright 2012, Zeljko Ancimer * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ /* * Based on RFC 6787 * * TODO: * - TLS has not been tested * - MRCP conversation (similar to VoIP Calls) * - convert header value into the correct types (numbers, booleans,...); * currently all values are treated as strings so one has to be * careful with the usage of filters; to do this, one has to go through * the mrcp draft and look for the definition of each header (see * chapter titled "15. ABNF Normative Definition") */ #include "config.h" /* Include only as needed */ #include #include #include #include "packet-tcp.h" #include #include void proto_register_mrcpv2(void); void proto_reg_handoff_mrcpv2(void); /* mrcp-version SP message-length */ /* mrcp-version = "MRCP" "/" 1*2DIGIT "." 1*2DIGIT ==> up to 10 chars */ /* SP ==> whitespace, 1 char */ /* message-length = 1*19DIGIT ==> up to 19 chars */ /* total = 10 + 1 + 19 = 30 */ /* min length to determine MRCPv2 version */ #define MRCPV2_MIN_LENGTH 10 /* min length to determine MRCPv2 PDU length */ #define MRCPV2_MIN_PDU_LEN 30 /* line type */ typedef enum { REQUEST_LINE, RESPONSE_LINE, EVENT_LINE, UNKNOWN_LINE } LINE_TYPE; /* header type */ typedef enum { UNKNOWN = 0, ABORT_MODEL = 1, ABORT_PHRASE_ENROLLMENT = 2, ABORT_VERIFICATION = 3, ACCEPT = 4, ACCEPT_CHARSET = 5, ACTIVE_REQUEST_ID_LIST = 6, ADAPT_MODEL = 7, AUDIO_FETCH_HINT = 8, CACHE_CONTROL = 9, CANCEL_IF_QUEUE = 10, CAPTURE_ON_SPEECH = 11, CHANNEL_IDENTIFIER = 12, CLASH_THRESHOLD = 13, CLEAR_DTMF_BUFFER = 14, COMPLETION_CAUSE = 15, COMPLETION_REASON = 16, CONFIDENCE_THRESHOLD = 17, CONFUSABLE_PHRASES_URI = 18, CONSISTENCY_THRESHOLD = 19, CONTENT_BASE = 20, CONTENT_ENCODING = 21, CONTENT_ID = 22, CONTENT_LENGTH = 23, CONTENT_LOCATION = 24, CONTENT_TYPE = 25, DTMF_BUFFER_TIME = 26, DTMF_INTERDIGIT_TIMEOUT = 27, DTMF_TERM_CHAR = 28, DTMF_TERM_TIMEOUT = 29, EARLY_NO_MATCH = 30, ENROLL_UTTERANCE = 31, FAILED_URI = 32, FAILED_URI_CAUSE = 33, FETCH_HINT = 34, FETCH_TIMEOUT = 35, FINAL_SILENCE = 36, HOTWORD_MAX_DURATION = 37, HOTWORD_MIN_DURATION = 38, INPUT_TYPE = 39, INPUT_WAVEFORM_URI = 40, INTERPRET_TEXT = 41, JUMP_SIZE = 42, KILL_ON_BARGE_IN = 43, LEXICON_SEARCH_ORDER = 44, LOAD_LEXICON = 45, LOGGING_TAG = 46, MAX_TIME = 47, MEDIA_TYPE = 48, MIN_VERIFICATION_SCORE = 49, N_BEST_LIST_LENGTH = 50, NEW_AUDIO_CHANNEL = 51, NEW_PHRASE_ID = 52, NO_INPUT_TIMEOUT = 53, NUM_MAX_VERIFICATION_PHRASES = 54, NUM_MIN_CONSISTENT_PRONUNCIATIONS = 55, NUM_MIN_VERIFICATION_PHRASES = 56, PERSONAL_GRAMMAR_URI = 57, PHRASE_ID = 58, PHRASE_NL = 59, PROSODY_CONTOUR = 60, PROSODY_DURATION = 61, PROSODY_PITCH = 62, PROSODY_RANGE = 63, PROSODY_RATE = 64, PROSODY_VOLUME = 65, PROXY_SYNC_ID = 66, RECOGNITION_MODE = 67, RECOGNITION_TIMEOUT = 68, RECOGNIZER_CONTEXT_BLOCK = 69, RECORD_URI = 70, REPOSITORY_URI = 71, SAVE_BEST_WAVEFORM = 72, SAVE_WAVEFORM = 73, SENSITIVITY_LEVEL = 74, SET_COOKIE = 75, SPEAK_LENGTH = 76, SPEAK_RESTART = 77, SPEAKER_PROFILE = 78, SPEECH_COMPLETE_TIMEOUT = 79, SPEECH_INCOMPLETE_TIMEOUT = 80, SPEECH_LANGUAGE = 81, SPEECH_MARKER = 82, SPEED_VS_ACCURACY = 83, START_INPUT_TIMERS = 84, TRIM_LENGTH = 85, VENDOR_SPECIFIC_PARAMETERS = 86, VER_BUFFER_UTTERANCE = 87, VERIFICATION_MODE = 88, VOICE_AGE = 89, VOICE_GENDER = 90, VOICE_NAME = 91, VOICE_VARIANT = 92, VOICEPRINT_EXISTS = 93, VOICEPRINT_IDENTIFIER = 94, WAVEFORM_URI = 95, WEIGHT = 96 } HEADER_TYPE; static const value_string header_type_vals[] = { { ABORT_MODEL, "abort-model" }, { ABORT_PHRASE_ENROLLMENT, "abort-phrase-enrollment" }, { ABORT_VERIFICATION, "abort-verification" }, { ACCEPT, "accept" }, { ACCEPT_CHARSET, "accept-charset" }, { ACTIVE_REQUEST_ID_LIST, "active-request-id-list" }, { ADAPT_MODEL, "adapt-model" }, { AUDIO_FETCH_HINT, "audio-fetch-hint" }, { CACHE_CONTROL, "cache-control" }, { CANCEL_IF_QUEUE, "cancel-if-queue" }, { CAPTURE_ON_SPEECH, "capture-on-speech" }, { CHANNEL_IDENTIFIER, "channel-identifier" }, { CLASH_THRESHOLD, "clash-threshold" }, { CLEAR_DTMF_BUFFER, "clear-dtmf-buffer" }, { COMPLETION_CAUSE, "completion-cause" }, { COMPLETION_REASON, "completion-reason" }, { CONFIDENCE_THRESHOLD, "confidence-threshold" }, { CONFUSABLE_PHRASES_URI, "confusable-phrases-uri" }, { CONSISTENCY_THRESHOLD, "consistency-threshold" }, { CONTENT_BASE, "content-base" }, { CONTENT_ENCODING, "content-encoding" }, { CONTENT_ID, "content-id" }, { CONTENT_LENGTH, "content-length" }, { CONTENT_LOCATION, "content-location" }, { CONTENT_TYPE, "content-type" }, { DTMF_BUFFER_TIME, "dtmf-buffer-time" }, { DTMF_INTERDIGIT_TIMEOUT, "dtmf-interdigit-timeout" }, { DTMF_TERM_CHAR, "dtmf-term-char" }, { DTMF_TERM_TIMEOUT, "dtmf-term-timeout" }, { EARLY_NO_MATCH, "early-no-match" }, { ENROLL_UTTERANCE, "enroll-utterance" }, { FAILED_URI, "failed-uri" }, { FAILED_URI_CAUSE, "failed-uri-cause" }, { FETCH_HINT, "fetch-hint" }, { FETCH_TIMEOUT, "fetch-timeout" }, { FINAL_SILENCE, "final-silence" }, { HOTWORD_MAX_DURATION, "hotword-max-duration" }, { HOTWORD_MIN_DURATION, "hotword-min-duration" }, { INPUT_TYPE, "input-type" }, { INPUT_WAVEFORM_URI, "input-waveform-uri" }, { INTERPRET_TEXT, "interpret-text" }, { JUMP_SIZE, "jump-size" }, { KILL_ON_BARGE_IN, "kill-on-barge-in" }, { LEXICON_SEARCH_ORDER, "lexicon-search-order" }, { LOAD_LEXICON, "load-lexicon" }, { LOGGING_TAG, "logging-tag" }, { MAX_TIME, "max-time" }, { MEDIA_TYPE, "media-type" }, { MIN_VERIFICATION_SCORE, "min-verification-score" }, { N_BEST_LIST_LENGTH, "n-best-list-length" }, { NEW_AUDIO_CHANNEL, "new-audio-channel" }, { NEW_PHRASE_ID, "new-phrase-id" }, { NO_INPUT_TIMEOUT, "no-input-timeout" }, { NUM_MAX_VERIFICATION_PHRASES, "num-max-verification-phrases" }, { NUM_MIN_CONSISTENT_PRONUNCIATIONS, "num-min-consistent-pronunciations" }, { NUM_MIN_VERIFICATION_PHRASES, "num-min-verification-phrases" }, { PERSONAL_GRAMMAR_URI, "personal-grammar-uri" }, { PHRASE_ID, "phrase-id" }, { PHRASE_NL, "phrase-nl" }, { PROSODY_CONTOUR, "prosody-contour" }, { PROSODY_DURATION, "prosody-duration" }, { PROSODY_PITCH, "prosody-pitch" }, { PROSODY_RANGE, "prosody-range" }, { PROSODY_RATE, "prosody-rate" }, { PROSODY_VOLUME, "prosody-volume" }, { PROXY_SYNC_ID, "proxy-sync-id" }, { RECOGNITION_MODE, "recognition-mode" }, { RECOGNITION_TIMEOUT, "recognition-timeout" }, { RECOGNIZER_CONTEXT_BLOCK, "recognizer-context-block" }, { RECORD_URI, "record-uri" }, { REPOSITORY_URI, "repository-uri" }, { SAVE_BEST_WAVEFORM, "save-best-waveform" }, { SAVE_WAVEFORM, "save-waveform" }, { SENSITIVITY_LEVEL, "sensitivity-level" }, { SET_COOKIE, "set-cookie" }, { SPEAK_LENGTH, "speak-length" }, { SPEAK_RESTART, "speak-restart" }, { SPEAKER_PROFILE, "speaker-profile" }, { SPEECH_COMPLETE_TIMEOUT, "speech-complete-timeout" }, { SPEECH_INCOMPLETE_TIMEOUT, "speech-incomplete-timeout" }, { SPEECH_LANGUAGE, "speech-language" }, { SPEECH_MARKER, "speech-marker" }, { SPEED_VS_ACCURACY, "speed-vs-accuracy" }, { START_INPUT_TIMERS, "start-input-timers" }, { TRIM_LENGTH, "trim-length" }, { VENDOR_SPECIFIC_PARAMETERS, "vendor-specific-parameters" }, { VER_BUFFER_UTTERANCE, "ver-buffer-utterance" }, { VERIFICATION_MODE, "verification-mode" }, { VOICE_AGE, "voice-age" }, { VOICE_GENDER, "voice-gender" }, { VOICE_NAME, "voice-name" }, { VOICE_VARIANT, "voice-variant" }, { VOICEPRINT_EXISTS, "voiceprint-exists" }, { VOICEPRINT_IDENTIFIER, "voiceprint-identifier" }, { WAVEFORM_URI, "waveform-uri" }, { WEIGHT, "weight" }, { 0, NULL } }; /* Initialize the protocol and registered fields */ static int proto_mrcpv2 = -1; static int hf_mrcpv2_Request_Line = -1; static int hf_mrcpv2_Response_Line = -1; static int hf_mrcpv2_Event_Line = -1; static int hf_mrcpv2_Unknown_Message = -1; static int hf_mrcpv2_Unknown_Header = -1; static int hf_mrcpv2_Data = -1; static int hf_mrcpv2_Method = -1; static int hf_mrcpv2_Event = -1; static int hf_mrcpv2_version = -1; static int hf_mrcpv2_message_length = -1; static int hf_mrcpv2_request_id = -1; static int hf_mrcpv2_status_code = -1; static int hf_mrcpv2_request_state = -1; static int hf_mrcpv2_Abort_Model = -1; static int hf_mrcpv2_Abort_Phrase_Enrollment = -1; static int hf_mrcpv2_Abort_Verification = -1; static int hf_mrcpv2_Accept = -1; static int hf_mrcpv2_Accept_Charset = -1; static int hf_mrcpv2_Active_Request_Id_List = -1; static int hf_mrcpv2_Adapt_Model = -1; static int hf_mrcpv2_Audio_Fetch_Hint = -1; static int hf_mrcpv2_Cache_Control = -1; static int hf_mrcpv2_Cancel_If_Queue = -1; static int hf_mrcpv2_Capture_On_Speech = -1; static int hf_mrcpv2_Channel_Identifier = -1; static int hf_mrcpv2_Clash_Threshold = -1; static int hf_mrcpv2_Clear_Dtmf_Buffer = -1; static int hf_mrcpv2_Completion_Cause = -1; static int hf_mrcpv2_Completion_Reason = -1; static int hf_mrcpv2_Confidence_Threshold = -1; static int hf_mrcpv2_Confusable_Phrases_URI = -1; static int hf_mrcpv2_Consistency_Threshold = -1; static int hf_mrcpv2_Content_Base = -1; static int hf_mrcpv2_Content_Encoding = -1; static int hf_mrcpv2_Content_ID = -1; static int hf_mrcpv2_Content_Length = -1; static int hf_mrcpv2_Content_Location = -1; static int hf_mrcpv2_Content_Type = -1; static int hf_mrcpv2_Dtmf_Buffer_Time = -1; static int hf_mrcpv2_Dtmf_Interdigit_Timeout = -1; static int hf_mrcpv2_Dtmf_Term_Char = -1; static int hf_mrcpv2_Dtmf_Term_Timeout = -1; static int hf_mrcpv2_Early_No_Match = -1; static int hf_mrcpv2_Enroll_Utterance = -1; static int hf_mrcpv2_Failed_URI = -1; static int hf_mrcpv2_Failed_URI_Cause = -1; static int hf_mrcpv2_Fetch_Hint = -1; static int hf_mrcpv2_Fetch_Timeout = -1; static int hf_mrcpv2_Final_Silence = -1; static int hf_mrcpv2_Hotword_Max_Duration = -1; static int hf_mrcpv2_Hotword_Min_Duration = -1; static int hf_mrcpv2_Input_Type = -1; static int hf_mrcpv2_Input_Waveform_URI = -1; static int hf_mrcpv2_Interpret_Text = -1; static int hf_mrcpv2_Jump_Size = -1; static int hf_mrcpv2_Kill_On_Barge_In = -1; static int hf_mrcpv2_Lexicon_Search_Order = -1; static int hf_mrcpv2_Load_Lexicon = -1; static int hf_mrcpv2_Logging_Tag = -1; static int hf_mrcpv2_Max_Time = -1; static int hf_mrcpv2_Media_Type = -1; static int hf_mrcpv2_Min_Verification_Score = -1; static int hf_mrcpv2_N_Best_List_Length = -1; static int hf_mrcpv2_New_Audio_Channel = -1; static int hf_mrcpv2_New_Phrase_ID = -1; static int hf_mrcpv2_No_Input_Timeout = -1; static int hf_mrcpv2_Num_Max_Verification_Phrases = -1; static int hf_mrcpv2_Num_Min_Consistent_Pronunciations = -1; static int hf_mrcpv2_Num_Min_Verification_Phrases = -1; static int hf_mrcpv2_Personal_Grammar_URI = -1; static int hf_mrcpv2_Phrase_ID = -1; static int hf_mrcpv2_Phrase_NL = -1; static int hf_mrcpv2_Prosody_Contour = -1; static int hf_mrcpv2_Prosody_Duration = -1; static int hf_mrcpv2_Prosody_Pitch = -1; static int hf_mrcpv2_Prosody_Range = -1; static int hf_mrcpv2_Prosody_Rate = -1; static int hf_mrcpv2_Prosody_Volume = -1; static int hf_mrcpv2_Proxy_Sync_Id = -1; static int hf_mrcpv2_Recognition_Mode = -1; static int hf_mrcpv2_Recognition_Timeout = -1; static int hf_mrcpv2_Recognizer_Context_Block = -1; static int hf_mrcpv2_Record_URI = -1; static int hf_mrcpv2_Repository_URI = -1; static int hf_mrcpv2_Save_Best_Waveform = -1; static int hf_mrcpv2_Save_Waveform = -1; static int hf_mrcpv2_Sensitivity_Level = -1; static int hf_mrcpv2_Set_Cookie = -1; static int hf_mrcpv2_Speak_Length = -1; static int hf_mrcpv2_Speak_Restart = -1; static int hf_mrcpv2_Speaker_Profile = -1; static int hf_mrcpv2_Speech_Complete_Timeout = -1; static int hf_mrcpv2_Speech_Incomplete_Timeout = -1; static int hf_mrcpv2_Speech_Language = -1; static int hf_mrcpv2_Speech_Marker = -1; static int hf_mrcpv2_Speed_Vs_Accuracy = -1; static int hf_mrcpv2_Start_Input_Timers = -1; static int hf_mrcpv2_Trim_Length = -1; static int hf_mrcpv2_Vendor_Specific_Parameters = -1; static int hf_mrcpv2_Ver_Buffer_Utterance = -1; static int hf_mrcpv2_Verification_Mode = -1; static int hf_mrcpv2_Voice_Age = -1; static int hf_mrcpv2_Voice_Gender = -1; static int hf_mrcpv2_Voice_Name = -1; static int hf_mrcpv2_Voice_Variant = -1; static int hf_mrcpv2_Voiceprint_Exists = -1; static int hf_mrcpv2_Voiceprint_Identifier = -1; static int hf_mrcpv2_Waveform_URI = -1; static int hf_mrcpv2_Weight = -1; static expert_field ei_mrcpv2_Content_Length_invalid = EI_INIT; /* Global MRCPv2 port pref */ #define TCP_DEFAULT_RANGE "6075, 30000-30200" /* Not IANA registered */ /* Initialize the subtree pointers */ static gint ett_mrcpv2 = -1; static gint ett_Request_Line = -1; static gint ett_Response_Line = -1; static gint ett_Event_Line = -1; static gint ett_Status_Code = -1; /* format status code description */ static const string_string status_code_vals[] = { { "200", "Success" }, { "201", "Success with some optional header fields ignored" }, { "401", "Client Failure: Method not allowed" }, { "402", "Client Failure: Method not valid in this state" }, { "403", "Client Failure: Unsupported header field" }, { "404", "Client Failure: Illegal value for header field. This is the error for a syntax violation." }, { "405", "Client Failure: Resource not allocated for this session or does not exist" }, { "406", "Client Failure: Mandatory Header Field Missing" }, { "407", "Client Failure: Method or Operation Failed (e.g., Grammar compilation failed in the recognizer. Detailed cause codes might be available through a resource specific header.)" }, { "408", "Client Failure: Unrecognized or unsupported message entity" }, { "409", "Client Failure: Unsupported Header Field Value. This is a value that is syntactically legal but exceeds the implementation's capabilities or expectations." }, { "410", "Client Failure: Non-Monotonic or Out of order sequence number in request." }, { "501", "Server Failure: Server Internal Error" }, { "502", "Server Failure: Protocol Version not supported" }, { "503", "Server Failure: Reserved for future assignment" }, { "504", "Server Failure: Message too large" }, { NULL, NULL } }; /* Code to actually dissect the packets */ static int dissect_mrcpv2_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti; proto_tree *mrcpv2_tree; gint next_offset, linelen; gint tvb_len; gint pdu_size; gint offset; gint value_offset; gint str_len; gchar *header_name; gchar *header_value; LINE_TYPE line_type = UNKNOWN_LINE; HEADER_TYPE header_type; gint colon_offset; gint content_length; const value_string *p = NULL; proto_item *line_item = NULL; proto_item *request_line_item = NULL; proto_item *response_line_item = NULL; proto_item *event_line_item = NULL; proto_item *status_code_item = NULL; proto_item *pi = NULL; gint sp_start; gint sp_end; guint8 *field1; guint8 *field2; guint8 *field3; guint8 *field4; guint8 *field5 = NULL; /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MRCPv2"); offset = 0; tvb_len = tvb_reported_length(tvb); ti = proto_tree_add_item(tree, proto_mrcpv2, tvb, 0, -1, ENC_UTF_8); mrcpv2_tree = proto_item_add_subtree(ti, ett_mrcpv2); /* get first line */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* find out MRCP message type: request-line = mrcp-version SP message-length SP method-name SP request-id CRLF response-line = mrcp-version SP message-length SP request-id SP status-code SP request-state CRLF event-line = mrcp-version SP message-length SP event-name SP request-id SP request-state CRLF */ /* version */ sp_end = tvb_find_guint8(tvb, 0, linelen, ' '); if ((sp_end == -1) || (sp_end > tvb_len) || (sp_end > linelen)) return -1; field1 = tvb_get_string_enc(pinfo->pool, tvb, 0, sp_end, ENC_ASCII); sp_start = sp_end + 1; /* length */ sp_end = tvb_find_guint8(tvb, sp_start, linelen - sp_start, ' '); if ((sp_end == -1) || (sp_end > tvb_len) || (sp_end > linelen)) return -1; field2 = tvb_get_string_enc(pinfo->pool, tvb, sp_start, sp_end - sp_start, ENC_ASCII); sp_start = sp_end + 1; /* method, request ID or event */ sp_end = tvb_find_guint8(tvb, sp_start, linelen - sp_start, ' '); if ((sp_end == -1) || (sp_end > tvb_len) || (sp_end > linelen)) return -1; field3 = tvb_get_string_enc(pinfo->pool, tvb, sp_start, sp_end - sp_start, ENC_ASCII); sp_start = sp_end + 1; /* request ID or status code */ sp_end = tvb_find_guint8(tvb, sp_start, linelen - sp_start, ' '); if (sp_end == -1) { field4 = tvb_get_string_enc(pinfo->pool, tvb, sp_start, linelen - sp_start, ENC_ASCII); line_type = REQUEST_LINE; /* only request line has 4 parameters */ } else { if ((sp_end > tvb_len) || (sp_end > linelen)) return -1; field4 = tvb_get_string_enc(pinfo->pool, tvb, sp_start, sp_end - sp_start, ENC_ASCII); if (g_ascii_isdigit(field3[0])) /* request ID is number, so it has to be response */ line_type = RESPONSE_LINE; else line_type = EVENT_LINE; sp_start = sp_end + 1; sp_end = linelen; if ((sp_end > tvb_len) || (sp_end > linelen)) return -1; field5 = tvb_get_string_enc(pinfo->pool, tvb, sp_start, sp_end - sp_start, ENC_ASCII); } /* check pdu size */ if (!ws_strtou32(field2, NULL, &pdu_size) || pdu_size > tvb_len) return -1; /* process MRCP header line */ switch(line_type){ case REQUEST_LINE: { col_set_str(pinfo->cinfo, COL_INFO, "Request: "); line_item = proto_tree_add_item(mrcpv2_tree, hf_mrcpv2_Request_Line, tvb, offset, linelen, ENC_UTF_8); request_line_item = proto_item_add_subtree(line_item, ett_Request_Line); /* version */ str_len = (gint)strlen(field1); proto_tree_add_item(request_line_item, hf_mrcpv2_version, tvb, offset, str_len, ENC_UTF_8); offset += str_len + 1; /* add SP */ /* message length */ str_len = (gint)strlen(field2); proto_tree_add_item(request_line_item, hf_mrcpv2_message_length, tvb, offset, str_len, ENC_UTF_8); offset += str_len + 1; /* add SP */ /* method name */ col_append_str(pinfo->cinfo, COL_INFO, field3); str_len = (gint)strlen(field3); proto_tree_add_item(request_line_item, hf_mrcpv2_Method, tvb, offset, str_len, ENC_UTF_8); offset += str_len + 1; /* add SP */ /* request ID */ str_len = (gint)strlen(field4); proto_tree_add_item(request_line_item, hf_mrcpv2_request_id, tvb, offset, str_len, ENC_UTF_8); /*offset += str_len + 2;*/ /* add CRLF */ } break; case RESPONSE_LINE: { col_set_str(pinfo->cinfo, COL_INFO, "Response: "); line_item = proto_tree_add_item(mrcpv2_tree, hf_mrcpv2_Response_Line, tvb, offset, linelen, ENC_UTF_8); response_line_item = proto_item_add_subtree(line_item, ett_Response_Line); /* version */ str_len = (gint)strlen(field1); proto_tree_add_item(response_line_item, hf_mrcpv2_version, tvb, offset, str_len, ENC_UTF_8); offset += str_len + 1; /* add SP */ /* message length */ str_len = (gint)strlen(field2); proto_tree_add_item(response_line_item, hf_mrcpv2_message_length, tvb, offset, str_len, ENC_UTF_8); offset += str_len + 1; /* add SP */ /* request ID */ str_len = (gint)strlen(field3); proto_tree_add_item(response_line_item, hf_mrcpv2_request_id, tvb, offset, str_len, ENC_UTF_8); offset += str_len + 1; /* add SP */ /* status code */ str_len = (gint)strlen(field4); status_code_item = proto_tree_add_item(response_line_item, hf_mrcpv2_status_code, tvb, offset, str_len, ENC_UTF_8); proto_item_append_text(status_code_item, " %s", str_to_str(field4, status_code_vals, "Unknown Status Code")); offset += str_len + 1; /* add SP */ /* request state */ col_append_fstr(pinfo->cinfo, COL_INFO, "(%s) %s", field4, field5); str_len = (gint)strlen(field5); proto_tree_add_item(response_line_item, hf_mrcpv2_request_state, tvb, offset, str_len, ENC_UTF_8); /*offset += str_len + 2;*/ /* add CRLF */ } break; case EVENT_LINE: { col_set_str(pinfo->cinfo, COL_INFO, "Event: "); line_item = proto_tree_add_item(mrcpv2_tree, hf_mrcpv2_Event_Line, tvb, offset, linelen, ENC_UTF_8); event_line_item = proto_item_add_subtree(line_item, ett_Event_Line); /* version */ str_len = (gint)strlen(field1); proto_tree_add_item(event_line_item, hf_mrcpv2_version, tvb, offset, str_len, ENC_UTF_8); offset += str_len + 1; /* add SP */ /* message length */ str_len = (gint)strlen(field2); proto_tree_add_item(event_line_item, hf_mrcpv2_message_length, tvb, offset, str_len, ENC_UTF_8); offset += str_len + 1; /* add SP */ /* event name */ col_append_str(pinfo->cinfo, COL_INFO, field3); str_len = (gint)strlen(field3); proto_tree_add_item(event_line_item, hf_mrcpv2_Event, tvb, offset, str_len, ENC_UTF_8); offset += str_len + 1; /* add SP */ /* request ID */ str_len = (gint)strlen(field4); proto_tree_add_item(event_line_item, hf_mrcpv2_request_id, tvb, offset, str_len, ENC_UTF_8); offset += str_len + 1; /* add SP */ /* request state */ str_len = (gint)strlen(field5); proto_tree_add_item(event_line_item, hf_mrcpv2_request_state, tvb, offset, str_len, ENC_UTF_8); /*offset += str_len + 2;*/ /* add CRLF */ } break; default: { /* mark whole packet as unknown and return */ col_set_str(pinfo->cinfo, COL_INFO, "UNKNOWN message"); proto_tree_add_item(mrcpv2_tree, hf_mrcpv2_Unknown_Message, tvb, offset, tvb_len, ENC_UTF_8); return tvb_len; } } if (tree) { /* process the rest of the header lines here */ content_length = 0; while (tvb_offset_exists(tvb, next_offset)) { /* get next line */ offset = next_offset; linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* blank line separates msg header and msg body */ if (linelen == 0) { if (content_length > 0) { /* content length > 0 and CRLF detected, this has to be msg body */ offset += 2; /* skip separating CRLF */ proto_tree_add_item(mrcpv2_tree, hf_mrcpv2_Data, tvb, offset, tvb_len - offset, ENC_ASCII); next_offset = tvb_len; /* we are done */ } continue; } /* get header type and its value */ colon_offset = tvb_find_guint8(tvb, offset, linelen, ':'); if (colon_offset == -1) { /* header type should end with ':' */ proto_tree_add_item(mrcpv2_tree, hf_mrcpv2_Unknown_Header, tvb, offset, linelen, ENC_UTF_8); continue; } header_name = tvb_get_string_enc(pinfo->pool, tvb, offset, colon_offset - offset, ENC_ASCII); ascii_strdown_inplace(header_name); value_offset = tvb_skip_wsp(tvb, colon_offset + 1, offset + linelen - (colon_offset + 1)); header_value = tvb_get_string_enc(pinfo->pool, tvb, value_offset, offset + linelen - value_offset, ENC_ASCII); /* find out header type */ header_type = UNKNOWN; for (p = header_type_vals; p->strptr != NULL; ++p) { if (strncmp(p->strptr, header_name, strlen(p->strptr)) == 0) { header_type = (HEADER_TYPE)p->value; break; } } /* add header type and value into the tree */ switch (header_type) { case ABORT_MODEL: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Abort_Model, tvb, offset, linelen, header_value); break; case ABORT_PHRASE_ENROLLMENT: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Abort_Phrase_Enrollment, tvb, offset, linelen, header_value); break; case ABORT_VERIFICATION: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Abort_Verification, tvb, offset, linelen, header_value); break; case ACCEPT: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Accept, tvb, offset, linelen, header_value); break; case ACCEPT_CHARSET: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Accept_Charset, tvb, offset, linelen, header_value); break; case ACTIVE_REQUEST_ID_LIST: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Active_Request_Id_List, tvb, offset, linelen, header_value); break; case ADAPT_MODEL: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Adapt_Model, tvb, offset, linelen, header_value); break; case AUDIO_FETCH_HINT: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Audio_Fetch_Hint, tvb, offset, linelen, header_value); break; case CACHE_CONTROL: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Cache_Control, tvb, offset, linelen, header_value); break; case CANCEL_IF_QUEUE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Cancel_If_Queue, tvb, offset, linelen, header_value); break; case CAPTURE_ON_SPEECH: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Capture_On_Speech, tvb, offset, linelen, header_value); break; case CHANNEL_IDENTIFIER: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Channel_Identifier, tvb, offset, linelen, header_value); break; case CLASH_THRESHOLD: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Clash_Threshold, tvb, offset, linelen, header_value); break; case CLEAR_DTMF_BUFFER: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Clear_Dtmf_Buffer, tvb, offset, linelen, header_value); break; case COMPLETION_CAUSE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Completion_Cause, tvb, offset, linelen, header_value); break; case COMPLETION_REASON: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Completion_Reason, tvb, offset, linelen, header_value); break; case CONFIDENCE_THRESHOLD: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Confidence_Threshold, tvb, offset, linelen, header_value); break; case CONFUSABLE_PHRASES_URI: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Confusable_Phrases_URI, tvb, offset, linelen, header_value); break; case CONSISTENCY_THRESHOLD: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Consistency_Threshold, tvb, offset, linelen, header_value); break; case CONTENT_BASE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Content_Base, tvb, offset, linelen, header_value); break; case CONTENT_ENCODING: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Content_Encoding, tvb, offset, linelen, header_value); break; case CONTENT_ID: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Content_ID, tvb, offset, linelen, header_value); break; case CONTENT_LENGTH: pi = proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Content_Length, tvb, offset, linelen, header_value); /* if content length is > 0, then there are some data after the headers */ if (!ws_strtou32(header_value, NULL, &content_length)) { content_length = 0; expert_add_info(pinfo, pi, &ei_mrcpv2_Content_Length_invalid); } break; case CONTENT_LOCATION: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Content_Location, tvb, offset, linelen, header_value); break; case CONTENT_TYPE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Content_Type, tvb, offset, linelen, header_value); break; case DTMF_BUFFER_TIME: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Dtmf_Buffer_Time, tvb, offset, linelen, header_value); break; case DTMF_INTERDIGIT_TIMEOUT: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Dtmf_Interdigit_Timeout, tvb, offset, linelen, header_value); break; case DTMF_TERM_CHAR: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Dtmf_Term_Char, tvb, offset, linelen, header_value); break; case DTMF_TERM_TIMEOUT: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Dtmf_Term_Timeout, tvb, offset, linelen, header_value); break; case EARLY_NO_MATCH: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Early_No_Match, tvb, offset, linelen, header_value); break; case ENROLL_UTTERANCE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Enroll_Utterance, tvb, offset, linelen, header_value); break; case FAILED_URI: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Failed_URI, tvb, offset, linelen, header_value); break; case FAILED_URI_CAUSE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Failed_URI_Cause, tvb, offset, linelen, header_value); break; case FETCH_HINT: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Fetch_Hint, tvb, offset, linelen, header_value); break; case FETCH_TIMEOUT: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Fetch_Timeout, tvb, offset, linelen, header_value); break; case FINAL_SILENCE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Final_Silence, tvb, offset, linelen, header_value); break; case HOTWORD_MAX_DURATION: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Hotword_Max_Duration, tvb, offset, linelen, header_value); break; case HOTWORD_MIN_DURATION: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Hotword_Min_Duration, tvb, offset, linelen, header_value); break; case INPUT_TYPE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Input_Type, tvb, offset, linelen, header_value); break; case INPUT_WAVEFORM_URI: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Input_Waveform_URI, tvb, offset, linelen, header_value); break; case INTERPRET_TEXT: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Interpret_Text, tvb, offset, linelen, header_value); break; case JUMP_SIZE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Jump_Size, tvb, offset, linelen, header_value); break; case KILL_ON_BARGE_IN: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Kill_On_Barge_In, tvb, offset, linelen, header_value); break; case LEXICON_SEARCH_ORDER: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Lexicon_Search_Order, tvb, offset, linelen, header_value); break; case LOAD_LEXICON: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Load_Lexicon, tvb, offset, linelen, header_value); break; case LOGGING_TAG: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Logging_Tag, tvb, offset, linelen, header_value); break; case MAX_TIME: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Max_Time, tvb, offset, linelen, header_value); break; case MEDIA_TYPE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Media_Type, tvb, offset, linelen, header_value); break; case MIN_VERIFICATION_SCORE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Min_Verification_Score, tvb, offset, linelen, header_value); break; case N_BEST_LIST_LENGTH: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_N_Best_List_Length, tvb, offset, linelen, header_value); break; case NEW_AUDIO_CHANNEL: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_New_Audio_Channel, tvb, offset, linelen, header_value); break; case NEW_PHRASE_ID: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_New_Phrase_ID, tvb, offset, linelen, header_value); break; case NO_INPUT_TIMEOUT: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_No_Input_Timeout, tvb, offset, linelen, header_value); break; case NUM_MAX_VERIFICATION_PHRASES: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Num_Max_Verification_Phrases, tvb, offset, linelen, header_value); break; case NUM_MIN_CONSISTENT_PRONUNCIATIONS: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Num_Min_Consistent_Pronunciations, tvb, offset, linelen, header_value); break; case NUM_MIN_VERIFICATION_PHRASES: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Num_Min_Verification_Phrases, tvb, offset, linelen, header_value); break; case PERSONAL_GRAMMAR_URI: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Personal_Grammar_URI, tvb, offset, linelen, header_value); break; case PHRASE_ID: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Phrase_ID, tvb, offset, linelen, header_value); break; case PHRASE_NL: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Phrase_NL, tvb, offset, linelen, header_value); break; case PROSODY_CONTOUR: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Prosody_Contour, tvb, offset, linelen, header_value); break; case PROSODY_DURATION: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Prosody_Duration, tvb, offset, linelen, header_value); break; case PROSODY_PITCH: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Prosody_Pitch, tvb, offset, linelen, header_value); break; case PROSODY_RANGE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Prosody_Range, tvb, offset, linelen, header_value); break; case PROSODY_RATE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Prosody_Rate, tvb, offset, linelen, header_value); break; case PROSODY_VOLUME: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Prosody_Volume, tvb, offset, linelen, header_value); break; case PROXY_SYNC_ID: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Proxy_Sync_Id, tvb, offset, linelen, header_value); break; case RECOGNITION_MODE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Recognition_Mode, tvb, offset, linelen, header_value); break; case RECOGNITION_TIMEOUT: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Recognition_Timeout, tvb, offset, linelen, header_value); break; case RECOGNIZER_CONTEXT_BLOCK: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Recognizer_Context_Block, tvb, offset, linelen, header_value); break; case RECORD_URI: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Record_URI, tvb, offset, linelen, header_value); break; case REPOSITORY_URI: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Repository_URI, tvb, offset, linelen, header_value); break; case SAVE_BEST_WAVEFORM: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Save_Best_Waveform, tvb, offset, linelen, header_value); break; case SAVE_WAVEFORM: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Save_Waveform, tvb, offset, linelen, header_value); break; case SENSITIVITY_LEVEL: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Sensitivity_Level, tvb, offset, linelen, header_value); break; case SET_COOKIE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Set_Cookie, tvb, offset, linelen, header_value); break; case SPEAK_LENGTH: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Speak_Length, tvb, offset, linelen, header_value); break; case SPEAK_RESTART: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Speak_Restart, tvb, offset, linelen, header_value); break; case SPEAKER_PROFILE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Speaker_Profile, tvb, offset, linelen, header_value); break; case SPEECH_COMPLETE_TIMEOUT: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Speech_Complete_Timeout, tvb, offset, linelen, header_value); break; case SPEECH_INCOMPLETE_TIMEOUT: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Speech_Incomplete_Timeout, tvb, offset, linelen, header_value); break; case SPEECH_LANGUAGE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Speech_Language, tvb, offset, linelen, header_value); break; case SPEECH_MARKER: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Speech_Marker, tvb, offset, linelen, header_value); break; case SPEED_VS_ACCURACY: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Speed_Vs_Accuracy, tvb, offset, linelen, header_value); break; case START_INPUT_TIMERS: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Start_Input_Timers, tvb, offset, linelen, header_value); break; case TRIM_LENGTH: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Trim_Length, tvb, offset, linelen, header_value); break; case VENDOR_SPECIFIC_PARAMETERS: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Vendor_Specific_Parameters, tvb, offset, linelen, header_value); break; case VER_BUFFER_UTTERANCE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Ver_Buffer_Utterance, tvb, offset, linelen, header_value); break; case VERIFICATION_MODE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Verification_Mode, tvb, offset, linelen, header_value); break; case VOICE_AGE: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Voice_Age, tvb, offset, linelen, header_value); break; case VOICE_GENDER: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Voice_Gender, tvb, offset, linelen, header_value); break; case VOICE_NAME: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Voice_Name, tvb, offset, linelen, header_value); break; case VOICE_VARIANT: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Voice_Variant, tvb, offset, linelen, header_value); break; case VOICEPRINT_EXISTS: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Voiceprint_Exists, tvb, offset, linelen, header_value); break; case VOICEPRINT_IDENTIFIER: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Voiceprint_Identifier, tvb, offset, linelen, header_value); break; case WAVEFORM_URI: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Waveform_URI, tvb, offset, linelen, header_value); break; case WEIGHT: proto_tree_add_string(mrcpv2_tree, hf_mrcpv2_Weight, tvb, offset, linelen, header_value); break; default: proto_tree_add_item(mrcpv2_tree, hf_mrcpv2_Unknown_Header, tvb, offset, linelen, ENC_UTF_8); break; } } } /* Return the amount of data this dissector was able to dissect */ return tvb_captured_length(tvb); } /* get the length of the MRCP message */ static guint get_mrcpv2_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) { gint len_start; gint len_end; guint8 *msg_len; guint num_msg_len = 0; /* first string is version */ len_start = tvb_find_guint8(tvb, offset, MRCPV2_MIN_PDU_LEN, ' '); if (len_start == -1) return 0; len_start += 1; /* skip whitespace */ /* second string is message length */ len_end = tvb_find_guint8(tvb, len_start, MRCPV2_MIN_PDU_LEN - len_start, ' '); if (len_end == -1) msg_len = tvb_get_string_enc(pinfo->pool, tvb, len_start, MRCPV2_MIN_PDU_LEN - len_start, ENC_ASCII); else msg_len = tvb_get_string_enc(pinfo->pool, tvb, len_start, len_end - len_start, ENC_ASCII); ws_strtou32(msg_len, NULL, &num_msg_len); return num_msg_len; } static int dissect_mrcpv2_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { return dissect_mrcpv2_common(tvb, pinfo, tree); } static int dissect_mrcpv2_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { gint len; gint value_size; guint8 *version; guint8 *major; guint8 *minor; gint slash_offset; gint dot_offset; gint sp_offset; int value; len = tvb_captured_length(tvb); if (len < MRCPV2_MIN_LENGTH) /* too short, can't conclude if it's mrcp */ return 0; /* we are looking for MRCP string */ slash_offset = tvb_find_guint8(tvb, 0, MRCPV2_MIN_LENGTH, '/'); if (slash_offset != 4) return 0; version = tvb_get_string_enc(pinfo->pool, tvb, 0, slash_offset, ENC_ASCII); if (strcmp(version, "MRCP") != 0) return 0; /* get first digit after the '/'; it should be 2 */ dot_offset = tvb_find_guint8(tvb, slash_offset + 1, MRCPV2_MIN_LENGTH - slash_offset - 1, '.'); if (dot_offset == -1) return 0; value_size = dot_offset - slash_offset - 1; if ((value_size != 1) && (value_size != 2)) return 0; major = tvb_get_string_enc(pinfo->pool, tvb, slash_offset + 1, value_size, ENC_ASCII); if (!ws_strtou32(major, NULL, &value) || value != 2) return 0; /* get second digit, it should be 0 */ sp_offset = tvb_find_guint8(tvb, dot_offset + 1, MRCPV2_MIN_LENGTH - dot_offset - 1, ' '); if (sp_offset == -1) { minor = tvb_get_string_enc(pinfo->pool, tvb, dot_offset + 1, MRCPV2_MIN_LENGTH - dot_offset - 1, ENC_ASCII); len = MRCPV2_MIN_LENGTH; } else { minor = tvb_get_string_enc(pinfo->pool, tvb, dot_offset + 1, MRCPV2_MIN_LENGTH - sp_offset - 1, ENC_ASCII); len = sp_offset; } if (!ws_strtou32(minor, NULL, &value) || value != 0) return 0; /* if we are here, then we have MRCP v 2.0 protocol, so proceed with the dissection */ tcp_dissect_pdus(tvb, pinfo, tree, TRUE, MRCPV2_MIN_PDU_LEN, get_mrcpv2_pdu_len, dissect_mrcpv2_tcp_pdu, data); return len; } void proto_register_mrcpv2(void) { expert_module_t* expert_mrcpv2; static hf_register_info hf[] = { { &hf_mrcpv2_Request_Line, { "Request-Line", "mrcpv2.Request-Line", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_mrcpv2_Response_Line, { "Response-Line", "mrcpv2.Response-Line", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_mrcpv2_Event_Line, { "Event-Line", "mrcpv2.Event-Line", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_mrcpv2_Unknown_Message, { "Unknown Message", "mrcpv2.Unknown-Message", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_mrcpv2_Unknown_Header, { "Unknown Header", "mrcpv2.Unknown-Header", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_mrcpv2_Data, { "Message data", "mrcpv2.Data", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_mrcpv2_Method, { "Method", "mrcpv2.Method", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_mrcpv2_Event, { "Event", "mrcpv2.Event", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_mrcpv2_version, { "Version", "mrcpv2.Version", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_mrcpv2_message_length, { "Message Length", "mrcpv2.msg_len", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_mrcpv2_request_id, { "Request ID", "mrcpv2.reqID", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_mrcpv2_status_code, { "Status Code", "mrcpv2.status_code", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_mrcpv2_request_state, { "Request State", "mrcpv2.request_state", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_mrcpv2_Abort_Model, { "Abort-Model", "mrcpv2.Abort-Model", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Abort_Phrase_Enrollment, { "Abort-Phrase-Enrollment", "mrcpv2.Abort-Phrase-Enrollment", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Abort_Verification, { "Abort-Verification", "mrcpv2.Abort-Verification", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Accept, { "Accept", "mrcpv2.Accept", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Accept_Charset, { "Accept-Charset", "mrcpv2.Accept-Charset", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Active_Request_Id_List, { "Active-Request-Id-List", "mrcpv2.Active-Request-Id-List", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Adapt_Model, { "Adapt-Model", "mrcpv2.Adapt-Model", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Audio_Fetch_Hint, { "Audio-Fetch-Hint", "mrcpv2.Audio-Fetch-Hint", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Cache_Control, { "Cache-Control", "mrcpv2.Cache-Control", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Cancel_If_Queue, { "Cancel-If-Queue", "mrcpv2.Cancel-If-Queue", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Capture_On_Speech, { "Capture-On-Speech", "mrcpv2.Capture-On-Speech", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Channel_Identifier, { "Channel-Identifier", "mrcpv2.Channel-Identifier", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Clash_Threshold, { "Clash-Threshold", "mrcpv2.Clash-Threshold", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Clear_Dtmf_Buffer, { "Clear-Dtmf-Buffer", "mrcpv2.Clear-Dtmf-Buffer", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Completion_Cause, { "Completion-Cause", "mrcpv2.Completion-Cause", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Completion_Reason, { "Completion-Reason", "mrcpv2.Completion-Reason", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Confidence_Threshold, { "Confidence-Threshold", "mrcpv2.Confidence-Threshold", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Confusable_Phrases_URI, { "Confusable-Phrases-URI", "mrcpv2.Confusable-Phrases-URI", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Consistency_Threshold, { "Consistency-Threshold", "mrcpv2.Consistency-Threshold", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Content_Base, { "Content-Base", "mrcpv2.Content-Base", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Content_Encoding, { "Content-Encoding", "mrcpv2.Content-Encoding", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Content_ID, { "Content-ID", "mrcpv2.Content-ID", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Content_Length, { "Content-Length", "mrcpv2.Content-Length", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Content_Location, { "Content-Location", "mrcpv2.Content-Location", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Content_Type, { "Content-Type", "mrcpv2.Content-Type", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Dtmf_Buffer_Time, { "Dtmf-Buffer-Time", "mrcpv2.Dtmf-Buffer-Time", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Dtmf_Interdigit_Timeout, { "Dtmf-Interdigit-Timeout", "mrcpv2.Dtmf-Interdigit-Timeout", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Dtmf_Term_Char, { "Dtmf-Term-Char", "mrcpv2.Dtmf-Term-Char", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Dtmf_Term_Timeout, { "Dtmf-Term-Timeout", "mrcpv2.Dtmf-Term-Timeout", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Early_No_Match, { "Early-No-Match", "mrcpv2.Early-No-Match", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Enroll_Utterance, { "Enroll-Utterance", "mrcpv2.Enroll-Utterance", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Failed_URI, { "Failed-URI", "mrcpv2.Failed-URI", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Failed_URI_Cause, { "Failed-URI-Cause", "mrcpv2.Failed-URI-Cause", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Fetch_Hint, { "Fetch-Hint", "mrcpv2.Fetch-Hint", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Fetch_Timeout, { "Fetch-Timeout", "mrcpv2.Fetch-Timeout", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Final_Silence, { "Final-Silence", "mrcpv2.Final-Silence", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Hotword_Max_Duration, { "Hotword-Max-Duration", "mrcpv2.Hotword-Max-Duration", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Hotword_Min_Duration, { "Hotword-Min-Duration", "mrcpv2.Hotword-Min-Duration", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Input_Type, { "Input-Type", "mrcpv2.Input-Type", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Input_Waveform_URI, { "Input-Waveform-URI", "mrcpv2.Input-Waveform-URI", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Interpret_Text, { "Interpret-Text", "mrcpv2.Interpret-Text", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Jump_Size, { "Jump-Size", "mrcpv2.Jump-Size", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Kill_On_Barge_In, { "Kill-On-Barge-In", "mrcpv2.Kill-On-Barge-In", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Lexicon_Search_Order, { "Lexicon-Search-Order", "mrcpv2.Lexicon-Search-Order", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Load_Lexicon, { "Load-Lexicon", "mrcpv2.Load-Lexicon", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Logging_Tag, { "Logging-Tag", "mrcpv2.Logging-Tag", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Max_Time, { "Max-Time", "mrcpv2.Max-Time", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Media_Type, { "Media-Type", "mrcpv2.Media-Type", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Min_Verification_Score, { "Min-Verification-Score", "mrcpv2.Min-Verification-Score", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_N_Best_List_Length, { "N-Best-List-Length", "mrcpv2.N-Best-List-Length", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_New_Audio_Channel, { "New-Audio-Channel", "mrcpv2.New-Audio-Channel", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_New_Phrase_ID, { "New-Phrase-ID", "mrcpv2.New-Phrase-ID", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_No_Input_Timeout, { "No-Input-Timeout", "mrcpv2.No-Input-Timeout", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Num_Max_Verification_Phrases, { "Num-Max-Verification-Phrases", "mrcpv2.Num-Max-Verification-Phrases", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Num_Min_Consistent_Pronunciations, { "Num-Min-Consistent-Pronunciations", "mrcpv2.Num-Min-Consistent-Pronunciations", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Num_Min_Verification_Phrases, { "Num-Min-Verification-Phrases", "mrcpv2.Num-Min-Verification-Phrases", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Personal_Grammar_URI, { "Personal-Grammar-URI", "mrcpv2.Personal-Grammar-URI", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Phrase_ID, { "Phrase-ID", "mrcpv2.Phrase-ID", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Phrase_NL, { "Phrase-NL", "mrcpv2.Phrase-NL", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Prosody_Contour, { "Prosody-Contour", "mrcpv2.Prosody-Contour", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Prosody_Duration, { "Prosody-Duration", "mrcpv2.Prosody-Duration", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Prosody_Pitch, { "Prosody-Pitch", "mrcpv2.Prosody-Pitch", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Prosody_Range, { "Prosody-Range", "mrcpv2.Prosody-Range", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Prosody_Rate, { "Prosody-Rate", "mrcpv2.Prosody-Rate", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Prosody_Volume, { "Prosody-Volume", "mrcpv2.Prosody-Volume", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Proxy_Sync_Id, { "Proxy-Sync-Id", "mrcpv2.Proxy-Sync-Id", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Recognition_Mode, { "Recognition-Mode", "mrcpv2.Recognition-Mode", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Recognition_Timeout, { "Recognition-Timeout", "mrcpv2.Recognition-Timeout", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Recognizer_Context_Block, { "Recognizer-Context-Block", "mrcpv2.Recognizer-Context-Block", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Record_URI, { "Record-URI", "mrcpv2.Record-URI", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Repository_URI, { "Repository-URI", "mrcpv2.Repository-URI", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Save_Best_Waveform, { "Save-Best-Waveform", "mrcpv2.Save-Best-Waveform", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Save_Waveform, { "Save-Waveform", "mrcpv2.Save-Waveform", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Sensitivity_Level, { "Sensitivity-Level", "mrcpv2.Sensitivity-Level", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Set_Cookie, { "Set-Cookie", "mrcpv2.Set-Cookie", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Speak_Length, { "Speak-Length", "mrcpv2.Speak-Length", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Speak_Restart, { "Speak-Restart", "mrcpv2.Speak-Restart", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Speaker_Profile, { "Speaker-Profile", "mrcpv2.Speaker-Profile", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Speech_Complete_Timeout, { "Speech-Complete-Timeout", "mrcpv2.Speech-Complete-Timeout", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Speech_Incomplete_Timeout, { "Speech-Incomplete-Timeout", "mrcpv2.Speech-Incomplete-Timeout", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Speech_Language, { "Speech-Language", "mrcpv2.Speech-Language", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Speech_Marker, { "Speech-Marker", "mrcpv2.Speech-Marker", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Speed_Vs_Accuracy, { "Speed-Vs-Accuracy", "mrcpv2.Speed-Vs-Accuracy", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Start_Input_Timers, { "Start-Input-Timers", "mrcpv2.Start-Input-Timers", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Trim_Length, { "Trim-Length", "mrcpv2.Trim-Length", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Vendor_Specific_Parameters, { "Vendor-Specific-Parameters", "mrcpv2.Vendor-Specific-Parameters", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Ver_Buffer_Utterance, { "Ver-Buffer-Utterance", "mrcpv2.Ver-Buffer-Utterance", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Verification_Mode, { "Verification-Mode", "mrcpv2.Verification-Mode", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Voice_Age, { "Voice-Age", "mrcpv2.Voice-Age", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Voice_Gender, { "Voice-Gender", "mrcpv2.Voice-Gender", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Voice_Name, { "Voice-Name", "mrcpv2.Voice-Name", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Voice_Variant, { "Voice-Variant", "mrcpv2.Voice-Variant", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Voiceprint_Exists, { "Voiceprint-Exists", "mrcpv2.Voiceprint-Exists", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Voiceprint_Identifier, { "Voiceprint-Identifier", "mrcpv2.Voiceprint-Identifier", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Waveform_URI, { "Waveform-URI", "mrcpv2.Waveform-URI", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, }, { &hf_mrcpv2_Weight, { "Weight", "mrcpv2.Weight", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }, } }; static ei_register_info ei[] = { { &ei_mrcpv2_Content_Length_invalid, { "mrcpv2.Content-Length.invalid", PI_MALFORMED, PI_ERROR, "Content Length must be a string containing an integer", EXPFILL }} }; static gint *ett[] = { &ett_mrcpv2, &ett_Request_Line, &ett_Response_Line, &ett_Event_Line, &ett_Status_Code }; proto_mrcpv2 = proto_register_protocol("Media Resource Control Protocol Version 2 (MRCPv2)", "MRCPv2", "mrcpv2"); proto_register_field_array(proto_mrcpv2, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); expert_mrcpv2 = expert_register_protocol(proto_mrcpv2); expert_register_field_array(expert_mrcpv2, ei, array_length(ei)); } void proto_reg_handoff_mrcpv2(void) { dissector_handle_t mrcpv2_handle; mrcpv2_handle = create_dissector_handle(dissect_mrcpv2_tcp, proto_mrcpv2); dissector_add_uint_range_with_preference ("tcp.port", TCP_DEFAULT_RANGE, mrcpv2_handle); } /* * Editor modelines * * Local Variables: * c-basic-offset: 4 * tab-width: 8 * indent-tabs-mode: nil * End: * * ex: set shiftwidth=4 tabstop=8 expandtab: * :indentSize=4:tabSize=8:noTabs=true: */