Beispiel #1
0
static void
dissect_mpeg_sect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
    gint     offset           = 0;
    guint    section_length   = 0;
    gboolean syntax_indicator = FALSE;
    guint8   table_id;

    proto_item *ti;
    proto_tree *mpeg_sect_tree;

    table_id = tvb_get_guint8(tvb, offset);

    /* Check if a dissector can parse the current table */
    if (dissector_try_uint(mpeg_sect_tid_dissector_table, table_id, tvb, pinfo, tree))
        return;

    /* If no dissector is registered, use the common one */
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "MPEG SECT");
    col_add_fstr(pinfo->cinfo, COL_INFO, "Table ID 0x%02x", table_id);

    ti = proto_tree_add_item(tree, proto_mpeg_sect, tvb, offset, -1, ENC_NA);
    mpeg_sect_tree = proto_item_add_subtree(ti, ett_mpeg_sect);

    proto_item_append_text(ti, " Table_ID=0x%02x", table_id);

    packet_mpeg_sect_header(tvb, offset, mpeg_sect_tree,
                &section_length, &syntax_indicator);

    if (syntax_indicator)
        packet_mpeg_sect_crc(tvb, pinfo, mpeg_sect_tree, 0, (section_length-1));
}
Beispiel #2
0
static void
dissect_dvb_tdt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{

    guint offset = 0;

    proto_item *ti;
    proto_tree *dvb_tdt_tree;

    nstime_t    utc_time;

    col_set_str(pinfo->cinfo, COL_INFO, "Time and Date Table (TDT)");

    ti = proto_tree_add_item(tree, proto_dvb_tdt, tvb, offset, -1, ENC_NA);
    dvb_tdt_tree = proto_item_add_subtree(ti, ett_dvb_tdt);

    offset += packet_mpeg_sect_header(tvb, offset, dvb_tdt_tree, NULL, NULL);

    if (packet_mpeg_sect_mjd_to_utc_time(tvb, offset, &utc_time) < 0) {
        proto_tree_add_text(dvb_tdt_tree, tvb, offset, 5, "Unparseable time");
    } else {
        proto_tree_add_time(dvb_tdt_tree, hf_dvb_tdt_utc_time, tvb, offset, 5, &utc_time);
    }
    offset += 5;

    proto_item_set_len(ti, offset);
}
static void
dissect_mpeg_ca(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{

    guint offset = 0, length = 0;

    proto_item *ti = NULL;
    proto_tree *mpeg_ca_tree = NULL;

    /* The TVB should start right after the section_length in the Section packet */

    col_clear(pinfo->cinfo, COL_INFO);
    col_set_str(pinfo->cinfo, COL_INFO, "Conditional Access Table (CA)");

    if (!tree)

        return;

    ti = proto_tree_add_item(tree, proto_mpeg_ca, tvb, offset, -1, ENC_NA);
    mpeg_ca_tree = proto_item_add_subtree(ti, ett_mpeg_ca);

    offset += packet_mpeg_sect_header(tvb, offset, mpeg_ca_tree, &length, NULL);
    length -= 4;

    proto_tree_add_item(mpeg_ca_tree, hf_mpeg_ca_reserved, tvb, offset, 3, ENC_BIG_ENDIAN);
    proto_tree_add_item(mpeg_ca_tree, hf_mpeg_ca_version_number, tvb, offset, 3, ENC_BIG_ENDIAN);
    proto_tree_add_item(mpeg_ca_tree, hf_mpeg_ca_current_next_indicator, tvb, offset, 3, ENC_BIG_ENDIAN);
    offset += 3;

    proto_tree_add_item(mpeg_ca_tree, hf_mpeg_ca_section_number, tvb, offset, 1, ENC_BIG_ENDIAN);
    offset++;

    proto_tree_add_item(mpeg_ca_tree, hf_mpeg_ca_last_section_number, tvb, offset, 1, ENC_BIG_ENDIAN);
    offset++;

    /* Parse all the programs */
    while (offset < length)
        offset += proto_mpeg_descriptor_dissect(tvb, offset, mpeg_ca_tree);

    packet_mpeg_sect_crc(tvb, pinfo, mpeg_ca_tree, 0, offset);

}
static void
dissect_dvb_tot(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{

    guint       offset = 0;
    guint       descriptor_len;

    proto_item *ti;
    proto_tree *dvb_tot_tree;

    nstime_t    utc_time;

    col_set_str(pinfo->cinfo, COL_INFO, "Time Offset Table (TOT)");

    ti = proto_tree_add_item(tree, proto_dvb_tot, tvb, offset, -1, ENC_NA);
    dvb_tot_tree = proto_item_add_subtree(ti, ett_dvb_tot);

    offset += packet_mpeg_sect_header(tvb, offset, dvb_tot_tree, NULL, NULL);

    if (packet_mpeg_sect_mjd_to_utc_time(tvb, offset, &utc_time) < 0) {
        proto_tree_add_text(dvb_tot_tree, tvb, offset, 5, "UTC Time : Unparseable time");
    } else {
        proto_tree_add_time_format(dvb_tot_tree, hf_dvb_tot_utc_time, tvb, offset, 5, &utc_time,
            "UTC Time : %s UTC", abs_time_to_str(&utc_time, ABSOLUTE_TIME_UTC, FALSE));
    }

    offset += 5;

    descriptor_len = tvb_get_ntohs(tvb, offset) & DVB_TOT_DESCRIPTORS_LOOP_LENGTH_MASK;
    proto_tree_add_item(dvb_tot_tree, hf_dvb_tot_reserved, tvb, offset, 2, ENC_BIG_ENDIAN);
    proto_tree_add_item(dvb_tot_tree, hf_dvb_tot_descriptors_loop_length, tvb, offset, 2, ENC_BIG_ENDIAN);
    offset += 2;

    offset += proto_mpeg_descriptor_loop_dissect(tvb, offset, descriptor_len, dvb_tot_tree);

    offset += packet_mpeg_sect_crc(tvb, pinfo, dvb_tot_tree, 0, offset);
    proto_item_set_len(ti, offset);
}
static void
dissect_dvb_sdt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{

	guint offset = 0, length = 0, descriptor_end = 0;
	guint16 svc_id = 0, descriptor_len = 0;

	proto_item *ti = NULL;
	proto_tree *dvb_sdt_tree = NULL;
	proto_item *si = NULL;
	proto_tree *dvb_sdt_service_tree = NULL;

	/* The TVB should start right after the section_length in the Section packet */

	col_clear(pinfo->cinfo, COL_INFO);
	col_set_str(pinfo->cinfo, COL_INFO, "Service Description Table (SDT)");

	if (!tree)
		return;

	ti = proto_tree_add_item(tree, proto_dvb_sdt, tvb, offset, -1, ENC_NA);
	dvb_sdt_tree = proto_item_add_subtree(ti, ett_dvb_sdt);

	offset += packet_mpeg_sect_header(tvb, offset, dvb_sdt_tree, &length, NULL);
	length -= 4;

	proto_tree_add_item(dvb_sdt_tree, hf_dvb_sdt_transport_stream_id, tvb, offset, 2, ENC_BIG_ENDIAN);
	offset += 2;

	proto_tree_add_item(dvb_sdt_tree, hf_dvb_sdt_reserved1, tvb, offset, 1, ENC_BIG_ENDIAN);
	proto_tree_add_item(dvb_sdt_tree, hf_dvb_sdt_version_number, tvb, offset, 1, ENC_BIG_ENDIAN);
	proto_tree_add_item(dvb_sdt_tree, hf_dvb_sdt_current_next_indicator, tvb, offset, 1, ENC_BIG_ENDIAN);
	offset++;

	proto_tree_add_item(dvb_sdt_tree, hf_dvb_sdt_section_number, tvb, offset, 1, ENC_BIG_ENDIAN);
	offset++;

	proto_tree_add_item(dvb_sdt_tree, hf_dvb_sdt_last_section_number, tvb, offset, 1, ENC_BIG_ENDIAN);
	offset++;

	proto_tree_add_item(dvb_sdt_tree, hf_dvb_sdt_original_network_id, tvb, offset, 2, ENC_BIG_ENDIAN);
	offset += 2;

	proto_tree_add_item(dvb_sdt_tree, hf_dvb_sdt_reserved2, tvb, offset, 1, ENC_BIG_ENDIAN);
	offset++;


	if (offset >= length)
		return;

	/* Parse all the services */
	while (offset < length) {

		svc_id = tvb_get_ntohs(tvb, offset);
		si = proto_tree_add_text(dvb_sdt_tree, tvb, offset, 5, "Service 0x%04hx", svc_id);
		dvb_sdt_service_tree = proto_item_add_subtree(si, ett_dvb_sdt_service);

		proto_tree_add_item(dvb_sdt_service_tree, hf_dvb_sdt_service_id, tvb, offset, 2, ENC_BIG_ENDIAN);
		offset += 2;

		proto_tree_add_item(dvb_sdt_service_tree, hf_dvb_sdt_reserved3, tvb, offset, 1, ENC_BIG_ENDIAN);
		proto_tree_add_item(dvb_sdt_service_tree, hf_dvb_sdt_eit_schedule_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
		proto_tree_add_item(dvb_sdt_service_tree, hf_dvb_sdt_eit_present_following_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
		offset++;

		proto_tree_add_item(dvb_sdt_service_tree, hf_dvb_sdt_running_status, tvb, offset, 2, ENC_BIG_ENDIAN);
		proto_tree_add_item(dvb_sdt_service_tree, hf_dvb_sdt_free_ca_mode, tvb, offset, 2, ENC_BIG_ENDIAN);
		proto_tree_add_item(dvb_sdt_service_tree, hf_dvb_sdt_descriptors_loop_length, tvb, offset, 2, ENC_BIG_ENDIAN);
		descriptor_len = tvb_get_ntohs(tvb, offset) & DVB_SDT_DESCRIPTORS_LOOP_LENGTH_MASK;
		offset += 2;

		descriptor_end = offset + descriptor_len;
		while (offset < descriptor_end)
			offset += proto_mpeg_descriptor_dissect(tvb, offset, dvb_sdt_service_tree);

	}

	packet_mpeg_sect_crc(tvb, pinfo, dvb_sdt_tree, 0, offset);
}
Beispiel #6
0
static void
dissect_mpeg_pat(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{

	guint offset = 0, length = 0;
	guint16 prog_num = 0, prog_pid;

	proto_item *ti = NULL;
	proto_tree *mpeg_pat_tree = NULL;
	proto_item *pi = NULL;
	proto_tree *mpeg_pat_prog_tree = NULL;

	/* The TVB should start right after the section_length in the Section packet */

	col_clear(pinfo->cinfo, COL_INFO);
	col_set_str(pinfo->cinfo, COL_INFO, "Program Association Table (PAT)");

	ti = proto_tree_add_item(tree, proto_mpeg_pat, tvb, offset, -1, ENC_NA);
	mpeg_pat_tree = proto_item_add_subtree(ti, ett_mpeg_pat);

	if (!tree)
		return;

	offset += packet_mpeg_sect_header(tvb, offset, mpeg_pat_tree, &length, NULL);
	length -= 4;

	proto_tree_add_item(mpeg_pat_tree, hf_mpeg_pat_transport_stream_id, tvb, offset, 2, ENC_BIG_ENDIAN);
	offset += 2;

	proto_tree_add_item(mpeg_pat_tree, hf_mpeg_pat_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
	proto_tree_add_item(mpeg_pat_tree, hf_mpeg_pat_version_number, tvb, offset, 1, ENC_BIG_ENDIAN);
	proto_tree_add_item(mpeg_pat_tree, hf_mpeg_pat_current_next_indicator, tvb, offset, 1, ENC_BIG_ENDIAN);
	offset++;

	proto_tree_add_item(mpeg_pat_tree, hf_mpeg_pat_section_number, tvb, offset, 1, ENC_BIG_ENDIAN);
	offset++;

	proto_tree_add_item(mpeg_pat_tree, hf_mpeg_pat_last_section_number, tvb, offset, 1, ENC_BIG_ENDIAN);
	offset++;

	if (offset >= length)
		return;


	/* Parse all the programs */
	while (offset < length) {

		prog_num = tvb_get_ntohs(tvb, offset);
		prog_pid = tvb_get_ntohs(tvb, offset + 2) & MPEG_PAT_PROGRAM_MAP_PID_MASK;

		pi = proto_tree_add_text(mpeg_pat_tree, tvb, offset, 4, "Program 0x%04hx -> PID 0x%04hx", prog_num, prog_pid);
		mpeg_pat_prog_tree = proto_item_add_subtree(pi, ett_mpeg_pat_prog);

		proto_tree_add_item(mpeg_pat_prog_tree, hf_mpeg_pat_program_number, tvb, offset, 2, ENC_BIG_ENDIAN);
		offset += 2;

		proto_tree_add_item(mpeg_pat_prog_tree, hf_mpeg_pat_program_reserved, tvb, offset, 2, ENC_BIG_ENDIAN);
		proto_tree_add_item(mpeg_pat_prog_tree, hf_mpeg_pat_program_map_pid, tvb, offset, 2, ENC_BIG_ENDIAN);
		offset += 2;

	}

	packet_mpeg_sect_crc(tvb, pinfo, mpeg_pat_tree, 0, offset);
}
static void
dissect_dvb_eit(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{

	guint       offset = 0, length = 0;
	guint       descriptor_len, descriptor_end;
	guint16     evt_id;

	proto_item *ti;
	proto_tree *dvb_eit_tree;
	proto_item *ei;
	proto_tree *dvb_eit_event_tree;
	proto_item *duration_item;

	nstime_t    start_time;

	col_set_str(pinfo->cinfo, COL_INFO, "Event Information Table (EIT)");

	ti = proto_tree_add_item(tree, proto_dvb_eit, tvb, offset, -1, ENC_NA);
	dvb_eit_tree = proto_item_add_subtree(ti, ett_dvb_eit);

	offset += packet_mpeg_sect_header(tvb, offset, dvb_eit_tree, &length, NULL);
	length -= 4;

	proto_tree_add_item(dvb_eit_tree, hf_dvb_eit_service_id,                  tvb, offset, 2, ENC_BIG_ENDIAN);
	offset += 2;

	proto_tree_add_item(dvb_eit_tree, hf_dvb_eit_reserved,                    tvb, offset, 1, ENC_BIG_ENDIAN);
	proto_tree_add_item(dvb_eit_tree, hf_dvb_eit_version_number,              tvb, offset, 1, ENC_BIG_ENDIAN);
	proto_tree_add_item(dvb_eit_tree, hf_dvb_eit_current_next_indicator,      tvb, offset, 1, ENC_BIG_ENDIAN);
	offset += 1;

	proto_tree_add_item(dvb_eit_tree, hf_dvb_eit_section_number,              tvb, offset, 1, ENC_BIG_ENDIAN);
	offset += 1;

	proto_tree_add_item(dvb_eit_tree, hf_dvb_eit_last_section_number,         tvb, offset, 1, ENC_BIG_ENDIAN);
	offset += 1;

	proto_tree_add_item(dvb_eit_tree, hf_dvb_eit_transport_stream_id,         tvb, offset, 2, ENC_BIG_ENDIAN);
	offset += 2;

	proto_tree_add_item(dvb_eit_tree, hf_dvb_eit_original_network_id,         tvb, offset, 2, ENC_BIG_ENDIAN);
	offset += 2;

	proto_tree_add_item(dvb_eit_tree, hf_dvb_eit_segment_last_section_number, tvb, offset, 1, ENC_BIG_ENDIAN);
	offset += 1;

	proto_tree_add_item(dvb_eit_tree, hf_dvb_eit_last_table_id, tvb, offset, 1, ENC_BIG_ENDIAN);
	offset += 1;

	if (offset >= length) {
		packet_mpeg_sect_crc(tvb, pinfo, dvb_eit_tree, 0, offset);

		return;
	}

	/* Parse all the events */
	while (offset < length) {

		evt_id = tvb_get_ntohs(tvb, offset);
		ei = proto_tree_add_text(dvb_eit_tree, tvb, offset, 12, "Event 0x%04hx", evt_id);
		dvb_eit_event_tree = proto_item_add_subtree(ei, ett_dvb_eit_event);

		proto_tree_add_item(dvb_eit_event_tree, hf_dvb_eit_event_id, tvb, offset, 2, ENC_BIG_ENDIAN);
		offset += 2;

		if (tvb_memeql(tvb, offset, "\xFF\xFF\xFF\xFF\xFF", 5)) {
			if (packet_mpeg_sect_mjd_to_utc_time(tvb, offset, &start_time) < 0) {
				proto_tree_add_text(tree, tvb, offset, 5, "Unparseable time");
			} else {
				proto_tree_add_time_format(dvb_eit_event_tree, hf_dvb_eit_start_time, tvb, offset,
					5, &start_time,
					"Start Time: %s UTC", abs_time_to_str(&start_time, ABSOLUTE_TIME_UTC, FALSE));
			}
		} else {
			proto_tree_add_text(tree, tvb, offset, 5, "Start Time: Undefined (0xFFFFFFFFFF)");
		}
		offset += 5;

		duration_item = proto_tree_add_item(dvb_eit_event_tree, hf_dvb_eit_duration, tvb, offset, 3, ENC_BIG_ENDIAN);
		proto_item_append_text(duration_item, " (%02u:%02u:%02u)",
			MPEG_SECT_BCD44_TO_DEC(tvb_get_guint8(tvb, offset)),
			MPEG_SECT_BCD44_TO_DEC(tvb_get_guint8(tvb, offset + 1)),
			MPEG_SECT_BCD44_TO_DEC(tvb_get_guint8(tvb, offset + 2)));
		offset += 3;

		proto_tree_add_item(dvb_eit_event_tree, hf_dvb_eit_running_status,          tvb, offset, 2, ENC_BIG_ENDIAN);
		proto_tree_add_item(dvb_eit_event_tree, hf_dvb_eit_free_ca_mode,            tvb, offset, 2, ENC_BIG_ENDIAN);
		proto_tree_add_item(dvb_eit_event_tree, hf_dvb_eit_descriptors_loop_length, tvb, offset, 2, ENC_BIG_ENDIAN);
		descriptor_len = tvb_get_ntohs(tvb, offset) & DVB_EIT_DESCRIPTORS_LOOP_LENGTH_MASK;
		offset += 2;

		descriptor_end = offset + descriptor_len;
		while (offset < descriptor_end)
			offset += proto_mpeg_descriptor_dissect(tvb, offset, dvb_eit_event_tree);

	}

	offset += packet_mpeg_sect_crc(tvb, pinfo, dvb_eit_tree, 0, offset);
	proto_item_set_len(ti, offset);
}
static void
dissect_dvb_data_mpe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{

    guint       offset = 0, tot_len = 0;
    guint8      llc_snap_flag;
    int         i;

    proto_item *ti;
    proto_tree *dvb_data_mpe_tree;
    tvbuff_t   *mac_tvb;
    tvbuff_t   *mac_bytes_tvb[6];
    tvbuff_t   *data_tvb;

    /* The TVB should start right after the section_length in the Section packet */

    col_set_str(pinfo->cinfo, COL_PROTOCOL, "DVB-DATA");
    col_set_str(pinfo->cinfo, COL_INFO, "MultiProtocol Encapsulation");

    ti = proto_tree_add_item(tree, proto_dvb_data_mpe, tvb, offset, -1, ENC_NA);
    dvb_data_mpe_tree = proto_item_add_subtree(ti, ett_dvb_data_mpe);

    offset += packet_mpeg_sect_header(tvb, offset, dvb_data_mpe_tree, &tot_len, NULL);


    /* Parse the DMC-CC private section header */

    mac_bytes_tvb[5] = tvb_new_subset(tvb, offset, 1, 1);
    offset += 1;
    mac_bytes_tvb[4] = tvb_new_subset(tvb, offset, 1, 1);
    offset += 1;

    proto_tree_add_item(dvb_data_mpe_tree, hf_dvb_data_mpe_reserved,                   tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(dvb_data_mpe_tree, hf_dvb_data_mpe_payload_scrambling_control, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(dvb_data_mpe_tree, hf_dvb_data_mpe_address_scrambling_control, tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(dvb_data_mpe_tree, hf_dvb_data_mpe_llc_snap_flag,              tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(dvb_data_mpe_tree, hf_dvb_data_mpe_current_next_indicator,     tvb, offset, 1, ENC_BIG_ENDIAN);
    llc_snap_flag = tvb_get_guint8(tvb, offset) & DVB_DATA_MPE_LLC_SNAP_FLAG_MASK;
    offset += 1;

    proto_tree_add_item(dvb_data_mpe_tree, hf_dvb_data_mpe_section_number,             tvb, offset, 1, ENC_BIG_ENDIAN);
    offset += 1;

    proto_tree_add_item(dvb_data_mpe_tree, hf_dvb_data_mpe_last_section_number,        tvb, offset, 1, ENC_BIG_ENDIAN);
    offset += 1;

    for (i = 3; i >= 0; i--) {
        mac_bytes_tvb[i] = tvb_new_subset(tvb, offset, 1, 1);
        offset += 1;
    }

    mac_tvb = tvb_new_composite();

    for (i = 0; i < 6; i++)
        tvb_composite_append(mac_tvb, mac_bytes_tvb[i]);

    tvb_composite_finalize(mac_tvb);

    proto_tree_add_item(dvb_data_mpe_tree, hf_dvb_data_mpe_dst_mac, mac_tvb, 0 , 6, ENC_NA);
    col_add_str(pinfo->cinfo, COL_RES_DL_DST, tvb_ether_to_str(mac_tvb, 0));

    data_tvb = tvb_new_subset_remaining(tvb, offset);

    if (llc_snap_flag) {
        call_dissector(llc_handle, data_tvb, pinfo, tree);
    } else {
        call_dissector(ip_handle, data_tvb, pinfo, tree);
    }

    packet_mpeg_sect_crc(tvb, pinfo, dvb_data_mpe_tree, 0, tot_len - 1);
    return;

}
Beispiel #9
0
static void
dissect_dvb_bat(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{

    guint   offset = 0, length = 0, ts_loop_end;
    guint16 ts_id, descriptor_len, ts_loop_len;

    proto_item *ti;
    proto_tree *dvb_bat_tree;
    proto_item *tsi;
    proto_tree *transport_stream_tree;

    col_set_str(pinfo->cinfo, COL_INFO, "Bouquet Association Table (BAT)");

    ti = proto_tree_add_item(tree, proto_dvb_bat,                              tvb, offset, -1, ENC_NA);
    dvb_bat_tree = proto_item_add_subtree(ti, ett_dvb_bat);

    offset += packet_mpeg_sect_header(tvb, offset, dvb_bat_tree, &length, NULL);
    length -= 4;

    proto_tree_add_item(dvb_bat_tree, hf_dvb_bat_bouquet_id,                   tvb, offset, 2, ENC_BIG_ENDIAN);
    offset += 2;

    proto_tree_add_item(dvb_bat_tree, hf_dvb_bat_reserved1,                    tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(dvb_bat_tree, hf_dvb_bat_version_number,               tvb, offset, 1, ENC_BIG_ENDIAN);
    proto_tree_add_item(dvb_bat_tree, hf_dvb_bat_current_next_indicator,       tvb, offset, 1, ENC_BIG_ENDIAN);
    offset += 1;

    proto_tree_add_item(dvb_bat_tree, hf_dvb_bat_section_number,               tvb, offset, 1, ENC_BIG_ENDIAN);
    offset += 1;

    proto_tree_add_item(dvb_bat_tree, hf_dvb_bat_last_section_number,          tvb, offset, 1, ENC_BIG_ENDIAN);
    offset += 1;

    descriptor_len = tvb_get_ntohs(tvb, offset) & DVB_BAT_BOUQUET_DESCRIPTORS_LENGTH_MASK;
    proto_tree_add_item(dvb_bat_tree, hf_dvb_bat_reserved2,                    tvb, offset, 2, ENC_BIG_ENDIAN);
    proto_tree_add_item(dvb_bat_tree, hf_dvb_bat_bouquet_descriptors_length,   tvb, offset, 2, ENC_BIG_ENDIAN);
    offset += 2;

    offset += proto_mpeg_descriptor_loop_dissect(tvb, offset, descriptor_len, dvb_bat_tree);

    ts_loop_len = tvb_get_ntohs(tvb, offset) & DVB_BAT_TRANSPORT_STREAM_LOOP_LENGTH_MASK;
    proto_tree_add_item(dvb_bat_tree, hf_dvb_bat_reserved3,                    tvb, offset, 2, ENC_BIG_ENDIAN);
    proto_tree_add_item(dvb_bat_tree, hf_dvb_bat_transport_stream_loop_length, tvb, offset, 2, ENC_BIG_ENDIAN);
    offset += 2;

    ts_loop_end = offset + ts_loop_len;
    while (offset < ts_loop_end) {
        ts_id = tvb_get_ntohs(tvb, offset);
        descriptor_len = tvb_get_ntohs(tvb, offset + 4) & DVB_BAT_TRANSPORT_DESCRIPTORS_LENGTH_MASK;

        tsi = proto_tree_add_text(dvb_bat_tree, tvb, offset, 6 + descriptor_len, "Transport Stream 0x%04x", ts_id);
        transport_stream_tree = proto_item_add_subtree(tsi, ett_dvb_bat_transport_stream);

        proto_tree_add_item(transport_stream_tree, hf_dvb_bat_transport_stream_id, tvb, offset, 2, ENC_BIG_ENDIAN);
        offset += 2;

        proto_tree_add_item(transport_stream_tree, hf_dvb_bat_original_network_id, tvb, offset, 2, ENC_BIG_ENDIAN);
        offset += 2;

        proto_tree_add_item(transport_stream_tree, hf_dvb_bat_reserved4, tvb, offset, 2, ENC_BIG_ENDIAN);
        proto_tree_add_item(transport_stream_tree, hf_dvb_bat_transport_descriptors_length, tvb, offset, 2, ENC_BIG_ENDIAN);
        offset += 2;

        offset += proto_mpeg_descriptor_loop_dissect(tvb, offset, descriptor_len, transport_stream_tree);
    }

    offset += packet_mpeg_sect_crc(tvb, pinfo, dvb_bat_tree, 0, offset);
    proto_item_set_len(ti, offset);
}