2 * Routines for GSM SMS TP-UD (GSM 03.40) dissection
4 * $Id: packet-gsm_sms_ud.c,v 1.5 2004/01/29 21:19:10 obiot Exp $
6 * Refer to the AUTHORS file or the AUTHORS section in the man page
7 * for contacting the author(s) of this file.
9 * Separated from the SMPP dissector by Chris Wilson.
11 * UDH and WSP dissection of SMS message, Short Message reassembly,
12 * "Decode Short Message with Port Number UDH as CL-WSP" preference,
13 * "Always try subdissection of 1st fragment" preference,
14 * provided by Olivier Biot.
16 * Note on SMS Message reassembly
17 * ------------------------------
18 * The current Short Message reassembly is possible thanks to the
19 * message identifier (8 or 16 bit identifier). It is able to reassemble
20 * short messages that are sent over either the same SMPP connection or
21 * distinct SMPP connections. Normally the reassembly code is able to deal
22 * with duplicate message identifiers since the fragment_add_seq_check()
25 * The SMS TP-UD preference "always try subdissection of 1st fragment" allows
26 * a subdissector to be called for the first Short Message fragment,
27 * even if reassembly is not possible. This way partial dissection
28 * is still possible. This preference is switched off by default.
30 * Note on Short Message decoding as CL-WSP
31 * ----------------------------------------
32 * The SMS TP-UD preference "port_number_udh_means_wsp" is switched off
33 * by default. If it is enabled, then any Short Message with a Port Number
34 * UDH will be decoded as CL-WSP if:
35 * - The Short Message is not segmented
36 * - The entire segmented Short Message is reassembled
37 * - It is the 1st segment of an unreassembled Short Message (if the
38 * "always try subdissection of 1st fragment" preference is enabled)
40 * Ethereal - Network traffic analyzer
41 * By Gerald Combs <gerald@ethereal.com>
42 * Copyright 1998 Gerald Combs
44 * This program is free software; you can redistribute it and/or
45 * modify it under the terms of the GNU General Public License
46 * as published by the Free Software Foundation; either version 2
47 * of the License, or (at your option) any later version.
49 * This program is distributed in the hope that it will be useful,
50 * but WITHOUT ANY WARRANTY; without even the implied warranty of
51 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
52 * GNU General Public License for more details.
54 * You should have received a copy of the GNU General Public License
55 * along with this program; if not, write to the Free Software
56 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
70 #include <epan/packet.h>
73 #include "reassemble.h"
75 static void dissect_gsm_sms_ud(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
77 static int proto_gsm_sms_ud = -1;
80 * Short Message fragment handling
82 static int hf_gsm_sms_ud_fragments = -1;
83 static int hf_gsm_sms_ud_fragment = -1;
84 static int hf_gsm_sms_ud_fragment_overlap = -1;
85 static int hf_gsm_sms_ud_fragment_overlap_conflicts = -1;
86 static int hf_gsm_sms_ud_fragment_multiple_tails = -1;
87 static int hf_gsm_sms_ud_fragment_too_long_fragment = -1;
88 static int hf_gsm_sms_ud_fragment_error = -1;
89 static int hf_gsm_sms_ud_reassembled_in = -1;
91 * User Data Header section
93 static int hf_gsm_sms_udh_length = -1;
94 static int hf_gsm_sms_udh_iei = -1;
95 static int hf_gsm_sms_udh_multiple_messages = -1;
96 static int hf_gsm_sms_udh_multiple_messages_msg_id = -1;
97 static int hf_gsm_sms_udh_multiple_messages_msg_parts = -1;
98 static int hf_gsm_sms_udh_multiple_messages_msg_part = -1;
99 static int hf_gsm_sms_udh_ports = -1;
100 static int hf_gsm_sms_udh_ports_src = -1;
101 static int hf_gsm_sms_udh_ports_dst = -1;
103 static gint ett_gsm_sms = -1;
104 static gint ett_udh = -1;
105 static gint ett_udh_ie = -1;
106 static gint ett_gsm_sms_ud_fragment = -1;
107 static gint ett_gsm_sms_ud_fragments = -1;
109 /* Subdissector declarations */
110 static dissector_table_t gsm_sms_dissector_table;
112 /* Short Message reassembly */
113 static GHashTable *sm_fragment_table = NULL;
114 static GHashTable *sm_reassembled_table = NULL;
116 static const fragment_items sm_frag_items = {
117 /* Fragment subtrees */
118 &ett_gsm_sms_ud_fragment,
119 &ett_gsm_sms_ud_fragments,
120 /* Fragment fields */
121 &hf_gsm_sms_ud_fragments,
122 &hf_gsm_sms_ud_fragment,
123 &hf_gsm_sms_ud_fragment_overlap,
124 &hf_gsm_sms_ud_fragment_overlap_conflicts,
125 &hf_gsm_sms_ud_fragment_multiple_tails,
126 &hf_gsm_sms_ud_fragment_too_long_fragment,
127 &hf_gsm_sms_ud_fragment_error,
128 /* Reassembled in field */
129 &hf_gsm_sms_ud_reassembled_in,
131 "Short Message fragments"
134 /* Dissect all SM data as WSP if the UDH contains a Port Number IE */
135 static gboolean port_number_udh_means_wsp = FALSE;
136 /* Always try dissecting the 1st fragment of a SM,
137 * even if it is not reassembled */
138 static gboolean try_dissect_1st_frag = FALSE;
139 /* Prevent subdissectors changing column data */
140 static gboolean prevent_subdissectors_changing_columns = FALSE;
142 static dissector_handle_t wsp_handle;
145 gsm_sms_ud_defragment_init (void)
147 fragment_table_init (&sm_fragment_table);
148 reassembled_table_init(&sm_reassembled_table);
152 * Value-arrays for field-contents
154 /* 3GPP TS 23.040 V6.1.0 (2003-06) */
155 static const value_string vals_udh_iei[] = {
156 { 0x00, "SMS - Concatenated short messages, 8-bit reference number" },
157 { 0x01, "SMS - Special SMS Message Indication" },
158 { 0x02, "Reserved" },
159 { 0x03, "Value not used to avoid misinterpretation as <LF> character" },
160 { 0x04, "SMS - Application port addressing scheme, 8 bit address" },
161 { 0x05, "SMS - Application port addressing scheme, 16 bit address" },
162 { 0x06, "SMS - SMSC Control Parameters" },
163 { 0x07, "SMS - UDH Source Indicator" },
164 { 0x08, "SMS - Concatenated short message, 16-bit reference number" },
165 { 0x09, "SMS - Wireless Control Message Protocol" },
166 { 0x0A, "EMS - Text Formatting" },
167 { 0x0B, "EMS - Predefined Sound" },
168 { 0x0C, "EMS - User Defined Sound (iMelody max 128 bytes)" },
169 { 0x0D, "EMS - Predefined Animation" },
170 { 0x0E, "EMS - Large Animation (16*16 times 4 = 32*4 =128 bytes)" },
171 { 0x0F, "EMS - Small Animation (8*8 times 4 = 8*4 =32 bytes)" },
172 { 0x10, "EMS - Large Picture (32*32 = 128 bytes)" },
173 { 0x11, "EMS - Small Picture (16*16 = 32 bytes)" },
174 { 0x12, "EMS - Variable Picture" },
175 { 0x13, "EMS - User prompt indicator" },
176 { 0x14, "EMS - Extended Object" },
177 { 0x15, "EMS - Reused Extended Object" },
178 { 0x16, "EMS - Compression Control" },
179 { 0x17, "EMS - Object Distribution Indicator" },
180 { 0x18, "EMS - Standard WVG object" },
181 { 0x19, "EMS - Character Size WVG object" },
182 { 0x1A, "EMS - Extended Object Data Request Command" },
183 { 0x20, "SMS - RFC 822 E-Mail Header" },
184 { 0x21, "SMS - Hyperlink format element" },
185 { 0x22, "SMS - Reply Address Element" },
190 /* Parse Short Message, only if UDH present
191 * (otherwise this function is not called).
192 * Call WSP dissector if port matches WSP traffic.
195 parse_gsm_sms_ud_message(proto_tree *sm_tree, tvbuff_t *tvb, packet_info *pinfo,
196 proto_tree *top_tree)
198 tvbuff_t *sm_tvb = NULL;
199 proto_item *subtree, *tree;
200 guint8 udh_len, udh, len;
201 guint sm_len = tvb_reported_length (tvb);
204 /* Multiple Messages UDH */
205 gboolean is_fragmented = FALSE;
206 fragment_data *fd_sm = NULL;
207 guint16 sm_id = 0, frags = 0, frag = 0;
208 gboolean save_fragmented = FALSE, try_gsm_sms_ud_reassemble = FALSE;
209 /* SMS Message reassembly */
210 gboolean reassembled = FALSE;
211 guint32 reassembled_in = 0;
212 /* Port Number UDH */
213 guint16 p_src = 0, p_dst = 0;
214 gboolean ports_available = FALSE;
216 udh_len = tvb_get_guint8(tvb, i++);
217 tree = proto_tree_add_uint(sm_tree, hf_gsm_sms_udh_length, tvb, 0, 1, udh_len);
218 tree = proto_item_add_subtree(tree, ett_udh);
219 while (i < udh_len) {
220 udh = tvb_get_guint8(tvb, i++);
221 len = tvb_get_guint8(tvb, i++);
222 subtree = proto_tree_add_uint(tree, hf_gsm_sms_udh_iei,
223 tvb, i-2, 2+len, udh);
225 case 0x00: /* Multiple messages - 8-bit message ID */
227 sm_id = tvb_get_guint8(tvb, i++);
228 frags = tvb_get_guint8(tvb, i++);
229 frag = tvb_get_guint8(tvb, i++);
231 is_fragmented = TRUE;
232 proto_item_append_text(subtree,
233 ": message %u, part %u of %u", sm_id, frag, frags);
234 subtree = proto_item_add_subtree(subtree,
236 proto_tree_add_uint (subtree,
237 hf_gsm_sms_udh_multiple_messages_msg_id,
239 proto_tree_add_uint (subtree,
240 hf_gsm_sms_udh_multiple_messages_msg_parts,
242 proto_tree_add_uint (subtree,
243 hf_gsm_sms_udh_multiple_messages_msg_part,
246 proto_item_append_text(subtree, " - Invalid format!");
251 case 0x08: /* Multiple messages - 16-bit message ID */
253 sm_id = tvb_get_ntohs(tvb, i); i += 2;
254 frags = tvb_get_guint8(tvb, i++);
255 frag = tvb_get_guint8(tvb, i++);
257 is_fragmented = TRUE;
258 proto_item_append_text(subtree,
259 ": message %u, part %u of %u", sm_id, frag, frags);
260 subtree = proto_item_add_subtree(subtree,
262 proto_tree_add_uint (subtree,
263 hf_gsm_sms_udh_multiple_messages_msg_id,
265 proto_tree_add_uint (subtree,
266 hf_gsm_sms_udh_multiple_messages_msg_parts,
268 proto_tree_add_uint (subtree,
269 hf_gsm_sms_udh_multiple_messages_msg_part,
272 proto_item_append_text(subtree, " - Invalid format!");
277 case 0x04: /* Port Number UDH - 8-bit address */
278 if (len == 2) { /* Port fields */
279 p_dst = tvb_get_guint8(tvb, i++);
280 p_src = tvb_get_guint8(tvb, i++);
281 proto_item_append_text(subtree,
282 ": source port %u, destination port %u",
284 subtree = proto_item_add_subtree(subtree, ett_udh_ie);
285 proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_dst,
287 proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_src,
289 ports_available = TRUE;
291 proto_item_append_text(subtree, " - Invalid format!");
296 case 0x05: /* Port Number UDH - 16-bit address */
297 if (len == 4) { /* Port fields */
298 p_dst = tvb_get_ntohs(tvb, i); i += 2;
299 p_src = tvb_get_ntohs(tvb, i); i += 2;
300 proto_item_append_text(subtree,
301 ": source port %u, destination port %u",
303 subtree = proto_item_add_subtree(subtree, ett_udh_ie);
304 proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_dst,
306 proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_src,
308 ports_available = TRUE;
310 proto_item_append_text(subtree, " - Invalid format!");
320 if (tvb_reported_length_remaining(tvb, i) <= 0)
321 return; /* No more data */
324 * XXX - where does the "1" come from? If it weren't there,
325 * "sm_data_len" would, I think, be the same as
326 * "tvb_reported_length_remaining(tvb, i)".
328 * I think that the above check ensures that "sm_len" won't
329 * be less than or equal to "udh_len", so it ensures that
330 * "sm_len" won't be less than "1 + udh_len", so we don't
331 * have to worry about "sm_data_len" being negative.
333 sm_data_len = sm_len - (1 + udh_len);
334 if (sm_data_len == 0)
335 return; /* no more data */
338 * Try reassembling the packets.
339 * XXX - fragment numbers are 1-origin, but the fragment number
341 * Should we flag a fragmented message with a fragment number field
343 * What if the fragment count is 0? Should we flag that as well?
345 if ( is_fragmented && frag != 0 && frags != 0 &&
346 tvb_bytes_exist (tvb, i, sm_data_len) ) {
347 try_gsm_sms_ud_reassemble = TRUE;
348 save_fragmented = pinfo->fragmented;
349 pinfo->fragmented = TRUE;
350 fd_sm = fragment_add_seq_check (tvb, i, pinfo,
351 sm_id, /* guint32 ID for fragments belonging together */
352 sm_fragment_table, /* list of message fragments */
353 sm_reassembled_table, /* list of reassembled messages */
354 frag-1, /* guint32 fragment sequence number */
355 sm_data_len, /* guint32 fragment length */
356 (frag != frags)); /* More fragments? */
359 reassembled_in = fd_sm->reassembled_in;
361 sm_tvb = process_reassembled_data(tvb, i, pinfo,
362 "Reassembled Short Message", fd_sm, &sm_frag_items,
364 if (reassembled) { /* Reassembled */
365 if (check_col (pinfo->cinfo, COL_INFO))
366 col_append_str (pinfo->cinfo, COL_INFO,
367 " (Short Message Reassembled)");
369 /* Not last packet of reassembled Short Message */
370 if (check_col (pinfo->cinfo, COL_INFO))
371 col_append_fstr (pinfo->cinfo, COL_INFO,
372 " (Short Message fragment %u of %u)", frag, frags);
374 } /* Else: not fragmented */
376 if (! sm_tvb) /* One single Short Message, or not reassembled */
377 sm_tvb = tvb_new_subset (tvb, i, -1, -1);
378 /* Try calling a subdissector */
380 if ((reassembled && pinfo->fd->num == reassembled_in)
381 || frag==0 || (frag==1 && try_dissect_1st_frag)) {
382 /* Try calling a subdissector only if:
383 * - the Short Message is reassembled in this very packet,
384 * - the Short Message consists of only one "fragment",
385 * - the preference "Always Try Dissection for 1st SM fragment"
386 * is switched on, and this is the SM's 1st fragment. */
387 if ( ports_available ) {
388 gboolean disallow_write = FALSE; /* TRUE if we changed writability
389 of the columns of the summary */
390 if ( prevent_subdissectors_changing_columns && col_get_writable(pinfo->cinfo) ) {
391 disallow_write = TRUE;
392 col_set_writable(pinfo->cinfo, FALSE);
395 if ( port_number_udh_means_wsp ) {
396 call_dissector (wsp_handle, sm_tvb, pinfo, top_tree);
398 if (! dissector_try_port(gsm_sms_dissector_table, p_src,
399 sm_tvb, pinfo, top_tree)) {
400 if (! dissector_try_port(gsm_sms_dissector_table, p_dst,
401 sm_tvb, pinfo, top_tree)) {
402 if (sm_tree) { /* Only display if needed */
403 proto_tree_add_text (sm_tree, sm_tvb, 0, -1,
404 "Short Message body");
410 if ( disallow_write )
411 col_set_writable(pinfo->cinfo, TRUE);
412 } else { /* No ports IE */
413 proto_tree_add_text (sm_tree, sm_tvb, 0, -1,
414 "Short Message body");
417 /* The packet is not reassembled,
418 * or it is reassembled in another packet */
419 proto_tree_add_text (sm_tree, sm_tvb, 0, -1,
420 "Unreassembled Short Message fragment %u of %u",
425 if (try_gsm_sms_ud_reassemble) /* Clean up defragmentation */
426 pinfo->fragmented = save_fragmented;
431 dissect_gsm_sms_ud(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
435 ti = proto_tree_add_item(tree, proto_gsm_sms_ud, tvb, 0, -1, TRUE);
436 subtree = proto_item_add_subtree(ti, ett_gsm_sms);
437 parse_gsm_sms_ud_message(subtree, tvb, pinfo, tree);
440 /* Register the protocol with Ethereal */
442 proto_register_gsm_sms_ud(void)
444 module_t *gsm_sms_ud_module; /* Preferences for GSM SMS UD */
446 /* Setup list of header fields */
447 static hf_register_info hf[] = {
451 { &hf_gsm_sms_udh_iei,
452 { "IE Id", "gsm-sms-ud.udh.iei",
453 FT_UINT8, BASE_HEX, VALS(vals_udh_iei), 0x00,
454 "Name of the User Data Header Information Element.",
458 { &hf_gsm_sms_udh_length,
459 { "UDH Length", "gsm-sms-ud.udh.len",
460 FT_UINT8, BASE_DEC, NULL, 0x00,
461 "Length of the User Data Header (bytes)",
465 { &hf_gsm_sms_udh_multiple_messages,
466 { "Multiple messages UDH", "gsm-sms-ud.udh.mm",
467 FT_NONE, BASE_NONE, NULL, 0x00,
468 "Multiple messages User Data Header",
472 { &hf_gsm_sms_udh_multiple_messages_msg_id,
473 { "Message identifier", "gsm-sms-ud.udh.mm.msg_id",
474 FT_UINT16, BASE_DEC, NULL, 0x00,
475 "Identification of the message",
479 { &hf_gsm_sms_udh_multiple_messages_msg_parts,
480 { "Message parts", "gsm-sms-ud.udh.mm.msg_parts",
481 FT_UINT8, BASE_DEC, NULL, 0x00,
482 "Total number of message parts (fragments)",
486 { &hf_gsm_sms_udh_multiple_messages_msg_part,
487 { "Message part number", "gsm-sms-ud.udh.mm.msg_part",
488 FT_UINT8, BASE_DEC, NULL, 0x00,
489 "Message part (fragment) sequence number",
493 { &hf_gsm_sms_udh_ports,
494 { "Port number UDH", "gsm-sms-ud.udh.ports",
495 FT_NONE, BASE_NONE, NULL, 0x00,
496 "Port number User Data Header",
500 { &hf_gsm_sms_udh_ports_src,
501 { "Source port", "gsm-sms-ud.udh.ports.src",
502 FT_UINT8, BASE_DEC, NULL, 0x00,
507 { &hf_gsm_sms_udh_ports_dst,
508 { "Destination port", "gsm-sms-ud.udh.ports.dst",
509 FT_UINT8, BASE_DEC, NULL, 0x00,
515 * Short Message fragment reassembly
517 { &hf_gsm_sms_ud_fragments,
518 { "Short Message fragments", "gsm-sms-ud.fragments",
519 FT_NONE, BASE_NONE, NULL, 0x00,
520 "GSM Short Message fragments",
524 { &hf_gsm_sms_ud_fragment,
525 { "Short Message fragment", "gsm-sms-ud.fragment",
526 FT_FRAMENUM, BASE_NONE, NULL, 0x00,
527 "GSM Short Message fragment",
531 { &hf_gsm_sms_ud_fragment_overlap,
532 { "Short Message fragment overlap", "gsm-sms-ud.fragment.overlap",
533 FT_BOOLEAN, BASE_NONE, NULL, 0x00,
534 "GSM Short Message fragment overlaps with other fragment(s)",
538 { &hf_gsm_sms_ud_fragment_overlap_conflicts,
539 { "Short Message fragment overlapping with conflicting data",
540 "gsm-sms-ud.fragment.overlap.conflicts",
541 FT_BOOLEAN, BASE_NONE, NULL, 0x00,
542 "GSM Short Message fragment overlaps with conflicting data",
546 { &hf_gsm_sms_ud_fragment_multiple_tails,
547 { "Short Message has multiple tail fragments",
548 "gsm-sms-ud.fragment.multiple_tails",
549 FT_BOOLEAN, BASE_NONE, NULL, 0x00,
550 "GSM Short Message fragment has multiple tail fragments",
554 { &hf_gsm_sms_ud_fragment_too_long_fragment,
555 { "Short Message fragment too long",
556 "gsm-sms-ud.fragment.too_long_fragment",
557 FT_BOOLEAN, BASE_NONE, NULL, 0x00,
558 "GSM Short Message fragment data goes beyond the packet end",
562 { &hf_gsm_sms_ud_fragment_error,
563 { "Short Message defragmentation error", "gsm-sms-ud.fragment.error",
564 FT_FRAMENUM, BASE_NONE, NULL, 0x00,
565 "GSM Short Message defragmentation error due to illegal fragments",
569 { &hf_gsm_sms_ud_reassembled_in,
571 "gsm-sms-ud.reassembled.in",
572 FT_FRAMENUM, BASE_NONE, NULL, 0x00,
573 "GSM Short Message has been reassembled in this packet.", HFILL
578 static gint *ett[] = {
582 &ett_gsm_sms_ud_fragment,
583 &ett_gsm_sms_ud_fragments,
585 /* Register the protocol name and description */
586 proto_gsm_sms_ud = proto_register_protocol(
587 "GSM Short Message Service User Data", /* Name */
588 "GSM SMS UD", /* Short name */
589 "gsm-sms-ud"); /* Filter name */
591 /* Required function calls to register header fields and subtrees used */
592 proto_register_field_array(proto_gsm_sms_ud, hf, array_length(hf));
593 proto_register_subtree_array(ett, array_length(ett));
595 /* Subdissector code */
596 gsm_sms_dissector_table = register_dissector_table("gsm-sms-ud.udh.port",
597 "GSM SMS port IE in UDH", FT_UINT16, BASE_DEC);
599 /* Preferences for GSM SMS UD */
600 gsm_sms_ud_module = prefs_register_protocol (proto_gsm_sms_ud, NULL);
601 prefs_register_bool_preference (gsm_sms_ud_module,
602 "port_number_udh_means_wsp",
603 "Port Number IE in UDH always triggers CL-WSP dissection",
604 "Always decode a GSM Short Message as Connectionless WSP "
605 "if a Port Number Information Element is present "
606 "in the SMS User Data Header.",
607 &port_number_udh_means_wsp);
608 prefs_register_bool_preference (gsm_sms_ud_module, "try_dissect_1st_fragment",
609 "Always try subdissection of 1st Short Message fragment",
610 "Always try subdissection of the 1st fragment of a fragmented "
611 "GSM Short Message. If reassembly is possible, the Short Message "
612 "may be dissected twice (once as a short frame, once in its "
614 &try_dissect_1st_frag);
615 prefs_register_bool_preference (gsm_sms_ud_module, "prevent_dissectors_chg_cols",
616 "Prevent sub-dissectors from changing column data",
617 "Prevent sub-dissectors from replacing column data with their "
618 "own. Eg. Prevent WSP dissector overwriting SMPP information.",
619 &prevent_subdissectors_changing_columns);
621 register_dissector("gsm-sms-ud", dissect_gsm_sms_ud, proto_gsm_sms_ud);
623 /* GSM SMS UD dissector initialization routines */
624 register_init_routine (gsm_sms_ud_defragment_init);
628 proto_reg_handoff_gsm_sms_ud(void)
630 dissector_handle_t gsm_sms_ud_handle;
631 gsm_sms_ud_handle = create_dissector_handle(dissect_gsm_sms_ud,
634 wsp_handle = find_dissector("wsp-cl");
635 g_assert(wsp_handle);