summaryrefslogblamecommitdiffstats
path: root/src/wireshark/smscb.patch
blob: 80005a3466f2cf4f483267f575239cd1cad00437 (plain) (tree)
1
2
3
4
5
6
7
8
                                                     
 


                                                                      
 
                                                    
   



                                                                               

                                                                              
                             











                                                                                    
                      

                                        
                 









                                                         























                                                                           



                            



















                                                      








                                            





                                      


                                        














                                                                             
                                                                                            

                                                                                       


                                                                      










                                                                   
                                 



                                  
 
                          



                                                   


                          







                                                    


                            





                                                     

   







                                                                                      





















                                                 
  


                                                         
 








                                                                                      
 




                                                                                  
                                                                                  
                                                                                                








                                                                             
 
















                                                                                 
 
                                                                                      
 



                                                                      
 

                               
 

































































































































































































                                                                                                           






                                                                                  
 

                                               
 

                                      
                                                              
 


                                                         

                                                                           









                                                                                           
 








                                                                               
                 


                               

  















                                                                  
 
                                
                                                                           






                                                                          

                                                                            



















                                                                            














































                                                                                  





















































                                                                                                         


                               



































                                                                                 
 










                                                                                      
                                   

                                     
                                                 
                          



                                                                                        
 




























                                                                                                        
 
 
Wireshark patch for SMSCB dissection support in LAPDm

Create a new gsm_smscb dissector module for SMSCB as defined in GSM TS
04.12.  Call it from packet-lapdm when the Link Protocol Discriminator
has the value "0 1".

Signed-off-by: Alex Badea <vamposdecampos@gmail.com>
---
 epan/dissectors/Makefile.common    |    1 +
 epan/dissectors/packet-gsm_smscb.c |  642 ++++++++++++++++++++++++++++++++++++
 epan/dissectors/packet-lapdm.c     |   18 +-
 3 files changed, 658 insertions(+), 3 deletions(-)

diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common
index 9f9a602..5684579 100644
--- a/epan/dissectors/Makefile.common
+++ b/epan/dissectors/Makefile.common
@@ -500,6 +500,7 @@ DISSECTOR_SRC = \
 	packet-gsm_bssmap_le.c	\
 	packet-gsm_sms.c	\
 	packet-gsm_sms_ud.c	\
+	packet-gsm_smscb.c	\
 	packet-gsm_um.c		\
 	packet-gsmtap.c		\
 	packet-gssapi.c		\
diff --git a/epan/dissectors/packet-gsm_smscb.c b/epan/dissectors/packet-gsm_smscb.c
new file mode 100644
index 0000000..a2f8bee
--- /dev/null
+++ b/epan/dissectors/packet-gsm_smscb.c
@@ -0,0 +1,642 @@
+/* packet-gsm_smscb.c
+ * Routines for GSM SMSCB (GSM 04.12) dissection
+ * Copyright 2010, Alex Badea <vamposdecampos@gmail.com>
+ *
+ * $Id$
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+
+#include <epan/packet.h>
+#include <epan/prefs.h>
+#include <epan/reassemble.h>
+#include <epan/asn1.h>
+#include "packet-gsm_map.h"
+#include "packet-gsm_sms.h"
+
+static gint proto_gsm_smscb = -1;
+static gint hf_smscb_addr = -1;
+static gint hf_smscb_addr_lb = -1;
+static gint hf_smscb_addr_seq = -1;
+static gint hf_smscb_serial_gs = -1;
+static gint hf_smscb_serial_mcode = -1;
+static gint hf_smscb_serial_updnum = -1;
+static gint hf_smscb_page_num = -1;
+static gint hf_smscb_page_cnt = -1;
+static gint hf_smscb_msgid = -1;
+static gint hf_smscb_content = -1;
+static gint hf_smscb_fragments = -1;
+static gint hf_smscb_fragment = -1;
+static gint hf_smscb_fragment_overlap = -1;
+static gint hf_smscb_fragment_overlap_conflicts = -1;
+static gint hf_smscb_fragment_multiple_tails = -1;
+static gint hf_smscb_fragment_too_long_fragment = -1;
+static gint hf_smscb_fragment_error = -1;
+static gint hf_smscb_reassembled_in = -1;
+static gint hf_smscb_reassembled_length = -1;
+static gint hf_smscb_sched_type = -1;
+static gint hf_smscb_sched_spare = -1;
+static gint hf_smscb_sched_begin_slot = -1;
+static gint hf_smscb_sched_end_slot = -1;
+static gint hf_smscb_sched_mdt1 = -1;
+static gint hf_smscb_sched_mdt2 = -1;
+static gint hf_smscb_sched_mdt8 = -1;
+static gint hf_smscb_sched_msgid = -1;
+static gint hf_smscb_sched_repslot = -1;
+
+static gint ett_smscb = -1;
+static gint ett_smscb_addr = -1;
+static gint ett_smscb_dcs = -1;
+static gint ett_smscb_fragment = -1;
+static gint ett_smscb_fragments = -1;
+static gint ett_smscb_sched_new = -1;
+static gint ett_smscb_sched_other = -1;
+static gint ett_smscb_sched_slot = -1;
+
+static GHashTable *smscb_fragment_table = NULL;
+static GHashTable *smscb_reassembled_table = NULL;
+
+static gboolean reassemble_smscb = TRUE;
+
+static dissector_handle_t data_handle;
+
+#define SMSCB_HDR_MINLEN	1
+
+/*
+ * Bits in the address field.
+ */
+#define	SMSCB_ADDR_LB		0x10	/* Address Last Bit */
+#define	SMSCB_ADDR_SEQ		0x0f	/* Address sequence number */
+#define	SMSCB_SERIAL_GS		0xc000	/* CBS Serial Number - Geographical Scope */
+#define	SMSCB_SERIAL_MCODE	0x3ff0	/* CBS Serial Number - Message Code */
+#define	SMSCB_SERIAL_UPDNUM	0x000f	/* CBS Serial Number - Update Number */
+#define	SMSCB_PAGE_NUM		0xf0	/* Page number */
+#define	SMSCB_PAGE_CNT		0x0f	/* Page total count */
+
+/*
+ * Bits in the Schedule message
+ */
+#define SMSCB_SCHED_TYPE	0xc0	/* Type */
+#define SMSCB_SCHED_SLOT	0x3f	/* Begin/End Slot Number */
+#define SMSCB_SCHED_SPARE	0xc0	/* Spare */
+#define SMSCB_SCHED_MDT1	0x8000	/* MDT (1 bit)*/
+#define SMSCB_SCHED_MSGID	0x7fff	/* Message ID */
+#define SMSCB_SCHED_MDT2	0xc0	/* MDT (2 bits) */
+#define SMSCB_SCHED_REPSLOT	0x3f	/* Repeated Slot Number */
+
+#define SMSCB_SEQ_LAST		3
+#define SMSCB_SEQ_1ST		0
+#define SMSCB_SEQ_1ST_SCHED	8
+
+#define SMSCB_SCHED_SLOT_MAX	48
+
+/* 04.12 section 3.3.1 */
+static const value_string smscb_addr_lb_vals[] = {
+	{ 0,		"More blocks" },
+	{ 1,		"Last block" },
+	{ 0,		NULL }
+};
+
+/* 04.12 section 3.3.1 */
+static const value_string smscb_addr_seq_vals[] = {
+	{ 0,		"First block" },
+	{ 1,		"Second block" },
+	{ 2,		"Third block" },
+	{ 3,		"Fourth block" },
+	{ 8,		"First schedule block" },
+	{ 15,		"Null message" },
+	{ 0,		NULL }
+};
+
+/* 03.41 section 9.3.2.1 */
+static const value_string smscb_serial_gs_vals[] = {
+	{ 0,		"Cell wide (immediate)" },
+	{ 1,		"PLMN wide" },
+	{ 2,		"Location Area wide" },
+	{ 3,		"Cell wide" },
+	{ 0,		NULL }
+};
+
+/* 04.14 section 3.5.5 */
+static const value_string smscb_sched_mdt8_vals[] = {
+	{ 0x00,		"Retransmission indication" },
+	{ 0x80,		"First transmission of an SMSCB within the Schedule Period" },
+	{ 0x40,		"Free Message Slot, optional reading" },
+	{ 0x41,		"Free Message Slot, reading advised" },
+	{ 0,		NULL }
+};
+
+static const fragment_items smscb_frag_items = {
+	/* Fragment subtrees */
+	&ett_smscb_fragment,
+	&ett_smscb_fragments,
+	/* Fragment fields */
+	&hf_smscb_fragments,
+	&hf_smscb_fragment,
+	&hf_smscb_fragment_overlap,
+	&hf_smscb_fragment_overlap_conflicts,
+	&hf_smscb_fragment_multiple_tails,
+	&hf_smscb_fragment_too_long_fragment,
+	&hf_smscb_fragment_error,
+	/* Reassembled in field */
+	&hf_smscb_reassembled_in,
+	/* Reassembled length field */
+	&hf_smscb_reassembled_length,
+	/* Tag */
+	"fragments"
+};
+
+static void smscb_defragment_init(void)
+{
+	fragment_table_init(&smscb_fragment_table);
+	reassembled_table_init(&smscb_reassembled_table);
+}
+
+/* [3GPP TS 03.41 section 9.3] */
+static int dissect_smscb_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	proto_item *ti;
+	gint offset = 0;
+	gint length, out_len, textlen;
+	guint8 encoding;
+	gchar msgbuf[88 + 1];
+	gchar *utf8_text, *p;
+
+	proto_tree_add_item(tree, hf_smscb_serial_gs, tvb, offset, 1, ENC_NA);
+	proto_tree_add_item(tree, hf_smscb_serial_mcode, tvb, offset, 2, ENC_NA);
+	offset++;
+	proto_tree_add_item(tree, hf_smscb_serial_updnum, tvb, offset, 1, ENC_NA);
+	offset++;
+	proto_tree_add_item(tree, hf_smscb_msgid, tvb, offset, 2, ENC_BIG_ENDIAN);
+	col_append_fstr(pinfo->cinfo, COL_INFO, " - Message ID %d", tvb_get_ntohs(tvb, offset));
+	offset += 2;
+	ti = proto_tree_add_text(tree, tvb, offset, 1, "Data Coding Scheme");
+	encoding = dissect_cbs_data_coding_scheme(
+		tvb_new_subset(tvb, offset, 1, -1), pinfo,
+		proto_item_add_subtree(ti, ett_smscb_dcs));
+	offset++;
+	proto_tree_add_item(tree, hf_smscb_page_num, tvb, offset, 1, ENC_NA);
+	proto_tree_add_item(tree, hf_smscb_page_cnt, tvb, offset, 1, ENC_NA);
+	offset++;
+
+	length = tvb_length(tvb) - offset;
+	switch (encoding) {
+	case SMS_ENCODING_7BIT:
+	case SMS_ENCODING_7BIT_LANG:
+		out_len = gsm_sms_char_7bit_unpack(0, length, sizeof(msgbuf) - 1,
+				tvb_get_ptr(tvb, offset, length), msgbuf);
+		msgbuf[out_len] = '\0';
+		utf8_text = gsm_sms_chars_to_utf8(msgbuf, out_len);
+		textlen = strlen(utf8_text);
+		break;
+	/* TODO: UCS2? */
+	case SMS_ENCODING_8BIT:
+	default:
+		utf8_text = tvb_get_ephemeral_string(tvb, offset, length);
+		textlen = length;
+		break;
+	}
+
+	proto_tree_add_string(tree, hf_smscb_content, tvb, offset, length, utf8_text);
+
+	/* strip padding */
+	if ((p = strchr( utf8_text, '\r')))
+		*p = 0;
+	col_append_fstr(pinfo->cinfo, COL_INFO, " \"%s\"", utf8_text);
+
+	return tvb_length(tvb);
+}
+
+/* [3GPP TS 04.14 section 3.5.5] */
+static int dissect_sched_msg_desc(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+	gint *slot_list, gint slot_count)
+{
+	gint offset = 0;
+	gint k;
+	proto_item *ti;
+	proto_tree *subtree;
+	guint8 mdt;
+
+	for (k = 0; k < slot_count; k++) {
+		mdt = tvb_get_guint8(tvb, offset);
+
+		if (mdt & 0x80)
+			mdt = 0x80;
+		else if (!(mdt & 0x40))
+			mdt = 0;
+
+		ti = proto_tree_add_text(tree, tvb, offset, 1, "Slot %d - %s",
+			slot_list[k],
+			val_to_str(mdt, smscb_sched_mdt8_vals, "Unknown (0x%02x)"));
+		subtree = proto_item_add_subtree(ti, ett_smscb_sched_slot);
+
+		if (mdt & 0x80) {
+			guint16 msgid = tvb_get_ntohs(tvb, offset) & SMSCB_SCHED_MSGID;
+			proto_item_append_text(ti, " (message ID %d)", msgid);
+			proto_item_set_len(ti, 2);
+			proto_tree_add_item(subtree, hf_smscb_sched_mdt1, tvb, offset, 2, ENC_BIG_ENDIAN);
+			proto_tree_add_item(subtree, hf_smscb_sched_msgid, tvb, offset, 2, ENC_BIG_ENDIAN);
+			offset += 2;
+		} else if (!(mdt & 0xc0)) {
+			guint8 slot = tvb_get_guint8(tvb, offset) & SMSCB_SCHED_SLOT;
+			proto_item_append_text(ti, " (slot %d)", slot);
+			proto_tree_add_item(subtree, hf_smscb_sched_mdt2, tvb, offset, 1, ENC_NA);
+			proto_tree_add_item(subtree, hf_smscb_sched_repslot, tvb, offset, 1, ENC_NA);
+			offset++;
+		} else {
+			proto_tree_add_item(subtree, hf_smscb_sched_mdt8, tvb, offset, 1, ENC_NA);
+			offset++;
+		}
+	}
+	return offset;
+}
+
+/* [3GPP TS 04.14 section 3.5] */
+static int dissect_sched_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	proto_item *ti;
+	gint offset = 0;
+	gint first, last, nm, len;
+	gint new_count = 0;
+	gint other_count = 0;
+	gint new_list[SMSCB_SCHED_SLOT_MAX];
+	gint other_list[SMSCB_SCHED_SLOT_MAX];
+
+	col_append_str(pinfo->cinfo, COL_INFO, " - Schedule message");
+
+	proto_tree_add_item(tree, hf_smscb_sched_type, tvb, offset, 1, ENC_NA);
+	proto_tree_add_item(tree, hf_smscb_sched_begin_slot, tvb, offset, 1, ENC_NA);
+	offset++;
+	proto_tree_add_item(tree, hf_smscb_sched_spare, tvb, offset, 1, ENC_NA);
+	proto_tree_add_item(tree, hf_smscb_sched_end_slot, tvb, offset, 1, ENC_NA);
+	offset++;
+
+	first = tvb_get_guint8(tvb, 0) & SMSCB_SCHED_SLOT;
+	last = tvb_get_guint8(tvb, 1) & SMSCB_SCHED_SLOT;
+	last = MIN(last, SMSCB_SCHED_SLOT_MAX);
+
+	ti = proto_tree_add_text(tree, tvb, offset, 6, "List of new message slots =");
+	for (nm = first; nm <= last; nm++) {
+		if (tvb_get_bits8(tvb, offset * 8 + nm - first, 1)) {
+			proto_item_append_text(ti, " %d", nm);
+			new_list[new_count++] = nm;
+		} else {
+			other_list[other_count++] = nm;
+		}
+	}
+	offset += 6;
+
+	ti = proto_tree_add_text(tree, tvb, offset, 0, "New Message Descriptions");
+	len = dissect_sched_msg_desc(tvb_new_subset(tvb, offset, -1, -1), pinfo,
+		proto_item_add_subtree(ti, ett_smscb_sched_new),
+		new_list, new_count);
+	offset += len;
+	proto_item_set_len(ti, len);
+
+	ti = proto_tree_add_text(tree, tvb, offset, 0, "Other Message Descriptions");
+	len = dissect_sched_msg_desc(tvb_new_subset(tvb, offset, -1, -1), pinfo,
+		proto_item_add_subtree(ti, ett_smscb_sched_other),
+		other_list, other_count);
+	offset += len;
+	proto_item_set_len(ti, len);
+
+	return offset;
+}
+
+static inline int seq_any_frags(guint8 seq)
+{
+	return seq <= SMSCB_SEQ_LAST || seq == SMSCB_SEQ_1ST_SCHED;
+}
+
+static inline int seq_more_frags(guint8 seq)
+{
+	return seq < SMSCB_SEQ_LAST || seq == SMSCB_SEQ_1ST_SCHED;
+}
+
+static inline int seq_first(guint8 seq)
+{
+	return seq == SMSCB_SEQ_1ST || seq == SMSCB_SEQ_1ST_SCHED;
+}
+
+static inline int seq_bits(guint8 seq)
+{
+	return seq & 3;
+}
+
+/*
+ * Do the reassembly thing.
+ *
+ * SMSCB fragmentation doesn't really fit in with the wireshark
+ * reassembler.  There are only two valid fragment sequences:
+ *   i) 0,1,2,3 for a SMSCB message
+ *   ii) 8,1,2,3 for a schedule message
+ *
+ * We can't use different fragment-IDs for each content type,
+ * since the last 3 blocks have identical sequence numbers.
+ *
+ * We can't just mask the lower 2 bits, because when reassembly
+ * completes (which is on the last block, sequence #3) we won't
+ * know which content type we've reassembled.
+ *
+ * We also can't munge e.g. the schedule sequence to 8,9,10,11,
+ * since the reassembler will think we're missing the first 8
+ * blocks and not do anything.
+ *
+ * Also, according to TS 03.41 section 8 we must discard
+ * non-consecutive sequences.
+ *
+ * So the approach here is to include the address header byte
+ * in the first fragment.  This way after reassembly we can peek
+ * at it and dissect accordingly.
+ *
+ * A clean implementation would likely be to add a FD_* reassembler
+ * flag to special-case this behaviour.
+ */
+static tvbuff_t *smscb_try_reassembly(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+	guint8 *seq_p, guint8 more)
+{
+	guint8 seq = *seq_p;
+	fragment_data *frag;
+	guint32 frag_id = 0x42;
+	guchar expected_seq = 0;
+	tvbuff_t *reassembled = NULL;
+	gboolean save_fragmented = pinfo->fragmented;
+
+	if (!reassemble_smscb || !seq_any_frags(seq))
+		return tvb;
+
+	frag = fragment_get(pinfo, frag_id, smscb_fragment_table);
+	if (frag) {
+		while (frag->next)
+			frag = frag->next;
+		expected_seq = frag->offset + 1;
+	}
+
+	if (seq != expected_seq)
+		g_free(fragment_delete(pinfo, frag_id, smscb_fragment_table));
+
+	if (!seq_first(seq))
+		tvb = tvb_new_subset(tvb, 1, -1, -1);
+
+	pinfo->fragmented = more;
+	frag = fragment_add_seq_check(tvb, 0, pinfo, frag_id,
+		smscb_fragment_table,
+		smscb_reassembled_table, seq_bits(seq),
+		tvb_length(tvb),
+		more);
+
+	reassembled = process_reassembled_data(tvb, 0, pinfo,
+		"Reassembled SMSCB", frag, &smscb_frag_items, NULL, tree);
+
+	if (frag && pinfo->fd->num == frag->reassembled_in) {
+		*seq_p = tvb_get_guint8(reassembled, 0) & SMSCB_ADDR_SEQ;
+		reassembled = tvb_new_subset(reassembled, 1, -1, -1);
+	} else {
+		col_append_str(pinfo->cinfo, COL_INFO, " (Fragment)");
+		proto_tree_add_text(tree, tvb, 0, -1, "Fragment Data");
+		reassembled = NULL;
+	}
+
+	pinfo->fragmented = save_fragmented;
+	return reassembled;
+}
+
+static int dissect_gsm_smscb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	proto_item *ti;
+	proto_tree *gsm_smscb_tree = NULL;
+	proto_tree *subtree = NULL;
+	guint8 addr, seq, more;
+	tvbuff_t *payload;
+
+	if (tvb_length(tvb) < SMSCB_HDR_MINLEN)
+		return 0;
+
+	addr = tvb_get_guint8(tvb, 0);
+	seq = addr & SMSCB_ADDR_SEQ;
+	more = !(addr & SMSCB_ADDR_LB) && seq_more_frags(seq);
+
+	col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMSCB");
+
+	col_clear(pinfo->cinfo, COL_INFO);
+	col_append_str(pinfo->cinfo, COL_INFO,
+		val_to_str(seq, smscb_addr_seq_vals, "Unknown block #%d"));
+
+	if (tree) {
+		ti = proto_tree_add_item(tree, proto_gsm_smscb, tvb, 0, -1, ENC_NA);
+		gsm_smscb_tree = proto_item_add_subtree(ti, ett_smscb);
+
+		ti = proto_tree_add_item(gsm_smscb_tree, hf_smscb_addr, tvb, 0, 1, ENC_NA);
+		subtree = proto_item_add_subtree(ti, ett_smscb_addr);
+		proto_tree_add_item(subtree, hf_smscb_addr_lb, tvb, 0, 1, ENC_NA);
+		proto_tree_add_item(subtree, hf_smscb_addr_seq, tvb, 0, 1, ENC_NA);
+	}
+
+	payload = smscb_try_reassembly(tvb, pinfo, gsm_smscb_tree, &seq, more);
+	if (payload) {
+		switch (seq) {
+		case SMSCB_SEQ_1ST:
+			dissect_smscb_message(payload, pinfo, gsm_smscb_tree);
+			break;
+		case SMSCB_SEQ_1ST_SCHED:
+			dissect_sched_message(payload, pinfo, gsm_smscb_tree);
+			break;
+		}
+	}
+
+	return tvb_length(tvb);
+}
+
+static hf_register_info hf[] = {
+	{ &hf_smscb_addr, {
+		"Address Field", "smscb.addr", FT_UINT8, BASE_HEX,
+		NULL, 0x0,
+		"Address", HFILL,
+	}},
+	{ &hf_smscb_addr_lb, {
+		"LB", "smscb.addr.lb", FT_UINT8, BASE_DEC,
+		VALS(smscb_addr_lb_vals), SMSCB_ADDR_LB,
+		"Last Block bit", HFILL,
+	}},
+	{ &hf_smscb_addr_seq, {
+		"SEQ", "smscb.addr.seq", FT_UINT8, BASE_DEC,
+		VALS(smscb_addr_seq_vals), SMSCB_ADDR_SEQ,
+		"Sequence Number", HFILL,
+	}},
+
+	{ &hf_smscb_serial_gs, {
+		"Geographic Scope", "smscb.serial.gs", FT_UINT16, BASE_DEC,
+		VALS(smscb_serial_gs_vals), SMSCB_SERIAL_GS, NULL, HFILL,
+	}},
+	{ &hf_smscb_serial_mcode, {
+		"Message Code", "smscb.serial.mcode", FT_UINT16, BASE_DEC,
+		NULL, SMSCB_SERIAL_MCODE, NULL, HFILL,
+	}},
+	{ &hf_smscb_serial_updnum, {
+		"Update Number", "smscb.serial.updnum", FT_UINT16, BASE_DEC,
+		NULL, SMSCB_SERIAL_UPDNUM, NULL, HFILL,
+	}},
+
+	{ &hf_smscb_msgid, {
+		"Message Identifier", "smscb.msgid", FT_UINT16, BASE_DEC,
+		NULL, 0, NULL, HFILL,
+	}},
+
+	{ &hf_smscb_page_num, {
+		"Page number", "smscb.page.num", FT_UINT8, BASE_DEC,
+		NULL, SMSCB_PAGE_NUM, NULL, HFILL,
+	}},
+	{ &hf_smscb_page_cnt, {
+		"Total pages", "smscb.page.cnt", FT_UINT8, BASE_DEC,
+		NULL, SMSCB_PAGE_CNT, NULL, HFILL,
+	}},
+	{ &hf_smscb_content, {
+		"Content of Message", "smscb.content", FT_STRING, BASE_NONE,
+		NULL, 0x00, NULL, HFILL,
+	}},
+
+	/* Schedule message */
+	{ &hf_smscb_sched_type, {
+		"Type", "smscb.sched.type", FT_UINT8, BASE_HEX,
+		NULL, SMSCB_SCHED_TYPE,
+		"Type", HFILL,
+	}},
+	{ &hf_smscb_sched_spare, {
+		"Spare", "smscb.sched.spare", FT_UINT8, BASE_DEC,
+		NULL, SMSCB_SCHED_TYPE,
+		"Spare", HFILL,
+	}},
+	{ &hf_smscb_sched_begin_slot, {
+		"Begin slot", "smscb.sched.begin_slot", FT_UINT8, BASE_DEC,
+		NULL, SMSCB_SCHED_SLOT,
+		"Begin slot", HFILL,
+	}},
+	{ &hf_smscb_sched_end_slot, {
+		"End slot", "smscb.sched.end_slot", FT_UINT8, BASE_DEC,
+		NULL, SMSCB_SCHED_SLOT,
+		"End slot", HFILL,
+	}},
+	{ &hf_smscb_sched_mdt1, {
+		"MDT", "smscb.sched.mdt1", FT_UINT16, BASE_DEC,
+		NULL, SMSCB_SCHED_MDT1,
+		"Message Description Type", HFILL,
+	}},
+	{ &hf_smscb_sched_msgid, {
+		"Message ID", "smscb.sched.msg_id", FT_UINT16, BASE_DEC,
+		NULL, SMSCB_SCHED_MSGID,
+		"Message ID", HFILL,
+	}},
+	{ &hf_smscb_sched_mdt2, {
+		"MDT", "smscb.sched.mdt2", FT_UINT8, BASE_DEC,
+		NULL, SMSCB_SCHED_MDT2,
+		"Message Description Type", HFILL,
+	}},
+	{ &hf_smscb_sched_repslot, {
+		"Repeated Slot Number", "smscb.sched.repslot", FT_UINT8, BASE_DEC,
+		NULL, SMSCB_SCHED_REPSLOT,
+		"Repeated Slot Number", HFILL,
+	}},
+	{ &hf_smscb_sched_mdt8, {
+		"MDT", "smscb.sched.mdt8", FT_UINT8, BASE_HEX,
+		VALS(smscb_sched_mdt8_vals), 0x00,
+		"Message Description Type", HFILL,
+	}},
+
+	/* Fragment reassembly */
+	{ &hf_smscb_fragments, {
+		"Message fragments", "smscb.fragments",
+		FT_NONE, BASE_NONE, NULL, 0x00,
+		"SMSCB Message fragments", HFILL,
+	}},
+	{ &hf_smscb_fragment, {
+		"Message fragment", "smscb.fragment",
+		FT_FRAMENUM, BASE_NONE, NULL, 0x00,
+		"SMSCB Message fragment", HFILL,
+	}},
+	{ &hf_smscb_fragment_overlap, {
+		"Message fragment overlap", "smscb.fragment.overlap",
+		FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+		"SMSCB Message fragment overlaps with other fragment(s)", HFILL,
+	}},
+	{ &hf_smscb_fragment_overlap_conflicts, {
+		"Message fragment overlapping with conflicting data", "smscb.fragment.overlap.conflicts",
+		FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+		"SMSCB Message fragment overlaps with conflicting data", HFILL,
+	}},
+	{ &hf_smscb_fragment_multiple_tails, {
+		"Message has multiple tail fragments", "smscb.fragment.multiple_tails",
+		FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+		"SMSCB Message fragment has multiple tail fragments", HFILL,
+	}},
+	{ &hf_smscb_fragment_too_long_fragment, {
+		"Message fragment too long", "smscb.fragment.too_long_fragment",
+		FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+		"SMSCB Message fragment data goes beyond the packet end", HFILL,
+	}},
+	{ &hf_smscb_fragment_error, {
+		"Message defragmentation error", "smscb.fragment.error",
+		FT_FRAMENUM, BASE_NONE, NULL, 0x00,
+		"SMSCB Message defragmentation error due to illegal fragments", HFILL,
+	}},
+	{ &hf_smscb_reassembled_in, {
+		"Reassembled in", "smscb.reassembled.in",
+		FT_FRAMENUM, BASE_NONE, NULL, 0x00,
+		"SMSCB Message has been reassembled in this packet.", HFILL,
+	}},
+	{ &hf_smscb_reassembled_length, {
+		"Reassembled SMSCB length", "smscb.reassembled.length",
+		FT_UINT32, BASE_DEC, NULL, 0x00,
+		"The total length of the reassembled payload", HFILL,
+	}},
+};
+
+static gint *ett[] = {
+	&ett_smscb,
+	&ett_smscb_addr,
+	&ett_smscb_dcs,
+	&ett_smscb_fragment,
+	&ett_smscb_fragments,
+	&ett_smscb_sched_new,
+	&ett_smscb_sched_other,
+	&ett_smscb_sched_slot,
+};
+
+void proto_reg_handoff_gsm_smscb(void)
+{
+	data_handle = find_dissector("data");
+}
+
+void proto_register_gsm_smscb(void)
+{
+	proto_gsm_smscb = proto_register_protocol(
+		"Short Message Service Cell Broadcast",
+		"SMSCB", "gsm_smscb");
+
+	proto_register_field_array(proto_gsm_smscb, hf, array_length(hf));
+	proto_register_subtree_array(ett, array_length(ett));
+
+	new_register_dissector("gsm_smscb", dissect_gsm_smscb, proto_gsm_smscb);
+	register_init_routine(smscb_defragment_init);
+}
diff --git a/epan/dissectors/packet-lapdm.c b/epan/dissectors/packet-lapdm.c
index dbeac85..add859d 100644
--- a/epan/dissectors/packet-lapdm.c
+++ b/epan/dissectors/packet-lapdm.c
@@ -110,6 +110,7 @@ static GHashTable *lapdm_reassembled_table = NULL;
 static dissector_table_t lapdm_sapi_dissector_table;
 
 static dissector_handle_t data_handle;
+static dissector_handle_t smscb_handle;
 
 static gboolean reassemble_lapdm = TRUE;
 
@@ -121,6 +122,7 @@ static gboolean reassemble_lapdm = TRUE;
 #define	LAPDM_CR		0x02	/* Command/Response bit */
 #define	LAPDM_EA		0x01	/* First Address Extension bit */
 #define	LAPDM_LPD		0x60	/* Link Protocol Discriminator */
+#define	LAPDM_LPD_CB		0x20	/* Cell Broadcast LPD */
 
 /*
  * Bits in the length field.
@@ -219,6 +221,7 @@ dissect_lapdm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     tvbuff_t *payload;
     int available_length;
     gboolean is_response = FALSE;
+    gboolean is_cbs = FALSE;
 
     /* Check that there's enough data */
     if (tvb_length(tvb) < LAPDM_HEADER_LEN)
@@ -229,6 +232,7 @@ dissect_lapdm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     addr = tvb_get_guint8(tvb, 0);
     length = tvb_get_guint8(tvb, 2);
 
+    is_cbs = (addr & LAPDM_LPD) == LAPDM_LPD_CB;
     cr = addr & LAPDM_CR;
     if (pinfo->p2p_dir == P2P_DIR_RECV) {
         is_response = cr ? FALSE : TRUE;
@@ -245,15 +249,22 @@ dissect_lapdm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
         addr_tree = proto_item_add_subtree(addr_ti, ett_lapdm_address);
 
         proto_tree_add_uint(addr_tree, hf_lapdm_lpd, tvb, 0, 1, addr);
-        proto_tree_add_uint(addr_tree, hf_lapdm_sapi, tvb, 0, 1, addr);
-        proto_tree_add_uint(addr_tree, hf_lapdm_cr, tvb, 0, 1, addr);
-        proto_tree_add_uint(addr_tree, hf_lapdm_ea, tvb, 0, 1, addr);
+        if (!is_cbs) {
+            proto_tree_add_uint(addr_tree, hf_lapdm_sapi, tvb, 0, 1, addr);
+            proto_tree_add_uint(addr_tree, hf_lapdm_cr, tvb, 0, 1, addr);
+            proto_tree_add_uint(addr_tree, hf_lapdm_ea, tvb, 0, 1, addr);
+        }
     }
     else {
         lapdm_ti = NULL;
         lapdm_tree = NULL;
     }
 
+    if (is_cbs) {
+        call_dissector(smscb_handle, tvb, pinfo, tree);
+        return;
+    }
+
     control = dissect_xdlc_control(tvb, 1, pinfo, lapdm_tree, hf_lapdm_control,
               ett_lapdm_control, &lapdm_cf_items, NULL /* LAPDm doesnt support extended */, NULL, NULL,
               is_response, FALSE, FALSE);
@@ -486,5 +497,6 @@ void
 proto_reg_handoff_lapdm(void)
 {
     data_handle = find_dissector("data");
+    smscb_handle = find_dissector("gsm_smscb");
 }
 
+