/* Process an APP2 block. * * XXX - This code only works on US-ASCII systems!!! */ static void process_app2_segment(proto_tree *tree, tvbuff_t *tvb, guint32 len, guint16 marker, const char *marker_name) { proto_item *ti = NULL; proto_tree *subtree = NULL; char *str; gint str_size; if (!tree) return; ti = proto_tree_add_item(tree, hf_marker_segment, tvb, 0, -1, ENC_NA); subtree = proto_item_add_subtree(ti, ett_marker_segment); proto_item_append_text(ti, ": %s (0x%04X)", marker_name, marker); proto_tree_add_item(subtree, hf_marker, tvb, 0, 2, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_len, tvb, 2, 2, ENC_BIG_ENDIAN); str = tvb_get_stringz(wmem_packet_scope(), tvb, 4, &str_size); ti = proto_tree_add_item(subtree, hf_identifier, tvb, 4, str_size, ENC_ASCII|ENC_NA); if (strcmp(str, "FPXR") == 0) { proto_tree_add_text(tree, tvb, 0, -1, "Exif FlashPix APP2 application marker"); } else { proto_tree_add_text(subtree, tvb, 4 + str_size, -1, "Remaining segment data (%u bytes)", len - 2 - str_size); proto_item_append_text(ti, " (Unknown identifier)"); } }
/* Parses a ts2 channel list (TS2T_CHANNELLIST) and adds it to the tree */ static void ts2_parse_channellist(tvbuff_t *tvb, proto_tree *ts2_tree) { gint32 offset; guint32 string_len; proto_tree *subtree; proto_item *item; offset=0; proto_tree_add_item(ts2_tree, hf_ts2_number_of_channels, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset+=4; while(offset<tvb_length_remaining(tvb, 0)) { proto_tree_add_item(ts2_tree, hf_ts2_channel_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset+=4; /* Channel flags */ item = proto_tree_add_item(ts2_tree, hf_ts2_channel_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN); subtree = proto_item_add_subtree(item, ett_ts2_channel_flags); proto_tree_add_item(subtree, hf_ts2_channel_unregistered, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_ts2_channel_moderated, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_ts2_channel_password, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_ts2_channel_subchannels, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_ts2_channel_default, tvb, offset, 1, ENC_BIG_ENDIAN); offset+=1; proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, offset, 1, ENC_NA); offset+=1; proto_tree_add_item(ts2_tree, hf_ts2_codec, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset+=2; proto_tree_add_item(ts2_tree, hf_ts2_parent_channel_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset+=4; proto_tree_add_item(ts2_tree, hf_ts2_channel_order, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset+=2; proto_tree_add_item(ts2_tree, hf_ts2_max_users, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset+=2; tvb_get_stringz(wmem_packet_scope(), tvb, offset, &string_len); proto_tree_add_item(ts2_tree, hf_ts2_channel_name, tvb, offset,string_len , ENC_ASCII|ENC_NA); offset+=string_len; tvb_get_stringz(wmem_packet_scope(), tvb, offset, &string_len); proto_tree_add_item(ts2_tree, hf_ts2_channel_topic, tvb, offset,string_len ,ENC_ASCII|ENC_NA); offset+=string_len; tvb_get_stringz(wmem_packet_scope(), tvb, offset, &string_len); proto_tree_add_item(ts2_tree, hf_ts2_channel_description, tvb, offset,string_len , ENC_ASCII|ENC_NA); offset+=string_len; } }
WSLUA_METHOD TvbRange_stringz(lua_State* L) { /* Obtain a zero terminated string from a TvbRange */ TvbRange tvbr = checkTvbRange(L,1); if ( !(tvbr && tvbr->tvb)) return 0; if (tvbr->tvb->expired) { luaL_error(L,"expired tvb"); return 0; } lua_pushstring(L, (gchar*)tvb_get_stringz(wmem_packet_scope(),tvbr->tvb->ws_tvb,tvbr->offset,NULL) ); WSLUA_RETURN(1); /* The zero terminated string */ }
static int dissect_bson_document(tvbuff_t *tvb, packet_info *pinfo, guint offset, proto_tree *tree, int hf_mongo_doc, int nest_level) { gint32 document_length; guint final_offset; proto_item *ti, *elements, *element, *objectid, *js_code, *js_scope; proto_tree *doc_tree, *elements_tree, *element_sub_tree, *objectid_sub_tree, *js_code_sub_tree, *js_scope_sub_tree; document_length = tvb_get_letohl(tvb, offset); ti = proto_tree_add_item(tree, hf_mongo_doc, tvb, offset, document_length, ENC_NA); doc_tree = proto_item_add_subtree(ti, ett_mongo_doc); proto_tree_add_item(doc_tree, hf_mongo_document_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); if (nest_level > BSON_MAX_NESTING) { expert_add_info_format(pinfo, ti, &ei_mongo_document_recursion_exceeded, "BSON document recursion exceeds %u", BSON_MAX_NESTING); THROW(ReportedBoundsError); } if (document_length < 5) { expert_add_info_format(pinfo, ti, &ei_mongo_document_length_bad, "BSON document length too short: %u", document_length); THROW(ReportedBoundsError); } if (document_length > BSON_MAX_DOC_SIZE) { expert_add_info_format(pinfo, ti, &ei_mongo_document_length_bad, "BSON document length too long: %u", document_length); THROW(ReportedBoundsError); } if (document_length == 5) { /* document with length 5 is an empty document */ /* don't display the element subtree */ proto_tree_add_item(tree, hf_mongo_document_empty, tvb, offset, document_length, ENC_NA); return document_length; } final_offset = offset + document_length; offset += 4; elements = proto_tree_add_item(doc_tree, hf_mongo_elements, tvb, offset, document_length-5, ENC_NA); elements_tree = proto_item_add_subtree(elements, ett_mongo_elements); do { /* Read document elements */ guint8 e_type = -1; /* Element type */ gint str_len = -1; /* String length */ gint e_len = -1; /* Element length */ gint doc_len = -1; /* Document length */ e_type = tvb_get_guint8(tvb, offset); tvb_get_stringz(wmem_packet_scope(), tvb, offset+1, &str_len); element = proto_tree_add_item(elements_tree, hf_mongo_element_name, tvb, offset+1, str_len-1, ENC_UTF_8|ENC_NA); element_sub_tree = proto_item_add_subtree(element, ett_mongo_element); proto_tree_add_item(element_sub_tree, hf_mongo_element_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += str_len+1; switch(e_type) { case BSON_ELEMENT_TYPE_DOUBLE: proto_tree_add_item(element_sub_tree, hf_mongo_element_value_double, tvb, offset, 8, ENC_LITTLE_ENDIAN); offset += 8; break; case BSON_ELEMENT_TYPE_STRING: case BSON_ELEMENT_TYPE_JS_CODE: case BSON_ELEMENT_TYPE_SYMBOL: str_len = tvb_get_letohl(tvb, offset); proto_tree_add_item(element_sub_tree, hf_mongo_element_value_string_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(element_sub_tree, hf_mongo_element_value_string, tvb, offset+4, str_len, ENC_UTF_8|ENC_NA); offset += str_len+4; break; case BSON_ELEMENT_TYPE_DOC: case BSON_ELEMENT_TYPE_ARRAY: offset += dissect_bson_document(tvb, pinfo, offset, element_sub_tree, hf_mongo_document, nest_level+1); break; case BSON_ELEMENT_TYPE_BINARY: e_len = tvb_get_letohl(tvb, offset); /* TODO - Add functions to decode various binary subtypes */ proto_tree_add_item(element_sub_tree, hf_mongo_element_value_binary_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(element_sub_tree, hf_mongo_element_value_binary, tvb, offset+5, e_len, ENC_NA); offset += e_len+5; break; case BSON_ELEMENT_TYPE_UNDEF: case BSON_ELEMENT_TYPE_NULL: case BSON_ELEMENT_TYPE_MIN_KEY: case BSON_ELEMENT_TYPE_MAX_KEY: /* Nothing to do, as there is no element content */ break; case BSON_ELEMENT_TYPE_OBJ_ID: objectid = proto_tree_add_item(element_sub_tree, hf_mongo_element_value_objectid, tvb, offset, 12, ENC_NA); objectid_sub_tree = proto_item_add_subtree(objectid, ett_mongo_objectid); /* Unlike most BSON elements, parts of ObjectID are stored Big Endian, so they can be compared bit by bit */ proto_tree_add_item(objectid_sub_tree, hf_mongo_element_value_objectid_time, tvb, offset, 4, ENC_BIG_ENDIAN); proto_tree_add_item(objectid_sub_tree, hf_mongo_element_value_objectid_machine, tvb, offset+4, 3, ENC_LITTLE_ENDIAN); proto_tree_add_item(objectid_sub_tree, hf_mongo_element_value_objectid_pid, tvb, offset+7, 2, ENC_LITTLE_ENDIAN); proto_tree_add_item(objectid_sub_tree, hf_mongo_element_value_objectid_inc, tvb, offset+9, 3, ENC_BIG_ENDIAN); offset += 12; break; case BSON_ELEMENT_TYPE_BOOL: proto_tree_add_item(element_sub_tree, hf_mongo_element_value_boolean, tvb, offset, 1, ENC_NA); offset += 1; break; case BSON_ELEMENT_TYPE_REGEX: /* regex pattern */ tvb_get_stringz(wmem_packet_scope(), tvb, offset, &str_len); proto_tree_add_item(element_sub_tree, hf_mongo_element_value_regex_pattern, tvb, offset, str_len, ENC_UTF_8|ENC_NA); offset += str_len; /* regex options */ tvb_get_stringz(wmem_packet_scope(), tvb, offset, &str_len); proto_tree_add_item(element_sub_tree, hf_mongo_element_value_regex_options, tvb, offset, str_len, ENC_UTF_8|ENC_NA); offset += str_len; break; case BSON_ELEMENT_TYPE_DB_PTR: str_len = tvb_get_letohl(tvb, offset); proto_tree_add_item(element_sub_tree, hf_mongo_element_value_string_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(element_sub_tree, hf_mongo_element_value_string, tvb, offset+4, str_len, ENC_UTF_8|ENC_NA); offset += str_len; proto_tree_add_item(element_sub_tree, hf_mongo_element_value_db_ptr, tvb, offset, 12, ENC_NA); offset += 12; break; case BSON_ELEMENT_TYPE_JS_CODE_SCOPE: /* code_w_s ::= int32 string document */ proto_tree_add_item(element_sub_tree, hf_mongo_element_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); e_len = tvb_get_letohl(tvb, offset); offset += 4; str_len = tvb_get_letohl(tvb, offset); js_code = proto_tree_add_item(element_sub_tree, hf_mongo_element_value_js_code, tvb, offset, str_len+4, ENC_NA); js_code_sub_tree = proto_item_add_subtree(js_code, ett_mongo_code); proto_tree_add_item(js_code_sub_tree, hf_mongo_element_value_string_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(js_code_sub_tree, hf_mongo_element_value_string, tvb, offset+4, str_len, ENC_UTF_8|ENC_NA); offset += str_len+4; doc_len = e_len - (str_len + 8); js_scope = proto_tree_add_item(element_sub_tree, hf_mongo_element_value_js_scope, tvb, offset, doc_len, ENC_NA); js_scope_sub_tree = proto_item_add_subtree(js_scope, ett_mongo_code); offset += dissect_bson_document(tvb, pinfo, offset, js_scope_sub_tree, hf_mongo_document, nest_level+1); break; case BSON_ELEMENT_TYPE_INT32: proto_tree_add_item(element_sub_tree, hf_mongo_element_value_int32, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; break; case BSON_ELEMENT_TYPE_DATETIME: case BSON_ELEMENT_TYPE_TIMESTAMP: /* TODO Implement routine to convert datetime & timestamp values to UTC date/time */ /* for now, simply display the integer value */ case BSON_ELEMENT_TYPE_INT64: proto_tree_add_item(element_sub_tree, hf_mongo_element_value_int64, tvb, offset, 8, ENC_LITTLE_ENDIAN); offset += 8; break; default: break; } /* end switch() */ } while (offset < final_offset-1); return document_length; }
/* Code to actually dissect the packets */ static void dissect_ipa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gint remaining; gint header_length = 3; int offset = 0; col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPA"); col_clear(pinfo->cinfo, COL_INFO); while ((remaining = tvb_reported_length_remaining(tvb, offset)) > 0) { proto_item *ti; proto_tree *ipa_tree = NULL; guint16 len, msg_type; tvbuff_t *next_tvb; len = tvb_get_ntohs(tvb, offset); msg_type = tvb_get_guint8(tvb, offset+2); col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(msg_type, ipa_protocol_vals, "unknown 0x%02x")); /* * The IPA header is different depending on the transport protocol. * With UDP there seems to be a fourth byte for the IPA header. * We attempt to detect this by checking if the length from the * header + four bytes of the IPA header equals the remaining size. */ if ((pinfo->ipproto == IP_PROTO_UDP) && (len + 4 == remaining)) { header_length++; } if (tree) { ti = proto_tree_add_protocol_format(tree, proto_ipa, tvb, offset, len+header_length, "IPA protocol ip.access, type: %s", val_to_str(msg_type, ipa_protocol_vals, "unknown 0x%02x")); ipa_tree = proto_item_add_subtree(ti, ett_ipa); proto_tree_add_item(ipa_tree, hf_ipa_data_len, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(ipa_tree, hf_ipa_protocol, tvb, offset+2, 1, ENC_BIG_ENDIAN); } next_tvb = tvb_new_subset(tvb, offset+header_length, len, len); switch (msg_type) { case ABISIP_OML: /* hand this off to the standard A-bis OML dissector */ if (sub_handles[SUB_OML]) call_dissector(sub_handles[SUB_OML], next_tvb, pinfo, tree); break; case ABISIP_IPACCESS: dissect_ipaccess(next_tvb, pinfo, tree); break; case AIP_SCCP: /* hand this off to the standard SCCP dissector */ call_dissector(sub_handles[SUB_SCCP], next_tvb, pinfo, tree); break; case IPA_MGCP: /* hand this off to the standard MGCP dissector */ call_dissector(sub_handles[SUB_MGCP], next_tvb, pinfo, tree); break; case OSMO_EXT: dissect_osmo(next_tvb, pinfo, ipa_tree, tree); break; case HSL_DEBUG: if (tree) { proto_tree_add_item(ipa_tree, hf_ipa_hsl_debug, next_tvb, 0, len, ENC_ASCII|ENC_NA); if (global_ipa_in_root == TRUE) proto_tree_add_item(tree, hf_ipa_hsl_debug, next_tvb, 0, len, ENC_ASCII|ENC_NA); } if (global_ipa_in_info == TRUE) col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", tvb_get_stringz(wmem_packet_scope(), next_tvb, 0, NULL)); break; default: if (msg_type < ABISIP_RSL_MAX) { /* hand this off to the standard A-bis RSL dissector */ call_dissector(sub_handles[SUB_RSL], next_tvb, pinfo, tree); } break; } offset += len + header_length; } }
static void dissect_turbocell(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti, *name_item; proto_tree *turbocell_tree = NULL, *network_tree; tvbuff_t *next_tvb; int i=0; guint8 packet_type; guint8 * str_name; guint str_len; gint remaining_length; packet_type = tvb_get_guint8(tvb, 0); if (!(packet_type & 0x0F)){ col_set_str(pinfo->cinfo, COL_INFO, "Turbocell Packet (Beacon)"); col_set_str(pinfo->cinfo, COL_PROTOCOL, "Turbocell"); } else if ( packet_type == TURBOCELL_TYPE_MANAGEMENT ) { col_set_str(pinfo->cinfo, COL_INFO, "Turbocell Packet (Management)"); col_set_str(pinfo->cinfo, COL_PROTOCOL, "Turbocell"); } else if ( packet_type == TURBOCELL_TYPE_DATA ) { col_set_str(pinfo->cinfo, COL_INFO, "Turbocell Packet (Data)"); col_set_str(pinfo->cinfo, COL_PROTOCOL, "Turbocell"); } else { col_set_str(pinfo->cinfo, COL_INFO, "Turbocell Packet (Unknown)"); col_set_str(pinfo->cinfo, COL_PROTOCOL, "Turbocell"); } if (tree) { ti = proto_tree_add_item(tree, proto_turbocell, tvb, 0, 20, ENC_NA); turbocell_tree = proto_item_add_subtree(ti, ett_turbocell); proto_tree_add_item(turbocell_tree, hf_turbocell_type, tvb, 0, 1, ENC_BIG_ENDIAN); proto_tree_add_item(turbocell_tree, hf_turbocell_satmode, tvb, 1, 1, ENC_BIG_ENDIAN); proto_tree_add_item(turbocell_tree, hf_turbocell_nwid, tvb, 1, 1, ENC_BIG_ENDIAN); /* it seem when we have this magic number,that means an alternate header version */ if (tvb_get_bits64(tvb, 64,48,ENC_BIG_ENDIAN) != G_GINT64_CONSTANT(0x000001fe23dc45ba)){ proto_tree_add_item(turbocell_tree, hf_turbocell_counter, tvb, 0x02, 2, ENC_BIG_ENDIAN); proto_tree_add_item(turbocell_tree, hf_turbocell_dst, tvb, 0x04, 6, ENC_NA); proto_tree_add_item(turbocell_tree, hf_turbocell_timestamp, tvb, 0x0A, 3, ENC_BIG_ENDIAN); } else { proto_tree_add_item(turbocell_tree, hf_turbocell_timestamp, tvb, 0x02, 3, ENC_BIG_ENDIAN); proto_tree_add_item(turbocell_tree, hf_turbocell_counter, tvb, 0x05, 3, ENC_BIG_ENDIAN); proto_tree_add_item(turbocell_tree, hf_turbocell_dst, tvb, 0x08, 6, ENC_NA); } proto_tree_add_item(turbocell_tree, hf_turbocell_unknown, tvb, 0x0E, 2, ENC_BIG_ENDIAN); proto_tree_add_item(turbocell_tree, hf_turbocell_ip, tvb, 0x10, 4, ENC_BIG_ENDIAN); } remaining_length=tvb_length_remaining(tvb, 0x14); if (remaining_length > 6) { /* If the first character is a printable character that means we have a payload with network info */ /* I couldn't find anything in the header that would definitvely indicate if payload is either data or network info */ /* Since the frame size is limited this should work ok */ if (tvb_get_guint8(tvb, 0x14)>=0x20){ name_item = proto_tree_add_item(turbocell_tree, hf_turbocell_name, tvb, 0x14, 30, ENC_ASCII|ENC_NA); network_tree = proto_item_add_subtree(name_item, ett_network); str_name=tvb_get_stringz(wmem_packet_scope(), tvb, 0x14, &str_len); col_append_fstr(pinfo->cinfo, COL_INFO, ", Network=\"%s\"",format_text(str_name, str_len-1)); while(tvb_get_guint8(tvb, 0x34 + 8*i)==0x00 && (tvb_length_remaining(tvb,0x34 + 8*i) > 6) && (i<32)) { proto_tree_add_item(network_tree, hf_turbocell_station[i], tvb, 0x34+8*i, 6, ENC_NA); i++; } /*Couldn't make sense of the apparently random data in the end*/ next_tvb = tvb_new_subset_remaining(tvb, 0x34 + 8*i); call_dissector(data_handle, next_tvb, pinfo, tree); } else { tvbuff_t *volatile msdu_tvb = NULL; guint32 msdu_offset = 0x04; guint16 j = 1; guint16 msdu_length; proto_item *parent_item; proto_tree *mpdu_tree; proto_tree *subframe_tree; next_tvb = tvb_new_subset(tvb, 0x14, -1, tvb_get_ntohs(tvb, 0x14)); parent_item = proto_tree_add_protocol_format(tree, proto_aggregate, next_tvb, 0, tvb_reported_length_remaining(next_tvb, 0), "Turbocell Aggregate Frames"); mpdu_tree = proto_item_add_subtree(parent_item, ett_msdu_aggregation_parent_tree); proto_tree_add_item(mpdu_tree, hf_turbocell_aggregate_len, next_tvb, 0x00, 2, ENC_BIG_ENDIAN); proto_tree_add_item(mpdu_tree, hf_turbocell_aggregate_unknown1, next_tvb, 0x02, 2, ENC_BIG_ENDIAN); remaining_length=tvb_length_remaining(next_tvb, msdu_offset); do { msdu_length = (tvb_get_letohs(next_tvb, msdu_offset) & 0x0FFF); if (msdu_length==0) break; parent_item = proto_tree_add_uint_format(mpdu_tree, hf_turbocell_aggregate_msdu_header_text, next_tvb,msdu_offset, msdu_length + 0x02,j, "A-MSDU Subframe #%u", j); subframe_tree = proto_item_add_subtree(parent_item, ett_msdu_aggregation_subframe_tree); j++; proto_tree_add_item(subframe_tree, hf_turbocell_aggregate_msdu_len, next_tvb, msdu_offset, 2, ENC_LITTLE_ENDIAN); proto_tree_add_item(subframe_tree, hf_turbocell_aggregate_unknown2, next_tvb, msdu_offset+1, 1, ENC_BIG_ENDIAN); msdu_offset += 0x02; remaining_length -= 0x02; msdu_tvb = tvb_new_subset(next_tvb, msdu_offset, (msdu_length>remaining_length)?remaining_length:msdu_length, msdu_length); call_dissector(eth_handle, msdu_tvb, pinfo, subframe_tree); msdu_offset += msdu_length; remaining_length -= msdu_length; } while (remaining_length > 6); if (remaining_length > 2) { next_tvb = tvb_new_subset_remaining(next_tvb, msdu_offset); call_dissector(data_handle, next_tvb, pinfo, tree); } } } }
/* Process an APP1 block. * * XXX - This code only works on US-ASCII systems!!! */ static int process_app1_segment(proto_tree *tree, tvbuff_t *tvb, guint32 len, guint16 marker, const char *marker_name) { proto_item *ti = NULL; proto_tree *subtree = NULL; char *str; gint str_size; int offset = 0; int tiff_start; if (!tree) return 0; ti = proto_tree_add_item(tree, hf_marker_segment, tvb, 0, -1, ENC_NA); subtree = proto_item_add_subtree(ti, ett_marker_segment); proto_item_append_text(ti, ": %s (0x%04X)", marker_name, marker); proto_tree_add_item(subtree, hf_marker, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(subtree, hf_len, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; str = tvb_get_stringz(wmem_packet_scope(), tvb, offset, &str_size); ti = proto_tree_add_item(subtree, hf_identifier, tvb, offset, str_size, ENC_ASCII|ENC_NA); offset += str_size; if (strcmp(str, "Exif") == 0) { /* * Endianness */ gboolean is_little_endian; guint16 val_16; guint32 val_32; guint16 num_fields; offset++; /* Skip a byte supposed to be 0x00 */ tiff_start = offset; val_16 = tvb_get_ntohs(tvb, offset); if (val_16 == 0x4949) { is_little_endian = TRUE; proto_tree_add_text(subtree, tvb, offset, 2, "Endianness: little endian"); } else if (val_16 == 0x4D4D) { is_little_endian = FALSE; proto_tree_add_text(subtree, tvb, offset, 2, "Endianness: big endian"); } else { /* Error: invalid endianness encoding */ proto_tree_add_text(subtree, tvb, offset, 2, "Incorrect endianness encoding - skipping the remainder of this application marker"); return offset; } offset += 2; /* * Fixed value 42 = 0x002a */ offset += 2; /* * Offset to IFD */ if (is_little_endian) { val_32 = tvb_get_letohl(tvb, offset); } else { val_32 = tvb_get_ntohl(tvb, offset); } /* * Check for a bogus val_32 value. * XXX - bogus value message should also deal with a * value that's too large and causes an overflow. * Or should it just check against the segment length, * which is 16 bits? */ if (val_32 + tiff_start < (guint32)offset + 4) { proto_tree_add_text(subtree, tvb, offset, 4, "Start offset of IFD starting from the TIFF header start: %u bytes (bogus, should be >= %u", val_32, offset + 4 - tiff_start); return offset; } proto_tree_add_text(subtree, tvb, offset, 4, "Start offset of IFD starting from the TIFF header start: %u bytes", val_32); offset += 4; /* * Skip the following portion */ if (val_32 + tiff_start > (guint32)offset) { proto_tree_add_text(subtree, tvb, offset, val_32 + tiff_start - offset, "Skipped data between end of TIFF header and start of IFD (%u bytes)", val_32 + tiff_start - offset); } for (;;) { offset = val_32 + tiff_start; /* * Process the IFD */ if (is_little_endian) { num_fields = tvb_get_letohs(tvb, offset); } else { num_fields = tvb_get_ntohs(tvb, offset); } proto_tree_add_text(subtree, tvb, offset, 2, "Number of fields in this IFD: %u", num_fields); offset += 2; while (num_fields-- > 0) { guint16 tag, type; guint32 count, off; if (is_little_endian) { tag = tvb_get_letohs(tvb, offset); type = tvb_get_letohs(tvb, offset + 2); count = tvb_get_letohl(tvb, offset + 4); off = tvb_get_letohl(tvb, offset + 8); } else { tag = tvb_get_ntohs(tvb, offset); type = tvb_get_ntohs(tvb, offset + 2); count = tvb_get_ntohl(tvb, offset + 4); off = tvb_get_ntohl(tvb, offset + 8); } /* TODO - refine this */ proto_tree_add_text(subtree, tvb, offset, 2, "Exif Tag: 0x%04X (%s), Type: %u (%s), Count: %u, " "Value offset from start of TIFF header: %u", tag, val_to_str_const(tag, vals_exif_tags, "Unknown Exif tag"), type, val_to_str_const(type, vals_exif_types, "Unknown Exif type"), count, off); offset += 12; } /* * Offset to the next IFD */ if (is_little_endian) { val_32 = tvb_get_letohl(tvb, offset); } else { val_32 = tvb_get_ntohl(tvb, offset); } if (val_32 != 0 && val_32 + tiff_start < (guint32)offset + 4) { proto_tree_add_text(subtree, tvb, offset, 4, "Offset to next IFD from start of TIFF header: %u bytes (bogus, should be >= %u)", val_32, offset + 4 - tiff_start); return offset; } proto_tree_add_text(subtree, tvb, offset, 4, "Offset to next IFD from start of TIFF header: %u bytes", val_32); offset += 4; if (val_32 == 0) break; } } else { proto_tree_add_text(subtree, tvb, offset, -1, "Remaining segment data (%u bytes)", len - 2 - str_size); proto_item_append_text(ti, " (Unknown identifier)"); } return offset; }
/* Process an APP0 block. * * XXX - This code only works on US-ASCII systems!!! */ static int process_app0_segment(proto_tree *tree, tvbuff_t *tvb, guint32 len, guint16 marker, const char *marker_name) { proto_item *ti = NULL; proto_tree *subtree = NULL; proto_tree *subtree_details = NULL; guint32 offset; char *str; gint str_size; if (!tree) return 0 ; ti = proto_tree_add_item(tree, hf_marker_segment, tvb, 0, -1, ENC_NA); subtree = proto_item_add_subtree(ti, ett_marker_segment); proto_item_append_text(ti, ": %s (0x%04X)", marker_name, marker); proto_tree_add_item(subtree, hf_marker, tvb, 0, 2, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_len, tvb, 2, 2, ENC_BIG_ENDIAN); str = tvb_get_stringz(wmem_packet_scope(), tvb, 4, &str_size); ti = proto_tree_add_item(subtree, hf_identifier, tvb, 4, str_size, ENC_ASCII|ENC_NA); if (strcmp(str, "JFIF") == 0) { /* Version */ ti = proto_tree_add_none_format(subtree, hf_version, tvb, 9, 2, "Version: %u.%u", tvb_get_guint8(tvb, 9), tvb_get_guint8(tvb, 10)); subtree_details = proto_item_add_subtree(ti, ett_details); proto_tree_add_item(subtree_details, hf_version_major, tvb, 9, 1, ENC_BIG_ENDIAN); proto_tree_add_item(subtree_details, hf_version_minor, tvb, 10, 1, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_units, tvb, 11, 1, ENC_BIG_ENDIAN); /* Aspect ratio */ proto_tree_add_item(subtree, hf_xdensity, tvb, 12, 2, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_ydensity, tvb, 14, 2, ENC_BIG_ENDIAN); /* Thumbnail */ proto_tree_add_item(subtree, hf_xthumbnail, tvb, 16, 1, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_ythumbnail, tvb, 17, 1, ENC_BIG_ENDIAN); { guint16 x = tvb_get_guint8(tvb, 16); guint16 y = tvb_get_guint8(tvb, 17); if (x || y) { proto_tree_add_item(subtree, hf_rgb, tvb, 18, 3 * (x * y), ENC_NA); offset = 18 + (3 * (x * y)); } else { offset = 18; } } } else if (strcmp(str, "JFXX") == 0) { proto_tree_add_item(subtree, hf_extension_code, tvb, 9, 1, ENC_BIG_ENDIAN); { guint8 code = tvb_get_guint8(tvb, 9); switch (code) { case 0x10: /* Thumbnail coded using JPEG */ break; case 0x11: /* thumbnail stored using 1 byte per pixel */ break; case 0x13: /* thumbnail stored using 3 bytes per pixel */ break; default: /* Error */ break; } } offset = 10; } else { /* Unknown */ proto_item_append_text(ti, " (unknown identifier)"); offset = 4 + str_size; proto_tree_add_text(subtree, tvb, offset, -1, "Remaining segment data (%u bytes)", len - 2 - str_size); } return offset; }