gsmmap: Dump SYSTEM INFORMATION messages while processing
[osmocom-bb.git] / src / wireshark / smscb.patch
1 Wireshark patch for SMSCB dissection support in LAPDm
2
3 Create a new gsm_smscb dissector module for SMSCB as defined in GSM TS
4 04.12.  Call it from packet-lapdm when the Link Protocol Discriminator
5 has the value "0 1".
6
7 Signed-off-by: Alex Badea <vamposdecampos@gmail.com>
8 ---
9  epan/dissectors/Makefile.common    |    1 +
10  epan/dissectors/packet-gsm_smscb.c |  642 ++++++++++++++++++++++++++++++++++++
11  epan/dissectors/packet-lapdm.c     |   18 +-
12  3 files changed, 658 insertions(+), 3 deletions(-)
13
14 diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common
15 index 9f9a602..5684579 100644
16 --- a/epan/dissectors/Makefile.common
17 +++ b/epan/dissectors/Makefile.common
18 @@ -500,6 +500,7 @@ DISSECTOR_SRC = \
19         packet-gsm_bssmap_le.c  \
20         packet-gsm_sms.c        \
21         packet-gsm_sms_ud.c     \
22 +       packet-gsm_smscb.c      \
23         packet-gsm_um.c         \
24         packet-gsmtap.c         \
25         packet-gssapi.c         \
26 diff --git a/epan/dissectors/packet-gsm_smscb.c b/epan/dissectors/packet-gsm_smscb.c
27 new file mode 100644
28 index 0000000..a2f8bee
29 --- /dev/null
30 +++ b/epan/dissectors/packet-gsm_smscb.c
31 @@ -0,0 +1,642 @@
32 +/* packet-gsm_smscb.c
33 + * Routines for GSM SMSCB (GSM 04.12) dissection
34 + * Copyright 2010, Alex Badea <vamposdecampos@gmail.com>
35 + *
36 + * $Id$
37 + *
38 + * Wireshark - Network traffic analyzer
39 + * By Gerald Combs <gerald@wireshark.org>
40 + * Copyright 1998 Gerald Combs
41 + *
42 + * This program is free software; you can redistribute it and/or modify
43 + * it under the terms of the GNU General Public License as published by
44 + * the Free Software Foundation; either version 2 of the License, or
45 + * (at your option) any later version.
46 + *
47 + * This program is distributed in the hope that it will be useful,
48 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
49 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
50 + * GNU General Public License for more details.
51 + *
52 + * You should have received a copy of the GNU General Public License along
53 + * with this program; if not, write to the Free Software Foundation, Inc.,
54 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
55 + */
56 +
57 +#ifdef HAVE_CONFIG_H
58 +# include "config.h"
59 +#endif
60 +
61 +#include <glib.h>
62 +
63 +#include <epan/packet.h>
64 +#include <epan/prefs.h>
65 +#include <epan/reassemble.h>
66 +#include <epan/asn1.h>
67 +#include "packet-gsm_map.h"
68 +#include "packet-gsm_sms.h"
69 +
70 +static gint proto_gsm_smscb = -1;
71 +static gint hf_smscb_addr = -1;
72 +static gint hf_smscb_addr_lb = -1;
73 +static gint hf_smscb_addr_seq = -1;
74 +static gint hf_smscb_serial_gs = -1;
75 +static gint hf_smscb_serial_mcode = -1;
76 +static gint hf_smscb_serial_updnum = -1;
77 +static gint hf_smscb_page_num = -1;
78 +static gint hf_smscb_page_cnt = -1;
79 +static gint hf_smscb_msgid = -1;
80 +static gint hf_smscb_content = -1;
81 +static gint hf_smscb_fragments = -1;
82 +static gint hf_smscb_fragment = -1;
83 +static gint hf_smscb_fragment_overlap = -1;
84 +static gint hf_smscb_fragment_overlap_conflicts = -1;
85 +static gint hf_smscb_fragment_multiple_tails = -1;
86 +static gint hf_smscb_fragment_too_long_fragment = -1;
87 +static gint hf_smscb_fragment_error = -1;
88 +static gint hf_smscb_reassembled_in = -1;
89 +static gint hf_smscb_reassembled_length = -1;
90 +static gint hf_smscb_sched_type = -1;
91 +static gint hf_smscb_sched_spare = -1;
92 +static gint hf_smscb_sched_begin_slot = -1;
93 +static gint hf_smscb_sched_end_slot = -1;
94 +static gint hf_smscb_sched_mdt1 = -1;
95 +static gint hf_smscb_sched_mdt2 = -1;
96 +static gint hf_smscb_sched_mdt8 = -1;
97 +static gint hf_smscb_sched_msgid = -1;
98 +static gint hf_smscb_sched_repslot = -1;
99 +
100 +static gint ett_smscb = -1;
101 +static gint ett_smscb_addr = -1;
102 +static gint ett_smscb_dcs = -1;
103 +static gint ett_smscb_fragment = -1;
104 +static gint ett_smscb_fragments = -1;
105 +static gint ett_smscb_sched_new = -1;
106 +static gint ett_smscb_sched_other = -1;
107 +static gint ett_smscb_sched_slot = -1;
108 +
109 +static GHashTable *smscb_fragment_table = NULL;
110 +static GHashTable *smscb_reassembled_table = NULL;
111 +
112 +static gboolean reassemble_smscb = TRUE;
113 +
114 +static dissector_handle_t data_handle;
115 +
116 +#define SMSCB_HDR_MINLEN       1
117 +
118 +/*
119 + * Bits in the address field.
120 + */
121 +#define        SMSCB_ADDR_LB           0x10    /* Address Last Bit */
122 +#define        SMSCB_ADDR_SEQ          0x0f    /* Address sequence number */
123 +#define        SMSCB_SERIAL_GS         0xc000  /* CBS Serial Number - Geographical Scope */
124 +#define        SMSCB_SERIAL_MCODE      0x3ff0  /* CBS Serial Number - Message Code */
125 +#define        SMSCB_SERIAL_UPDNUM     0x000f  /* CBS Serial Number - Update Number */
126 +#define        SMSCB_PAGE_NUM          0xf0    /* Page number */
127 +#define        SMSCB_PAGE_CNT          0x0f    /* Page total count */
128 +
129 +/*
130 + * Bits in the Schedule message
131 + */
132 +#define SMSCB_SCHED_TYPE       0xc0    /* Type */
133 +#define SMSCB_SCHED_SLOT       0x3f    /* Begin/End Slot Number */
134 +#define SMSCB_SCHED_SPARE      0xc0    /* Spare */
135 +#define SMSCB_SCHED_MDT1       0x8000  /* MDT (1 bit)*/
136 +#define SMSCB_SCHED_MSGID      0x7fff  /* Message ID */
137 +#define SMSCB_SCHED_MDT2       0xc0    /* MDT (2 bits) */
138 +#define SMSCB_SCHED_REPSLOT    0x3f    /* Repeated Slot Number */
139 +
140 +#define SMSCB_SEQ_LAST         3
141 +#define SMSCB_SEQ_1ST          0
142 +#define SMSCB_SEQ_1ST_SCHED    8
143 +
144 +#define SMSCB_SCHED_SLOT_MAX   48
145 +
146 +/* 04.12 section 3.3.1 */
147 +static const value_string smscb_addr_lb_vals[] = {
148 +       { 0,            "More blocks" },
149 +       { 1,            "Last block" },
150 +       { 0,            NULL }
151 +};
152 +
153 +/* 04.12 section 3.3.1 */
154 +static const value_string smscb_addr_seq_vals[] = {
155 +       { 0,            "First block" },
156 +       { 1,            "Second block" },
157 +       { 2,            "Third block" },
158 +       { 3,            "Fourth block" },
159 +       { 8,            "First schedule block" },
160 +       { 15,           "Null message" },
161 +       { 0,            NULL }
162 +};
163 +
164 +/* 03.41 section 9.3.2.1 */
165 +static const value_string smscb_serial_gs_vals[] = {
166 +       { 0,            "Cell wide (immediate)" },
167 +       { 1,            "PLMN wide" },
168 +       { 2,            "Location Area wide" },
169 +       { 3,            "Cell wide" },
170 +       { 0,            NULL }
171 +};
172 +
173 +/* 04.14 section 3.5.5 */
174 +static const value_string smscb_sched_mdt8_vals[] = {
175 +       { 0x00,         "Retransmission indication" },
176 +       { 0x80,         "First transmission of an SMSCB within the Schedule Period" },
177 +       { 0x40,         "Free Message Slot, optional reading" },
178 +       { 0x41,         "Free Message Slot, reading advised" },
179 +       { 0,            NULL }
180 +};
181 +
182 +static const fragment_items smscb_frag_items = {
183 +       /* Fragment subtrees */
184 +       &ett_smscb_fragment,
185 +       &ett_smscb_fragments,
186 +       /* Fragment fields */
187 +       &hf_smscb_fragments,
188 +       &hf_smscb_fragment,
189 +       &hf_smscb_fragment_overlap,
190 +       &hf_smscb_fragment_overlap_conflicts,
191 +       &hf_smscb_fragment_multiple_tails,
192 +       &hf_smscb_fragment_too_long_fragment,
193 +       &hf_smscb_fragment_error,
194 +       /* Reassembled in field */
195 +       &hf_smscb_reassembled_in,
196 +       /* Reassembled length field */
197 +       &hf_smscb_reassembled_length,
198 +       /* Tag */
199 +       "fragments"
200 +};
201 +
202 +static void smscb_defragment_init(void)
203 +{
204 +       fragment_table_init(&smscb_fragment_table);
205 +       reassembled_table_init(&smscb_reassembled_table);
206 +}
207 +
208 +/* [3GPP TS 03.41 section 9.3] */
209 +static int dissect_smscb_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
210 +{
211 +       proto_item *ti;
212 +       gint offset = 0;
213 +       gint length, out_len, textlen;
214 +       guint8 encoding;
215 +       gchar msgbuf[88 + 1];
216 +       gchar *utf8_text, *p;
217 +
218 +       proto_tree_add_item(tree, hf_smscb_serial_gs, tvb, offset, 1, ENC_NA);
219 +       proto_tree_add_item(tree, hf_smscb_serial_mcode, tvb, offset, 2, ENC_NA);
220 +       offset++;
221 +       proto_tree_add_item(tree, hf_smscb_serial_updnum, tvb, offset, 1, ENC_NA);
222 +       offset++;
223 +       proto_tree_add_item(tree, hf_smscb_msgid, tvb, offset, 2, ENC_BIG_ENDIAN);
224 +       col_append_fstr(pinfo->cinfo, COL_INFO, " - Message ID %d", tvb_get_ntohs(tvb, offset));
225 +       offset += 2;
226 +       ti = proto_tree_add_text(tree, tvb, offset, 1, "Data Coding Scheme");
227 +       encoding = dissect_cbs_data_coding_scheme(
228 +               tvb_new_subset(tvb, offset, 1, -1), pinfo,
229 +               proto_item_add_subtree(ti, ett_smscb_dcs));
230 +       offset++;
231 +       proto_tree_add_item(tree, hf_smscb_page_num, tvb, offset, 1, ENC_NA);
232 +       proto_tree_add_item(tree, hf_smscb_page_cnt, tvb, offset, 1, ENC_NA);
233 +       offset++;
234 +
235 +       length = tvb_length(tvb) - offset;
236 +       switch (encoding) {
237 +       case SMS_ENCODING_7BIT:
238 +       case SMS_ENCODING_7BIT_LANG:
239 +               out_len = gsm_sms_char_7bit_unpack(0, length, sizeof(msgbuf) - 1,
240 +                               tvb_get_ptr(tvb, offset, length), msgbuf);
241 +               msgbuf[out_len] = '\0';
242 +               utf8_text = gsm_sms_chars_to_utf8(msgbuf, out_len);
243 +               textlen = strlen(utf8_text);
244 +               break;
245 +       /* TODO: UCS2? */
246 +       case SMS_ENCODING_8BIT:
247 +       default:
248 +               utf8_text = tvb_get_ephemeral_string(tvb, offset, length);
249 +               textlen = length;
250 +               break;
251 +       }
252 +
253 +       proto_tree_add_string(tree, hf_smscb_content, tvb, offset, length, utf8_text);
254 +
255 +       /* strip padding */
256 +       if ((p = strchr( utf8_text, '\r')))
257 +               *p = 0;
258 +       col_append_fstr(pinfo->cinfo, COL_INFO, " \"%s\"", utf8_text);
259 +
260 +       return tvb_length(tvb);
261 +}
262 +
263 +/* [3GPP TS 04.14 section 3.5.5] */
264 +static int dissect_sched_msg_desc(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
265 +       gint *slot_list, gint slot_count)
266 +{
267 +       gint offset = 0;
268 +       gint k;
269 +       proto_item *ti;
270 +       proto_tree *subtree;
271 +       guint8 mdt;
272 +
273 +       for (k = 0; k < slot_count; k++) {
274 +               mdt = tvb_get_guint8(tvb, offset);
275 +
276 +               if (mdt & 0x80)
277 +                       mdt = 0x80;
278 +               else if (!(mdt & 0x40))
279 +                       mdt = 0;
280 +
281 +               ti = proto_tree_add_text(tree, tvb, offset, 1, "Slot %d - %s",
282 +                       slot_list[k],
283 +                       val_to_str(mdt, smscb_sched_mdt8_vals, "Unknown (0x%02x)"));
284 +               subtree = proto_item_add_subtree(ti, ett_smscb_sched_slot);
285 +
286 +               if (mdt & 0x80) {
287 +                       guint16 msgid = tvb_get_ntohs(tvb, offset) & SMSCB_SCHED_MSGID;
288 +                       proto_item_append_text(ti, " (message ID %d)", msgid);
289 +                       proto_item_set_len(ti, 2);
290 +                       proto_tree_add_item(subtree, hf_smscb_sched_mdt1, tvb, offset, 2, ENC_BIG_ENDIAN);
291 +                       proto_tree_add_item(subtree, hf_smscb_sched_msgid, tvb, offset, 2, ENC_BIG_ENDIAN);
292 +                       offset += 2;
293 +               } else if (!(mdt & 0xc0)) {
294 +                       guint8 slot = tvb_get_guint8(tvb, offset) & SMSCB_SCHED_SLOT;
295 +                       proto_item_append_text(ti, " (slot %d)", slot);
296 +                       proto_tree_add_item(subtree, hf_smscb_sched_mdt2, tvb, offset, 1, ENC_NA);
297 +                       proto_tree_add_item(subtree, hf_smscb_sched_repslot, tvb, offset, 1, ENC_NA);
298 +                       offset++;
299 +               } else {
300 +                       proto_tree_add_item(subtree, hf_smscb_sched_mdt8, tvb, offset, 1, ENC_NA);
301 +                       offset++;
302 +               }
303 +       }
304 +       return offset;
305 +}
306 +
307 +/* [3GPP TS 04.14 section 3.5] */
308 +static int dissect_sched_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
309 +{
310 +       proto_item *ti;
311 +       gint offset = 0;
312 +       gint first, last, nm, len;
313 +       gint new_count = 0;
314 +       gint other_count = 0;
315 +       gint new_list[SMSCB_SCHED_SLOT_MAX];
316 +       gint other_list[SMSCB_SCHED_SLOT_MAX];
317 +
318 +       col_append_str(pinfo->cinfo, COL_INFO, " - Schedule message");
319 +
320 +       proto_tree_add_item(tree, hf_smscb_sched_type, tvb, offset, 1, ENC_NA);
321 +       proto_tree_add_item(tree, hf_smscb_sched_begin_slot, tvb, offset, 1, ENC_NA);
322 +       offset++;
323 +       proto_tree_add_item(tree, hf_smscb_sched_spare, tvb, offset, 1, ENC_NA);
324 +       proto_tree_add_item(tree, hf_smscb_sched_end_slot, tvb, offset, 1, ENC_NA);
325 +       offset++;
326 +
327 +       first = tvb_get_guint8(tvb, 0) & SMSCB_SCHED_SLOT;
328 +       last = tvb_get_guint8(tvb, 1) & SMSCB_SCHED_SLOT;
329 +       last = MIN(last, SMSCB_SCHED_SLOT_MAX);
330 +
331 +       ti = proto_tree_add_text(tree, tvb, offset, 6, "List of new message slots =");
332 +       for (nm = first; nm <= last; nm++) {
333 +               if (tvb_get_bits8(tvb, offset * 8 + nm - first, 1)) {
334 +                       proto_item_append_text(ti, " %d", nm);
335 +                       new_list[new_count++] = nm;
336 +               } else {
337 +                       other_list[other_count++] = nm;
338 +               }
339 +       }
340 +       offset += 6;
341 +
342 +       ti = proto_tree_add_text(tree, tvb, offset, 0, "New Message Descriptions");
343 +       len = dissect_sched_msg_desc(tvb_new_subset(tvb, offset, -1, -1), pinfo,
344 +               proto_item_add_subtree(ti, ett_smscb_sched_new),
345 +               new_list, new_count);
346 +       offset += len;
347 +       proto_item_set_len(ti, len);
348 +
349 +       ti = proto_tree_add_text(tree, tvb, offset, 0, "Other Message Descriptions");
350 +       len = dissect_sched_msg_desc(tvb_new_subset(tvb, offset, -1, -1), pinfo,
351 +               proto_item_add_subtree(ti, ett_smscb_sched_other),
352 +               other_list, other_count);
353 +       offset += len;
354 +       proto_item_set_len(ti, len);
355 +
356 +       return offset;
357 +}
358 +
359 +static inline int seq_any_frags(guint8 seq)
360 +{
361 +       return seq <= SMSCB_SEQ_LAST || seq == SMSCB_SEQ_1ST_SCHED;
362 +}
363 +
364 +static inline int seq_more_frags(guint8 seq)
365 +{
366 +       return seq < SMSCB_SEQ_LAST || seq == SMSCB_SEQ_1ST_SCHED;
367 +}
368 +
369 +static inline int seq_first(guint8 seq)
370 +{
371 +       return seq == SMSCB_SEQ_1ST || seq == SMSCB_SEQ_1ST_SCHED;
372 +}
373 +
374 +static inline int seq_bits(guint8 seq)
375 +{
376 +       return seq & 3;
377 +}
378 +
379 +/*
380 + * Do the reassembly thing.
381 + *
382 + * SMSCB fragmentation doesn't really fit in with the wireshark
383 + * reassembler.  There are only two valid fragment sequences:
384 + *   i) 0,1,2,3 for a SMSCB message
385 + *   ii) 8,1,2,3 for a schedule message
386 + *
387 + * We can't use different fragment-IDs for each content type,
388 + * since the last 3 blocks have identical sequence numbers.
389 + *
390 + * We can't just mask the lower 2 bits, because when reassembly
391 + * completes (which is on the last block, sequence #3) we won't
392 + * know which content type we've reassembled.
393 + *
394 + * We also can't munge e.g. the schedule sequence to 8,9,10,11,
395 + * since the reassembler will think we're missing the first 8
396 + * blocks and not do anything.
397 + *
398 + * Also, according to TS 03.41 section 8 we must discard
399 + * non-consecutive sequences.
400 + *
401 + * So the approach here is to include the address header byte
402 + * in the first fragment.  This way after reassembly we can peek
403 + * at it and dissect accordingly.
404 + *
405 + * A clean implementation would likely be to add a FD_* reassembler
406 + * flag to special-case this behaviour.
407 + */
408 +static tvbuff_t *smscb_try_reassembly(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
409 +       guint8 *seq_p, guint8 more)
410 +{
411 +       guint8 seq = *seq_p;
412 +       fragment_data *frag;
413 +       guint32 frag_id = 0x42;
414 +       guchar expected_seq = 0;
415 +       tvbuff_t *reassembled = NULL;
416 +       gboolean save_fragmented = pinfo->fragmented;
417 +
418 +       if (!reassemble_smscb || !seq_any_frags(seq))
419 +               return tvb;
420 +
421 +       frag = fragment_get(pinfo, frag_id, smscb_fragment_table);
422 +       if (frag) {
423 +               while (frag->next)
424 +                       frag = frag->next;
425 +               expected_seq = frag->offset + 1;
426 +       }
427 +
428 +       if (seq != expected_seq)
429 +               g_free(fragment_delete(pinfo, frag_id, smscb_fragment_table));
430 +
431 +       if (!seq_first(seq))
432 +               tvb = tvb_new_subset(tvb, 1, -1, -1);
433 +
434 +       pinfo->fragmented = more;
435 +       frag = fragment_add_seq_check(tvb, 0, pinfo, frag_id,
436 +               smscb_fragment_table,
437 +               smscb_reassembled_table, seq_bits(seq),
438 +               tvb_length(tvb),
439 +               more);
440 +
441 +       reassembled = process_reassembled_data(tvb, 0, pinfo,
442 +               "Reassembled SMSCB", frag, &smscb_frag_items, NULL, tree);
443 +
444 +       if (frag && pinfo->fd->num == frag->reassembled_in) {
445 +               *seq_p = tvb_get_guint8(reassembled, 0) & SMSCB_ADDR_SEQ;
446 +               reassembled = tvb_new_subset(reassembled, 1, -1, -1);
447 +       } else {
448 +               col_append_str(pinfo->cinfo, COL_INFO, " (Fragment)");
449 +               proto_tree_add_text(tree, tvb, 0, -1, "Fragment Data");
450 +               reassembled = NULL;
451 +       }
452 +
453 +       pinfo->fragmented = save_fragmented;
454 +       return reassembled;
455 +}
456 +
457 +static int dissect_gsm_smscb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
458 +{
459 +       proto_item *ti;
460 +       proto_tree *gsm_smscb_tree = NULL;
461 +       proto_tree *subtree = NULL;
462 +       guint8 addr, seq, more;
463 +       tvbuff_t *payload;
464 +
465 +       if (tvb_length(tvb) < SMSCB_HDR_MINLEN)
466 +               return 0;
467 +
468 +       addr = tvb_get_guint8(tvb, 0);
469 +       seq = addr & SMSCB_ADDR_SEQ;
470 +       more = !(addr & SMSCB_ADDR_LB) && seq_more_frags(seq);
471 +
472 +       col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMSCB");
473 +
474 +       col_clear(pinfo->cinfo, COL_INFO);
475 +       col_append_str(pinfo->cinfo, COL_INFO,
476 +               val_to_str(seq, smscb_addr_seq_vals, "Unknown block #%d"));
477 +
478 +       if (tree) {
479 +               ti = proto_tree_add_item(tree, proto_gsm_smscb, tvb, 0, -1, ENC_NA);
480 +               gsm_smscb_tree = proto_item_add_subtree(ti, ett_smscb);
481 +
482 +               ti = proto_tree_add_item(gsm_smscb_tree, hf_smscb_addr, tvb, 0, 1, ENC_NA);
483 +               subtree = proto_item_add_subtree(ti, ett_smscb_addr);
484 +               proto_tree_add_item(subtree, hf_smscb_addr_lb, tvb, 0, 1, ENC_NA);
485 +               proto_tree_add_item(subtree, hf_smscb_addr_seq, tvb, 0, 1, ENC_NA);
486 +       }
487 +
488 +       payload = smscb_try_reassembly(tvb, pinfo, gsm_smscb_tree, &seq, more);
489 +       if (payload) {
490 +               switch (seq) {
491 +               case SMSCB_SEQ_1ST:
492 +                       dissect_smscb_message(payload, pinfo, gsm_smscb_tree);
493 +                       break;
494 +               case SMSCB_SEQ_1ST_SCHED:
495 +                       dissect_sched_message(payload, pinfo, gsm_smscb_tree);
496 +                       break;
497 +               }
498 +       }
499 +
500 +       return tvb_length(tvb);
501 +}
502 +
503 +static hf_register_info hf[] = {
504 +       { &hf_smscb_addr, {
505 +               "Address Field", "smscb.addr", FT_UINT8, BASE_HEX,
506 +               NULL, 0x0,
507 +               "Address", HFILL,
508 +       }},
509 +       { &hf_smscb_addr_lb, {
510 +               "LB", "smscb.addr.lb", FT_UINT8, BASE_DEC,
511 +               VALS(smscb_addr_lb_vals), SMSCB_ADDR_LB,
512 +               "Last Block bit", HFILL,
513 +       }},
514 +       { &hf_smscb_addr_seq, {
515 +               "SEQ", "smscb.addr.seq", FT_UINT8, BASE_DEC,
516 +               VALS(smscb_addr_seq_vals), SMSCB_ADDR_SEQ,
517 +               "Sequence Number", HFILL,
518 +       }},
519 +
520 +       { &hf_smscb_serial_gs, {
521 +               "Geographic Scope", "smscb.serial.gs", FT_UINT16, BASE_DEC,
522 +               VALS(smscb_serial_gs_vals), SMSCB_SERIAL_GS, NULL, HFILL,
523 +       }},
524 +       { &hf_smscb_serial_mcode, {
525 +               "Message Code", "smscb.serial.mcode", FT_UINT16, BASE_DEC,
526 +               NULL, SMSCB_SERIAL_MCODE, NULL, HFILL,
527 +       }},
528 +       { &hf_smscb_serial_updnum, {
529 +               "Update Number", "smscb.serial.updnum", FT_UINT16, BASE_DEC,
530 +               NULL, SMSCB_SERIAL_UPDNUM, NULL, HFILL,
531 +       }},
532 +
533 +       { &hf_smscb_msgid, {
534 +               "Message Identifier", "smscb.msgid", FT_UINT16, BASE_DEC,
535 +               NULL, 0, NULL, HFILL,
536 +       }},
537 +
538 +       { &hf_smscb_page_num, {
539 +               "Page number", "smscb.page.num", FT_UINT8, BASE_DEC,
540 +               NULL, SMSCB_PAGE_NUM, NULL, HFILL,
541 +       }},
542 +       { &hf_smscb_page_cnt, {
543 +               "Total pages", "smscb.page.cnt", FT_UINT8, BASE_DEC,
544 +               NULL, SMSCB_PAGE_CNT, NULL, HFILL,
545 +       }},
546 +       { &hf_smscb_content, {
547 +               "Content of Message", "smscb.content", FT_STRING, BASE_NONE,
548 +               NULL, 0x00, NULL, HFILL,
549 +       }},
550 +
551 +       /* Schedule message */
552 +       { &hf_smscb_sched_type, {
553 +               "Type", "smscb.sched.type", FT_UINT8, BASE_HEX,
554 +               NULL, SMSCB_SCHED_TYPE,
555 +               "Type", HFILL,
556 +       }},
557 +       { &hf_smscb_sched_spare, {
558 +               "Spare", "smscb.sched.spare", FT_UINT8, BASE_DEC,
559 +               NULL, SMSCB_SCHED_TYPE,
560 +               "Spare", HFILL,
561 +       }},
562 +       { &hf_smscb_sched_begin_slot, {
563 +               "Begin slot", "smscb.sched.begin_slot", FT_UINT8, BASE_DEC,
564 +               NULL, SMSCB_SCHED_SLOT,
565 +               "Begin slot", HFILL,
566 +       }},
567 +       { &hf_smscb_sched_end_slot, {
568 +               "End slot", "smscb.sched.end_slot", FT_UINT8, BASE_DEC,
569 +               NULL, SMSCB_SCHED_SLOT,
570 +               "End slot", HFILL,
571 +       }},
572 +       { &hf_smscb_sched_mdt1, {
573 +               "MDT", "smscb.sched.mdt1", FT_UINT16, BASE_DEC,
574 +               NULL, SMSCB_SCHED_MDT1,
575 +               "Message Description Type", HFILL,
576 +       }},
577 +       { &hf_smscb_sched_msgid, {
578 +               "Message ID", "smscb.sched.msg_id", FT_UINT16, BASE_DEC,
579 +               NULL, SMSCB_SCHED_MSGID,
580 +               "Message ID", HFILL,
581 +       }},
582 +       { &hf_smscb_sched_mdt2, {
583 +               "MDT", "smscb.sched.mdt2", FT_UINT8, BASE_DEC,
584 +               NULL, SMSCB_SCHED_MDT2,
585 +               "Message Description Type", HFILL,
586 +       }},
587 +       { &hf_smscb_sched_repslot, {
588 +               "Repeated Slot Number", "smscb.sched.repslot", FT_UINT8, BASE_DEC,
589 +               NULL, SMSCB_SCHED_REPSLOT,
590 +               "Repeated Slot Number", HFILL,
591 +       }},
592 +       { &hf_smscb_sched_mdt8, {
593 +               "MDT", "smscb.sched.mdt8", FT_UINT8, BASE_HEX,
594 +               VALS(smscb_sched_mdt8_vals), 0x00,
595 +               "Message Description Type", HFILL,
596 +       }},
597 +
598 +       /* Fragment reassembly */
599 +       { &hf_smscb_fragments, {
600 +               "Message fragments", "smscb.fragments",
601 +               FT_NONE, BASE_NONE, NULL, 0x00,
602 +               "SMSCB Message fragments", HFILL,
603 +       }},
604 +       { &hf_smscb_fragment, {
605 +               "Message fragment", "smscb.fragment",
606 +               FT_FRAMENUM, BASE_NONE, NULL, 0x00,
607 +               "SMSCB Message fragment", HFILL,
608 +       }},
609 +       { &hf_smscb_fragment_overlap, {
610 +               "Message fragment overlap", "smscb.fragment.overlap",
611 +               FT_BOOLEAN, BASE_NONE, NULL, 0x0,
612 +               "SMSCB Message fragment overlaps with other fragment(s)", HFILL,
613 +       }},
614 +       { &hf_smscb_fragment_overlap_conflicts, {
615 +               "Message fragment overlapping with conflicting data", "smscb.fragment.overlap.conflicts",
616 +               FT_BOOLEAN, BASE_NONE, NULL, 0x0,
617 +               "SMSCB Message fragment overlaps with conflicting data", HFILL,
618 +       }},
619 +       { &hf_smscb_fragment_multiple_tails, {
620 +               "Message has multiple tail fragments", "smscb.fragment.multiple_tails",
621 +               FT_BOOLEAN, BASE_NONE, NULL, 0x0,
622 +               "SMSCB Message fragment has multiple tail fragments", HFILL,
623 +       }},
624 +       { &hf_smscb_fragment_too_long_fragment, {
625 +               "Message fragment too long", "smscb.fragment.too_long_fragment",
626 +               FT_BOOLEAN, BASE_NONE, NULL, 0x0,
627 +               "SMSCB Message fragment data goes beyond the packet end", HFILL,
628 +       }},
629 +       { &hf_smscb_fragment_error, {
630 +               "Message defragmentation error", "smscb.fragment.error",
631 +               FT_FRAMENUM, BASE_NONE, NULL, 0x00,
632 +               "SMSCB Message defragmentation error due to illegal fragments", HFILL,
633 +       }},
634 +       { &hf_smscb_reassembled_in, {
635 +               "Reassembled in", "smscb.reassembled.in",
636 +               FT_FRAMENUM, BASE_NONE, NULL, 0x00,
637 +               "SMSCB Message has been reassembled in this packet.", HFILL,
638 +       }},
639 +       { &hf_smscb_reassembled_length, {
640 +               "Reassembled SMSCB length", "smscb.reassembled.length",
641 +               FT_UINT32, BASE_DEC, NULL, 0x00,
642 +               "The total length of the reassembled payload", HFILL,
643 +       }},
644 +};
645 +
646 +static gint *ett[] = {
647 +       &ett_smscb,
648 +       &ett_smscb_addr,
649 +       &ett_smscb_dcs,
650 +       &ett_smscb_fragment,
651 +       &ett_smscb_fragments,
652 +       &ett_smscb_sched_new,
653 +       &ett_smscb_sched_other,
654 +       &ett_smscb_sched_slot,
655 +};
656 +
657 +void proto_reg_handoff_gsm_smscb(void)
658 +{
659 +       data_handle = find_dissector("data");
660 +}
661 +
662 +void proto_register_gsm_smscb(void)
663 +{
664 +       proto_gsm_smscb = proto_register_protocol(
665 +               "Short Message Service Cell Broadcast",
666 +               "SMSCB", "gsm_smscb");
667 +
668 +       proto_register_field_array(proto_gsm_smscb, hf, array_length(hf));
669 +       proto_register_subtree_array(ett, array_length(ett));
670 +
671 +       new_register_dissector("gsm_smscb", dissect_gsm_smscb, proto_gsm_smscb);
672 +       register_init_routine(smscb_defragment_init);
673 +}
674 diff --git a/epan/dissectors/packet-lapdm.c b/epan/dissectors/packet-lapdm.c
675 index dbeac85..add859d 100644
676 --- a/epan/dissectors/packet-lapdm.c
677 +++ b/epan/dissectors/packet-lapdm.c
678 @@ -110,6 +110,7 @@ static GHashTable *lapdm_reassembled_table = NULL;
679  static dissector_table_t lapdm_sapi_dissector_table;
680  
681  static dissector_handle_t data_handle;
682 +static dissector_handle_t smscb_handle;
683  
684  static gboolean reassemble_lapdm = TRUE;
685  
686 @@ -121,6 +122,7 @@ static gboolean reassemble_lapdm = TRUE;
687  #define        LAPDM_CR                0x02    /* Command/Response bit */
688  #define        LAPDM_EA                0x01    /* First Address Extension bit */
689  #define        LAPDM_LPD               0x60    /* Link Protocol Discriminator */
690 +#define        LAPDM_LPD_CB            0x20    /* Cell Broadcast LPD */
691  
692  /*
693   * Bits in the length field.
694 @@ -219,6 +221,7 @@ dissect_lapdm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
695      tvbuff_t *payload;
696      int available_length;
697      gboolean is_response = FALSE;
698 +    gboolean is_cbs = FALSE;
699  
700      /* Check that there's enough data */
701      if (tvb_length(tvb) < LAPDM_HEADER_LEN)
702 @@ -229,6 +232,7 @@ dissect_lapdm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
703      addr = tvb_get_guint8(tvb, 0);
704      length = tvb_get_guint8(tvb, 2);
705  
706 +    is_cbs = (addr & LAPDM_LPD) == LAPDM_LPD_CB;
707      cr = addr & LAPDM_CR;
708      if (pinfo->p2p_dir == P2P_DIR_RECV) {
709          is_response = cr ? FALSE : TRUE;
710 @@ -245,15 +249,22 @@ dissect_lapdm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
711          addr_tree = proto_item_add_subtree(addr_ti, ett_lapdm_address);
712  
713          proto_tree_add_uint(addr_tree, hf_lapdm_lpd, tvb, 0, 1, addr);
714 -        proto_tree_add_uint(addr_tree, hf_lapdm_sapi, tvb, 0, 1, addr);
715 -        proto_tree_add_uint(addr_tree, hf_lapdm_cr, tvb, 0, 1, addr);
716 -        proto_tree_add_uint(addr_tree, hf_lapdm_ea, tvb, 0, 1, addr);
717 +        if (!is_cbs) {
718 +            proto_tree_add_uint(addr_tree, hf_lapdm_sapi, tvb, 0, 1, addr);
719 +            proto_tree_add_uint(addr_tree, hf_lapdm_cr, tvb, 0, 1, addr);
720 +            proto_tree_add_uint(addr_tree, hf_lapdm_ea, tvb, 0, 1, addr);
721 +        }
722      }
723      else {
724          lapdm_ti = NULL;
725          lapdm_tree = NULL;
726      }
727  
728 +    if (is_cbs) {
729 +        call_dissector(smscb_handle, tvb, pinfo, tree);
730 +        return;
731 +    }
732 +
733      control = dissect_xdlc_control(tvb, 1, pinfo, lapdm_tree, hf_lapdm_control,
734                ett_lapdm_control, &lapdm_cf_items, NULL /* LAPDm doesnt support extended */, NULL, NULL,
735                is_response, FALSE, FALSE);
736 @@ -486,5 +497,6 @@ void
737  proto_reg_handoff_lapdm(void)
738  {
739      data_handle = find_dissector("data");
740 +    smscb_handle = find_dissector("gsm_smscb");
741  }
742  
743 +