2 * Routines for GSM SMS TP-UD (GSM 03.40) dissection
4 * Separated from the SMPP dissector by Chris Wilson <chris@mxtelecom.com>
6 * UDH and WSP dissection of SMS message, Short Message reassembly,
7 * "Decode Short Message with Port Number UDH as CL-WSP" preference,
8 * "Always try subdissection of 1st fragment" preference,
9 * provided by Olivier Biot.
13 * Note on SMS Message reassembly
14 * ------------------------------
15 * The current Short Message reassembly is possible thanks to the
16 * message identifier (8 or 16 bit identifier). It is able to reassemble
17 * short messages that are sent over either the same SMPP connection or
18 * distinct SMPP connections. Normally the reassembly code is able to deal
19 * with duplicate message identifiers since the fragment_add_seq_check()
22 * The SMS TP-UD preference "always try subdissection of 1st fragment" allows
23 * a subdissector to be called for the first Short Message fragment,
24 * even if reassembly is not possible. This way partial dissection
25 * is still possible. This preference is switched off by default.
27 * Note on Short Message decoding as CL-WSP
28 * ----------------------------------------
29 * The SMS TP-UD preference "port_number_udh_means_wsp" is switched off
30 * by default. If it is enabled, then any Short Message with a Port Number
31 * UDH will be decoded as CL-WSP if:
32 * - The Short Message is not segmented
33 * - The entire segmented Short Message is reassembled
34 * - It is the 1st segment of an unreassembled Short Message (if the
35 * "always try subdissection of 1st fragment" preference is enabled)
37 * Ethereal - Network traffic analyzer
38 * By Gerald Combs <gerald@ethereal.com>
39 * Copyright 1998 Gerald Combs
41 * This program is free software; you can redistribute it and/or
42 * modify it under the terms of the GNU General Public License
43 * as published by the Free Software Foundation; either version 2
44 * of the License, or (at your option) any later version.
46 * This program is distributed in the hope that it will be useful,
47 * but WITHOUT ANY WARRANTY; without even the implied warranty of
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49 * GNU General Public License for more details.
51 * You should have received a copy of the GNU General Public License
52 * along with this program; if not, write to the Free Software
53 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
67 #include <epan/packet.h>
70 #include "reassemble.h"
72 static void dissect_gsm_sms_ud(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
74 static int proto_gsm_sms_ud = -1;
77 * Short Message fragment handling
79 static int hf_gsm_sms_ud_fragments = -1;
80 static int hf_gsm_sms_ud_fragment = -1;
81 static int hf_gsm_sms_ud_fragment_overlap = -1;
82 static int hf_gsm_sms_ud_fragment_overlap_conflicts = -1;
83 static int hf_gsm_sms_ud_fragment_multiple_tails = -1;
84 static int hf_gsm_sms_ud_fragment_too_long_fragment = -1;
85 static int hf_gsm_sms_ud_fragment_error = -1;
86 static int hf_gsm_sms_ud_reassembled_in = -1;
88 * User Data Header section
90 static int hf_gsm_sms_udh_length = -1;
91 static int hf_gsm_sms_udh_iei = -1;
92 static int hf_gsm_sms_udh_multiple_messages = -1;
93 static int hf_gsm_sms_udh_multiple_messages_msg_id = -1;
94 static int hf_gsm_sms_udh_multiple_messages_msg_parts = -1;
95 static int hf_gsm_sms_udh_multiple_messages_msg_part = -1;
96 static int hf_gsm_sms_udh_ports = -1;
97 static int hf_gsm_sms_udh_ports_src = -1;
98 static int hf_gsm_sms_udh_ports_dst = -1;
100 static gint ett_gsm_sms = -1;
101 static gint ett_udh = -1;
102 static gint ett_udh_ie = -1;
103 static gint ett_gsm_sms_ud_fragment = -1;
104 static gint ett_gsm_sms_ud_fragments = -1;
106 /* Subdissector declarations */
107 static dissector_table_t gsm_sms_dissector_table;
109 /* Short Message reassembly */
110 static GHashTable *sm_fragment_table = NULL;
111 static GHashTable *sm_reassembled_table = NULL;
113 static const fragment_items sm_frag_items = {
114 /* Fragment subtrees */
115 &ett_gsm_sms_ud_fragment,
116 &ett_gsm_sms_ud_fragments,
117 /* Fragment fields */
118 &hf_gsm_sms_ud_fragments,
119 &hf_gsm_sms_ud_fragment,
120 &hf_gsm_sms_ud_fragment_overlap,
121 &hf_gsm_sms_ud_fragment_overlap_conflicts,
122 &hf_gsm_sms_ud_fragment_multiple_tails,
123 &hf_gsm_sms_ud_fragment_too_long_fragment,
124 &hf_gsm_sms_ud_fragment_error,
125 /* Reassembled in field */
126 &hf_gsm_sms_ud_reassembled_in,
128 "Short Message fragments"
131 /* Dissect all SM data as WSP if the UDH contains a Port Number IE */
132 static gboolean port_number_udh_means_wsp = FALSE;
133 /* Always try dissecting the 1st fragment of a SM,
134 * even if it is not reassembled */
135 static gboolean try_dissect_1st_frag = FALSE;
137 static dissector_handle_t wsp_handle;
140 gsm_sms_ud_defragment_init (void)
142 fragment_table_init (&sm_fragment_table);
143 reassembled_table_init(&sm_reassembled_table);
147 * Value-arrays for field-contents
149 /* 3GPP TS 23.040 V6.1.0 (2003-06) */
150 static const value_string vals_udh_iei[] = {
151 { 0x00, "SMS - Concatenated short messages, 8-bit reference number" },
152 { 0x01, "SMS - Special SMS Message Indication" },
153 { 0x02, "Reserved" },
154 { 0x03, "Value not used to avoid misinterpretation as <LF> character" },
155 { 0x04, "SMS - Application port addressing scheme, 8 bit address" },
156 { 0x05, "SMS - Application port addressing scheme, 16 bit address" },
157 { 0x06, "SMS - SMSC Control Parameters" },
158 { 0x07, "SMS - UDH Source Indicator" },
159 { 0x08, "SMS - Concatenated short message, 16-bit reference number" },
160 { 0x09, "SMS - Wireless Control Message Protocol" },
161 { 0x0A, "EMS - Text Formatting" },
162 { 0x0B, "EMS - Predefined Sound" },
163 { 0x0C, "EMS - User Defined Sound (iMelody max 128 bytes)" },
164 { 0x0D, "EMS - Predefined Animation" },
165 { 0x0E, "EMS - Large Animation (16*16 times 4 = 32*4 =128 bytes)" },
166 { 0x0F, "EMS - Small Animation (8*8 times 4 = 8*4 =32 bytes)" },
167 { 0x10, "EMS - Large Picture (32*32 = 128 bytes)" },
168 { 0x11, "EMS - Small Picture (16*16 = 32 bytes)" },
169 { 0x12, "EMS - Variable Picture" },
170 { 0x13, "EMS - User prompt indicator" },
171 { 0x14, "EMS - Extended Object" },
172 { 0x15, "EMS - Reused Extended Object" },
173 { 0x16, "EMS - Compression Control" },
174 { 0x17, "EMS - Object Distribution Indicator" },
175 { 0x18, "EMS - Standard WVG object" },
176 { 0x19, "EMS - Character Size WVG object" },
177 { 0x1A, "EMS - Extended Object Data Request Command" },
178 { 0x20, "SMS - RFC 822 E-Mail Header" },
179 { 0x21, "SMS - Hyperlink format element" },
180 { 0x22, "SMS - Reply Address Element" },
185 /* Parse Short Message, only if UDH present
186 * (otherwise this function is not called).
187 * Call WSP dissector if port matches WSP traffic.
190 parse_gsm_sms_ud_message(proto_tree *sm_tree, tvbuff_t *tvb, packet_info *pinfo,
191 proto_tree *top_tree)
193 tvbuff_t *sm_tvb = NULL;
194 proto_item *subtree, *tree;
195 guint8 udh_len, udh, len;
196 guint sm_len = tvb_reported_length (tvb);
199 /* Multiple Messages UDH */
200 gboolean is_fragmented = FALSE;
201 fragment_data *fd_sm = NULL;
202 guint16 sm_id = 0, frags = 0, frag = 0;
203 gboolean save_fragmented = FALSE, try_gsm_sms_ud_reassemble = FALSE;
204 /* SMS Message reassembly */
205 gboolean reassembled = FALSE;
206 guint32 reassembled_in = 0;
207 /* Port Number UDH */
208 guint16 p_src = 0, p_dst = 0;
209 gboolean ports_available = FALSE;
211 udh_len = tvb_get_guint8(tvb, i++);
212 printf("udhlen %d\n", udh_len);
213 tree = proto_tree_add_uint(sm_tree, hf_gsm_sms_udh_length, tvb, 0, 1, udh_len);
214 tree = proto_item_add_subtree(tree, ett_udh);
215 while (i < udh_len) {
216 udh = tvb_get_guint8(tvb, i++);
217 len = tvb_get_guint8(tvb, i++);
218 subtree = proto_tree_add_uint(tree, hf_gsm_sms_udh_iei,
219 tvb, i-2, 2+len, udh);
221 case 0x00: /* Multiple messages - 8-bit message ID */
223 is_fragmented = TRUE;
224 sm_id = tvb_get_guint8(tvb, i++);
225 frags = tvb_get_guint8(tvb, i++);
226 frag = tvb_get_guint8(tvb, i++);
227 proto_item_append_text(subtree,
228 ": message %u, part %u of %u", sm_id, frag, frags);
229 subtree = proto_item_add_subtree(subtree,
231 proto_tree_add_uint (subtree,
232 hf_gsm_sms_udh_multiple_messages_msg_id,
234 proto_tree_add_uint (subtree,
235 hf_gsm_sms_udh_multiple_messages_msg_parts,
237 proto_tree_add_uint (subtree,
238 hf_gsm_sms_udh_multiple_messages_msg_part,
241 proto_item_append_text(subtree, " - Invalid format!");
246 case 0x08: /* Multiple messages - 16-bit message ID */
248 is_fragmented = TRUE;
249 sm_id = tvb_get_ntohs(tvb, i); i += 2;
250 frags = tvb_get_guint8(tvb, i++);
251 frag = tvb_get_guint8(tvb, i++);
252 proto_item_append_text(subtree,
253 ": message %u, part %u of %u", sm_id, frag, frags);
254 subtree = proto_item_add_subtree(subtree,
256 proto_tree_add_uint (subtree,
257 hf_gsm_sms_udh_multiple_messages_msg_id,
259 proto_tree_add_uint (subtree,
260 hf_gsm_sms_udh_multiple_messages_msg_parts,
262 proto_tree_add_uint (subtree,
263 hf_gsm_sms_udh_multiple_messages_msg_part,
266 proto_item_append_text(subtree, " - Invalid format!");
271 case 0x04: /* Port Number UDH - 8-bit address */
272 if (len == 2) { /* Port fields */
273 p_dst = tvb_get_guint8(tvb, i++);
274 p_src = tvb_get_guint8(tvb, i++);
275 proto_item_append_text(subtree,
276 ": source port %u, destination port %u",
278 subtree = proto_item_add_subtree(subtree, ett_udh_ie);
279 proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_dst,
281 proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_src,
283 ports_available = TRUE;
285 proto_item_append_text(subtree, " - Invalid format!");
290 case 0x05: /* Port Number UDH - 16-bit address */
291 if (len == 4) { /* Port fields */
292 p_dst = tvb_get_ntohs(tvb, i); i += 2;
293 p_src = tvb_get_ntohs(tvb, i); i += 2;
294 proto_item_append_text(subtree,
295 ": source port %u, destination port %u",
297 subtree = proto_item_add_subtree(subtree, ett_udh_ie);
298 proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_dst,
300 proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_src,
302 ports_available = TRUE;
304 proto_item_append_text(subtree, " - Invalid format!");
314 if (tvb_reported_length_remaining(tvb, i) <= 0)
315 return; /* No more data */
318 * XXX - where does the "1" come from? If it weren't there,
319 * "sm_data_len" would, I think, be the same as
320 * "tvb_reported_length_remaining(tvb, i)".
322 * I think that the above check ensures that "sm_len" won't
323 * be less than or equal to "udh_len", so it ensures that
324 * "sm_len" won't be less than "1 + udh_len", so we don't
325 * have to worry about "sm_data_len" being negative.
327 sm_data_len = sm_len - (1 + udh_len);
328 if (sm_data_len == 0)
329 return; /* no more data */
332 * Try reassembling the packets.
333 * XXX - fragment numbers are 1-origin, but the fragment number
335 * Should we flag a fragmented message with a fragment number field
337 * What if the fragment count is 0? Should we flag that as well?
339 if ( is_fragmented && frag != 0 && frags != 0 &&
340 tvb_bytes_exist (tvb, i, sm_data_len) ) {
341 try_gsm_sms_ud_reassemble = TRUE;
342 save_fragmented = pinfo->fragmented;
343 pinfo->fragmented = TRUE;
344 fd_sm = fragment_add_seq_check (tvb, i, pinfo,
345 sm_id, /* guint32 ID for fragments belonging together */
346 sm_fragment_table, /* list of message fragments */
347 sm_reassembled_table, /* list of reassembled messages */
348 frag-1, /* guint32 fragment sequence number */
349 sm_data_len, /* guint32 fragment length */
350 (frag != frags)); /* More fragments? */
353 reassembled_in = fd_sm->reassembled_in;
355 sm_tvb = process_reassembled_data(tvb, i, pinfo,
356 "Reassembled Short Message", fd_sm, &sm_frag_items,
358 if (reassembled) { /* Reassembled */
359 if (check_col (pinfo->cinfo, COL_INFO))
360 col_append_str (pinfo->cinfo, COL_INFO,
361 " (Short Message Reassembled)");
363 /* Not last packet of reassembled Short Message */
364 if (check_col (pinfo->cinfo, COL_INFO))
365 col_append_fstr (pinfo->cinfo, COL_INFO,
366 " (Short Message fragment %u of %u)", frag, frags);
368 } /* Else: not fragmented */
370 if (! sm_tvb) /* One single Short Message, or not reassembled */
371 sm_tvb = tvb_new_subset (tvb, i, -1, -1);
372 /* Try calling a subdissector */
374 if ((reassembled && pinfo->fd->num == reassembled_in)
375 || frag==0 || (frag==1 && try_dissect_1st_frag)) {
376 /* Try calling a subdissector only if:
377 * - the Short Message is reassembled in this very packet,
378 * - the Short Message consists of only one "fragment",
379 * - the preference "Always Try Dissection for 1st SM fragment"
380 * is switched on, and this is the SM's 1st fragment. */
381 if ( ports_available ) {
382 if ( port_number_udh_means_wsp ) {
383 call_dissector (wsp_handle, sm_tvb, pinfo, top_tree);
385 if (! dissector_try_port(gsm_sms_dissector_table, p_src,
386 sm_tvb, pinfo, top_tree)) {
387 if (! dissector_try_port(gsm_sms_dissector_table, p_dst,
388 sm_tvb, pinfo, top_tree)) {
389 if (sm_tree) { /* Only display if needed */
390 proto_tree_add_text (sm_tree, sm_tvb, 0, -1,
391 "Short Message body");
396 } else { /* No ports IE */
397 proto_tree_add_text (sm_tree, sm_tvb, 0, -1,
398 "Short Message body");
401 /* The packet is not reassembled,
402 * or it is reassembled in another packet */
403 proto_tree_add_text (sm_tree, sm_tvb, 0, -1,
404 "Unreassembled Short Message fragment %u of %u",
409 if (try_gsm_sms_ud_reassemble) /* Clean up defragmentation */
410 pinfo->fragmented = save_fragmented;
415 dissect_gsm_sms_ud(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
419 ti = proto_tree_add_item(tree, proto_gsm_sms_ud, tvb, 0, -1, TRUE);
420 subtree = proto_item_add_subtree(ti, ett_gsm_sms);
421 parse_gsm_sms_ud_message(subtree, tvb, pinfo, tree);
424 /* Register the protocol with Ethereal */
426 proto_register_gsm_sms_ud(void)
428 module_t *gsm_sms_ud_module; /* Preferences for GSM SMS UD */
430 /* Setup list of header fields */
431 static hf_register_info hf[] = {
435 { &hf_gsm_sms_udh_iei,
436 { "IE Id", "gsm-sms-ud.udh.iei",
437 FT_UINT8, BASE_HEX, VALS(vals_udh_iei), 0x00,
438 "Name of the User Data Header Information Element.",
442 { &hf_gsm_sms_udh_length,
443 { "UDH Length", "gsm-sms-ud.udh.len",
444 FT_UINT8, BASE_DEC, NULL, 0x00,
445 "Length of the User Data Header (bytes)",
449 { &hf_gsm_sms_udh_multiple_messages,
450 { "Multiple messages UDH", "gsm-sms-ud.udh.mm",
451 FT_NONE, BASE_NONE, NULL, 0x00,
452 "Multiple messages User Data Header",
456 { &hf_gsm_sms_udh_multiple_messages_msg_id,
457 { "Message identifier", "gsm-sms-ud.udh.mm.msg_id",
458 FT_UINT16, BASE_DEC, NULL, 0x00,
459 "Identification of the message",
463 { &hf_gsm_sms_udh_multiple_messages_msg_parts,
464 { "Message parts", "gsm-sms-ud.udh.mm.msg_parts",
465 FT_UINT8, BASE_DEC, NULL, 0x00,
466 "Total number of message parts (fragments)",
470 { &hf_gsm_sms_udh_multiple_messages_msg_part,
471 { "Message part number", "gsm-sms-ud.udh.mm.msg_part",
472 FT_UINT8, BASE_DEC, NULL, 0x00,
473 "Message part (fragment) sequence number",
477 { &hf_gsm_sms_udh_ports,
478 { "Port number UDH", "gsm-sms-ud.udh.ports",
479 FT_NONE, BASE_NONE, NULL, 0x00,
480 "Port number User Data Header",
484 { &hf_gsm_sms_udh_ports_src,
485 { "Source port", "gsm-sms-ud.udh.ports.src",
486 FT_UINT8, BASE_DEC, NULL, 0x00,
491 { &hf_gsm_sms_udh_ports_dst,
492 { "Destination port", "gsm-sms-ud.udh.ports.dst",
493 FT_UINT8, BASE_DEC, NULL, 0x00,
499 * Short Message fragment reassembly
501 { &hf_gsm_sms_ud_fragments,
502 { "Short Message fragments", "gsm-sms-ud.fragments",
503 FT_NONE, BASE_NONE, NULL, 0x00,
504 "GSM Short Message fragments",
508 { &hf_gsm_sms_ud_fragment,
509 { "Short Message fragment", "gsm-sms-ud.fragment",
510 FT_FRAMENUM, BASE_NONE, NULL, 0x00,
511 "GSM Short Message fragment",
515 { &hf_gsm_sms_ud_fragment_overlap,
516 { "Short Message fragment overlap", "gsm-sms-ud.fragment.overlap",
517 FT_BOOLEAN, BASE_NONE, NULL, 0x00,
518 "GSM Short Message fragment overlaps with other fragment(s)",
522 { &hf_gsm_sms_ud_fragment_overlap_conflicts,
523 { "Short Message fragment overlapping with conflicting data",
524 "gsm-sms-ud.fragment.overlap.conflicts",
525 FT_BOOLEAN, BASE_NONE, NULL, 0x00,
526 "GSM Short Message fragment overlaps with conflicting data",
530 { &hf_gsm_sms_ud_fragment_multiple_tails,
531 { "Short Message has multiple tail fragments",
532 "gsm-sms-ud.fragment.multiple_tails",
533 FT_BOOLEAN, BASE_NONE, NULL, 0x00,
534 "GSM Short Message fragment has multiple tail fragments",
538 { &hf_gsm_sms_ud_fragment_too_long_fragment,
539 { "Short Message fragment too long",
540 "gsm-sms-ud.fragment.too_long_fragment",
541 FT_BOOLEAN, BASE_NONE, NULL, 0x00,
542 "GSM Short Message fragment data goes beyond the packet end",
546 { &hf_gsm_sms_ud_fragment_error,
547 { "Short Message defragmentation error", "gsm-sms-ud.fragment.error",
548 FT_FRAMENUM, BASE_NONE, NULL, 0x00,
549 "GSM Short Message defragmentation error due to illegal fragments",
553 { &hf_gsm_sms_ud_reassembled_in,
555 "gsm-sms-ud.reassembled.in",
556 FT_FRAMENUM, BASE_NONE, NULL, 0x00,
557 "GSM Short Message has been reassembled in this packet.", HFILL
562 static gint *ett[] = {
566 &ett_gsm_sms_ud_fragment,
567 &ett_gsm_sms_ud_fragments,
569 /* Register the protocol name and description */
570 proto_gsm_sms_ud = proto_register_protocol(
571 "GSM Short Message Service User Data", /* Name */
572 "GSM SMS UD", /* Short name */
573 "gsm-sms-ud"); /* Filter name */
575 /* Required function calls to register header fields and subtrees used */
576 proto_register_field_array(proto_gsm_sms_ud, hf, array_length(hf));
577 proto_register_subtree_array(ett, array_length(ett));
579 /* Subdissector code */
580 gsm_sms_dissector_table = register_dissector_table("gsm-sms-ud.udh.port",
581 "GSM SMS port IE in UDH", FT_UINT16, BASE_DEC);
583 /* Preferences for GSM SMS UD */
584 gsm_sms_ud_module = prefs_register_protocol (proto_gsm_sms_ud, NULL);
585 prefs_register_bool_preference (gsm_sms_ud_module,
586 "port_number_udh_means_wsp",
587 "Port Number IE in UDH always triggers CL-WSP dissection",
588 "Always decode a GSM Short Message as Connectionless WSP "
589 "if a Port Number Information Element is present "
590 "in the SMS User Data Header.",
591 &port_number_udh_means_wsp);
592 prefs_register_bool_preference (gsm_sms_ud_module, "try_dissect_1st_fragment",
593 "Always try subdissection of 1st Short Message fragment",
594 "Always try subdissection of the 1st fragment of a fragmented "
595 "GSM Short Message. If reassembly is possible, the Short Message "
596 "may be dissected twice (once as a short frame, once in its "
598 &try_dissect_1st_frag);
600 register_dissector("gsm-sms-ud", dissect_gsm_sms_ud, proto_gsm_sms_ud);
602 /* GSM SMS UD dissector initialization routines */
603 register_init_routine (gsm_sms_ud_defragment_init);
607 proto_reg_handoff_gsm_sms_ud(void)
609 dissector_handle_t gsm_sms_ud_handle;
610 gsm_sms_ud_handle = create_dissector_handle(dissect_gsm_sms_ud,