1 Wireshark patch for SMSCB dissection support in LAPDm
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
7 The dissector supports reassembly of SMSCB Message blocks. Schedule
8 block reassmebly or dissection is not yet implemented.
10 Signed-off-by: Alex Badea <vamposdecampos@gmail.com>
13 packet-gsm_smscb.c | 404 +++++++++++++++++++++++++++++++++++++++++++++++++++++
14 packet-lapdm.c | 18 +-
15 3 files changed, 420 insertions(+), 3 deletions(-)
17 diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common
18 index 1c1e60b..86bc856 100644
19 --- a/epan/dissectors/Makefile.common
20 +++ b/epan/dissectors/Makefile.common
21 @@ -500,6 +500,7 @@ DISSECTOR_SRC = \
22 packet-gsm_bssmap_le.c \
25 + packet-gsm_smscb.c \
29 diff --git a/epan/dissectors/packet-gsm_smscb.c b/epan/dissectors/packet-gsm_smscb.c
31 index 0000000..12b98f9
33 +++ b/epan/dissectors/packet-gsm_smscb.c
35 +/* packet-gsm_smscb.c
36 + * Routines for GSM SMSCB (GSM 04.12) dissection
37 + * Copyright 2010, Alex Badea <vamposdecampos@gmail.com>
41 + * Wireshark - Network traffic analyzer
42 + * By Gerald Combs <gerald@wireshark.org>
43 + * Copyright 1998 Gerald Combs
45 + * Copied from WHATEVER_FILE_YOU_USED (where "WHATEVER_FILE_YOU_USED"
46 + * is a dissector file; if you just copied this from README.developer,
47 + * don't bother with the "Copied from" - you don't even need to put
48 + * in a "Copied from" if you copied an existing dissector, especially
49 + * if the bulk of the code in the new dissector is your code)
51 + * This program is free software; you can redistribute it and/or modify
52 + * it under the terms of the GNU General Public License as published by
53 + * the Free Software Foundation; either version 2 of the License, or
54 + * (at your option) any later version.
56 + * This program is distributed in the hope that it will be useful,
57 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
58 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
59 + * GNU General Public License for more details.
61 + * You should have received a copy of the GNU General Public License along
62 + * with this program; if not, write to the Free Software Foundation, Inc.,
63 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
72 +#include <epan/packet.h>
73 +#include <epan/prefs.h>
74 +#include <epan/reassemble.h>
75 +#include <epan/asn1.h>
76 +#include "packet-gsm_map.h"
77 +#include "packet-gsm_sms.h"
79 +static gint proto_gsm_smscb = -1;
80 +static gint hf_smscb_addr = -1;
81 +static gint hf_smscb_addr_lb = -1;
82 +static gint hf_smscb_addr_seq = -1;
83 +static gint hf_smscb_serial_gs = -1;
84 +static gint hf_smscb_serial_mcode = -1;
85 +static gint hf_smscb_serial_updnum = -1;
86 +static gint hf_smscb_page_num = -1;
87 +static gint hf_smscb_page_cnt = -1;
88 +static gint hf_smscb_msgid = -1;
89 +static gint hf_smscb_content = -1;
90 +static gint hf_smscb_fragments = -1;
91 +static gint hf_smscb_fragment = -1;
92 +static gint hf_smscb_fragment_overlap = -1;
93 +static gint hf_smscb_fragment_overlap_conflicts = -1;
94 +static gint hf_smscb_fragment_multiple_tails = -1;
95 +static gint hf_smscb_fragment_too_long_fragment = -1;
96 +static gint hf_smscb_fragment_error = -1;
97 +static gint hf_smscb_reassembled_in = -1;
98 +static gint hf_smscb_reassembled_length = -1;
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;
106 +static GHashTable *smscb_fragment_table = NULL;
107 +static GHashTable *smscb_reassembled_table = NULL;
109 +static gboolean reassemble_smscb = TRUE;
111 +static dissector_handle_t data_handle;
113 +#define SMSCB_HDR_MINLEN 1
116 + * Bits in the address field.
118 +#define SMSCB_ADDR_LB 0x10 /* Address Last Bit */
119 +#define SMSCB_ADDR_SEQ 0x0f /* Address sequence number */
120 +#define SMSCB_SERIAL_GS 0xc0 /* CBS Serial Number - Geographical Scope */
121 +#define SMSCB_SERIAL_MCODE 0x3ffc /* CBS Serial Number - Message Code */
122 +#define SMSCB_SERIAL_UPDNUM 0x03 /* CBS Serial Number - Update Number */
123 +#define SMSCB_PAGE_NUM 0xf0 /* Page number */
124 +#define SMSCB_PAGE_CNT 0x0f /* Page total count */
126 +#define SMSCB_SEQ_LAST 3
128 +/* 04.12 section 3.3.1 */
129 +static const value_string smscb_addr_lb_vals[] = {
130 + { 0, "More blocks" },
131 + { 1, "Last block" },
135 +/* 04.12 section 3.3.1 */
136 +static const value_string smscb_addr_seq_vals[] = {
137 + { 0, "First block" },
138 + { 1, "Second block" },
139 + { 2, "Third block" },
140 + { 3, "Fourth block" },
141 + { 8, "First schedule block" },
142 + { 15, "Null message" },
146 +/* 03.41 section 9.3.2.1 */
147 +static const value_string smscb_serial_gs_vals[] = {
148 + { 0, "Cell wide (immediate)" },
149 + { 1, "PLMN wide" },
150 + { 2, "Location Area wide" },
151 + { 3, "Cell wide" },
156 +static const fragment_items smscb_frag_items = {
157 + /* Fragment subtrees */
158 + &ett_smscb_fragment,
159 + &ett_smscb_fragments,
160 + /* Fragment fields */
161 + &hf_smscb_fragments,
162 + &hf_smscb_fragment,
163 + &hf_smscb_fragment_overlap,
164 + &hf_smscb_fragment_overlap_conflicts,
165 + &hf_smscb_fragment_multiple_tails,
166 + &hf_smscb_fragment_too_long_fragment,
167 + &hf_smscb_fragment_error,
168 + /* Reassembled in field */
169 + &hf_smscb_reassembled_in,
170 + /* Reassembled length field */
171 + &hf_smscb_reassembled_length,
176 +static void smscb_defragment_init(void)
178 + fragment_table_init(&smscb_fragment_table);
179 + reassembled_table_init(&smscb_reassembled_table);
182 +/* [3GPP TS 03.41 section 9.3] */
183 +static int dissect_smscb_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
187 + gint length, out_len, textlen;
189 + gchar msgbuf[88 + 1];
190 + gchar *utf8_text, *p;
192 + proto_tree_add_item(tree, hf_smscb_serial_gs, tvb, offset, 1, ENC_NA);
193 + proto_tree_add_item(tree, hf_smscb_serial_mcode, tvb, offset, 2, ENC_NA);
195 + proto_tree_add_item(tree, hf_smscb_serial_updnum, tvb, offset, 1, ENC_NA);
197 + proto_tree_add_item(tree, hf_smscb_msgid, tvb, offset, 1, ENC_BIG_ENDIAN);
199 + ti = proto_tree_add_text(tree, tvb, offset, 1, "Data Coding Scheme");
200 + encoding = dissect_cbs_data_coding_scheme(
201 + tvb_new_subset(tvb, offset, 1, -1), pinfo,
202 + proto_item_add_subtree(ti, ett_smscb_dcs));
204 + proto_tree_add_item(tree, hf_smscb_page_num, tvb, offset, 1, ENC_NA);
205 + proto_tree_add_item(tree, hf_smscb_page_cnt, tvb, offset, 1, ENC_NA);
208 + length = tvb_length(tvb) - offset;
209 + switch (encoding) {
210 + case SMS_ENCODING_7BIT:
211 + case SMS_ENCODING_7BIT_LANG:
212 + out_len = gsm_sms_char_7bit_unpack(0, length, sizeof(msgbuf) - 1,
213 + tvb_get_ptr(tvb, offset, length), msgbuf);
214 + msgbuf[out_len] = '\0';
215 + utf8_text = gsm_sms_chars_to_utf8(msgbuf, out_len);
216 + textlen = strlen(utf8_text);
219 + case SMS_ENCODING_8BIT:
221 + utf8_text = tvb_get_ephemeral_string(tvb, offset, length);
226 + proto_tree_add_string(tree, hf_smscb_content, tvb, offset, length, utf8_text);
228 + /* strip padding */
229 + if ((p = strchr( utf8_text, '\r')))
231 + col_append_fstr(pinfo->cinfo, COL_INFO, " \"%s\"", utf8_text);
233 + return tvb_length(tvb);
236 +static int dissect_gsm_smscb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
239 + proto_tree *gsm_smscb_tree = NULL;
240 + proto_tree *subtree = NULL;
241 + guint8 addr, seq, more;
244 + if (tvb_length(tvb) < SMSCB_HDR_MINLEN)
247 + addr = tvb_get_guint8(tvb, 0);
248 + seq = addr & SMSCB_ADDR_SEQ;
249 + more = !(addr & SMSCB_ADDR_LB) && seq < SMSCB_SEQ_LAST;
251 + col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMSCB");
253 + col_clear(pinfo->cinfo, COL_INFO);
254 + col_append_fstr(pinfo->cinfo, COL_INFO, "seq=%d", seq);
257 + ti = proto_tree_add_item(tree, proto_gsm_smscb, tvb, 0, -1, ENC_NA);
258 + gsm_smscb_tree = proto_item_add_subtree(ti, ett_smscb);
260 + ti = proto_tree_add_item(gsm_smscb_tree, hf_smscb_addr, tvb, 0, 1, ENC_NA);
261 + subtree = proto_item_add_subtree(ti, ett_smscb_addr);
262 + proto_tree_add_item(subtree, hf_smscb_addr_lb, tvb, 0, 1, ENC_NA);
263 + proto_tree_add_item(subtree, hf_smscb_addr_seq, tvb, 0, 1, ENC_NA);
266 + payload = tvb_new_subset(tvb, 1, -1, -1);
268 + if (reassemble_smscb && seq <= SMSCB_SEQ_LAST) {
269 + fragment_data *frag;
270 + guint32 frag_id = 0x42;
271 + guchar expected_seq = 0;
272 + tvbuff_t *reassembled = NULL;
273 + gboolean save_fragmented = pinfo->fragmented;
275 + frag = fragment_get(pinfo, frag_id, smscb_fragment_table);
279 + expected_seq = frag->offset + 1;
283 + * TS 03.41 section 8 says we should discard sequences
284 + * which do not consist of consecutive blocks
286 + if (seq != expected_seq)
287 + g_free(fragment_delete(pinfo, frag_id, smscb_fragment_table));
289 + pinfo->fragmented = more;
290 + frag = fragment_add_seq_check(payload, 0, pinfo, frag_id,
291 + smscb_fragment_table,
292 + smscb_reassembled_table, seq,
293 + tvb_length(payload),
296 + reassembled = process_reassembled_data(payload, 0, pinfo,
297 + "Reassembled SMSCB", frag, &smscb_frag_items, NULL,
300 + if (frag && pinfo->fd->num == frag->reassembled_in) {
301 + dissect_smscb_message(reassembled, pinfo, gsm_smscb_tree);
303 + col_append_str(pinfo->cinfo, COL_INFO, " (Fragment)");
304 + proto_tree_add_text(gsm_smscb_tree, payload, 0, -1, "Fragment Data");
307 + pinfo->fragmented = save_fragmented;
308 + } else if (seq == 0) {
309 + dissect_smscb_message(payload, pinfo, gsm_smscb_tree);
311 + /* TODO: reassemble & dissect Schedule messages */
312 + call_dissector(data_handle, payload, pinfo, tree);
315 + return tvb_length(tvb);
318 +static hf_register_info hf[] = {
319 + { &hf_smscb_addr, {
320 + "Address Field", "smscb.addr", FT_UINT8, BASE_HEX,
324 + { &hf_smscb_addr_lb, {
325 + "LB", "smscb.addr.lb", FT_UINT8, BASE_DEC,
326 + VALS(smscb_addr_lb_vals), SMSCB_ADDR_LB,
327 + "Last Block bit", HFILL,
329 + { &hf_smscb_addr_seq, {
330 + "SEQ", "smscb.addr.seq", FT_UINT8, BASE_DEC,
331 + VALS(smscb_addr_seq_vals), SMSCB_ADDR_SEQ,
332 + "Sequence Number", HFILL,
335 + { &hf_smscb_serial_gs, {
336 + "Geographic Scope", "smscb.serial.gs", FT_UINT8, BASE_DEC,
337 + VALS(smscb_serial_gs_vals), SMSCB_SERIAL_GS, NULL, HFILL,
339 + { &hf_smscb_serial_mcode, {
340 + "Message Code", "smscb.serial.mcode", FT_UINT16, BASE_DEC,
341 + NULL, SMSCB_SERIAL_MCODE, NULL, HFILL,
343 + { &hf_smscb_serial_updnum, {
344 + "Update Number", "smscb.serial.updnum", FT_UINT8, BASE_DEC,
345 + NULL, SMSCB_SERIAL_MCODE, NULL, HFILL,
348 + { &hf_smscb_msgid, {
349 + "Message Identifier", "smscb.msgid", FT_UINT16, BASE_DEC,
350 + NULL, 0, NULL, HFILL,
353 + { &hf_smscb_page_num, {
354 + "Page number", "smscb.page.num", FT_UINT8, BASE_DEC,
355 + NULL, SMSCB_PAGE_NUM, NULL, HFILL,
357 + { &hf_smscb_page_cnt, {
358 + "Total pages", "smscb.page.cnt", FT_UINT8, BASE_DEC,
359 + NULL, SMSCB_PAGE_CNT, NULL, HFILL,
361 + { &hf_smscb_content, {
362 + "Content of Message", "smscb.content", FT_STRING, BASE_NONE,
363 + NULL, 0x00, NULL, HFILL,
366 + /* Fragment reassembly */
367 + { &hf_smscb_fragments, {
368 + "Message fragments", "smscb.fragments",
369 + FT_NONE, BASE_NONE, NULL, 0x00,
370 + "SMSCB Message fragments", HFILL,
372 + { &hf_smscb_fragment, {
373 + "Message fragment", "smscb.fragment",
374 + FT_FRAMENUM, BASE_NONE, NULL, 0x00,
375 + "SMSCB Message fragment", HFILL,
377 + { &hf_smscb_fragment_overlap, {
378 + "Message fragment overlap", "smscb.fragment.overlap",
379 + FT_BOOLEAN, BASE_NONE, NULL, 0x0,
380 + "SMSCB Message fragment overlaps with other fragment(s)", HFILL,
382 + { &hf_smscb_fragment_overlap_conflicts, {
383 + "Message fragment overlapping with conflicting data", "smscb.fragment.overlap.conflicts",
384 + FT_BOOLEAN, BASE_NONE, NULL, 0x0,
385 + "SMSCB Message fragment overlaps with conflicting data", HFILL,
387 + { &hf_smscb_fragment_multiple_tails, {
388 + "Message has multiple tail fragments", "smscb.fragment.multiple_tails",
389 + FT_BOOLEAN, BASE_NONE, NULL, 0x0,
390 + "SMSCB Message fragment has multiple tail fragments", HFILL,
392 + { &hf_smscb_fragment_too_long_fragment, {
393 + "Message fragment too long", "smscb.fragment.too_long_fragment",
394 + FT_BOOLEAN, BASE_NONE, NULL, 0x0,
395 + "SMSCB Message fragment data goes beyond the packet end", HFILL,
397 + { &hf_smscb_fragment_error, {
398 + "Message defragmentation error", "smscb.fragment.error",
399 + FT_FRAMENUM, BASE_NONE, NULL, 0x00,
400 + "SMSCB Message defragmentation error due to illegal fragments", HFILL,
402 + { &hf_smscb_reassembled_in, {
403 + "Reassembled in", "smscb.reassembled.in",
404 + FT_FRAMENUM, BASE_NONE, NULL, 0x00,
405 + "SMSCB Message has been reassembled in this packet.", HFILL,
407 + { &hf_smscb_reassembled_length, {
408 + "Reassembled SMSCB length", "smscb.reassembled.length",
409 + FT_UINT32, BASE_DEC, NULL, 0x00,
410 + "The total length of the reassembled payload", HFILL,
414 +static gint *ett[] = {
418 + &ett_smscb_fragment,
419 + &ett_smscb_fragments,
422 +void proto_reg_handoff_gsm_smscb(void)
424 + data_handle = find_dissector("data");
427 +void proto_register_gsm_smscb(void)
429 + proto_gsm_smscb = proto_register_protocol(
430 + "Short Message Service Cell Broadcast",
431 + "SMSCB", "gsm_smscb");
433 + proto_register_field_array(proto_gsm_smscb, hf, array_length(hf));
434 + proto_register_subtree_array(ett, array_length(ett));
436 + new_register_dissector("gsm_smscb", dissect_gsm_smscb, proto_gsm_smscb);
437 + register_init_routine(smscb_defragment_init);
439 diff --git a/epan/dissectors/packet-lapdm.c b/epan/dissectors/packet-lapdm.c
440 index dbeac85..add859d 100644
441 --- a/epan/dissectors/packet-lapdm.c
442 +++ b/epan/dissectors/packet-lapdm.c
443 @@ -110,6 +110,7 @@ static GHashTable *lapdm_reassembled_table = NULL;
444 static dissector_table_t lapdm_sapi_dissector_table;
446 static dissector_handle_t data_handle;
447 +static dissector_handle_t smscb_handle;
449 static gboolean reassemble_lapdm = TRUE;
451 @@ -121,6 +122,7 @@ static gboolean reassemble_lapdm = TRUE;
452 #define LAPDM_CR 0x02 /* Command/Response bit */
453 #define LAPDM_EA 0x01 /* First Address Extension bit */
454 #define LAPDM_LPD 0x60 /* Link Protocol Discriminator */
455 +#define LAPDM_LPD_CB 0x20 /* Cell Broadcast LPD */
458 * Bits in the length field.
459 @@ -219,6 +221,7 @@ dissect_lapdm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
461 int available_length;
462 gboolean is_response = FALSE;
463 + gboolean is_cbs = FALSE;
465 /* Check that there's enough data */
466 if (tvb_length(tvb) < LAPDM_HEADER_LEN)
467 @@ -229,6 +232,7 @@ dissect_lapdm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
468 addr = tvb_get_guint8(tvb, 0);
469 length = tvb_get_guint8(tvb, 2);
471 + is_cbs = (addr & LAPDM_LPD) == LAPDM_LPD_CB;
472 cr = addr & LAPDM_CR;
473 if (pinfo->p2p_dir == P2P_DIR_RECV) {
474 is_response = cr ? FALSE : TRUE;
475 @@ -245,15 +249,22 @@ dissect_lapdm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
476 addr_tree = proto_item_add_subtree(addr_ti, ett_lapdm_address);
478 proto_tree_add_uint(addr_tree, hf_lapdm_lpd, tvb, 0, 1, addr);
479 - proto_tree_add_uint(addr_tree, hf_lapdm_sapi, tvb, 0, 1, addr);
480 - proto_tree_add_uint(addr_tree, hf_lapdm_cr, tvb, 0, 1, addr);
481 - proto_tree_add_uint(addr_tree, hf_lapdm_ea, tvb, 0, 1, addr);
483 + proto_tree_add_uint(addr_tree, hf_lapdm_sapi, tvb, 0, 1, addr);
484 + proto_tree_add_uint(addr_tree, hf_lapdm_cr, tvb, 0, 1, addr);
485 + proto_tree_add_uint(addr_tree, hf_lapdm_ea, tvb, 0, 1, addr);
494 + call_dissector(smscb_handle, tvb, pinfo, tree);
498 control = dissect_xdlc_control(tvb, 1, pinfo, lapdm_tree, hf_lapdm_control,
499 ett_lapdm_control, &lapdm_cf_items, NULL /* LAPDm doesnt support extended */, NULL, NULL,
500 is_response, FALSE, FALSE);
501 @@ -486,5 +497,6 @@ void
502 proto_reg_handoff_lapdm(void)
504 data_handle = find_dissector("data");
505 + smscb_handle = find_dissector("gsm_smscb");