add details for doxygen, various code cleanups as a result of this
[obnox/wireshark/wip.git] / packet-gsm_sms_ud.c
1 /* packet-gsm_sms_ud.c
2  * Routines for GSM SMS TP-UD (GSM 03.40) dissection
3  *
4  * $Id: packet-gsm_sms_ud.c,v 1.5 2004/01/29 21:19:10 obiot Exp $
5  *
6  * Refer to the AUTHORS file or the AUTHORS section in the man page
7  * for contacting the author(s) of this file.
8  *
9  * Separated from the SMPP dissector by Chris Wilson.
10  *
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.
15  *
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()
23  *   call is used.
24  *
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.
29  *
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)
39  *
40  * Ethereal - Network traffic analyzer
41  * By Gerald Combs <gerald@ethereal.com>
42  * Copyright 1998 Gerald Combs
43  *
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.
48  *
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.
53  *
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.
57  */
58
59 #ifdef HAVE_CONFIG_H
60 # include "config.h"
61 #endif
62
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <time.h>
67
68 #include <glib.h>
69
70 #include <epan/packet.h>
71
72 #include "prefs.h"
73 #include "reassemble.h"
74
75 static void dissect_gsm_sms_ud(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
76
77 static int proto_gsm_sms_ud = -1;
78
79 /*
80  * Short Message fragment handling
81  */
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;
90 /*
91  * User Data Header section
92  */
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;
102
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;
108
109 /* Subdissector declarations */
110 static dissector_table_t gsm_sms_dissector_table;
111
112 /* Short Message reassembly */
113 static GHashTable *sm_fragment_table = NULL;
114 static GHashTable *sm_reassembled_table = NULL;
115
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,
130         /* Tag */
131         "Short Message fragments"
132 };
133
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;
141
142 static dissector_handle_t wsp_handle;
143
144 static void
145 gsm_sms_ud_defragment_init (void)
146 {
147         fragment_table_init (&sm_fragment_table);
148         reassembled_table_init(&sm_reassembled_table);
149 }
150
151 /*
152  * Value-arrays for field-contents
153  */
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" },
186         { 0x00, NULL }
187 };
188
189
190 /* Parse Short Message, only if UDH present
191  * (otherwise this function is not called).
192  * Call WSP dissector if port matches WSP traffic.
193  */
194 static void
195 parse_gsm_sms_ud_message(proto_tree *sm_tree, tvbuff_t *tvb, packet_info *pinfo,
196                 proto_tree *top_tree)
197 {
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);
202         guint sm_data_len;
203         guint32 i = 0;
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;
215
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);
224                 switch (udh) {
225                         case 0x00: /* Multiple messages - 8-bit message ID */
226                                 if (len == 3) {
227                                         sm_id = tvb_get_guint8(tvb, i++);
228                                         frags = tvb_get_guint8(tvb, i++);
229                                         frag  = tvb_get_guint8(tvb, i++);
230                                         if (frags > 1)
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,
235                                                         ett_udh_ie);
236                                         proto_tree_add_uint (subtree,
237                                                         hf_gsm_sms_udh_multiple_messages_msg_id,
238                                                         tvb, i-3, 1, sm_id);
239                                         proto_tree_add_uint (subtree,
240                                                         hf_gsm_sms_udh_multiple_messages_msg_parts,
241                                                         tvb, i-2, 1, frags);
242                                         proto_tree_add_uint (subtree,
243                                                         hf_gsm_sms_udh_multiple_messages_msg_part,
244                                                         tvb, i-1, 1, frag);
245                                 } else {
246                                         proto_item_append_text(subtree, " - Invalid format!");
247                                         i += len;
248                                 }
249                                 break;
250
251                         case 0x08: /* Multiple messages - 16-bit message ID */
252                                 if (len == 4) {
253                                         sm_id = tvb_get_ntohs(tvb, i); i += 2;
254                                         frags = tvb_get_guint8(tvb, i++);
255                                         frag  = tvb_get_guint8(tvb, i++);
256                                         if (frags > 1)
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,
261                                                         ett_udh_ie);
262                                         proto_tree_add_uint (subtree,
263                                                         hf_gsm_sms_udh_multiple_messages_msg_id,
264                                                         tvb, i-4, 2, sm_id);
265                                         proto_tree_add_uint (subtree,
266                                                         hf_gsm_sms_udh_multiple_messages_msg_parts,
267                                                         tvb, i-2, 1, frags);
268                                         proto_tree_add_uint (subtree,
269                                                         hf_gsm_sms_udh_multiple_messages_msg_part,
270                                                         tvb, i-1, 1, frag);
271                                 } else {
272                                         proto_item_append_text(subtree, " - Invalid format!");
273                                         i += len;
274                                 }
275                                 break;
276
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",
283                                                         p_src, p_dst);
284                                         subtree = proto_item_add_subtree(subtree, ett_udh_ie);
285                                         proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_dst,
286                                                         tvb, i-2, 1, p_dst);
287                                         proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_src,
288                                                         tvb, i-1, 1, p_src);
289                                         ports_available = TRUE;
290                                 } else {
291                                         proto_item_append_text(subtree, " - Invalid format!");
292                                         i += len;
293                                 }
294                                 break;
295
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",
302                                                         p_src, p_dst);
303                                         subtree = proto_item_add_subtree(subtree, ett_udh_ie);
304                                         proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_dst,
305                                                         tvb, i-4, 2, p_dst);
306                                         proto_tree_add_uint (subtree, hf_gsm_sms_udh_ports_src,
307                                                         tvb, i-2, 2, p_src);
308                                         ports_available = TRUE;
309                                 } else {
310                                         proto_item_append_text(subtree, " - Invalid format!");
311                                         i += len;
312                                 }
313                                 break;
314
315                         default:
316                                 i += len;
317                                 break;
318                 }
319         }
320         if (tvb_reported_length_remaining(tvb, i) <= 0)
321                 return; /* No more data */
322
323         /*
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)".
327          *
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.
332          */
333         sm_data_len = sm_len - (1 + udh_len);
334         if (sm_data_len == 0)
335                 return; /* no more data */
336
337         /*
338          * Try reassembling the packets.
339          * XXX - fragment numbers are 1-origin, but the fragment number
340          * field could be 0.
341          * Should we flag a fragmented message with a fragment number field
342          * of 0?
343          * What if the fragment count is 0?  Should we flag that as well?
344          */
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? */
357                 if (fd_sm) {
358                         reassembled = TRUE;
359                         reassembled_in = fd_sm->reassembled_in;
360                 }
361                 sm_tvb = process_reassembled_data(tvb, i, pinfo,
362                     "Reassembled Short Message", fd_sm, &sm_frag_items,
363                     NULL, sm_tree);
364                 if (reassembled) { /* Reassembled */
365                         if (check_col (pinfo->cinfo, COL_INFO))
366                                 col_append_str (pinfo->cinfo, COL_INFO,
367                                                 " (Short Message Reassembled)");
368                 } else {
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);
373                 }
374         } /* Else: not fragmented */
375
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 */
379         if (sm_tvb) {
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);
393                                 }                               
394
395                                 if ( port_number_udh_means_wsp ) {
396                                         call_dissector (wsp_handle, sm_tvb, pinfo, top_tree);
397                                 } else {
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");
405                                                         }
406                                                 }
407                                         }
408                                 }
409                                 
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");
415                         }
416                 } else {
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",
421                                         frag, frags);
422                 }
423         }
424
425         if (try_gsm_sms_ud_reassemble) /* Clean up defragmentation */
426                 pinfo->fragmented = save_fragmented;
427         return;
428 }
429
430 static void
431 dissect_gsm_sms_ud(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
432 {
433         proto_item *ti;
434         proto_tree *subtree;
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);
438 }
439
440 /* Register the protocol with Ethereal */
441 void
442 proto_register_gsm_sms_ud(void)
443 {
444         module_t *gsm_sms_ud_module; /* Preferences for GSM SMS UD */
445
446     /* Setup list of header fields      */
447     static hf_register_info hf[] = {
448         /*
449          * User Data Header
450          */
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.",
455                 HFILL
456                 }
457         },
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)",
462                 HFILL
463             }
464         },
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",
469                 HFILL
470             }
471         },
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",
476                 HFILL
477             }
478         },
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)",
483                 HFILL
484             }
485         },
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",
490                 HFILL
491             }
492         },
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",
497                 HFILL
498             }
499         },
500         {   &hf_gsm_sms_udh_ports_src,
501             {   "Source port", "gsm-sms-ud.udh.ports.src",
502                 FT_UINT8, BASE_DEC, NULL, 0x00,
503                 "Source port",
504                 HFILL
505             }
506         },
507         {   &hf_gsm_sms_udh_ports_dst,
508             {   "Destination port", "gsm-sms-ud.udh.ports.dst",
509                 FT_UINT8, BASE_DEC, NULL, 0x00,
510                 "Destination port",
511                 HFILL
512             }
513         },
514         /*
515          * Short Message fragment reassembly
516          */
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",
521                         HFILL
522                 }
523         },
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",
528                         HFILL
529                 }
530         },
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)",
535                         HFILL
536                 }
537         },
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",
543                         HFILL
544                 }
545         },
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",
551                         HFILL
552                 }
553         },
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",
559                         HFILL
560                 }
561         },
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",
566                         HFILL
567                 }
568         },
569         {       &hf_gsm_sms_ud_reassembled_in,
570                 {       "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
574                 }
575         },
576         };
577
578     static gint *ett[] = {
579         &ett_gsm_sms,
580         &ett_udh,
581         &ett_udh_ie,
582         &ett_gsm_sms_ud_fragment,
583         &ett_gsm_sms_ud_fragments,
584     };
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 */
590
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));
594
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);
598
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 "
613             "entirety).",
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);
620
621     register_dissector("gsm-sms-ud", dissect_gsm_sms_ud, proto_gsm_sms_ud);
622
623     /* GSM SMS UD dissector initialization routines */
624     register_init_routine (gsm_sms_ud_defragment_init);
625 }
626
627 void
628 proto_reg_handoff_gsm_sms_ud(void)
629 {
630         dissector_handle_t gsm_sms_ud_handle;
631         gsm_sms_ud_handle = create_dissector_handle(dissect_gsm_sms_ud,
632                         proto_gsm_sms_ud);
633                         
634         wsp_handle = find_dissector("wsp-cl");
635         g_assert(wsp_handle);
636 }
637
638
639