static int call_dop_oid_callback(char *base_string, tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *col_info) { char* binding_param; binding_param = ep_strdup_printf("%s.%s", base_string, binding_type ? binding_type : ""); if (col_info && (check_col(pinfo->cinfo, COL_INFO))) col_append_fstr(pinfo->cinfo, COL_INFO, " %s", col_info); if (dissector_try_string(dop_dissector_table, binding_param, tvb, pinfo, tree)) { offset += tvb_length_remaining (tvb, offset); } else { proto_item *item=NULL; proto_tree *next_tree=NULL; item = proto_tree_add_text(tree, tvb, 0, tvb_length_remaining(tvb, offset), "Dissector for parameter %s OID:%s not implemented. Contact Wireshark developers if you want this supported", base_string, binding_type ? binding_type : "<empty>"); if (item) { next_tree = proto_item_add_subtree(item, ett_dop_unknown); } offset = dissect_unknown_ber(pinfo, tvb, offset, next_tree); expert_add_info_format(pinfo, item, PI_UNDECODED, PI_WARN, "Unknown binding-parameter"); } return offset; }
static int call_dop_oid_callback(const char *base_string, tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, const char *col_info, void* data) { char* binding_param; binding_param = wmem_strdup_printf(wmem_packet_scope(), "%s.%s", base_string, binding_type ? binding_type : ""); col_append_fstr(pinfo->cinfo, COL_INFO, " %s", col_info); if (dissector_try_string(dop_dissector_table, binding_param, tvb, pinfo, tree, data)) { offset = tvb_reported_length (tvb); } else { proto_item *item=NULL; proto_tree *next_tree=NULL; item = proto_tree_add_text(tree, tvb, 0, tvb_length_remaining(tvb, offset), "Dissector for parameter %s OID:%s not implemented. Contact Wireshark developers if you want this supported", base_string, binding_type ? binding_type : "<empty>"); if (item) { next_tree = proto_item_add_subtree(item, ett_dop_unknown); } offset = dissect_unknown_ber(pinfo, tvb, offset, next_tree); expert_add_info(pinfo, item, &ei_dop_unknown_binding_parameter); } return offset; }
int call_ros_oid_callback(const char *oid, tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, struct SESSION_DATA_STRUCTURE* session) { tvbuff_t *next_tvb; next_tvb = tvb_new_subset_remaining(tvb, offset); if(!ros_try_string(oid, next_tvb, pinfo, tree, session) && !dissector_try_string(ros_oid_dissector_table, oid, next_tvb, pinfo, tree, session)){ proto_item *item=proto_tree_add_text(tree, next_tvb, 0, tvb_length_remaining(tvb, offset), "ROS: Dissector for OID:%s not implemented. Contact Wireshark developers if you want this supported", oid); proto_tree *next_tree=proto_item_add_subtree(item, ett_ros_unknown); expert_add_info_format(pinfo, item, &ei_ros_dissector_oid_not_implemented, "ROS: Dissector for OID %s not implemented", oid); dissect_unknown_ber(pinfo, next_tvb, offset, next_tree); } /*XXX until we change the #.REGISTER signature for _PDU()s * into new_dissector_t we have to do this kludge with * manually step past the content in the ANY type. */ offset+=tvb_length_remaining(tvb, offset); return offset; }
static int call_rtse_oid_callback(const char *oid, tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, void* data) { tvbuff_t *next_tvb; next_tvb = tvb_new_subset_remaining(tvb, offset); if(!dissector_try_string(rtse_oid_dissector_table, oid, next_tvb, pinfo, tree, data)){ proto_item *item; proto_tree *next_tree; next_tree = proto_tree_add_subtree_format(tree, next_tvb, 0, -1, ett_rtse_unknown, &item, "RTSE: Dissector for OID:%s not implemented. Contact Wireshark developers if you want this supported", oid); expert_add_info_format(pinfo, item, &ei_rtse_dissector_oid_not_implemented, "RTSE: Dissector for OID %s not implemented", oid); dissect_unknown_ber(pinfo, next_tvb, offset, next_tree); } /*XXX until we change the #.REGISTER signature for _PDU()s * into new_dissector_t we have to do this kludge with * manually step past the content in the ANY type. */ offset+=tvb_captured_length_remaining(tvb, offset); return offset; }
int call_ros_oid_callback(const char *oid, tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, struct SESSION_DATA_STRUCTURE* session) { tvbuff_t *next_tvb; int len; next_tvb = tvb_new_subset_remaining(tvb, offset); if(((len = ros_try_string(oid, next_tvb, pinfo, tree, session)) == 0) && ((len = dissector_try_string(ros_oid_dissector_table, oid, next_tvb, pinfo, tree, session)) == 0)) { proto_item *item; proto_tree *next_tree; next_tree = proto_tree_add_subtree_format(tree, next_tvb, 0, -1, ett_ros_unknown, &item, "ROS: Dissector for OID:%s not implemented. Contact Wireshark developers if you want this supported", oid); expert_add_info_format(pinfo, item, &ei_ros_dissector_oid_not_implemented, "ROS: Dissector for OID %s not implemented", oid); len = dissect_unknown_ber(pinfo, next_tvb, offset, next_tree); } offset += len; return offset; }
/** Dissect a DCP packet. Details follow * here. * \param[in,out] tvb The buffer containing the packet * \param[in,out] pinfo The packet info structure * \param[in,out] tree The structure containing the details which will be displayed, filtered, etc. static void */ static gboolean dissect_dcp_etsi (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) { guint8 *sync; proto_tree *dcp_tree = NULL; /* 6.1 AF packet structure * * AF Header * SYNC LEN SEQ AR PT * 2 bytes 4 bytes 2 bytes 1 byte 1 byte * * SYNC: two-byte ASCII representation of "AF". * LEN: length of the payload, in bytes. * SEQ: sequence number * AR: AF protocol Revision - a field combining the CF, MAJ and MIN fields * CF: CRC Flag, 0 if the CRC field is not used * MAJ: major revision of the AF protocol in use, see clause 6.2. * MIN: minor revision of the AF protocol in use, see clause 6.2. * Protocol Type (PT): single byte encoding the protocol of the data carried in the payload. For TAG Packets, the value * shall be the ASCII representation of "T". * * 7.1 PFT fragment structure * PFT Header * 14, 16, 18 or 20 bytes (depending on options) Optional present if FEC=1 Optional present if Addr = 1 * Psync Pseq Findex Fcount FEC HCRC Addr Plen | RSk RSz | Source Dest * 16 bits 16 bits 24 bits 24 bits 1 bit 16 bits 1 bit 14 bits | 8 bits 8 bits | 16 bits 16 bits * * Psync: the ASCII string "PF" is used as the synchronization word for the PFT Layer * * Don't accept this packet unless at least a full AF header present(10 bytes). * It should be possible to strengthen the heuristic further if need be. */ if(tvb_length(tvb) < 11) return FALSE; sync = tvb_get_ephemeral_string (tvb, 0, 2); if((sync[0]!='A' && sync[0]!='P') || sync[1]!='F') return FALSE; pinfo->current_proto = "DCP (ETSI)"; /* Clear out stuff in the info column */ col_clear(pinfo->cinfo, COL_INFO); col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCP (ETSI)"); /*col_append_fstr (pinfo->cinfo, COL_INFO, " tvb %d", tvb_length(tvb));*/ if(tree) { proto_item *ti = NULL; ti = proto_tree_add_item (tree, proto_dcp_etsi, tvb, 0, -1, FALSE); dcp_tree = proto_item_add_subtree (ti, ett_edcp); } dissector_try_string(dcp_dissector_table, (char*)sync, tvb, pinfo, dcp_tree); return TRUE; }
/** Dissect the Tag Packet Layer. * Split the AF packet into its tag items. Each tag item has a 4 character * tag, a length in bits and a value. The *ptr tag is dissected in the routine. * All other tags are listed and may be handled by other dissectors. * Child dissectors are tied to the parent tree, not to this tree, so that * they appear at the same level as DCP. * \param[in,out] tvb The buffer containing the packet * \param[in,out] pinfo The packet info structure * \param[in,out] tree The structure containing the details which will be displayed, filtered, etc. */ static void dissect_tpl(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) { proto_tree *tpl_tree = NULL; guint offset=0; char *prot=NULL; guint16 maj, min; pinfo->current_proto = "DCP-TPL"; col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCP-TPL"); if(tree) { proto_item *ti = NULL; ti = proto_tree_add_item (tree, proto_tpl, tvb, 0, -1, FALSE); tpl_tree = proto_item_add_subtree (ti, ett_tpl); } while(offset<tvb_length(tvb)) { guint32 bits; guint32 bytes; char *tag = (char*)tvb_get_ephemeral_string (tvb, offset, 4); offset += 4; bits = tvb_get_ntohl(tvb, offset); offset += 4; bytes = bits / 8; if(bits % 8) bytes++; if(tree) { proto_item *i = NULL; const guint8 *p = tvb_get_ptr(tvb, offset, bytes); if(strcmp(tag, "*ptr")==0) { prot = (char*)tvb_get_ephemeral_string (tvb, offset, 4); maj = tvb_get_ntohs(tvb, offset+4); min = tvb_get_ntohs(tvb, offset+6); i = proto_tree_add_bytes_format(tpl_tree, hf_tpl_tlv, tvb, offset-8, bytes+8, p, "%s %s rev %d.%d", tag, prot, maj, min); } else { i = proto_tree_add_bytes_format(tpl_tree, hf_tpl_tlv, tvb, offset-8, bytes+8, p, "%s (%u bits)", tag, bits); } } offset += bytes; } if(prot) { /* prot is non-NULL only if we have our tree. */ dissector_try_string(tpl_dissector_table, prot, tvb, pinfo, tree->parent); } }
static int call_rtse_oid_callback(const char *oid, tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, void* data) { tvbuff_t *next_tvb; int len; next_tvb = tvb_new_subset_remaining(tvb, offset); if ((len = dissector_try_string(rtse_oid_dissector_table, oid, next_tvb, pinfo, tree, data)) == 0) { proto_item *item; proto_tree *next_tree; next_tree = proto_tree_add_subtree_format(tree, next_tvb, 0, -1, ett_rtse_unknown, &item, "RTSE: Dissector for OID:%s not implemented. Contact Wireshark developers if you want this supported", oid); expert_add_info_format(pinfo, item, &ei_rtse_dissector_oid_not_implemented, "RTSE: Dissector for OID %s not implemented", oid); len = dissect_unknown_ber(pinfo, next_tvb, offset, next_tree); } offset += len; return offset; }
/* * Process a multipart body-part: * MIME-part-headers [ line-end *OCTET ] * line-end dashed-boundary transport-padding line-end * * If applicable, call a media subdissector. * * Return the offset to the start of the next body-part. */ static gint process_body_part(proto_tree *tree, tvbuff_t *tvb, const guint8 *boundary, gint boundary_len, packet_info *pinfo, gint start, gboolean *last_boundary) { proto_tree *subtree; proto_item *ti; gint offset = start, next_offset = 0; char *parameters = NULL; gint body_start, boundary_start, boundary_line_len; gchar *content_type_str = NULL; gchar *content_encoding_str = NULL; char *filename = NULL; char *mimetypename = NULL; int len = 0; gboolean last_field = FALSE; ti = proto_tree_add_item(tree, hf_multipart_part, tvb, start, 0, ENC_ASCII|ENC_NA); subtree = proto_item_add_subtree(ti, ett_multipart_body); /* * Process the MIME-part-headers */ while (!last_field) { gint colon_offset; char *hdr_str; char *header_str; /* Look for the end of the header (denoted by cr) * 3:d argument to imf_find_field_end() maxlen; must be last offset in the tvb. */ next_offset = imf_find_field_end(tvb, offset, tvb_length_remaining(tvb, offset)+offset, &last_field); /* If cr not found, won't have advanced - get out to avoid infinite loop! */ if (next_offset == offset) { break; } hdr_str = tvb_get_string(wmem_packet_scope(), tvb, offset, next_offset - offset); header_str = unfold_and_compact_mime_header(hdr_str, &colon_offset); if (colon_offset <= 0) { proto_tree_add_text(subtree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); } else { gint hf_index; /* Split header name from header value */ header_str[colon_offset] = '\0'; hf_index = is_known_multipart_header(header_str, colon_offset); if (hf_index == -1) { proto_tree_add_text(subtree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); } else { char *value_str = header_str + colon_offset + 1; proto_tree_add_string_format(subtree, hf_header_array[hf_index], tvb, offset, next_offset - offset, (const char *)value_str, "%s", tvb_format_text(tvb, offset, next_offset - offset)); switch (hf_index) { case POS_CONTENT_TYPE: { /* The Content-Type starts at colon_offset + 1 */ gint semicolon_offset = index_of_char( value_str, ';'); if (semicolon_offset > 0) { value_str[semicolon_offset] = '\0'; parameters = wmem_strdup(wmem_packet_scope(), value_str + semicolon_offset + 1); } else { parameters = NULL; } content_type_str = wmem_ascii_strdown(wmem_packet_scope(), value_str, -1); /* Show content-type in root 'part' label */ proto_item_append_text(ti, " (%s)", content_type_str); /* find the "name" parameter in case we don't find a content disposition "filename" */ if((mimetypename = find_parameter(parameters, "name=", &len)) != NULL) { mimetypename = g_strndup(mimetypename, len); } } break; case POS_CONTENT_TRANSFER_ENCODING: { /* The Content-Transfeing starts at colon_offset + 1 */ gint cr_offset = index_of_char(value_str, '\r'); if (cr_offset > 0) { value_str[cr_offset] = '\0'; } content_encoding_str = wmem_ascii_strdown(wmem_packet_scope(), value_str, -1); } break; case POS_CONTENT_DISPOSITION: { /* find the "filename" parameter */ if((filename = find_parameter(value_str, "filename=", &len)) != NULL) { filename = g_strndup(filename, len); } } break; default: break; } } } offset = next_offset; } body_start = next_offset; /* * Process the body */ boundary_start = find_next_boundary(tvb, body_start, boundary, boundary_len, &boundary_line_len, last_boundary); if (boundary_start > 0) { gint body_len = boundary_start - body_start; tvbuff_t *tmp_tvb = tvb_new_subset(tvb, body_start, body_len, body_len); if (content_type_str) { /* * subdissection */ void *save_private_data = pinfo->private_data; gboolean dissected; /* * Try and remove any content transfer encoding so that each sub-dissector * doesn't have to do it itself * */ if(content_encoding_str && remove_base64_encoding) { if(!g_ascii_strncasecmp(content_encoding_str, "base64", 6)) tmp_tvb = base64_decode(pinfo, tmp_tvb, filename ? filename : (mimetypename ? mimetypename : content_type_str)); } pinfo->private_data = parameters; /* * First try the dedicated multipart dissector table */ dissected = dissector_try_string(multipart_media_subdissector_table, content_type_str, tmp_tvb, pinfo, subtree, NULL); if (! dissected) { /* * Fall back to the default media dissector table */ dissected = dissector_try_string(media_type_dissector_table, content_type_str, tmp_tvb, pinfo, subtree, NULL); } if (! dissected) { const char *save_match_string = pinfo->match_string; pinfo->match_string = content_type_str; call_dissector(media_handle, tmp_tvb, pinfo, subtree); pinfo->match_string = save_match_string; } pinfo->private_data = save_private_data; parameters = NULL; /* Shares same memory as content_type_str */ } else { call_dissector(data_handle, tmp_tvb, pinfo, subtree); } proto_item_set_len(ti, boundary_start - start); if (*last_boundary == TRUE) { proto_tree_add_text(tree, tvb, boundary_start, boundary_line_len, "Last boundary: %s", tvb_format_text(tvb, boundary_start, boundary_line_len)); } else { proto_tree_add_text(tree, tvb, boundary_start, boundary_line_len, "Boundary: %s", tvb_format_text(tvb, boundary_start, boundary_line_len)); } g_free(filename); g_free(mimetypename); return boundary_start + boundary_line_len; } g_free(filename); g_free(mimetypename); return -1; }
static int dissect_rtspmessage(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { proto_tree *rtsp_tree = NULL; proto_tree *sub_tree = NULL; proto_item *ti = NULL; const guchar *line; gint next_offset; const guchar *linep, *lineend; int orig_offset; int first_linelen, linelen; int line_end_offset; int colon_offset; gboolean is_request_or_reply; gboolean body_requires_content_len; gboolean saw_req_resp_or_header; guchar c; rtsp_type_t rtsp_type; gboolean is_header; int datalen; int content_length; int reported_datalen; int value_offset; int value_len; e164_info_t e164_info; gint rdt_feature_level = 0; gchar *media_type_str_lower_case = NULL; int semi_colon_offset; int par_end_offset; /* * Is this a request or response? * * Note that "tvb_find_line_end()" will return a value that * is not longer than what's in the buffer, so the * "tvb_get_ptr()" call won't throw an exception. */ first_linelen = tvb_find_line_end(tvb, offset, tvb_ensure_length_remaining(tvb, offset), &next_offset, FALSE); /* * Is the first line a request or response? */ line = tvb_get_ptr(tvb, offset, first_linelen); is_request_or_reply = is_rtsp_request_or_reply(line, first_linelen, &rtsp_type); if (is_request_or_reply) { /* * Yes, it's a request or response. * Do header desegmentation if we've been told to, * and do body desegmentation if we've been told to and * we find a Content-Length header. */ if (!req_resp_hdrs_do_reassembly(tvb, offset, pinfo, rtsp_desegment_headers, rtsp_desegment_body)) { /* * More data needed for desegmentation. */ return -1; } } /* * RFC 2326 says that a content length must be specified * in requests that have a body, although section 4.4 speaks * of a server closing the connection indicating the end of * a reply body. * * We assume that an absent content length in a request means * that we don't have a body, and that an absent content length * in a reply means that the reply body runs to the end of * the connection. If the first line is neither, we assume * that whatever follows a blank line should be treated as a * body; there's not much else we can do, as we're jumping * into the message in the middle. * * XXX - if there was no Content-Length entity header, we should * accumulate all data until the end of the connection. * That'd require that the TCP dissector call subdissectors * for all frames with FIN, even if they contain no data, * which would require subdissectors to deal intelligently * with empty segments. */ if (rtsp_type == RTSP_REQUEST) body_requires_content_len = TRUE; else body_requires_content_len = FALSE; col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTSP"); if (check_col(pinfo->cinfo, COL_INFO)) { /* * Put the first line from the buffer into the summary * if it's an RTSP request or reply (but leave out the * line terminator). * Otherwise, just call it a continuation. * * Note that "tvb_find_line_end()" will return a value that * is not longer than what's in the buffer, so the * "tvb_get_ptr()" call won't throw an exception. */ line = tvb_get_ptr(tvb, offset, first_linelen); if (is_request_or_reply) if ( rtsp_type == RTSP_REPLY ) { col_set_str(pinfo->cinfo, COL_INFO, "Reply: "); col_append_str(pinfo->cinfo, COL_INFO, format_text(line, first_linelen)); } else col_add_str(pinfo->cinfo, COL_INFO, format_text(line, first_linelen)); else col_set_str(pinfo->cinfo, COL_INFO, "Continuation"); } orig_offset = offset; if (tree) { ti = proto_tree_add_item(tree, proto_rtsp, tvb, offset, -1, FALSE); rtsp_tree = proto_item_add_subtree(ti, ett_rtsp); } /* * We haven't yet seen a Content-Length header. */ content_length = -1; /* * Process the packet data, a line at a time. */ saw_req_resp_or_header = FALSE; /* haven't seen anything yet */ while (tvb_reported_length_remaining(tvb, offset) != 0) { /* * We haven't yet concluded that this is a header. */ is_header = FALSE; /* * Find the end of the line. */ linelen = tvb_find_line_end(tvb, offset, tvb_ensure_length_remaining(tvb, offset), &next_offset, FALSE); if (linelen < 0) return -1; line_end_offset = offset + linelen; /* * colon_offset may be -1 */ colon_offset = tvb_find_guint8(tvb, offset, linelen, ':'); /* * Get a buffer that refers to the line. */ line = tvb_get_ptr(tvb, offset, linelen); lineend = line + linelen; /* * OK, does it look like an RTSP request or response? */ is_request_or_reply = is_rtsp_request_or_reply(line, linelen, &rtsp_type); if (is_request_or_reply) goto is_rtsp; /* * No. Does it look like a blank line (as would appear * at the end of an RTSP request)? */ if (linelen == 0) goto is_rtsp; /* Yes. */ /* * No. Does it look like a header? */ linep = line; while (linep < lineend) { c = *linep++; /* * This must be a CHAR to be part of a token; that * means it must be ASCII. */ if (!isascii(c)) break; /* not ASCII, thus not a CHAR */ /* * This mustn't be a CTL to be part of a token. * * XXX - what about leading LWS on continuation * lines of a header? */ if (iscntrl(c)) break; /* CTL, not part of a header */ switch (c) { case '(': case ')': case '<': case '>': case '@': case ',': case ';': case '\\': case '"': case '/': case '[': case ']': case '?': case '=': case '{': case '}': /* * It's a tspecial, so it's not * part of a token, so it's not * a field name for the beginning * of a header. */ goto not_rtsp; case ':': /* * This ends the token; we consider * this to be a header. */ is_header = TRUE; goto is_rtsp; case ' ': case '\t': /* * LWS (RFC-2616, 4.2); continue the previous * header. */ goto is_rtsp; } } /* * We haven't seen the colon, but everything else looks * OK for a header line. * * If we've already seen an RTSP request or response * line, or a header line, and we're at the end of * the tvbuff, we assume this is an incomplete header * line. (We quit this loop after seeing a blank line, * so if we've seen a request or response line, or a * header line, this is probably more of the request * or response we're presumably seeing. There is some * risk of false positives, but the same applies for * full request or response lines or header lines, * although that's less likely.) * * We throw an exception in that case, by checking for * the existence of the next byte after the last one * in the line. If it exists, "tvb_ensure_bytes_exist()" * throws no exception, and we fall through to the * "not RTSP" case. If it doesn't exist, * "tvb_ensure_bytes_exist()" will throw the appropriate * exception. */ if (saw_req_resp_or_header) tvb_ensure_bytes_exist(tvb, offset, linelen + 1); not_rtsp: /* * We don't consider this part of an RTSP request or * reply, so we don't display it. */ break; is_rtsp: /* * Process this line. */ if (linelen == 0) { /* * This is a blank line, which means that * whatever follows it isn't part of this * request or reply. */ proto_tree_add_text(rtsp_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); offset = next_offset; break; } /* * Not a blank line - either a request, a reply, or a header * line. */ saw_req_resp_or_header = TRUE; if (rtsp_tree) { switch (rtsp_type) { case RTSP_REQUEST: process_rtsp_request(tvb, offset, line, linelen, next_offset, rtsp_tree); break; case RTSP_REPLY: process_rtsp_reply(tvb, offset, line, linelen, next_offset, rtsp_tree); break; case RTSP_NOT_FIRST_LINE: /* Drop through, it may well be a header line */ break; } } if (is_header) { /* We know that colon_offset must be set */ /* Skip whitespace after the colon. */ value_offset = colon_offset + 1; while ((value_offset < line_end_offset) && ((c = tvb_get_guint8(tvb, value_offset)) == ' ' || c == '\t')) { value_offset++; } value_len = line_end_offset - value_offset; /* * Process some headers specially. */ #define HDR_MATCHES(header) \ ( (size_t)linelen > STRLEN_CONST(header) && \ g_ascii_strncasecmp(line, (header), STRLEN_CONST(header)) == 0) if (HDR_MATCHES(rtsp_transport)) { proto_tree_add_string(rtsp_tree, hf_rtsp_transport, tvb, offset, linelen, tvb_format_text(tvb, value_offset, value_len)); /* * Based on the port numbers specified * in the Transport: header, set up * a conversation that will be dissected * with the appropriate dissector. */ rtsp_create_conversation(pinfo, line, linelen, rdt_feature_level); } else if (HDR_MATCHES(rtsp_content_type)) { proto_tree_add_string(rtsp_tree, hf_rtsp_content_type, tvb, offset, linelen, tvb_format_text(tvb, value_offset, value_len)); offset = offset + STRLEN_CONST(rtsp_content_type); /* Skip wsp */ offset = tvb_skip_wsp(tvb, offset, value_len); semi_colon_offset = tvb_find_guint8(tvb, value_offset, value_len, ';'); if ( semi_colon_offset != -1) { /* m-parameter present */ par_end_offset = tvb_skip_wsp_return(tvb, semi_colon_offset-1); value_len = par_end_offset - offset; } media_type_str_lower_case = ascii_strdown_inplace( (gchar *)tvb_get_ephemeral_string(tvb, offset, value_len)); } else if (HDR_MATCHES(rtsp_content_length)) { proto_tree_add_uint(rtsp_tree, hf_rtsp_content_length, tvb, offset, linelen, atoi(tvb_format_text(tvb, value_offset, value_len))); /* * Only the amount specified by the * Content-Length: header should be treated * as payload. */ content_length = rtsp_get_content_length(line, linelen); } else if (HDR_MATCHES(rtsp_Session)) { /* Put the value into the protocol tree */ proto_tree_add_string(rtsp_tree, hf_rtsp_session, tvb, offset, linelen, tvb_format_text(tvb, value_offset, value_len)); } else if (HDR_MATCHES(rtsp_X_Vig_Msisdn)) { /* * Extract the X_Vig_Msisdn string */ if (colon_offset != -1) { /* Put the value into the protocol tree */ ti = proto_tree_add_string(rtsp_tree, hf_rtsp_X_Vig_Msisdn,tvb, offset, linelen , tvb_format_text(tvb, value_offset, value_len)); sub_tree = proto_item_add_subtree(ti, ett_rtsp_method); e164_info.e164_number_type = CALLING_PARTY_NUMBER; e164_info.nature_of_address = 0; e164_info.E164_number_str = tvb_get_ephemeral_string(tvb, value_offset, value_len); e164_info.E164_number_length = value_len; dissect_e164_number(tvb, sub_tree, value_offset, value_len, e164_info); } } else if (HDR_MATCHES(rtsp_rdt_feature_level)) { rdt_feature_level = atoi(tvb_format_text(tvb, value_offset, value_len)); proto_tree_add_uint(rtsp_tree, hf_rtsp_rdtfeaturelevel, tvb, offset, linelen, atoi(tvb_format_text(tvb, value_offset, value_len))); } else { /* Default case for headers. Show line as text */ proto_tree_add_text(rtsp_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); } } else if (rtsp_type == RTSP_NOT_FIRST_LINE) { /* Catch-all for all other lines... Show line as text. TODO: should these be shown as errors? */ proto_tree_add_text(rtsp_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); } offset = next_offset; } /* * Have now read all of the lines of this message. * * If a content length was supplied, the amount of data to be * processed as RTSP payload is the minimum of the content * length and the amount of data remaining in the frame. * * If no content length was supplied (or if a bad content length * was supplied), the amount of data to be processed is the amount * of data remaining in the frame. */ datalen = tvb_length_remaining(tvb, offset); reported_datalen = tvb_reported_length_remaining(tvb, offset); if (content_length != -1) { /* * Content length specified; display only that amount * as payload. */ if (datalen > content_length) datalen = content_length; /* * XXX - limit the reported length in the tvbuff we'll * hand to a subdissector to be no greater than the * content length. * * We really need both unreassembled and "how long it'd * be if it were reassembled" lengths for tvbuffs, so * that we throw the appropriate exceptions for * "not enough data captured" (running past the length), * "packet needed reassembly" (within the length but * running past the unreassembled length), and * "packet is malformed" (running past the reassembled * length). */ if (reported_datalen > content_length) reported_datalen = content_length; } else { /* * No content length specified; if this message doesn't * have a body if no content length is specified, process * nothing as payload. */ if (body_requires_content_len) datalen = 0; } if (datalen > 0) { /* * There's stuff left over; process it. */ tvbuff_t *new_tvb; /* * Now create a tvbuff for the Content-type stuff and * dissect it. * * The amount of data to be processed that's * available in the tvbuff is "datalen", which * is the minimum of the amount of data left in * the tvbuff and any specified content length. * * The amount of data to be processed that's in * this frame, regardless of whether it was * captured or not, is "reported_datalen", * which, if no content length was specified, * is -1, i.e. "to the end of the frame. */ new_tvb = tvb_new_subset(tvb, offset, datalen, reported_datalen); if (media_type_str_lower_case && dissector_try_string(media_type_dissector_table, media_type_str_lower_case, new_tvb, pinfo, rtsp_tree)){ }else { /* * Fix up the top-level item so that it doesn't * include the SDP stuff. */ if (ti != NULL) proto_item_set_len(ti, offset); if (tvb_get_guint8(tvb, offset) == RTSP_FRAMEHDR) { /* * This is interleaved stuff; don't * treat it as raw data - set "datalen" * to 0, so we won't skip the offset * past it, which will cause our * caller to process that stuff itself. */ datalen = 0; } else { proto_tree_add_text(rtsp_tree, tvb, offset, datalen, "Data (%d bytes)", reported_datalen); } } /* * We've processed "datalen" bytes worth of data * (which may be no data at all); advance the * offset past whatever data we've processed. */ offset += datalen; } return offset - orig_offset; }
/* Code to actually dissect the packets */ static int dissect_msrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gint offset = 0; gint next_offset = 0; proto_item *ti, *th, *msrp_headers_item, *msrp_element_item; proto_tree *msrp_tree, *reqresp_tree, *raw_tree, *msrp_hdr_tree, *msrp_end_tree; proto_tree *msrp_element_tree, *msrp_data_tree; gint linelen; gint space_offset; gint token_2_start; guint token_2_len; gint token_3_start; guint token_3_len; gint token_4_start = 0; guint token_4_len = 0; gboolean is_msrp_response; gint end_line_offset; gint end_line_len; gint line_end_offset; gint message_end_offset; gint colon_offset; char *transaction_id_str = NULL; gint header_len; gint hf_index; gint value_offset; guchar c; gint value_len; char *value; gboolean have_body = FALSE; gboolean found_match = FALSE; gint content_type_len, content_type_parameter_str_len; gchar *media_type_str_lower_case = NULL; char *content_type_parameter_str = NULL; tvbuff_t *next_tvb; gint parameter_offset; gint semi_colon_offset; if ( !check_msrp_header(tvb)){ return 0; } /* We have a MSRP header with at least three tokens * * Note that "tvb_find_line_end()" will return a value that * is not longer than what's in the buffer, so the * "tvb_get_ptr()" calls below won't throw exceptions. * */ offset = 0; linelen = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE); /* Find the first SP and skip the first token */ token_2_start = tvb_find_guint8(tvb, 0, linelen, ' ') + 1; /* Work out 2nd token's length by finding next space */ space_offset = tvb_find_guint8(tvb, token_2_start, linelen-token_2_start, ' '); token_2_len = space_offset - token_2_start; /* Transaction ID found store it for later use */ transaction_id_str = tvb_get_ephemeral_string(tvb, token_2_start, token_2_len); /* Look for another space in this line to indicate a 4th token */ token_3_start = space_offset + 1; space_offset = tvb_find_guint8(tvb, token_3_start,linelen-token_3_start, ' '); if ( space_offset == -1){ /* 3rd token runs to the end of the line */ token_3_len = linelen - token_3_start; }else{ /* We have a fourth token */ token_3_len = space_offset - token_3_start; token_4_start = space_offset + 1; token_4_len = linelen - token_4_start; } /* * Yes, so this is either a msrp-request or msrp-response. * To be a msrp-response, the second token must be * a 3-digit number. */ is_msrp_response = FALSE; if (token_3_len == 3) { if (isdigit(tvb_get_guint8(tvb, token_3_start)) && isdigit(tvb_get_guint8(tvb, token_3_start + 1)) && isdigit(tvb_get_guint8(tvb, token_3_start + 2))) { is_msrp_response = TRUE; } } /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MSRP"); if (is_msrp_response){ if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "Response: %s ", tvb_format_text(tvb, token_3_start, token_3_len)); if (token_4_len ) col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", tvb_format_text(tvb, token_4_start, token_4_len)); col_append_fstr(pinfo->cinfo, COL_INFO, "Transaction ID: %s", tvb_format_text(tvb, token_2_start, token_2_len)); } }else{ if (check_col(pinfo->cinfo, COL_INFO)) { proto_tree_add_text(tree, tvb, token_3_start, token_3_len, "Col %s L=%u", tvb_format_text(tvb, token_3_start, token_3_len),token_3_len); col_add_fstr(pinfo->cinfo, COL_INFO, "Request: %s ", tvb_format_text(tvb, token_3_start, token_3_len)); col_append_fstr(pinfo->cinfo, COL_INFO, "Transaction ID: %s", tvb_format_text(tvb, token_2_start, token_2_len)); } } /* Find the end line to be able to process the headers * Note that in case of [content-stuff] headers and [content-stuff] is separated by CRLF */ offset = next_offset; end_line_offset = find_end_line(tvb,offset); /* TODO if -1 (No end line found, is returned do something) */ end_line_len = tvb_find_line_end(tvb, end_line_offset, -1, &next_offset, FALSE); message_end_offset = end_line_offset + end_line_len + 2; if (tree) { ti = proto_tree_add_item(tree, proto_msrp, tvb, 0, message_end_offset, FALSE); msrp_tree = proto_item_add_subtree(ti, ett_msrp); if (is_msrp_response){ th = proto_tree_add_item(msrp_tree,hf_msrp_response_line,tvb,0,linelen,FALSE); reqresp_tree = proto_item_add_subtree(th, ett_msrp_reqresp); proto_tree_add_item(reqresp_tree,hf_msrp_transactionID,tvb,token_2_start,token_2_len,FALSE); proto_tree_add_uint(reqresp_tree,hf_msrp_status_code,tvb,token_3_start,token_3_len, atoi(tvb_get_ephemeral_string(tvb, token_3_start, token_3_len))); }else{ th = proto_tree_add_item(msrp_tree,hf_msrp_request_line,tvb,0,linelen,FALSE); reqresp_tree = proto_item_add_subtree(th, ett_msrp_reqresp); proto_tree_add_item(reqresp_tree,hf_msrp_transactionID,tvb,token_2_start,token_2_len,FALSE); proto_tree_add_item(reqresp_tree,hf_msrp_method,tvb,token_3_start,token_3_len,FALSE); } /* Conversation setup info */ if (global_msrp_show_setup_info) { show_setup_info(tvb, pinfo, msrp_tree); } /* Headers */ msrp_headers_item = proto_tree_add_item(msrp_tree, hf_msrp_msg_hdr, tvb, offset,(end_line_offset - offset), FALSE); msrp_hdr_tree = proto_item_add_subtree(msrp_headers_item, ett_msrp_hdr); /* * Process the headers */ while (tvb_reported_length_remaining(tvb, offset) > 0 && offset < end_line_offset ) { /* 'desegment' is FALSE so will set next_offset to beyond the end of the buffer if no line ending is found */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); if (linelen == 0) { /* * This is a blank line separating the * message header from the message body. */ have_body = TRUE; break; } line_end_offset = offset + linelen; colon_offset = tvb_find_guint8(tvb, offset, linelen, ':'); if (colon_offset == -1) { /* * Malformed header - no colon after the name. */ proto_tree_add_text(msrp_hdr_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, linelen)); } else { header_len = colon_offset - offset; hf_index = msrp_is_known_msrp_header(tvb, offset, header_len); if (hf_index == -1) { proto_tree_add_text(msrp_hdr_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, linelen)); } else { /* * Skip whitespace after the colon. */ value_offset = colon_offset + 1; while (value_offset < line_end_offset && ((c = tvb_get_guint8(tvb, value_offset)) == ' ' || c == '\t')) value_offset++; /* * Fetch the value. */ value_len = line_end_offset - value_offset; value = tvb_get_ephemeral_string(tvb, value_offset, value_len); /* * Add it to the protocol tree, * but display the line as is. */ msrp_element_item = proto_tree_add_string_format(msrp_hdr_tree, hf_header_array[hf_index], tvb, offset, next_offset - offset, value, "%s", tvb_format_text(tvb, offset, linelen)); msrp_element_tree = proto_item_add_subtree( msrp_element_item, ett_msrp_element); switch ( hf_index ) { case MSRP_CONTENT_TYPE : content_type_len = value_len; semi_colon_offset = tvb_find_guint8(tvb, value_offset,linelen, ';'); if ( semi_colon_offset != -1) { parameter_offset = semi_colon_offset +1; /* * Skip whitespace after the semicolon. */ while (parameter_offset < line_end_offset && ((c = tvb_get_guint8(tvb, parameter_offset)) == ' ' || c == '\t')) parameter_offset++; content_type_len = semi_colon_offset - value_offset; content_type_parameter_str_len = line_end_offset - parameter_offset; content_type_parameter_str = tvb_get_ephemeral_string(tvb, parameter_offset, content_type_parameter_str_len); } media_type_str_lower_case = ascii_strdown_inplace( (gchar *)tvb_get_ephemeral_string(tvb, value_offset, content_type_len)); break; default: break; } } } offset = next_offset; }/* End while */ if ( have_body ){ /* * There's a message body starting at "next_offset". * Set the length of the header item. */ proto_item_set_end(msrp_headers_item, tvb, next_offset); /* Create new tree & tvb for data */ next_tvb = tvb_new_subset_remaining(tvb, next_offset); ti = proto_tree_add_item(msrp_tree, hf_msrp_data, tvb, next_offset, -1, FALSE); msrp_data_tree = proto_item_add_subtree(ti, ett_msrp_data); /* give the content type parameters to sub dissectors */ if ( media_type_str_lower_case != NULL ) { void *save_private_data = pinfo->private_data; pinfo->private_data = content_type_parameter_str; found_match = dissector_try_string(media_type_dissector_table, media_type_str_lower_case, next_tvb, pinfo, msrp_data_tree); pinfo->private_data = save_private_data; /* If no match dump as text */ } if ( found_match != TRUE ) { offset = 0; while (tvb_offset_exists(next_tvb, offset)) { tvb_find_line_end(next_tvb, offset, -1, &next_offset, FALSE); linelen = next_offset - offset; proto_tree_add_text(msrp_data_tree, next_tvb, offset, linelen, "%s", tvb_format_text(next_tvb, offset, linelen)); offset = next_offset; }/* end while */ } } /* End line */ ti = proto_tree_add_item(msrp_tree,hf_msrp_end_line,tvb,end_line_offset,end_line_len,FALSE); msrp_end_tree = proto_item_add_subtree(ti, ett_msrp_end_line); proto_tree_add_item(msrp_end_tree,hf_msrp_transactionID,tvb,end_line_offset + 7,token_2_len,FALSE); /* continuation-flag */ proto_tree_add_item(msrp_end_tree,hf_msrp_cnt_flg,tvb,end_line_offset+end_line_len-1,1,FALSE); if (global_msrp_raw_text){ ti = proto_tree_add_text(tree, tvb, 0, -1,"Message Session Relay Protocol(as raw text)"); raw_tree = proto_item_add_subtree(ti, ett_msrp); tvb_raw_text_add(tvb,raw_tree); } }/* if tree */ return message_end_offset; /* return tvb_length(tvb); */ /* If this protocol has a sub-dissector call it here, see section 1.8 */ }
/* * Process a multipart body-part: * MIME-part-headers [ line-end *OCTET ] * line-end dashed-boundary transport-padding line-end * * If applicable, call a media subdissector. * * Return the offset to the start of the next body-part. */ static gint process_body_part(proto_tree *tree, tvbuff_t *tvb, multipart_info_t *m_info, packet_info *pinfo, gint start, gint idx, gboolean *last_boundary) { proto_tree *subtree; proto_item *ti; gint offset = start, next_offset = 0; char *parameters = NULL; gint body_start, boundary_start, boundary_line_len; gchar *content_type_str = NULL; gchar *content_encoding_str = NULL; char *filename = NULL; char *mimetypename = NULL; int len = 0; gboolean last_field = FALSE; gboolean is_raw_data = FALSE; const guint8 *boundary = (guint8 *)m_info->boundary; gint boundary_len = m_info->boundary_length; ti = proto_tree_add_item(tree, hf_multipart_part, tvb, start, 0, ENC_ASCII|ENC_NA); subtree = proto_item_add_subtree(ti, ett_multipart_body); /* find the next boundary to find the end of this body part */ boundary_start = find_next_boundary(tvb, offset, boundary, boundary_len, &boundary_line_len, last_boundary); if (boundary_start <= 0) { return -1; } /* * Process the MIME-part-headers */ while (!last_field) { gint colon_offset; char *hdr_str; char *header_str; /* Look for the end of the header (denoted by cr) * 3:d argument to imf_find_field_end() maxlen; must be last offset in the tvb. */ next_offset = imf_find_field_end(tvb, offset, tvb_reported_length_remaining(tvb, offset)+offset, &last_field); /* the following should never happen */ /* If cr not found, won't have advanced - get out to avoid infinite loop! */ /* if (next_offset == offset) { break; } */ if (last_field && (next_offset+2) <= boundary_start) { /* Add the extra CRLF of the last field */ next_offset += 2; } else if((next_offset-2) == boundary_start) { /* if CRLF is the start of next boundary it belongs to the boundary and not the field, so it's the last field without CRLF */ last_field = TRUE; next_offset -= 2; } else if (next_offset > boundary_start) { /* if there is no CRLF between last field and next boundary - trim it! */ next_offset = boundary_start; } hdr_str = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, next_offset - offset, ENC_ASCII); header_str = unfold_and_compact_mime_header(hdr_str, &colon_offset); if (colon_offset <= 0) { /* if there is no colon it's no header, so break and add complete line to the body */ next_offset = offset; break; } else { gint hf_index; /* Split header name from header value */ header_str[colon_offset] = '\0'; hf_index = is_known_multipart_header(header_str, colon_offset); if (hf_index == -1) { if(isprint_string(hdr_str)) { proto_tree_add_format_text(subtree, tvb, offset, next_offset - offset); } else { /* if the header name is unkown and not printable, break and add complete line to the body */ next_offset = offset; break; } } else { char *value_str = header_str + colon_offset + 1; proto_tree_add_string_format(subtree, hf_header_array[hf_index], tvb, offset, next_offset - offset, (const char *)value_str, "%s", tvb_format_text(tvb, offset, next_offset - offset)); switch (hf_index) { case POS_ORIGINALCONTENT: { gint semicolon_offset; /* The Content-Type starts at colon_offset + 1 or after the type parameter */ char* type_str = find_parameter(value_str, "type=", NULL); if(type_str != NULL) { value_str = type_str; } semicolon_offset = index_of_char( value_str, ';'); if (semicolon_offset > 0) { value_str[semicolon_offset] = '\0'; m_info->orig_parameters = wmem_strdup(wmem_packet_scope(), value_str + semicolon_offset + 1); } m_info->orig_content_type = wmem_ascii_strdown(wmem_packet_scope(), value_str, -1); } break; case POS_CONTENT_TYPE: { /* The Content-Type starts at colon_offset + 1 */ gint semicolon_offset = index_of_char( value_str, ';'); if (semicolon_offset > 0) { value_str[semicolon_offset] = '\0'; parameters = wmem_strdup(wmem_packet_scope(), value_str + semicolon_offset + 1); } else { parameters = NULL; } content_type_str = wmem_ascii_strdown(wmem_packet_scope(), value_str, -1); /* Show content-type in root 'part' label */ proto_item_append_text(ti, " (%s)", content_type_str); /* find the "name" parameter in case we don't find a content disposition "filename" */ if((mimetypename = find_parameter(parameters, "name=", &len)) != NULL) { mimetypename = g_strndup(mimetypename, len); } if(strncmp(content_type_str, "application/octet-stream", sizeof("application/octet-stream")-1) == 0) { is_raw_data = TRUE; } /* there are only 2 body parts possible and each part has specific content types */ if(m_info->protocol && idx == 0 && (is_raw_data || g_ascii_strncasecmp(content_type_str, m_info->protocol, strlen(m_info->protocol)) != 0)) { return -1; } } break; case POS_CONTENT_TRANSFER_ENCODING: { /* The Content-Transferring starts at colon_offset + 1 */ gint cr_offset = index_of_char(value_str, '\r'); if (cr_offset > 0) { value_str[cr_offset] = '\0'; } content_encoding_str = wmem_ascii_strdown(wmem_packet_scope(), value_str, -1); } break; case POS_CONTENT_DISPOSITION: { /* find the "filename" parameter */ if((filename = find_parameter(value_str, "filename=", &len)) != NULL) { filename = g_strndup(filename, len); } } break; default: break; } } } offset = next_offset; } body_start = next_offset; /* * Process the body */ { gint body_len = boundary_start - body_start; tvbuff_t *tmp_tvb = tvb_new_subset_length(tvb, body_start, body_len); /* if multipart subtype is encrypted the protcol string was set */ /* see: https://msdn.microsoft.com/en-us/library/cc251581.aspx */ /* there are only 2 body parts possible and each part has specific content types */ if(m_info->protocol && idx == 1 && is_raw_data) { gssapi_encrypt_info_t encrypt; memset(&encrypt, 0, sizeof(encrypt)); encrypt.decrypt_gssapi_tvb=DECRYPT_GSSAPI_NORMAL; dissect_kerberos_encrypted_message(tmp_tvb, pinfo, subtree, &encrypt); if(encrypt.gssapi_decrypted_tvb) { tmp_tvb = encrypt.gssapi_decrypted_tvb; is_raw_data = FALSE; content_type_str = m_info->orig_content_type; parameters = m_info->orig_parameters; } else if(encrypt.gssapi_encrypted_tvb) { tmp_tvb = encrypt.gssapi_encrypted_tvb; proto_tree_add_expert(tree, pinfo, &ei_multipart_decryption_not_possible, tmp_tvb, 0, -1); } } if (!is_raw_data && content_type_str) { /* * subdissection */ gboolean dissected; /* * Try and remove any content transfer encoding so that each sub-dissector * doesn't have to do it itself * */ if(content_encoding_str && remove_base64_encoding) { if(!g_ascii_strncasecmp(content_encoding_str, "base64", 6)) tmp_tvb = base64_decode(pinfo, tmp_tvb, filename ? filename : (mimetypename ? mimetypename : content_type_str)); } /* * First try the dedicated multipart dissector table */ dissected = dissector_try_string(multipart_media_subdissector_table, content_type_str, tmp_tvb, pinfo, subtree, parameters); if (! dissected) { /* * Fall back to the default media dissector table */ dissected = dissector_try_string(media_type_dissector_table, content_type_str, tmp_tvb, pinfo, subtree, parameters); } if (! dissected) { const char *save_match_string = pinfo->match_string; pinfo->match_string = content_type_str; call_dissector_with_data(media_handle, tmp_tvb, pinfo, subtree, parameters); pinfo->match_string = save_match_string; } parameters = NULL; /* Shares same memory as content_type_str */ } else { call_dissector(data_handle, tmp_tvb, pinfo, subtree); } proto_item_set_len(ti, boundary_start - start); if (*last_boundary == TRUE) { proto_tree_add_item(tree, hf_multipart_last_boundary, tvb, boundary_start, boundary_line_len, ENC_NA|ENC_ASCII); } else { proto_tree_add_item(tree, hf_multipart_boundary, tvb, boundary_start, boundary_line_len, ENC_NA|ENC_ASCII); } g_free(filename); g_free(mimetypename); return boundary_start + boundary_line_len; } }
static int dissect_InitiatingMessageValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { if (!ProcedureID) return 0; return (dissector_try_string(rnsap_proc_imsg_dissector_table, ProcedureID, tvb, pinfo, tree)) ? tvb_length(tvb) : 0; }
static int dissect_UnsuccessfulOutcomeValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { if (!ProcedureID) return 0; return (dissector_try_string(rnsap_proc_uout_dissector_table, ProcedureID, tvb, pinfo, tree)) ? tvb_length(tvb) : 0; }