/* 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)");
    }
}
Beispiel #2
0
/* 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;
    }
}
Beispiel #3
0
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;
}