From e1d434ee6a56f86ad9e79e2f127382e3bc4409e6 Mon Sep 17 00:00:00 2001 From: Anders Broman Date: Thu, 26 Jan 2012 19:51:48 +0000 Subject: From Mike Morrin: Add dissectors for GSM and UMTS Cell Broadcast protocols. ( - the patch for gsmtap ) https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6770 svn path=/trunk/; revision=40735 --- epan/dissectors/packet-gsm_cbch.c | 585 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 585 insertions(+) create mode 100644 epan/dissectors/packet-gsm_cbch.c (limited to 'epan/dissectors/packet-gsm_cbch.c') diff --git a/epan/dissectors/packet-gsm_cbch.c b/epan/dissectors/packet-gsm_cbch.c new file mode 100644 index 0000000000..26c47df9d4 --- /dev/null +++ b/epan/dissectors/packet-gsm_cbch.c @@ -0,0 +1,585 @@ +/* packet-gsm_cbch.c + * Routines for GSM CBCH dissection - A.K.A. 3GPP 44.012 (GSM 04.12) + * + * Copyright 2011, Mike Morrin + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include + +#include + +#include +#include +#include "packet-cell_broadcast.h" + +#define CBCH_FRAGMENT_SIZE 22 + +const value_string block_type_lpd_strings[] = { + { 0x00, "NOT Cell Broadcast"}, + { 0x01, "Cell Broadcast"}, + { 0x02, "NOT Cell Broadcast"}, + { 0x03, "NOT Cell Broadcast"}, + { 0, NULL} +}; + +const value_string block_type_seq_num_values[] = { + { 0x00, "First Block"}, + { 0x01, "Second Block"}, + { 0x02, "Third Block"}, + { 0x03, "Fourth Block"}, + { 0x08, "First Schedule Block"}, + { 0xFF, "Null message"}, + { 0, NULL} +}; + +const value_string sched_type_values[] = { + { 0x00, "messages formatted as specified in subclause 3.5 of 3GPP 44.012"}, + { 0xFF, "Unknown schedule message format"}, + { 0, NULL} +}; + +/* Initialize the protocol and registered fields */ +static int proto_cbch = -1; + +static int hf_gsm_cbch_spare_bit = -1; +static int hf_gsm_cbch_lpd = -1; +static int hf_gsm_cbch_lb = -1; +static int hf_gsm_cbch_seq_num = -1; +static int hf_gsm_cbch_sched_type = -1; +static int hf_gsm_cbch_sched_begin_slot = -1; +static int hf_gsm_cbch_sched_spare = -1; +static int hf_gsm_cbch_sched_end_slot = -1; +static int hf_gsm_cbch_sched_msg_id = -1; + +/* These fields are used when reassembling cbch fragments +*/ +static int hf_cbch_fragments = -1; +static int hf_cbch_fragment = -1; +static int hf_cbch_fragment_overlap = -1; +static int hf_cbch_fragment_overlap_conflict = -1; +static int hf_cbch_fragment_multiple_tails = -1; +static int hf_cbch_fragment_too_long_fragment = -1; +static int hf_cbch_fragment_error = -1; +static int hf_cbch_fragment_count = -1; +static int hf_cbch_reassembled_in = -1; +static int hf_cbch_reassembled_length = -1; + +/* Initialize the subtree pointers */ +static gint ett_cbch_msg = -1; +static gint ett_schedule_msg = -1; +static gint ett_schedule_new_msg = -1; +static gint ett_cbch_fragment = -1; +static gint ett_cbch_fragments = -1; + +static dissector_handle_t data_handle; +static dissector_handle_t cbs_handle; + +/* reassembly of CHCH blocks */ +static GHashTable *fragment_block_table = NULL; +static GHashTable *reassembled_message_table = NULL; + +/* Structure needed for the fragmentation routines in reassemble.c +*/ +static const fragment_items cbch_frag_items = { + &ett_cbch_fragment, + &ett_cbch_fragments, + &hf_cbch_fragments, + &hf_cbch_fragment, + &hf_cbch_fragment_overlap, + &hf_cbch_fragment_overlap_conflict, + &hf_cbch_fragment_multiple_tails, + &hf_cbch_fragment_too_long_fragment, + &hf_cbch_fragment_error, + &hf_cbch_fragment_count, + &hf_cbch_reassembled_in, + &hf_cbch_reassembled_length, + "blocks" +}; + +static void cbch_defragment_init(void) +{ + fragment_table_init(&fragment_block_table); + reassembled_table_init(&reassembled_message_table); +} + +static void dissect_schedule_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *top_tree) +{ + guint8 octet1, i, j, k=0, len, sched_begin, sched_end, new_slots[48] , offset = 0; + gboolean valid_message = TRUE; + guint16 other_slots[48]; + proto_item *item = NULL, *schedule_item = NULL; + proto_tree *sched_tree = NULL, *sched_subtree = NULL; + + len = tvb_length(tvb); + + col_append_str(pinfo->cinfo, COL_INFO, " CBCH Schedule Message "); + + schedule_item = proto_tree_add_protocol_format(top_tree, proto_cbch, tvb, 0, len, + "GSM CBCH Schedule Message"); + + sched_tree = proto_item_add_subtree(schedule_item, ett_schedule_msg); + + proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_type, tvb, offset, 1, ENC_BIG_ENDIAN); + octet1 = tvb_get_guint8(tvb, offset); + if (0 == (octet1 & 0xC0)) + { + sched_begin = octet1 & 0x3F; + proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_begin_slot, tvb, offset++, 1, ENC_BIG_ENDIAN); + if (1 == sched_begin) + { + proto_tree_add_text(sched_tree, tvb, offset - 1, 1, "(apparently) Scheduled Scheduling Message"); + } + else if ((2 <= sched_begin) && (48 >= sched_begin)) + { + proto_tree_add_text(sched_tree, tvb, offset - 1, 1, "(apparently) Unscheduled Scheduling Message"); + } + else + { + proto_tree_add_text(sched_tree, tvb, offset - 1, 1, "Begin Slot Number out of range: ignoring message"); + valid_message = FALSE; + } + proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_spare, tvb, offset, 1, ENC_BIG_ENDIAN); + sched_end = tvb_get_guint8(tvb, offset); + proto_tree_add_item(sched_tree, hf_gsm_cbch_sched_end_slot, tvb, offset++, 1, ENC_BIG_ENDIAN); + if (sched_end < sched_begin) + { + proto_tree_add_text(sched_tree, tvb, offset - 1, 1, "End Slot Number less than Begin Slot Number: ignoring message"); + valid_message = FALSE; + } + + if (valid_message) + { + /* build an array of new messages */ + memset(&new_slots, 0xFF, sizeof(new_slots)); + memset(&other_slots, 0xFF, sizeof(other_slots)); + + /* iterate over the octets */ + for (i=0; i<6; i++) + { + octet1 = tvb_get_guint8(tvb, offset++); + + /* iterate over the bits */ + for (j=0; j<8; j++) + { + if (octet1 & (0x80>>j)) + { + new_slots[k++] = (i<<3) + j + 1; + } + } + } + /* print the array of new messages */ + item = proto_tree_add_text(sched_tree, tvb, offset-6, 6, "This schedule contains %d slots with new messages", k); + sched_subtree = proto_item_add_subtree(item, ett_schedule_new_msg); + for (i=0; i= sched_end) + break; + + octet1 = tvb_get_guint8(tvb, offset); + if ((octet1 & 0x80) == 0x80) + { + if ((offset+1)cinfo, COL_PROTOCOL, " CBCH"); + + cbch_tree = proto_item_add_subtree(cbch_item, ett_cbch_msg); + + proto_tree_add_text(cbch_tree, tvb, offset, 1, + "CBCH Block"); + + proto_tree_add_uint(cbch_tree, hf_gsm_cbch_spare_bit, tvb, offset, 1, octet); + proto_tree_add_uint(cbch_tree, hf_gsm_cbch_lpd, tvb, offset, 1, octet); + proto_tree_add_uint(cbch_tree, hf_gsm_cbch_lb, tvb, offset, 1, octet); + proto_tree_add_uint(cbch_tree, hf_gsm_cbch_seq_num, tvb, offset, 1, octet); + seq_num = octet & 0x0F; + lpd = (octet & 0x60) >> 5; + lb = (octet & 0x10) >> 4; + + if (lpd == 1) + { + switch (seq_num) + { + case 0x00: + case 0x08: + pinfo->fragmented = TRUE; + /* we should have a unique ID for the reassembled page, but we don't really have anything from the protocol... + The GSM frame number div 4 might be used for this, but it has not been passed to this layer and does not + exist at all if the message is being passed over the RSL interface. + So we just use 0... */ + + /* after reassembly we will need to know if this is a scheduling message, + this information is carried in the initial sequence number, not the payload, + so we prepend the reassembly with the octet containing the initial sequence number + to allow later dissection of the payload */ + frag_data = fragment_add_seq_check(tvb, offset, pinfo, 0, + fragment_block_table, reassembled_message_table, + seq_num & 0x03, CBCH_FRAGMENT_SIZE + 1, !lb); + reass_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CBCH message", + frag_data, &cbch_frag_items, NULL, cbch_tree); + break; + + case 0x01: + case 0x02: + case 0x03: + pinfo->fragmented = TRUE; + offset++; /* step to beginning of payload */ + frag_data = fragment_add_seq_check(tvb, offset, pinfo, 0, + fragment_block_table, reassembled_message_table, seq_num, + CBCH_FRAGMENT_SIZE, !lb); + reass_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CBCH message", + frag_data, &cbch_frag_items, NULL, cbch_tree); + break; + + case 0x0F: + proto_tree_add_text(cbch_tree, tvb, offset, 1, "NULL message"); + call_dissector(data_handle, tvb, pinfo, cbch_tree); + break; + + default: + proto_tree_add_text(cbch_tree, tvb, offset, 1, "reserved Sequence Number"); + call_dissector(data_handle, tvb, pinfo, cbch_tree); + break; + } + if (reass_tvb) + { + /* Reassembled */ + + /* the tvb contains the reassmbled message prepended with the sequence number octet from the first block + We use this to determine whether this is a normal message or a scheduling message */ + offset = 0; + + octet = tvb_get_guint8(reass_tvb, offset++); + msg_tvb = tvb_new_subset_remaining(reass_tvb, offset); + + if (octet & 0x08) + { + dissect_schedule_message(msg_tvb, pinfo, tree); + } + else + { + call_dissector(cbs_handle, msg_tvb, pinfo, tree); + } + } + } + else + { + proto_tree_add_text(cbch_tree, tvb, offset, 1, "invalid Link Protocol Discriminator"); + call_dissector(data_handle, tvb, pinfo, cbch_tree); + } +} + +/* Register the protocol with Wireshark */ +void +proto_register_gsm_cbch(void) +{ + /* Setup list of header fields */ + static hf_register_info hf_smscb[] = + { + { &hf_gsm_cbch_spare_bit, + { "GSM CBCH spare bit", "gsm_cbch_block_type.spare", + FT_UINT8, BASE_HEX, NULL, 0x80, + NULL, HFILL} + }, + { &hf_gsm_cbch_lpd, + { "GSM CBCH Link Protocol Discriminator", "gsm_cbch_block_type.lpd", + FT_UINT8, BASE_DEC, VALS(block_type_lpd_strings), 0x60, + NULL, HFILL} + }, + { &hf_gsm_cbch_lb, + { "GSM CBCH Last Block", "gsm_cbch_block_type.lb", + FT_UINT8, BASE_DEC, NULL, 0x10, + "Last Block", HFILL} + }, + { &hf_gsm_cbch_seq_num, + { "GSM CBCH Sequence Number", "gsm_cbch_block_type.seq_num", + FT_UINT8, BASE_DEC, VALS(block_type_seq_num_values), 0x0F, + NULL, HFILL} + }, + { &hf_gsm_cbch_sched_type, + { "GSM CBCH Schedule Type", "gsm_cbch.sched_type", + FT_UINT8, BASE_DEC, VALS(sched_type_values), 0xC0, + NULL, HFILL} + }, + { &hf_gsm_cbch_sched_begin_slot, + { "GSM CBCH Schedule Begin slot", "gsm_cbch.schedule_begin", + FT_UINT8, BASE_DEC, NULL, 0x3F, + NULL, HFILL} + }, + { &hf_gsm_cbch_sched_spare, + { "GSM CBCH Schedule Spare Bits", "gsm_cbch.sched_spare", + FT_UINT8, BASE_DEC, NULL, 0xC0, + NULL, HFILL} + }, + { &hf_gsm_cbch_sched_end_slot, + { "GSM CBCH Schedule End Slot", "gsm_cbch.sched_end", + FT_UINT8, BASE_DEC, NULL, 0x3F, + NULL, HFILL} + }, + { &hf_gsm_cbch_sched_msg_id, + { "GSM CBCH Schedule Message ID", "gsm_cbch.sched_msg_id", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL} + }, + /* Fragment fields + */ + { &hf_cbch_fragment_overlap, + { "Fragment overlap", + "gsm_cbch.fragment.overlap", + FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Fragment overlaps with other fragments", HFILL + } + }, + { &hf_cbch_fragment_overlap_conflict, + { "Conflicting data in fragment overlap", + "gsm_cbch.fragment.overlap.conflict", + FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Overlapping fragments contained conflicting data", HFILL + } + }, + { &hf_cbch_fragment_multiple_tails, + { "Multiple tail fragments found", + "gsm_cbch.fragment.multipletails", + FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Several tails were found when defragmenting the packet", HFILL + } + }, + { &hf_cbch_fragment_too_long_fragment, + { "Fragment too long", + "gsm_cbch.fragment.toolongfragment", + FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Fragment contained data past end of packet", HFILL + } + }, + { &hf_cbch_fragment_error, + { "Defragmentation error", + "gsm_cbch.fragment.error", + FT_FRAMENUM, BASE_NONE, NULL, 0x0, + "Defragmentation error due to illegal fragments", HFILL + } + }, + { &hf_cbch_fragment_count, + { "Fragmentation count", + "gsm_cbch.fragment.count", + FT_UINT32, BASE_DEC, NULL, 0x0, + "Count of CBCH Fragments", HFILL + } + }, + { &hf_cbch_reassembled_in, + { "Reassembled in", + "gsm_cbch.reassembled.in", + FT_FRAMENUM, BASE_NONE, NULL, 0x0, + "CBCH fragments are reassembled in the given packet", HFILL + } + }, + { &hf_cbch_reassembled_length, + { "Reassembled message length is one less than indicated here", + "gsm_cbch.reassembled.length", + FT_UINT32, BASE_DEC, NULL, 0x0, + "The total length of the reassembled message", HFILL + } + }, + { &hf_cbch_fragment, + { "CBCH Fragment", + "gsm_cbch.fragment", + FT_FRAMENUM, BASE_NONE, NULL, 0x0, + NULL, HFILL + } + }, + { &hf_cbch_fragments, + { "CBCH Fragments", + "gsm_cbch.fragments", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL + } + } + }; + +/* Setup protocol subtree array */ + static gint *ett[] = { + &ett_cbch_msg, + &ett_schedule_msg, + &ett_schedule_new_msg, + &ett_cbch_fragment, + &ett_cbch_fragments, + }; + + /* Register the protocol name and description */ + proto_cbch = + proto_register_protocol("GSM Cell Broadcast Channel", "GSM CBCH", "gsm_cbch"); + + proto_register_field_array(proto_cbch, hf_smscb, array_length(hf_smscb)); + + /* subdissector code */ + register_dissector("gsm_cbch", dissect_cbch, proto_cbch); + register_init_routine(cbch_defragment_init); + + /* subtree array */ + proto_register_subtree_array(ett, array_length(ett)); +} + +void +proto_reg_handoff_gsm_cbch(void) +{ + data_handle = find_dissector("data"); + cbs_handle = find_dissector("gsm_cell_broadcast"); +} -- cgit v1.2.1