1 /* packet-gsm_sms_ud.c
2  * Routines for GSM SMS TP-UD (GSM 03.40) dissection
3  *
4  * Refer to the AUTHORS file or the AUTHORS section in the man page
5  * for contacting the author(s) of this file.
6  *
7  * Separated from the SMPP dissector by Chris Wilson.
8  *
9  * UDH and WSP dissection of SMS message, Short Message reassembly,
10  * "Decode Short Message with Port Number UDH as CL-WSP" preference,
11  * "Always try subdissection of 1st fragment" preference,
12  * provided by Olivier Biot.
13  *
14  * Note on SMS Message reassembly
15  * ------------------------------
16  *   The current Short Message reassembly is possible thanks to the
17  *   message identifier (8 or 16 bit identifier). It is able to reassemble
18  *   short messages that are sent over either the same SMPP connection or
19  *   distinct SMPP connections. Normally the reassembly code is able to deal
20  *   with duplicate message identifiers since the fragment_add_seq_check()
21  *   call is used.
22  *
23  *   The SMS TP-UD preference "always try subdissection of 1st fragment" allows
24  *   a subdissector to be called for the first Short Message fragment,
25  *   even if reassembly is not possible. This way partial dissection
26  *   is still possible. This preference is switched off by default.
27  *
28  * Note on Short Message decoding as CL-WSP
29  * ----------------------------------------
30  *    The SMS TP-UD preference "port_number_udh_means_wsp" is switched off
31  *    by default. If it is enabled, then any Short Message with a Port Number
32  *    UDH will be decoded as CL-WSP if:
33  *    -  The Short Message is not segmented
34  *    -  The entire segmented Short Message is reassembled
35  *    -  It is the 1st segment of an unreassembled Short Message (if the
36  *       "always try subdissection of 1st fragment" preference is enabled)
37  *
38  * Wireshark - Network traffic analyzer
39  * By Gerald Combs <gerald@wireshark.org>
40  * Copyright 1998 Gerald Combs
41  *
42  * SPDX-License-Identifier: GPL-2.0-or-later
43  */
44 
45 #include "config.h"
46 
47 #include <epan/packet.h>
48 
49 #include <epan/prefs.h>
50 #include <epan/reassemble.h>
51 
52 void proto_register_gsm_sms_ud(void);
53 void proto_reg_handoff_gsm_sms_ud(void);
54 
55 static int proto_gsm_sms_ud = -1;
56 
57 /*
58  * Short Message fragment handling
59  */
60 static int hf_gsm_sms_ud_fragments = -1;
61 static int hf_gsm_sms_ud_fragment = -1;
62 static int hf_gsm_sms_ud_fragment_overlap = -1;
63 static int hf_gsm_sms_ud_fragment_overlap_conflicts = -1;
64 static int hf_gsm_sms_ud_fragment_multiple_tails = -1;
65 static int hf_gsm_sms_ud_fragment_too_long_fragment = -1;
66 static int hf_gsm_sms_ud_fragment_error = -1;
67 static int hf_gsm_sms_ud_fragment_count = -1;
68 static int hf_gsm_sms_ud_reassembled_in = -1;
69 static int hf_gsm_sms_ud_reassembled_length = -1;
70 static int hf_gsm_sms_ud_short_msg = -1;
71 /*
72  * User Data Header section
73  */
74 static int hf_gsm_sms_udh_length = -1;
75 static int hf_gsm_sms_udh_iei = -1;
76 /* static int hf_gsm_sms_udh_multiple_messages = -1; */
77 static int hf_gsm_sms_udh_multiple_messages_msg_id = -1;
78 static int hf_gsm_sms_udh_multiple_messages_msg_parts = -1;
79 static int hf_gsm_sms_udh_multiple_messages_msg_part = -1;
80 /* static int hf_gsm_sms_udh_ports = -1; */
81 static int hf_gsm_sms_udh_ports_src = -1;
82 static int hf_gsm_sms_udh_ports_dst = -1;
83 static int hf_gsm_sms_udh_national_single_shift = -1;
84 static int hf_gsm_sms_udh_national_locking_shift = -1;
85 
86 static gint ett_gsm_sms = -1;
87 static gint ett_udh = -1;
88 static gint ett_udh_ie = -1;
89 static gint ett_gsm_sms_ud_fragment = -1;
90 static gint ett_gsm_sms_ud_fragments = -1;
91 
92 /* Subdissector declarations */
93 static dissector_table_t gsm_sms_dissector_table;
94 
95 /* Short Message reassembly */
96 static reassembly_table sm_reassembly_table;
97 
98 static const fragment_items sm_frag_items = {
99     /* Fragment subtrees */
100     &ett_gsm_sms_ud_fragment,
101     &ett_gsm_sms_ud_fragments,
102     /* Fragment fields */
103     &hf_gsm_sms_ud_fragments,
104     &hf_gsm_sms_ud_fragment,
105     &hf_gsm_sms_ud_fragment_overlap,
106     &hf_gsm_sms_ud_fragment_overlap_conflicts,
107     &hf_gsm_sms_ud_fragment_multiple_tails,
108     &hf_gsm_sms_ud_fragment_too_long_fragment,
109     &hf_gsm_sms_ud_fragment_error,
110     &hf_gsm_sms_ud_fragment_count,
111     /* Reassembled in field */
112     &hf_gsm_sms_ud_reassembled_in,
113     /* Reassembled length field */
114     &hf_gsm_sms_ud_reassembled_length,
115     /* Reassembled data field */
116     NULL,
117     /* Tag */
118     "Short Message fragments"
119 };
120 
121 /* Dissect all SM data as WSP if the UDH contains a Port Number IE */
122 static gboolean port_number_udh_means_wsp = FALSE;
123 
124 /* Always try dissecting the 1st fragment of a SM,
125  * even if it is not reassembled */
126 static gboolean try_dissect_1st_frag = FALSE;
127 
128 /* Prevent subdissectors changing column data */
129 static gboolean prevent_subdissectors_changing_columns = FALSE;
130 
131 static dissector_handle_t wsp_handle;
132 
133 /*
134  * Value-arrays for field-contents
135  */
136 /* 3GPP TS 23.040 V12.2.0 (2014-10) */
137 static const value_string vals_udh_iei[] = {
138     { 0x00, "SMS - Concatenated short messages, 8-bit reference number" },
139     { 0x01, "SMS - Special SMS Message Indication" },
140     { 0x02, "Reserved" },
141     { 0x03, "Value not used to avoid misinterpretation as <LF> character" },
142     { 0x04, "SMS - Application port addressing scheme, 8 bit address" },
143     { 0x05, "SMS - Application port addressing scheme, 16 bit address" },
144     { 0x06, "SMS - SMSC Control Parameters" },
145     { 0x07, "SMS - UDH Source Indicator" },
146     { 0x08, "SMS - Concatenated short message, 16-bit reference number" },
147     { 0x09, "SMS - Wireless Control Message Protocol" },
148     { 0x0A, "EMS - Text Formatting" },
149     { 0x0B, "EMS - Predefined Sound" },
150     { 0x0C, "EMS - User Defined Sound (iMelody max 128 bytes)" },
151     { 0x0D, "EMS - Predefined Animation" },
152     { 0x0E, "EMS - Large Animation (16*16 times 4 = 32*4 =128 bytes)" },
153     { 0x0F, "EMS - Small Animation (8*8 times 4 = 8*4 =32 bytes)" },
154     { 0x10, "EMS - Large Picture (32*32 = 128 bytes)" },
155     { 0x11, "EMS - Small Picture (16*16 = 32 bytes)" },
156     { 0x12, "EMS - Variable Picture" },
157     { 0x13, "EMS - User prompt indicator" },
158     { 0x14, "EMS - Extended Object" },
159     { 0x15, "EMS - Reused Extended Object" },
160     { 0x16, "EMS - Compression Control" },
161     { 0x17, "EMS - Object Distribution Indicator" },
162     { 0x18, "EMS - Standard WVG object" },
163     { 0x19, "EMS - Character Size WVG object" },
164     { 0x1A, "EMS - Extended Object Data Request Command" },
165     { 0x20, "SMS - RFC 822 E-Mail Header" },
166     { 0x21, "SMS - Hyperlink format element" },
167     { 0x22, "SMS - Reply Address Element" },
168     { 0x23, "SMS - Enhanced Voice Mail Information" },
169     { 0x24, "SMS - National Language Single Shift" },
170     { 0x25, "SMS - National Language Locking Shift" },
171     { 0x00, NULL }
172 };
173 
174 /* 3GPP TS 23.038 V12.0.0 (2014-10) */
175 static const value_string vals_udh_national_languages_single_shift[] = {
176     { 0x01, "Turkish" },
177     { 0x02, "Spanish" },
178     { 0x03, "Portuguese" },
179     { 0x04, "Bengali" },
180     { 0x05, "Gujarati" },
181     { 0x06, "Hindi" },
182     { 0x07, "Kannada" },
183     { 0x08, "Malayalam" },
184     { 0x09, "Oriya" },
185     { 0x0A, "Punjabi" },
186     { 0x0B, "Tamil" },
187     { 0x0C, "Telugu" },
188     { 0x0D, "Urdu" },
189     { 0x00, NULL }
190 };
191 
192 static const value_string vals_udh_national_languages_locking_shift[] = {
193     { 0x01, "Turkish" },
194     { 0x03, "Portuguese" },
195     { 0x04, "Bengali" },
196     { 0x05, "Gujarati" },
197     { 0x06, "Hindi" },
198     { 0x07, "Kannada" },
199     { 0x08, "Malayalam" },
200     { 0x09, "Oriya" },
201     { 0x0A, "Punjabi" },
202     { 0x0B, "Tamil" },
203     { 0x0C, "Telugu" },
204     { 0x0D, "Urdu" },
205     { 0x00, NULL }
206 };
207 
208 /* Parse Short Message, only if UDH present
209  * (otherwise this function is not called).
210  * Call WSP dissector if port matches WSP traffic.
211  */
212 static void
parse_gsm_sms_ud_message(proto_tree * sm_tree,tvbuff_t * tvb,packet_info * pinfo,proto_tree * top_tree)213 parse_gsm_sms_ud_message(proto_tree *sm_tree, tvbuff_t *tvb, packet_info *pinfo,
214         proto_tree *top_tree)
215 {
216     tvbuff_t      *sm_tvb                    = NULL;
217     proto_item    *ti;
218     proto_tree    *subtree, *tree;
219     guint8         udh_len, udh, len;
220     guint          sm_len                    = tvb_reported_length(tvb);
221     guint          sm_data_len;
222     guint32        i                         = 0;
223     /* Multiple Messages UDH */
224     gboolean       is_fragmented             = FALSE;
225     fragment_head *fd_sm                     = NULL;
226     guint16        sm_id                     = 0;
227     guint16        frags                     = 0;
228     guint16        frag                      = 0;
229     gboolean       save_fragmented           = FALSE;
230     gboolean       try_gsm_sms_ud_reassemble = FALSE;
231     /* SMS Message reassembly */
232     gboolean       reassembled               = FALSE;
233     guint32        reassembled_in            = 0;
234     /* Port Number UDH */
235     guint16        p_src                     = 0;
236     guint16        p_dst                     = 0;
237     gboolean       ports_available           = FALSE;
238 
239     udh_len = tvb_get_guint8(tvb, i++);
240     ti   = proto_tree_add_uint(sm_tree, hf_gsm_sms_udh_length, tvb, 0, 1, udh_len);
241     tree = proto_item_add_subtree(ti, ett_udh);
242     while (i < udh_len) {
243         udh = tvb_get_guint8(tvb, i++);
244         len = tvb_get_guint8(tvb, i++);
245         subtree = proto_tree_add_uint(tree, hf_gsm_sms_udh_iei,
246                 tvb, i-2, 2+len, udh);
247         switch (udh) {
248             case 0x00: /* Multiple messages - 8-bit message ID */
249                 if (len == 3) {
250                     sm_id = tvb_get_guint8(tvb, i++);
251                     frags = tvb_get_guint8(tvb, i++);
252                     frag  = tvb_get_guint8(tvb, i++);
253                     if (frags > 1)
254                         is_fragmented = TRUE;
255                     proto_item_append_text(subtree,
256                             ": message %u, part %u of %u", sm_id, frag, frags);
257                     subtree = proto_item_add_subtree(subtree,
258                             ett_udh_ie);
259                     proto_tree_add_uint(subtree,
260                             hf_gsm_sms_udh_multiple_messages_msg_id,
261                             tvb, i-3, 1, sm_id);
262                     proto_tree_add_uint(subtree,
263                             hf_gsm_sms_udh_multiple_messages_msg_parts,
264                             tvb, i-2, 1, frags);
265                     proto_tree_add_uint(subtree,
266                             hf_gsm_sms_udh_multiple_messages_msg_part,
267                             tvb, i-1, 1, frag);
268                 } else {
269                     proto_item_append_text(subtree, " - Invalid format!");
270                     i += len;
271                 }
272                 break;
273 
274             case 0x08: /* Multiple messages - 16-bit message ID */
275                 if (len == 4) {
276                     sm_id = tvb_get_ntohs(tvb, i); i += 2;
277                     frags = tvb_get_guint8(tvb, i++);
278                     frag  = tvb_get_guint8(tvb, i++);
279                     if (frags > 1)
280                         is_fragmented = TRUE;
281                     proto_item_append_text(subtree,
282                             ": message %u, part %u of %u", sm_id, frag, frags);
283                     subtree = proto_item_add_subtree(subtree,
284                             ett_udh_ie);
285                     proto_tree_add_uint(subtree,
286                             hf_gsm_sms_udh_multiple_messages_msg_id,
287                             tvb, i-4, 2, sm_id);
288                     proto_tree_add_uint(subtree,
289                             hf_gsm_sms_udh_multiple_messages_msg_parts,
290                             tvb, i-2, 1, frags);
291                     proto_tree_add_uint(subtree,
292                             hf_gsm_sms_udh_multiple_messages_msg_part,
293                             tvb, i-1, 1, frag);
294                 } else {
295                     proto_item_append_text(subtree, " - Invalid format!");
296                     i += len;
297                 }
298                 break;
299 
300             case 0x04: /* Port Number UDH - 8-bit address */
301                 if (len == 2) { /* Port fields */
302                     p_dst = tvb_get_guint8(tvb, i++);
303                     p_src = tvb_get_guint8(tvb, i++);
304                     proto_item_append_text(subtree,
305                             ": source port %u, destination port %u",
306                             p_src, p_dst);
307                     subtree = proto_item_add_subtree(subtree, ett_udh_ie);
308                     proto_tree_add_uint(subtree, hf_gsm_sms_udh_ports_dst,
309                             tvb, i-2, 1, p_dst);
310                     proto_tree_add_uint(subtree, hf_gsm_sms_udh_ports_src,
311                             tvb, i-1, 1, p_src);
312                     ports_available = TRUE;
313                 } else {
314                     proto_item_append_text(subtree, " - Invalid format!");
315                     i += len;
316                 }
317                 break;
318 
319             case 0x05: /* Port Number UDH - 16-bit address */
320                 if (len == 4) { /* Port fields */
321                     p_dst = tvb_get_ntohs(tvb, i); i += 2;
322                     p_src = tvb_get_ntohs(tvb, i); i += 2;
323                     proto_item_append_text(subtree,
324                             ": source port %u, destination port %u",
325                             p_src, p_dst);
326                     subtree = proto_item_add_subtree(subtree, ett_udh_ie);
327                     proto_tree_add_uint(subtree, hf_gsm_sms_udh_ports_dst,
328                             tvb, i-4, 2, p_dst);
329                     proto_tree_add_uint(subtree, hf_gsm_sms_udh_ports_src,
330                             tvb, i-2, 2, p_src);
331                     ports_available = TRUE;
332                 } else {
333                     proto_item_append_text(subtree, " - Invalid format!");
334                     i += len;
335                 }
336                 break;
337 
338             case 0x24: /* National Language Single Shift */
339                 if (len == 1) {
340                     subtree = proto_item_add_subtree(subtree, ett_udh_ie);
341                     proto_tree_add_item(subtree,
342                             hf_gsm_sms_udh_national_single_shift,
343                             tvb, i++, 1, ENC_BIG_ENDIAN);
344                 } else {
345                     proto_item_append_text(subtree, " - Invalid format!");
346                     i += len;
347                 }
348                 break;
349 
350             case 0x25: /* National Language Locking Shift */
351                 if (len == 1) {
352                     subtree = proto_item_add_subtree(subtree, ett_udh_ie);
353                     proto_tree_add_item(subtree,
354                             hf_gsm_sms_udh_national_locking_shift,
355                             tvb, i++, 1, ENC_BIG_ENDIAN);
356                 } else {
357                     proto_item_append_text(subtree, " - Invalid format!");
358                     i += len;
359                 }
360                 break;
361 
362             default:
363                 i += len;
364                 break;
365         }
366     }
367     if (tvb_reported_length_remaining(tvb, i) <= 0)
368         return; /* No more data */
369 
370     /*
371      * XXX - where does the "1" come from?  If it weren't there,
372      * "sm_data_len" would, I think, be the same as
373      * "tvb_reported_length_remaining(tvb, i)".
374      *
375      * I think that the above check ensures that "sm_len" won't
376      * be less than or equal to "udh_len", so it ensures that
377      * "sm_len" won't be less than "1 + udh_len", so we don't
378      * have to worry about "sm_data_len" being negative.
379      */
380     sm_data_len = sm_len - (1 + udh_len);
381     if (sm_data_len == 0)
382         return; /* no more data */
383 
384     /*
385      * Try reassembling the packets.
386      * XXX - fragment numbers are 1-origin, but the fragment number
387      * field could be 0.
388      * Should we flag a fragmented message with a fragment number field
389      * of 0?
390      * What if the fragment count is 0?  Should we flag that as well?
391      */
392     if (is_fragmented && frag != 0 && frags != 0 &&
393         tvb_bytes_exist(tvb, i, sm_data_len)) {
394         try_gsm_sms_ud_reassemble = TRUE;
395         save_fragmented = pinfo->fragmented;
396         pinfo->fragmented = TRUE;
397         fd_sm = fragment_add_seq_check(&sm_reassembly_table,
398                 tvb, i,
399                 pinfo,
400                 sm_id,                /* guint32 ID for fragments belonging together */
401                 NULL,
402                 frag-1,               /* guint32 fragment sequence number */
403                 sm_data_len,          /* guint32 fragment length */
404                 (frag != frags));     /* More fragments? */
405         if (fd_sm) {
406             reassembled    = TRUE;
407             reassembled_in = fd_sm->reassembled_in;
408         }
409         sm_tvb = process_reassembled_data(tvb, i, pinfo,
410             "Reassembled Short Message", fd_sm, &sm_frag_items,
411             NULL, sm_tree);
412         if (reassembled) { /* Reassembled */
413             col_append_str(pinfo->cinfo, COL_INFO,
414                         " (Short Message Reassembled)");
415         } else {
416             /* Not last packet of reassembled Short Message */
417             col_append_fstr(pinfo->cinfo, COL_INFO,
418                     " (Short Message fragment %u of %u)", frag, frags);
419         }
420     } /* Else: not fragmented */
421 
422     if (! sm_tvb) /* One single Short Message, or not reassembled */
423         sm_tvb = tvb_new_subset_remaining(tvb, i);
424     /* Try calling a subdissector */
425     if (sm_tvb) {
426         if ((reassembled && pinfo->num == reassembled_in)
427             || frag==0 || (frag==1 && try_dissect_1st_frag)) {
428             /* Try calling a subdissector only if:
429              *  - the Short Message is reassembled in this very packet,
430              *  - the Short Message consists of only one "fragment",
431              *  - the preference "Always Try Dissection for 1st SM fragment"
432              *    is switched on, and this is the SM's 1st fragment. */
433             if (ports_available) {
434                 gboolean disallow_write = FALSE; /* TRUE if we changed writability
435                                     of the columns of the summary */
436                 if (prevent_subdissectors_changing_columns && col_get_writable(pinfo->cinfo, -1)) {
437                     disallow_write = TRUE;
438                     col_set_writable(pinfo->cinfo, -1, FALSE);
439                 }
440 
441                 if (port_number_udh_means_wsp) {
442                     call_dissector(wsp_handle, sm_tvb, pinfo, top_tree);
443                 } else {
444                     if (! dissector_try_uint(gsm_sms_dissector_table, p_src,
445                                 sm_tvb, pinfo, top_tree)) {
446                         if (! dissector_try_uint(gsm_sms_dissector_table, p_dst,
447                                     sm_tvb, pinfo, top_tree)) {
448                             if (sm_tree) { /* Only display if needed */
449                                 proto_tree_add_item(sm_tree, hf_gsm_sms_ud_short_msg, sm_tvb, 0, -1, ENC_NA);
450                             }
451                         }
452                     }
453                 }
454 
455                 if (disallow_write)
456                     col_set_writable(pinfo->cinfo, -1, TRUE);
457             } else { /* No ports IE */
458                 proto_tree_add_item(sm_tree, hf_gsm_sms_ud_short_msg, sm_tvb, 0, -1, ENC_NA);
459             }
460         } else {
461             /* The packet is not reassembled,
462              * or it is reassembled in another packet */
463             proto_tree_add_bytes_format(sm_tree, hf_gsm_sms_ud_short_msg, sm_tvb, 0, -1,
464                     NULL, "Unreassembled Short Message fragment %u of %u",
465                     frag, frags);
466         }
467     }
468 
469     if (try_gsm_sms_ud_reassemble) /* Clean up defragmentation */
470         pinfo->fragmented = save_fragmented;
471     return;
472 }
473 
474 static int
dissect_gsm_sms_ud(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)475 dissect_gsm_sms_ud(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
476 {
477     proto_item *ti;
478     proto_tree *subtree;
479 
480     ti      = proto_tree_add_item(tree, proto_gsm_sms_ud, tvb, 0, -1, ENC_NA);
481     subtree = proto_item_add_subtree(ti, ett_gsm_sms);
482     parse_gsm_sms_ud_message(subtree, tvb, pinfo, tree);
483     return tvb_captured_length(tvb);
484 }
485 
486 /* Register the protocol with Wireshark */
487 void
proto_register_gsm_sms_ud(void)488 proto_register_gsm_sms_ud(void)
489 {
490     module_t *gsm_sms_ud_module; /* Preferences for GSM SMS UD */
491 
492     /* Setup list of header fields  */
493     static hf_register_info hf[] = {
494         /*
495          * User Data Header
496          */
497         {   &hf_gsm_sms_udh_iei,
498             {   "IE Id", "gsm_sms_ud.udh.iei",
499                 FT_UINT8, BASE_HEX, VALS(vals_udh_iei), 0x00,
500                 "Name of the User Data Header Information Element.",
501                 HFILL
502             }
503         },
504         {   &hf_gsm_sms_udh_length,
505             {   "UDH Length", "gsm_sms_ud.udh.len",
506                 FT_UINT8, BASE_DEC, NULL, 0x00,
507                 "Length of the User Data Header (bytes)",
508                 HFILL
509             }
510         },
511 #if 0
512         {   &hf_gsm_sms_udh_multiple_messages,
513             {   "Multiple messages UDH", "gsm_sms_ud.udh.mm",
514                 FT_NONE, BASE_NONE, NULL, 0x00,
515                 "Multiple messages User Data Header",
516                 HFILL
517             }
518         },
519 #endif
520         {   &hf_gsm_sms_udh_multiple_messages_msg_id,
521             {   "Message identifier", "gsm_sms_ud.udh.mm.msg_id",
522                 FT_UINT16, BASE_DEC, NULL, 0x00,
523                 "Identification of the message",
524                 HFILL
525             }
526         },
527         {   &hf_gsm_sms_udh_multiple_messages_msg_parts,
528             {   "Message parts", "gsm_sms_ud.udh.mm.msg_parts",
529                 FT_UINT8, BASE_DEC, NULL, 0x00,
530                 "Total number of message parts (fragments)",
531                 HFILL
532             }
533         },
534         {   &hf_gsm_sms_udh_multiple_messages_msg_part,
535             {   "Message part number", "gsm_sms_ud.udh.mm.msg_part",
536                 FT_UINT8, BASE_DEC, NULL, 0x00,
537                 "Message part (fragment) sequence number",
538                 HFILL
539             }
540         },
541 #if 0
542         {   &hf_gsm_sms_udh_ports,
543             {   "Port number UDH", "gsm_sms_ud.udh.ports",
544                 FT_NONE, BASE_NONE, NULL, 0x00,
545                 "Port number User Data Header",
546                 HFILL
547             }
548         },
549 #endif
550         {   &hf_gsm_sms_udh_ports_src,
551             {   "Source port", "gsm_sms_ud.udh.ports.src",
552                 FT_UINT8, BASE_DEC, NULL, 0x00,
553                 NULL,
554                 HFILL
555             }
556         },
557         {   &hf_gsm_sms_udh_ports_dst,
558             {   "Destination port", "gsm_sms_ud.udh.ports.dst",
559                 FT_UINT8, BASE_DEC, NULL, 0x00,
560                 NULL,
561                 HFILL
562             }
563         },
564         {   &hf_gsm_sms_udh_national_single_shift,
565             {   "Language", "gsm_sms_ud.udh.national.single_shift",
566                 FT_UINT8, BASE_DEC,
567                 VALS(vals_udh_national_languages_single_shift), 0x00,
568                 NULL,
569                 HFILL
570             }
571         },
572         {   &hf_gsm_sms_udh_national_locking_shift,
573             {   "Language", "gsm_sms_ud.udh.national.locking_shift",
574                 FT_UINT8, BASE_DEC,
575                 VALS(vals_udh_national_languages_locking_shift), 0x00,
576                 NULL,
577                 HFILL
578             }
579         },
580         /*
581          * Short Message fragment reassembly
582          */
583         {   &hf_gsm_sms_ud_fragments,
584             {   "Short Message fragments", "gsm_sms_ud.fragments",
585                 FT_NONE, BASE_NONE, NULL, 0x00,
586                 "GSM Short Message fragments",
587                 HFILL
588             }
589         },
590         {   &hf_gsm_sms_ud_fragment,
591             {   "Short Message fragment", "gsm_sms_ud.fragment",
592                 FT_FRAMENUM, BASE_NONE, NULL, 0x00,
593                 "GSM Short Message fragment",
594                 HFILL
595             }
596         },
597         {   &hf_gsm_sms_ud_fragment_overlap,
598             {   "Short Message fragment overlap", "gsm_sms_ud.fragment.overlap",
599                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
600                 "GSM Short Message fragment overlaps with other fragment(s)",
601                 HFILL
602             }
603         },
604         {   &hf_gsm_sms_ud_fragment_overlap_conflicts,
605             {   "Short Message fragment overlapping with conflicting data",
606                 "gsm_sms_ud.fragment.overlap.conflicts",
607                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
608                 "GSM Short Message fragment overlaps with conflicting data",
609                 HFILL
610             }
611         },
612         {   &hf_gsm_sms_ud_fragment_multiple_tails,
613             {   "Short Message has multiple tail fragments",
614                 "gsm_sms_ud.fragment.multiple_tails",
615                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
616                 "GSM Short Message fragment has multiple tail fragments",
617                 HFILL
618             }
619         },
620         {   &hf_gsm_sms_ud_fragment_too_long_fragment,
621             {   "Short Message fragment too long",
622                 "gsm_sms_ud.fragment.too_long_fragment",
623                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
624                 "GSM Short Message fragment data goes beyond the packet end",
625                 HFILL
626             }
627         },
628         {   &hf_gsm_sms_ud_fragment_error,
629             {   "Short Message defragmentation error", "gsm_sms_ud.fragment.error",
630                 FT_FRAMENUM, BASE_NONE, NULL, 0x00,
631                 "GSM Short Message defragmentation error due to illegal fragments",
632                 HFILL
633             }
634         },
635         {   &hf_gsm_sms_ud_fragment_count,
636             {   "Short Message fragment count", "gsm_sms_ud.fragment.count",
637                 FT_UINT32, BASE_DEC, NULL, 0x00,
638                 NULL,
639                 HFILL
640             }
641         },
642         {   &hf_gsm_sms_ud_reassembled_in,
643             {   "Reassembled in",
644                 "gsm_sms_ud.reassembled.in",
645                 FT_FRAMENUM, BASE_NONE, NULL, 0x00,
646                 "GSM Short Message has been reassembled in this packet.",
647                 HFILL
648             }
649         },
650         {   &hf_gsm_sms_ud_reassembled_length,
651             {   "Reassembled Short Message length",
652                 "gsm_sms_ud.reassembled.length",
653                 FT_UINT32, BASE_DEC, NULL, 0x00,
654                 "The total length of the reassembled payload",
655                 HFILL
656             }
657         },
658         {   &hf_gsm_sms_ud_short_msg,
659             {   "Short Message body",
660                 "gsm_sms_ud.short_msg",
661                 FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL
662             }
663         },
664     };
665 
666     static gint *ett[] = {
667     &ett_gsm_sms,
668     &ett_udh,
669     &ett_udh_ie,
670     &ett_gsm_sms_ud_fragment,
671     &ett_gsm_sms_ud_fragments,
672     };
673     /* Register the protocol name and description */
674     proto_gsm_sms_ud = proto_register_protocol(
675         "GSM Short Message Service User Data",  /* Name */
676         "GSM SMS UD",           /* Short name */
677         "gsm_sms_ud");          /* Filter name */
678 
679     /* Required function calls to register header fields and subtrees used */
680     proto_register_field_array(proto_gsm_sms_ud, hf, array_length(hf));
681     proto_register_subtree_array(ett, array_length(ett));
682 
683     /* Subdissector code */
684     gsm_sms_dissector_table = register_dissector_table("gsm_sms_ud.udh.port",
685         "GSM SMS port IE in UDH", proto_gsm_sms_ud, FT_UINT16, BASE_DEC);
686 
687     /* Preferences for GSM SMS UD */
688     gsm_sms_ud_module = prefs_register_protocol(proto_gsm_sms_ud, NULL);
689     /* For reading older preference files with "smpp-gsm-sms." preferences */
690     prefs_register_module_alias("smpp-gsm-sms", gsm_sms_ud_module);
691     prefs_register_bool_preference(gsm_sms_ud_module,
692         "port_number_udh_means_wsp",
693         "Port Number IE in UDH always triggers CL-WSP dissection",
694         "Always decode a GSM Short Message as Connectionless WSP "
695         "if a Port Number Information Element is present "
696         "in the SMS User Data Header.",
697         &port_number_udh_means_wsp);
698     prefs_register_bool_preference(gsm_sms_ud_module, "try_dissect_1st_fragment",
699         "Always try subdissection of 1st Short Message fragment",
700         "Always try subdissection of the 1st fragment of a fragmented "
701         "GSM Short Message. If reassembly is possible, the Short Message "
702         "may be dissected twice (once as a short frame, once in its "
703         "entirety).",
704         &try_dissect_1st_frag);
705     prefs_register_bool_preference(gsm_sms_ud_module, "prevent_dissectors_chg_cols",
706             "Prevent sub-dissectors from changing column data",
707         "Prevent sub-dissectors from replacing column data with their "
708         "own. Eg. Prevent WSP dissector overwriting SMPP information.",
709         &prevent_subdissectors_changing_columns);
710 
711     register_dissector("gsm_sms_ud", dissect_gsm_sms_ud, proto_gsm_sms_ud);
712 
713     reassembly_table_register(&sm_reassembly_table,
714                           &addresses_reassembly_table_functions);
715 }
716 
717 void
proto_reg_handoff_gsm_sms_ud(void)718 proto_reg_handoff_gsm_sms_ud(void)
719 {
720     wsp_handle = find_dissector_add_dependency("wsp-cl", proto_gsm_sms_ud);
721     DISSECTOR_ASSERT(wsp_handle);
722 }
723 
724 /*
725  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
726  *
727  * Local variables:
728  * c-basic-offset: 4
729  * tab-width: 8
730  * indent-tabs-mode: nil
731  * End:
732  *
733  * vi: set shiftwidth=4 tabstop=8 expandtab:
734  * :indentSize=4:tabSize=8:noTabs=true:
735  */
736