Move 3 ASN1 dissectors to 'clean' group; move 1 PIDL dissector to 'dirty' group.
[metze/wireshark/wip.git] / epan / dissectors / packet-gsm_sms.c
1 /* packet-gsm_sms.c
2  * Routines for GSM SMS TPDU (GSM 03.40) dissection
3  *
4  * Copyright 2003, Michael Lum <mlum [AT] telostech.com>
5  * In association with Telos Technology Inc.
6  *
7  * TPDU User-Data unpack routines from GNOKII.
8  *
9  *   Reference [1]
10  *   Universal Mobile Telecommunications System (UMTS);
11  *   Technical realization of Short Message Service (SMS)
12  *   (3GPP TS 23.040 version 5.4.0 Release 5)
13  *
14  * Header field support for TPDU Parameters added by
15  * Abhik Sarkar.
16  *
17  * $Id$
18  *
19  * Wireshark - Network traffic analyzer
20  * By Gerald Combs <gerald@wireshark.org>
21  * Copyright 1998 Gerald Combs
22  *
23  * This program is free software; you can redistribute it and/or
24  * modify it under the terms of the GNU General Public License
25  * as published by the Free Software Foundation; either version 2
26  * of the License, or (at your option) any later version.
27  *
28  * This program is distributed in the hope that it will be useful,
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  * GNU General Public License for more details.
32  *
33  * You should have received a copy of the GNU General Public License
34  * along with this program; if not, write to the Free Software
35  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
36  */
37
38 #include "config.h"
39
40 #include <glib.h>
41
42 #include <string.h>
43
44 #include <epan/packet.h>
45 #include <epan/prefs.h>
46 #include <epan/reassemble.h>
47
48 #include "packet-gsm_sms.h"
49
50 #define MAX_SMS_FRAG_LEN      134
51
52 /* PROTOTYPES/FORWARDS */
53
54 #define EXTRANEOUS_DATA_CHECK(edc_len, edc_max_len) \
55     if ((edc_len) > (edc_max_len)) \
56     { \
57         proto_tree_add_text(tree, tvb, \
58             offset, (edc_len) - (edc_max_len), "Extraneous Data"); \
59     }
60
61 #define SHORT_DATA_CHECK(sdc_len, sdc_min_len) \
62     if ((sdc_len) < (sdc_min_len)) \
63     { \
64         proto_tree_add_text(tree, tvb, \
65             offset, (sdc_len), "Short Data (?)"); \
66         return; \
67     }
68
69 #define EXACT_DATA_CHECK(edc_len, edc_eq_len) \
70     if ((edc_len) != (edc_eq_len)) \
71     { \
72         proto_tree_add_text(tree, tvb, \
73             offset, (edc_len), "Unexpected Data Length"); \
74         return; \
75     }
76
77 #define SMS_SHIFTMASK(m_val, m_bitmask, m_sval); \
78     { \
79         int        _temp_val = m_val; \
80         int        _temp_bm = m_bitmask; \
81         while (_temp_bm && !(_temp_bm & 0x01)) \
82         { \
83             _temp_bm = _temp_bm >> 1; \
84             _temp_val = _temp_val >> 1; \
85         } \
86         m_sval = _temp_val; \
87     }
88
89
90 static const char *gsm_sms_proto_name = "GSM SMS TPDU (GSM 03.40)";
91 static const char *gsm_sms_proto_name_short = "GSM SMS";
92
93 /* Initialize the subtree pointers */
94 static gint ett_gsm_sms = -1;
95 static gint ett_pid = -1;
96 static gint ett_pi = -1;
97 static gint ett_fcs = -1;
98 static gint ett_vp = -1;
99 static gint ett_scts = -1;
100 static gint ett_dt = -1;
101 static gint ett_st = -1;
102 static gint ett_addr = -1;
103 static gint ett_dcs = -1;
104 static gint ett_ud = -1;
105 static gint ett_udh = -1;
106
107 static gint ett_udh_tfm = -1;
108 static gint ett_udh_tfc = -1;
109
110 /* Initialize the protocol and registered fields */
111 static int proto_gsm_sms = -1;
112
113 static gint hf_gsm_sms_coding_group_bits2 = -1;
114 static gint hf_gsm_sms_coding_group_bits4 = -1;
115 static gint  hf_gsm_sms_ud_multiple_messages_msg_id = -1;
116 static gint  hf_gsm_sms_ud_multiple_messages_msg_parts = -1;
117 static gint  hf_gsm_sms_ud_multiple_messages_msg_part = -1;
118
119 /* TPDU Parameters */
120 static gint hf_gsm_sms_tp_mti_up = -1;
121 static gint hf_gsm_sms_tp_mti_down = -1;
122 static gint hf_gsm_sms_tp_mms = -1;
123 static gint hf_gsm_sms_tp_vpf = -1;
124 static gint hf_gsm_sms_tp_sri = -1;
125 static gint hf_gsm_sms_tp_srr = -1;
126 static gint hf_gsm_sms_tp_mr = -1;
127 static gint hf_gsm_sms_tp_oa = -1;
128 static gint hf_gsm_sms_tp_da = -1;
129 static gint hf_gsm_sms_tp_pid = -1;
130 static gint hf_gsm_sms_tp_dcs = -1;
131 static gint hf_gsm_sms_tp_ra = -1;
132 static gint hf_gsm_sms_tp_rp = -1;
133 static gint hf_gsm_sms_tp_udhi = -1;
134 static gint hf_gsm_sms_tp_rd = -1;
135 static gint hf_gsm_sms_tp_srq = -1;
136 static gint hf_gsm_sms_text = -1;
137 static gint hf_gsm_sms_tp_fail_cause = -1;
138 #if 0
139 static gint hf_gsm_sms_tp_scts = -1;
140 static gint hf_gsm_sms_tp_vp = -1;
141 static gint hf_gsm_sms_tp_dt = -1;
142 static gint hf_gsm_sms_tp_st = -1;
143 static gint hf_gsm_sms_tp_udl = -1;
144 static gint hf_gsm_sms_tp_mn = -1;
145 static gint hf_gsm_sms_tp_ct = -1;
146 static gint hf_gsm_sms_tp_cdl = -1;
147 static gint hf_gsm_sms_tp_cd = -1;
148 static gint hf_gsm_sms_tp_ud = -1;
149 #endif
150
151 static gboolean reassemble_sms = TRUE;
152 static char bigbuf[1024];
153 static packet_info *g_pinfo;
154 static proto_tree *g_tree;
155
156 /* 3GPP TS 23.038 version 7.0.0 Release 7
157  * The TP-Data-Coding-Scheme field, defined in 3GPP TS 23.040 [4],
158  * indicates the data coding scheme of the TP-UD field, and may indicate a message class.
159  * Any reserved codings shall be assumed to be the GSM 7 bit default alphabet
160  * (the same as codepoint 00000000) by a receiving entity.
161  * The octet is used according to a coding group which is indicated in bits 7..4.
162  */
163
164 /* Coding Group Bits */
165 static const value_string gsm_sms_coding_group_bits_vals[] = {
166     { 0,  "General Data Coding indication" },                    /* 00xx */
167     { 1,  "General Data Coding indication" },                    /* 00xx */
168     { 2,  "General Data Coding indication" },                    /* 00xx */
169     { 3,  "General Data Coding indication" },                    /* 00xx */
170     { 4,  "Message Marked for Automatic Deletion Group" },       /* 01xx */
171     { 5,  "Message Marked for Automatic Deletion Group" },       /* 01xx */
172     { 6,  "Message Marked for Automatic Deletion Group" },       /* 01xx */
173     { 7,  "Message Marked for Automatic Deletion Group" },       /* 01xx */
174     { 8,  "Reserved coding groups" },                            /* 1000..1011  */
175     { 9,  "Reserved coding groups" },                            /* 1000..1011  */
176     { 10, "Reserved coding groups" },                            /* 1000..1011  */
177     { 11, "Reserved coding groups" },                            /* 1000..1011  */
178     { 12, "Message Waiting Indication Group: Discard Message" }, /* 1100  */
179     { 13, "Message Waiting Indication Group: Store Message" },   /* 1101  */
180     { 14, "Message Waiting Indication Group: Store Message" },   /* 1110  */
181     { 15, "Data coding/message class" },                         /* 1111  */
182     { 0, NULL },
183 };
184
185 static guint16   g_sm_id;
186 static guint16   g_frags;
187 static guint16   g_frag;
188
189 static guint16   g_port_src;
190 static guint16   g_port_dst;
191 static gboolean  g_is_wsp;
192
193 static dissector_table_t gsm_sms_dissector_tbl;
194 /* Short Message reassembly */
195 static GHashTable *g_sm_fragment_table = NULL;
196 static GHashTable *g_sm_reassembled_table = NULL;
197 static GHashTable *g_sm_fragment_params_table = NULL;
198 static gint ett_gsm_sms_ud_fragment = -1;
199 static gint ett_gsm_sms_ud_fragments = -1;
200  /*
201  * Short Message fragment handling
202  */
203 static int hf_gsm_sms_ud_fragments = -1;
204 static int hf_gsm_sms_ud_fragment = -1;
205 static int hf_gsm_sms_ud_fragment_overlap = -1;
206 static int hf_gsm_sms_ud_fragment_overlap_conflicts = -1;
207 static int hf_gsm_sms_ud_fragment_multiple_tails = -1;
208 static int hf_gsm_sms_ud_fragment_too_long_fragment = -1;
209 static int hf_gsm_sms_ud_fragment_error = -1;
210 static int hf_gsm_sms_ud_fragment_count = -1;
211 static int hf_gsm_sms_ud_reassembled_in = -1;
212 static int hf_gsm_sms_ud_reassembled_length = -1;
213
214 static const fragment_items sm_frag_items = {
215     /* Fragment subtrees */
216     &ett_gsm_sms_ud_fragment,
217     &ett_gsm_sms_ud_fragments,
218     /* Fragment fields */
219     &hf_gsm_sms_ud_fragments,
220     &hf_gsm_sms_ud_fragment,
221     &hf_gsm_sms_ud_fragment_overlap,
222     &hf_gsm_sms_ud_fragment_overlap_conflicts,
223     &hf_gsm_sms_ud_fragment_multiple_tails,
224     &hf_gsm_sms_ud_fragment_too_long_fragment,
225     &hf_gsm_sms_ud_fragment_error,
226     &hf_gsm_sms_ud_fragment_count,
227     /* Reassembled in field */
228     &hf_gsm_sms_ud_reassembled_in,
229     /* Reassembled length field */
230     &hf_gsm_sms_ud_reassembled_length,
231     /* Reassembled data field */
232     NULL,
233     /* Tag */
234     "Short Message fragments"
235 };
236
237 typedef struct {
238     guint8 udl;
239     guint32 length;
240 } sm_fragment_params;
241
242 static void
243 gsm_sms_defragment_init (void)
244 {
245     fragment_table_init (&g_sm_fragment_table);
246     reassembled_table_init(&g_sm_reassembled_table);
247     if (g_sm_fragment_params_table) {
248         g_hash_table_destroy(g_sm_fragment_params_table);
249     }
250     g_sm_fragment_params_table = g_hash_table_new(g_direct_hash, g_direct_equal);
251 }
252
253 /*
254  * this is the GSM 03.40 definition with the bit 2
255  * set to 1 for uplink messages
256  */
257 static const value_string msg_type_strings[] = {
258     { 0,        "SMS-DELIVER" },
259     { 4,        "SMS-DELIVER REPORT" },
260     { 5,        "SMS-SUBMIT" },
261     { 1,        "SMS-SUBMIT REPORT" },
262     { 2,        "SMS-STATUS REPORT" },
263     { 6,        "SMS-COMMAND" },
264     { 3,        "Reserved" },
265     { 7,        "Reserved" },
266     { 0, NULL },
267 };
268
269 static const value_string msg_type_strings_sc_to_ms[] = {
270     { 0,        "SMS-DELIVER" },
271     { 1,        "SMS-SUBMIT REPORT" },
272     { 2,        "SMS-STATUS REPORT" },
273     { 3,        "Reserved" },
274     { 0, NULL },
275 };
276
277 static const value_string msg_type_strings_ms_to_sc[] = {
278     { 0,        "SMS-DELIVER REPORT" },
279     { 1,        "SMS-SUBMIT" },
280     { 2,        "SMS-COMMAND" },
281     { 3,        "Reserved" },
282     { 0, NULL },
283 };
284
285 /* 9.2.3.3 TP-Validity-Period-Format (TP-VPF) */
286 static const value_string vp_type_strings[] = {
287     { 0,        "TP-VP field not present"},
288     { 2,        "TP-VP field present - relative format"},
289     { 1,        "TP-VP field present - enhanced format"},
290     { 3,        "TP-VP field present - absolute format"},
291     { 0, NULL },
292 };
293
294 static const true_false_string mms_bool_strings = {
295     "No more messages are waiting for the MS in this SC",
296     "More messages are waiting for the MS in this SC"
297 };
298
299 static const true_false_string sri_bool_strings = {
300     "A status report shall be returned to the SME",
301     "A status report shall not be returned to the SME"
302 };
303
304 static const true_false_string srr_bool_strings = {
305     "A status report is requested",
306     "A status report is not requested"
307 };
308
309 static const true_false_string udhi_bool_strings = {
310     "The beginning of the TP UD field contains a Header in addition to the short message",
311     "The TP UD field contains only the short message"
312 };
313
314 static const true_false_string rp_bool_strings = {
315     "TP Reply Path parameter is set in this SMS SUBMIT/DELIVER",
316     "TP Reply Path parameter is not set in this SMS SUBMIT/DELIVER"
317 };
318
319 static const true_false_string rd_bool_strings = {
320     "Instruct SC to reject duplicates",
321     "Instruct SC to accept duplicates"
322 };
323
324 static const true_false_string srq_bool_strings = {
325     "The SMS STATUS REPORT is the result of an SMS COMMAND e.g. an Enquiry.",
326     "SMS STATUS REPORT is the result of a SMS SUBMIT."
327 };
328
329 #define NUM_UDH_IEIS        256
330 static gint ett_udh_ieis[NUM_UDH_IEIS];
331
332 #define MAX_ADDR_SIZE 20
333 static void
334 dis_field_addr(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p, const gchar *title)
335 {
336     static gchar digit_table[] = {"0123456789*#abc\0"};
337     proto_item   *item;
338     proto_tree   *subtree = NULL;
339     const gchar  *str = NULL;
340     guint8       oct;
341     guint32      offset;
342     guint32      numdigocts;
343     guint32      length;
344     guint32      i, j;
345     char         addrbuf[MAX_ADDR_SIZE+1];
346     gchar        *addrstr;
347
348     offset = *offset_p;
349
350     oct = tvb_get_guint8(tvb, offset);
351     numdigocts = (oct + 1) / 2;
352
353     length = tvb_length_remaining(tvb, offset);
354
355     if (length <= numdigocts)
356     {
357         proto_tree_add_text(tree,
358             tvb, offset, length,
359             "%s: Short Data (?)",
360             title);
361
362         *offset_p += length;
363         return;
364     }
365
366     item = proto_tree_add_text(tree, tvb,
367             offset, numdigocts + 2, "%s",
368             title);
369
370     subtree = proto_item_add_subtree(item, ett_addr);
371
372     proto_tree_add_text(subtree,
373         tvb, offset, 1,
374         "Length: %d address digits",
375         oct);
376
377     offset++;
378     oct = tvb_get_guint8(tvb, offset);
379
380     other_decode_bitfield_value(bigbuf, oct, 0x80, 8);
381     proto_tree_add_text(subtree, tvb,
382         offset, 1,
383         "%s :  %s",
384         bigbuf,
385         (oct & 0x80) ? "No extension" : "Extended");
386
387     switch ((oct & 0x70) >> 4)
388     {
389     case 0x00: str = "Unknown"; break;
390     case 0x01: str = "International"; break;
391     case 0x02: str = "National"; break;
392     case 0x03: str = "Network specific"; break;
393     case 0x04: str = "Subscriber"; break;
394     case 0x05: str = "Alphanumeric (coded according to 3GPP TS 23.038 GSM 7-bit default alphabet)"; break;
395     case 0x06: str = "Abbreviated number"; break;
396     case 0x07: str = "Reserved for extension"; break;
397     default: str = "Unknown, reserved (?)"; break;
398     }
399
400     other_decode_bitfield_value(bigbuf, oct, 0x70, 8);
401     proto_tree_add_text(subtree,
402         tvb, offset, 1,
403         "%s :  Type of number: (%d) %s",
404         bigbuf,
405         (oct & 0x70) >> 4,
406         str);
407
408     switch (oct & 0x0f)
409     {
410     case 0x00: str = "Unknown"; break;
411     case 0x01: str = "ISDN/telephone (E.164/E.163)"; break;
412     case 0x03: str = "Data numbering plan (X.121)"; break;
413     case 0x04: str = "Telex numbering plan"; break;
414     case 0x05: str = "Service Centre Specific plan"; break;
415     case 0x06: str = "Service Centre Specific plan"; break;
416     case 0x08: str = "National numbering plan"; break;
417     case 0x09: str = "Private numbering plan"; break;
418     case 0x0a: str = "ERMES numbering plan (ETSI DE/PS 3 01-3)"; break;
419     case 0x0f: str = "Reserved for extension"; break;
420     default: str = "Unknown, reserved (?)"; break;
421     }
422
423     other_decode_bitfield_value(bigbuf, oct, 0x0f, 8);
424     proto_tree_add_text(subtree,
425         tvb, offset, 1,
426         "%s :  Numbering plan: (%d) %s",
427         bigbuf,
428         oct & 0x0f,
429         str);
430
431     offset++;
432
433     j = 0;
434     switch ((oct & 0x70) >> 4)
435     {
436     case 0x05: /* "Alphanumeric (coded according to 3GPP TS 23.038 GSM 7-bit default alphabet)" */
437         i = gsm_sms_char_7bit_unpack(0, numdigocts, MAX_ADDR_SIZE, tvb_get_ptr(tvb, offset, numdigocts), addrbuf);
438         addrbuf[i] = '\0';
439         addrstr = gsm_sms_chars_to_utf8(addrbuf, i);
440         break;
441     default:
442         addrstr = ep_alloc(numdigocts*2 + 1);
443         for (i = 0; i < numdigocts; i++)
444         {
445             oct = tvb_get_guint8(tvb, offset + i);
446
447             addrstr[j++] = digit_table[oct & 0x0f];
448             addrstr[j++] = digit_table[(oct & 0xf0) >> 4];
449         }
450         addrstr[j++] = '\0';
451         break;
452     }
453
454     if (g_ascii_strncasecmp(title, "TP-O", 4) == 0) {
455         proto_tree_add_string(subtree, hf_gsm_sms_tp_oa, tvb,
456                 offset, numdigocts, addrstr);
457     } else if (g_ascii_strncasecmp(title, "TP-D", 4) == 0) {
458         proto_tree_add_string(subtree, hf_gsm_sms_tp_da, tvb,
459                 offset, numdigocts, addrstr);
460     } else if (g_ascii_strncasecmp(title, "TP-R", 4) == 0) {
461         proto_tree_add_string(subtree, hf_gsm_sms_tp_ra, tvb,
462                 offset, numdigocts, addrstr);
463     } else {
464         proto_tree_add_text(subtree, tvb,
465                 offset, numdigocts, "Digits: %s", addrstr);
466     }
467
468     proto_item_append_text(item, " - (%s)", addrstr);
469
470     *offset_p = offset + numdigocts;
471 }
472
473 /* 9.2.3.7 */
474 /* use dis_field_addr() */
475
476 /* 9.2.3.8 */
477 /* use dis_field_addr() */
478
479 /* 9.2.3.9 */
480 static void
481 dis_field_pid(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 oct)
482 {
483     proto_item    *item;
484     proto_tree    *subtree = NULL;
485     guint8        form;
486     guint8        telematic;
487     const gchar   *str = NULL;
488
489
490     item = proto_tree_add_item(tree, hf_gsm_sms_tp_pid, tvb, offset, 1, ENC_BIG_ENDIAN);
491
492     subtree = proto_item_add_subtree(item, ett_pid);
493
494     form = (oct & 0xc0) >> 6;
495
496     switch (form)
497     {
498     case 0:
499         other_decode_bitfield_value(bigbuf, oct, 0xc0, 8);
500         proto_tree_add_text(subtree, tvb,
501             offset, 1,
502             "%s :  defines formatting for subsequent bits",
503             bigbuf);
504
505         other_decode_bitfield_value(bigbuf, oct, 0x20, 8);
506         proto_tree_add_text(subtree, tvb,
507             offset, 1,
508             "%s :  %s",
509             bigbuf,
510             (oct & 0x20) ?
511             "telematic interworking" :
512             "no telematic interworking, but SME-to-SME protocol");
513
514         if (oct & 0x20)
515         {
516             telematic = oct & 0x1f;
517
518             switch (telematic)
519             {
520             case 0x00: str = "implicit - device type is specific to this SC, or can be concluded on the basis of the address"; break;
521             case 0x01: str = "telex (or teletex reduced to telex format)"; break;
522             case 0x02: str = "group 3 telefax"; break;
523             case 0x03: str = "group 4 telefax"; break;
524             case 0x04: str = "voice telephone (i.e. conversion to speech)"; break;
525             case 0x05: str = "ERMES (European Radio Messaging System)"; break;
526             case 0x06: str = "National Paging system (known to the SC)"; break;
527             case 0x07: str = "Videotex (T.100 [20] /T.101 [21])"; break;
528             case 0x08: str = "teletex, carrier unspecified"; break;
529             case 0x09: str = "teletex, in PSPDN"; break;
530             case 0x0a: str = "teletex, in CSPDN"; break;
531             case 0x0b: str = "teletex, in analog PSTN"; break;
532             case 0x0c: str = "teletex, in digital ISDN"; break;
533             case 0x0d: str = "UCI (Universal Computer Interface, ETSI DE/PS 3 01-3)"; break;
534             case 0x10: str = "a message handling facility (known to the SC)"; break;
535             case 0x11: str = "any public X.400-based message handling system"; break;
536             case 0x12: str = "Internet Electronic Mail"; break;
537             case 0x1f: str = "A GSM/UMTS mobile station"; break;
538             default:
539                 if ((telematic >= 0x18) &&
540                     (telematic <= 0x1e))
541                 {
542                     str = "values specific to each SC";
543                 }
544                 else
545                 {
546                     str = "reserved";
547                 }
548                 break;
549             }
550
551             other_decode_bitfield_value(bigbuf, oct, 0x1f, 8);
552             proto_tree_add_text(subtree, tvb,
553                 offset, 1,
554                 "%s :  device type: (%d) %s",
555                 bigbuf,
556                 telematic,
557                 str);
558         }
559         else
560         {
561             other_decode_bitfield_value(bigbuf, oct, 0x1f, 8);
562             proto_tree_add_text(subtree, tvb,
563                 offset, 1,
564                 "%s :  the SM-AL protocol being used between the SME and the MS (%d)",
565                 bigbuf,
566                 oct & 0x1f);
567         }
568         break;
569
570     case 1:
571         other_decode_bitfield_value(bigbuf, oct, 0xc0, 8);
572         proto_tree_add_text(subtree, tvb,
573             offset, 1,
574             "%s :  defines formatting for subsequent bits",
575             bigbuf);
576
577         switch (oct & 0x3f)
578         {
579         case 0x00: str = "Short Message Type 0"; break;
580         case 0x01: str = "Replace Short Message Type 1"; break;
581         case 0x02: str = "Replace Short Message Type 2"; break;
582         case 0x03: str = "Replace Short Message Type 3"; break;
583         case 0x04: str = "Replace Short Message Type 4"; break;
584         case 0x05: str = "Replace Short Message Type 5"; break;
585         case 0x06: str = "Replace Short Message Type 6"; break;
586         case 0x07: str = "Replace Short Message Type 7"; break;
587         case 0x1e: str = "Enhanced Message Service (Obsolete)"; break;
588         case 0x1f: str = "Return Call Message"; break;
589         case 0x3c: str = "ANSI-136 R-DATA"; break;
590         case 0x3d: str = "ME Data download"; break;
591         case 0x3e: str = "ME De-personalization Short Message"; break;
592         case 0x3f: str = "(U)SIM Data download"; break;
593         default:
594             str = "Reserved"; break;
595         }
596
597         other_decode_bitfield_value(bigbuf, oct, 0x3f, 8);
598         proto_tree_add_text(subtree, tvb,
599             offset, 1,
600             "%s :  (%d) %s",
601             bigbuf,
602             oct & 0x3f,
603             str);
604         break;
605
606     case 2:
607         other_decode_bitfield_value(bigbuf, oct, 0xc0, 8);
608         proto_tree_add_text(subtree, tvb,
609             offset, 1,
610             "%s :  Reserved",
611             bigbuf);
612
613         other_decode_bitfield_value(bigbuf, oct, 0x3f, 8);
614         proto_tree_add_text(subtree, tvb,
615             offset, 1,
616             "%s :  undefined",
617             bigbuf);
618         break;
619
620     case 3:
621         other_decode_bitfield_value(bigbuf, oct, 0xc0, 8);
622         proto_tree_add_text(subtree, tvb,
623             offset, 1,
624             "%s :  bits 0-5 for SC specific use",
625             bigbuf);
626
627         other_decode_bitfield_value(bigbuf, oct, 0x3f, 8);
628         proto_tree_add_text(subtree, tvb,
629             offset, 1,
630             "%s :  SC specific",
631             bigbuf);
632         break;
633     }
634 }
635
636 /* 9.2.3.10 */
637 static void
638 dis_field_dcs(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 oct,
639     gboolean *seven_bit, gboolean *eight_bit, gboolean *ucs2, gboolean *compressed)
640 {
641     proto_item    *item;
642     proto_tree    *subtree = NULL;
643     guint8        form;
644     const gchar   *str = NULL;
645     gboolean      default_5_bits;
646     gboolean      default_3_bits;
647     gboolean      default_data;
648
649
650     *seven_bit = FALSE;
651     *eight_bit = FALSE;
652     *ucs2 = FALSE;
653     *compressed = FALSE;
654
655     item = proto_tree_add_item(tree, hf_gsm_sms_tp_dcs, tvb, offset, 1, ENC_BIG_ENDIAN);
656
657     subtree = proto_item_add_subtree(item, ett_dcs);
658     if (oct&0x80) {
659         proto_tree_add_item(subtree, hf_gsm_sms_coding_group_bits4, tvb, offset, 1, ENC_BIG_ENDIAN);
660     } else {
661         proto_tree_add_item(subtree, hf_gsm_sms_coding_group_bits2, tvb, offset, 1, ENC_BIG_ENDIAN);
662     }
663
664     if (oct == 0x00)
665     {
666         proto_tree_add_text(subtree, tvb,
667             offset, 1,
668             "Special case, GSM 7 bit default alphabet");
669
670         *seven_bit = TRUE;
671         return;
672     }
673
674     default_5_bits = FALSE;
675     default_3_bits = FALSE;
676     default_data = FALSE;
677     form = (oct & 0xc0) >> 6;
678
679     switch (form)
680     {
681     case 0:
682         other_decode_bitfield_value(bigbuf, oct, 0xc0, 8);
683         proto_tree_add_text(subtree, tvb,
684             offset, 1,
685             "%s :  General Data Coding indication",
686             bigbuf);
687
688         default_5_bits = TRUE;
689         break;
690
691     case 1:
692         other_decode_bitfield_value(bigbuf, oct, 0xc0, 8);
693         proto_tree_add_text(subtree, tvb,
694             offset, 1,
695             "%s :  Message Marked for Automatic Deletion Group",
696             bigbuf);
697
698         default_5_bits = TRUE;
699         break;
700
701     case 2:
702         /* use top four bits */
703         other_decode_bitfield_value(bigbuf, oct, 0xf0, 8);
704         proto_tree_add_text(subtree, tvb,
705             offset, 1,
706             "%s :  Reserved coding groups",
707             bigbuf);
708         return;
709
710     case 3:
711         switch ((oct & 0x30) >> 4)
712         {
713         case 0x00: str = "Message Waiting Indication Group: Discard Message (GSM 7 bit default alphabet)";
714             default_3_bits = TRUE;
715             *seven_bit = TRUE;
716             break;
717         case 0x01: str = "Message Waiting Indication Group: Store Message (GSM 7 bit default alphabet)";
718             default_3_bits = TRUE;
719             *seven_bit = TRUE;
720             break;
721         case 0x02: str = "Message Waiting Indication Group: Store Message (uncompressed UCS2 alphabet)";
722             default_3_bits = TRUE;
723             break;
724         case 0x03: str = "Data coding/message class";
725             default_data = TRUE;
726             break;
727         }
728
729         /* use top four bits */
730         other_decode_bitfield_value(bigbuf, oct, 0xf0, 8);
731         proto_tree_add_text(subtree, tvb,
732             offset, 1,
733             "%s :  %s",
734             bigbuf,
735             str);
736         break;
737     }
738
739     if (default_5_bits)
740     {
741         other_decode_bitfield_value(bigbuf, oct, 0x20, 8);
742         proto_tree_add_text(subtree, tvb,
743             offset, 1,
744             "%s :  Text is %scompressed",
745             bigbuf,
746             (oct & 0x20) ?  "" : "not ");
747
748         *compressed = (oct & 0x20) >> 5;
749
750         other_decode_bitfield_value(bigbuf, oct, 0x10, 8);
751         proto_tree_add_text(subtree, tvb,
752             offset, 1,
753             "%s :  %s",
754             bigbuf,
755             (oct & 0x10) ?  "Message class is defined below" :
756                 "Reserved, no message class");
757
758         switch ((oct & 0x0c) >> 2)
759         {
760         case 0x00: str = "GSM 7 bit default alphabet";
761             *seven_bit = TRUE;
762             break;
763         case 0x01: str = "8 bit data";
764             *eight_bit = TRUE;
765             break;
766         case 0x02: str = "UCS2 (16 bit)";
767             *ucs2 = TRUE;
768             break;
769         case 0x03: str = "Reserved"; break;
770         }
771
772         other_decode_bitfield_value(bigbuf, oct, 0x0c, 8);
773         proto_tree_add_text(subtree, tvb,
774             offset, 1,
775             "%s :  Character set: %s",
776             bigbuf,
777             str);
778
779         switch (oct & 0x03)
780         {
781         case 0x00: str = "Class 0"; break;
782         case 0x01: str = "Class 1 Default meaning: ME-specific"; break;
783         case 0x02: str = "Class 2 (U)SIM specific message"; break;
784         case 0x03: str = "Class 3 Default meaning: TE-specific"; break;
785         }
786
787         other_decode_bitfield_value(bigbuf, oct, 0x03, 8);
788         proto_tree_add_text(subtree, tvb,
789             offset, 1,
790             "%s :  Message Class: %s%s",
791             bigbuf,
792             str,
793             (oct & 0x10) ?  "" : " (reserved)");
794     }
795     else if (default_3_bits)
796     {
797         other_decode_bitfield_value(bigbuf, oct, 0x08, 8);
798         proto_tree_add_text(subtree, tvb,
799             offset, 1,
800             "%s :  Indication Sense: %s",
801             bigbuf,
802             (oct & 0x08) ?  "Set Indication Active" : "Set Indication Inactive");
803
804         other_decode_bitfield_value(bigbuf, oct, 0x04, 8);
805         proto_tree_add_text(subtree, tvb,
806             offset, 1,
807             "%s :  Reserved",
808             bigbuf);
809
810         switch (oct & 0x03)
811         {
812         case 0x00: str = "Voicemail Message Waiting"; break;
813         case 0x01: str = "Fax Message Waiting"; break;
814         case 0x02: str = "Electronic Mail Message Waiting"; break;
815         case 0x03: str = "Other Message Waiting"; break;
816         }
817
818         other_decode_bitfield_value(bigbuf, oct, 0x03, 8);
819         proto_tree_add_text(subtree, tvb,
820             offset, 1,
821             "%s :  %s",
822             bigbuf,
823             str);
824     }
825     else if (default_data)
826     {
827         other_decode_bitfield_value(bigbuf, oct, 0x08, 8);
828         proto_tree_add_text(subtree, tvb,
829             offset, 1,
830             "%s :  Reserved",
831             bigbuf);
832
833         *seven_bit = !(*eight_bit = (oct & 0x04) ? TRUE : FALSE);
834
835         other_decode_bitfield_value(bigbuf, oct, 0x04, 8);
836         proto_tree_add_text(subtree, tvb,
837             offset, 1,
838             "%s :  Message coding: %s",
839             bigbuf,
840             (*eight_bit) ? "8 bit data" : "GSM 7 bit default alphabet");
841
842         switch (oct & 0x03)
843         {
844         case 0x00: str = "Class 0"; break;
845         case 0x01: str = "Class 1 Default meaning: ME-specific"; break;
846         case 0x02: str = "Class 2 (U)SIM specific message"; break;
847         case 0x03: str = "Class 3 Default meaning: TE-specific"; break;
848         }
849
850         other_decode_bitfield_value(bigbuf, oct, 0x03, 8);
851         proto_tree_add_text(subtree, tvb,
852             offset, 1,
853             "%s :  Message Class: %s",
854             bigbuf,
855             str);
856     }
857 }
858
859 static void
860 dis_field_scts_aux(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
861 {
862     guint8 oct, oct2, oct3;
863     char   sign;
864
865
866     oct = tvb_get_guint8(tvb, offset);
867     oct2 = tvb_get_guint8(tvb, offset+1);
868     oct3 = tvb_get_guint8(tvb, offset+2);
869
870     proto_tree_add_text(tree,
871         tvb, offset, 3,
872         "Year %d%d, Month %d%d, Day %d%d",
873         oct & 0x0f,
874         (oct & 0xf0) >> 4,
875         oct2 & 0x0f,
876         (oct2 & 0xf0) >> 4,
877         oct3 & 0x0f,
878         (oct3 & 0xf0) >> 4);
879
880     offset += 3;
881
882     oct = tvb_get_guint8(tvb, offset);
883     oct2 = tvb_get_guint8(tvb, offset+1);
884     oct3 = tvb_get_guint8(tvb, offset+2);
885
886     proto_tree_add_text(tree,
887         tvb, offset, 3,
888         "Hour %d%d, Minutes %d%d, Seconds %d%d",
889         oct & 0x0f,
890         (oct & 0xf0) >> 4,
891         oct2 & 0x0f,
892         (oct2 & 0xf0) >> 4,
893         oct3 & 0x0f,
894         (oct3 & 0xf0) >> 4);
895
896     offset += 3;
897
898     oct = tvb_get_guint8(tvb, offset);
899
900     sign = (oct & 0x08)?'-':'+';
901     oct = (oct >> 4) + (oct & 0x07) * 10;
902
903     proto_tree_add_text(tree,
904         tvb, offset, 1,
905         "Timezone: GMT %c %d hours %d minutes",
906         sign, oct / 4, oct % 4 * 15);
907 }
908
909 /* 9.2.3.11 */
910 static void
911 dis_field_scts(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p)
912 {
913     proto_item     *item;
914     proto_tree     *subtree = NULL;
915     guint32        offset;
916     guint32        length;
917
918
919     offset = *offset_p;
920
921     length = tvb_length_remaining(tvb, offset);
922
923     if (length < 7)
924     {
925         proto_tree_add_text(tree,
926             tvb, offset, length,
927             "TP-Service-Centre-Time-Stamp: Short Data (?)");
928
929         *offset_p += length;
930         return;
931     }
932
933     item =
934         proto_tree_add_text(tree, tvb,
935             offset, 7,
936             "TP-Service-Centre-Time-Stamp");
937
938     subtree = proto_item_add_subtree(item, ett_scts);
939
940     dis_field_scts_aux(tvb, subtree, *offset_p);
941
942     *offset_p += 7;
943 }
944
945 /* 9.2.3.12 */
946 static void
947 dis_field_vp(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p, guint8 vp_form)
948 {
949     proto_item    *item;
950     proto_tree    *subtree = NULL;
951     guint32       offset;
952     guint32       length;
953     guint8        oct, oct2, oct3;
954     guint8        loc_form;
955     guint32       mins, hours;
956     gboolean      done;
957
958
959     if (vp_form == 0x00) return;
960
961     offset = *offset_p;
962     subtree = tree;
963
964     done = FALSE;
965     do
966     {
967         switch (vp_form)
968         {
969         case 1:
970             length = tvb_length_remaining(tvb, offset);
971
972             if (length < 7)
973             {
974                 proto_tree_add_text(tree,
975                     tvb, offset, length,
976                     "TP-Validity-Period: Short Data (?)");
977
978                 *offset_p += length;
979                 return;
980             }
981
982             item =
983                 proto_tree_add_text(tree, tvb,
984                     offset, 7,
985                     "TP-Validity-Period");
986
987             subtree = proto_item_add_subtree(item, ett_vp);
988
989             oct = tvb_get_guint8(tvb, offset);
990
991             other_decode_bitfield_value(bigbuf, oct, 0x80, 8);
992             proto_tree_add_text(subtree, tvb,
993                 offset, 1,
994                 "%s :  %s",
995                 bigbuf,
996                 (oct & 0x80) ? "Extended" : "No extension");
997
998             if (oct & 0x80)
999             {
1000                 proto_tree_add_text(subtree,
1001                     tvb, offset + 1, 6,
1002                     "Extension not implemented, ignored");
1003
1004                 *offset_p += 7;
1005                 return;
1006             }
1007
1008             other_decode_bitfield_value(bigbuf, oct, 0x40, 8);
1009             proto_tree_add_text(subtree, tvb,
1010                 offset, 1,
1011                 "%s :  %s",
1012                 bigbuf,
1013                 (oct & 0x40) ? "Single shot SM" : "Not single shot SM");
1014
1015             other_decode_bitfield_value(bigbuf, oct, 0x38, 8);
1016             proto_tree_add_text(subtree, tvb,
1017                 offset, 1,
1018                 "%s :  Reserved",
1019                 bigbuf);
1020
1021             loc_form = oct & 0x7;
1022
1023             switch (loc_form)
1024             {
1025             case 0x00:
1026                 other_decode_bitfield_value(bigbuf, oct, 0x07, 8);
1027                 proto_tree_add_text(subtree, tvb,
1028                     offset, 1,
1029                     "%s :  No Validity Period specified",
1030                     bigbuf);
1031
1032                 done = TRUE;
1033                 break;
1034
1035             case 0x01:
1036                 other_decode_bitfield_value(bigbuf, oct, 0x07, 8);
1037                 proto_tree_add_text(subtree, tvb,
1038                     offset, 1,
1039                     "%s :  Validity Period Format: relative",
1040                     bigbuf);
1041
1042                 offset++;
1043                 /* go around again */
1044                 vp_form = 2;
1045                 break;
1046
1047             case 0x02:
1048                 other_decode_bitfield_value(bigbuf, oct, 0x07, 8);
1049                 proto_tree_add_text(subtree, tvb,
1050                     offset, 1,
1051                     "%s :  Validity Period Format: relative",
1052                     bigbuf);
1053
1054                 offset++;
1055                 oct = tvb_get_guint8(tvb, offset);
1056
1057                 proto_tree_add_text(subtree, tvb,
1058                     offset, 1,
1059                     "%d seconds",
1060                     oct);
1061
1062                 done = TRUE;
1063                 break;
1064
1065             case 0x03:
1066                 other_decode_bitfield_value(bigbuf, oct, 0x07, 8);
1067                 proto_tree_add_text(subtree, tvb,
1068                     offset, 1,
1069                     "%s :  Validity Period Format: relative",
1070                     bigbuf);
1071
1072                 offset++;
1073                 oct = tvb_get_guint8(tvb, offset);
1074                 oct2 = tvb_get_guint8(tvb, offset+1);
1075                 oct3 = tvb_get_guint8(tvb, offset+2);
1076
1077                 proto_tree_add_text(subtree,
1078                     tvb, offset, 3,
1079                     "Hour %d%d, Minutes %d%d, Seconds %d%d",
1080                     oct & 0x0f,
1081                     (oct & 0xf0) >> 4,
1082                     oct2 & 0x0f,
1083                     (oct2 & 0xf0) >> 4,
1084                     oct3 & 0x0f,
1085                     (oct3 & 0xf0) >> 4);
1086
1087                 done = TRUE;
1088                 break;
1089
1090             default:
1091                 other_decode_bitfield_value(bigbuf, oct, 0x07, 8);
1092                 proto_tree_add_text(subtree, tvb,
1093                     offset, 1,
1094                     "%s :  Validity Period Format: Reserved",
1095                     bigbuf);
1096
1097                 done = TRUE;
1098                 break;
1099             }
1100             break;
1101
1102         case 2:
1103             oct = tvb_get_guint8(tvb, offset);
1104
1105             if (oct <= 143)
1106             {
1107                 mins = (oct + 1) * 5;
1108                 if (mins >= 60)
1109                 {
1110                     hours = mins / 60;
1111                     mins %= 60;
1112
1113                     proto_tree_add_text(subtree, tvb,
1114                         offset, 1,
1115                         "TP-Validity-Period: %d hours %d minutes",
1116                         hours,
1117                         mins);
1118                 }
1119                 else
1120                 {
1121                     proto_tree_add_text(subtree, tvb,
1122                         offset, 1,
1123                         "TP-Validity-Period: %d minutes",
1124                         mins);
1125                 }
1126             }
1127             else if ((oct >= 144) &&
1128                 (oct <= 167))
1129             {
1130                 mins = (oct - 143) * 30;
1131                 hours = 12 + (mins / 60);
1132                 mins %= 60;
1133
1134                 proto_tree_add_text(subtree, tvb,
1135                     offset, 1,
1136                     "TP-Validity-Period: %d hours %d minutes",
1137                     hours,
1138                     mins);
1139             }
1140             else if ((oct >= 168) &&
1141                 (oct <= 196))
1142             {
1143                 proto_tree_add_text(subtree, tvb,
1144                     offset, 1,
1145                     "TP-Validity-Period: %d day(s)",
1146                     oct - 166);
1147             }
1148             else if (oct >= 197)
1149             {
1150                 proto_tree_add_text(subtree, tvb,
1151                     offset, 1,
1152                     "TP-Validity-Period: %d week(s)",
1153                     oct - 192);
1154             }
1155
1156             done = TRUE;
1157             break;
1158
1159         case 3:
1160             length = tvb_length_remaining(tvb, offset);
1161
1162             if (length < 7)
1163             {
1164                 proto_tree_add_text(tree,
1165                     tvb, offset, length,
1166                     "TP-Validity-Period: Short Data (?)");
1167
1168                 *offset_p += length;
1169                 return;
1170             }
1171
1172             item =
1173                 proto_tree_add_text(tree, tvb,
1174                     offset, 7,
1175                     "TP-Validity-Period: absolute");
1176
1177             subtree = proto_item_add_subtree(item, ett_vp);
1178
1179             dis_field_scts_aux(tvb, subtree, *offset_p);
1180
1181             done = TRUE;
1182             break;
1183         }
1184     }
1185     while (!done);
1186
1187     if (vp_form == 2)
1188     {
1189         (*offset_p)++;
1190     }
1191     else
1192     {
1193         *offset_p += 7;
1194     }
1195 }
1196
1197 /* 9.2.3.13 */
1198 static void
1199 dis_field_dt(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p)
1200 {
1201     proto_item     *item;
1202     proto_tree     *subtree = NULL;
1203     guint32        offset;
1204     guint32        length;
1205
1206
1207     offset = *offset_p;
1208
1209     length = tvb_length_remaining(tvb, offset);
1210
1211     if (length < 7)
1212     {
1213         proto_tree_add_text(tree,
1214             tvb, offset, length,
1215             "TP-Discharge-Time: Short Data (?)");
1216
1217         *offset_p += length;
1218         return;
1219     }
1220
1221     item =
1222         proto_tree_add_text(tree, tvb,
1223             offset, 7,
1224             "TP-Discharge-Time");
1225
1226     subtree = proto_item_add_subtree(item, ett_dt);
1227
1228     dis_field_scts_aux(tvb, subtree, *offset_p);
1229
1230     *offset_p += 7;
1231 }
1232
1233 /* 9.2.3.14 */
1234 /* use dis_field_addr() */
1235
1236 /* 9.2.3.15 */
1237 static void
1238 dis_field_st(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 oct)
1239 {
1240     static const gchar *sc_complete = "Short message transaction completed";
1241     static const gchar *sc_temporary = "Temporary error, SC still trying to transfer SM";
1242     static const gchar *sc_perm = "Permanent error, SC is not making any more transfer attempts";
1243     static const gchar *sc_tempfin = "Temporary error, SC is not making any more transfer attempts";
1244     proto_item         *item;
1245     proto_tree         *subtree = NULL;
1246     guint8             value;
1247     const gchar        *str = NULL;
1248     const gchar        *str2 = NULL;
1249
1250
1251     item =
1252         proto_tree_add_text(tree, tvb,
1253             offset, 1,
1254             "TP-Status");
1255
1256     subtree = proto_item_add_subtree(item, ett_st);
1257
1258     other_decode_bitfield_value(bigbuf, oct, 0x80, 8);
1259     proto_tree_add_text(subtree, tvb,
1260         offset, 1,
1261         "%s :  Definition of bits 0-6: %s",
1262         bigbuf,
1263         (oct & 0x80) ?  "Reserved" : "as follows");
1264
1265     value = oct & 0x7f;
1266
1267     switch (value)
1268     {
1269     case 0x00: str2 = sc_complete; str = "Short message received by the SME"; break;
1270     case 0x01: str2 = sc_complete; str = "Short message forwarded by the SC to the SME but the SC is unable to confirm delivery"; break;
1271     case 0x02: str2 = sc_complete; str = "Short message replaced by the SC Reserved values"; break;
1272
1273     case 0x20: str2 = sc_temporary; str = "Congestion"; break;
1274     case 0x21: str2 = sc_temporary; str = "SME busy"; break;
1275     case 0x22: str2 = sc_temporary; str = "No response from SME"; break;
1276     case 0x23: str2 = sc_temporary; str = "Service rejected"; break;
1277     case 0x24: str2 = sc_temporary; str = "Quality of service not available"; break;
1278     case 0x25: str2 = sc_temporary; str = "Error in SME"; break;
1279
1280     case 0x40: str2 = sc_perm; str = "Remote procedure error"; break;
1281     case 0x41: str2 = sc_perm; str = "Incompatible destination"; break;
1282     case 0x42: str2 = sc_perm; str = "Connection rejected by SME"; break;
1283     case 0x43: str2 = sc_perm; str = "Not obtainable"; break;
1284     case 0x44: str2 = sc_perm; str = "Quality of service not available"; break;
1285     case 0x45: str2 = sc_perm; str = "No interworking available"; break;
1286     case 0x46: str2 = sc_perm; str = "SM Validity Period Expired"; break;
1287     case 0x47: str2 = sc_perm; str = "SM Deleted by originating SME"; break;
1288     case 0x48: str2 = sc_perm; str = "SM Deleted by SC Administration"; break;
1289     case 0x49: str2 = sc_perm; str = "SM does not exist (The SM may have previously existed in the SC but the SC no longer has knowledge of it or the SM may never have previously existed in the SC)"; break;
1290
1291     case 0x60: str2 = sc_tempfin; str = "Congestion"; break;
1292     case 0x61: str2 = sc_tempfin; str = "SME busy"; break;
1293     case 0x62: str2 = sc_tempfin; str = "No response from SME"; break;
1294     case 0x63: str2 = sc_tempfin; str = "Service rejected"; break;
1295     case 0x64: str2 = sc_tempfin; str = "Quality of service not available"; break;
1296     case 0x65: str2 = sc_tempfin; str = "Error in SME"; break;
1297
1298     default:
1299         if ((value >= 0x03) &&
1300             (value <= 0x0f))
1301         {
1302             str2 = sc_complete;
1303             str = "Reserved";
1304         }
1305         else if ((value >= 0x10) &&
1306             (value <= 0x1f))
1307         {
1308             str2 = sc_complete;
1309             str = "Values specific to each SC";
1310         }
1311         else if ((value >= 0x26) &&
1312             (value <= 0x2f))
1313         {
1314             str2 = sc_temporary;
1315             str = "Reserved";
1316         }
1317         else if ((value >= 0x30) &&
1318             (value <= 0x3f))
1319         {
1320             str2 = sc_temporary;
1321             str = "Values specific to each SC";
1322         }
1323         else if ((value >= 0x4a) &&
1324             (value <= 0x4f))
1325         {
1326             str2 = sc_perm;
1327             str = "Reserved";
1328         }
1329         else if ((value >= 0x50) &&
1330             (value <= 0x5f))
1331         {
1332             str2 = sc_perm;
1333             str = "Values specific to each SC";
1334         }
1335         else if ((value >= 0x66) &&
1336             (value <= 0x6f))
1337         {
1338             str2 = sc_tempfin;
1339             str = "Reserved";
1340         }
1341         else if ((value >= 0x70) &&
1342             (value <= 0x7f))
1343         {
1344             str2 = sc_tempfin;
1345             str = "Values specific to each SC";
1346         }
1347         break;
1348     }
1349
1350     other_decode_bitfield_value(bigbuf, oct, 0x7f, 8);
1351     proto_tree_add_text(subtree, tvb,
1352         offset, 1,
1353         "%s :  (%d) %s, %s",
1354         bigbuf,
1355         value,
1356         str2,
1357         str);
1358 }
1359
1360 /* 9.2.3.16 */
1361 #define DIS_FIELD_UDL(m_tree, m_offset) \
1362 { \
1363     proto_tree_add_text(m_tree, tvb, \
1364         m_offset, 1, \
1365         "TP-User-Data-Length: (%d) %s", \
1366         oct, \
1367         oct ? "depends on Data-Coding-Scheme" : "no User-Data");\
1368 }
1369
1370 /* 9.2.3.17 */
1371 #define DIS_FIELD_RP(m_tree, m_bitmask, m_offset) \
1372 { \
1373     other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
1374     proto_tree_add_text(m_tree, tvb, \
1375         m_offset, 1, \
1376         "%s :  TP-Reply-Path: parameter is %sset in this SMS-SUBMIT/DELIVER", \
1377         bigbuf, \
1378         (oct & m_bitmask) ? "" : "not "); \
1379 }
1380
1381 /* 9.2.3.18 */
1382 #define DIS_FIELD_MN(m_tree, m_offset) \
1383 { \
1384     proto_tree_add_text(m_tree, tvb, \
1385         m_offset, 1, \
1386         "TP-Message-Number: %d", \
1387         oct); \
1388 }
1389
1390 /* 9.2.3.19 */
1391 #define DIS_FIELD_CT(m_tree, m_offset) \
1392 { \
1393     switch (oct) \
1394     { \
1395     case 0: str = "Enquiry relating to previously submitted short message"; break; \
1396     case 1: str = "Cancel Status Report Request relating to previously submitted short message"; break; \
1397     case 2: str = "Delete previously submitted Short Message"; break; \
1398     case 3: str = "Enable Status Report Request relating to previously submitted short message"; break; \
1399     default: \
1400         if ((oct >= 0x04) && \
1401             (oct <= 0x1f)) \
1402         { \
1403             str = "Reserved unspecified"; \
1404         } \
1405         else if (oct >= 0xe0) \
1406         { \
1407             str = "Values specific for each SC"; \
1408         } \
1409         else \
1410         { \
1411             str = "undefined"; \
1412         } \
1413         break; \
1414     } \
1415     proto_tree_add_text(m_tree, tvb, \
1416         m_offset, 1, \
1417         "TP-Command-Type: (%d), %s", \
1418         oct, \
1419         str); \
1420 }
1421
1422 /* 9.2.3.20 */
1423 #define DIS_FIELD_CDL(m_tree, m_offset) \
1424 { \
1425     proto_tree_add_text(m_tree, tvb, \
1426         m_offset, 1, \
1427         "TP-Command-Data-Length: (%d)%s", \
1428         oct, \
1429         oct ? "" : " no Command-Data");\
1430 }
1431
1432 /* 9.2.3.21 */
1433 /* done in-line in the message functions */
1434
1435 /*
1436  * 9.2.3.22 TP-Failure-Cause (TP-FCS)
1437  */
1438
1439
1440 static const value_string gsm_sms_tp_failure_cause_values[] = {
1441         /* 00 - 7F Reserved */
1442         /* 80 - 8F TP-PID errors */
1443   { 0x80,        "Telematic interworking not supported" },
1444   { 0x81,        "Short message Type 0 not supported" },
1445   { 0x82,        "Cannot replace short message" },
1446         /* 83 - 8E Reserved */
1447   { 0x83,        "Reserved" },
1448   { 0x84,        "Reserved" },
1449   { 0x85,        "Reserved" },
1450   { 0x86,        "Reserved" },
1451   { 0x87,        "Reserved" },
1452   { 0x88,        "Reserved" },
1453   { 0x89,        "Reserved" },
1454   { 0x8a,        "Reserved" },
1455   { 0x8b,        "Reserved" },
1456   { 0x8c,        "Reserved" },
1457   { 0x8d,        "Reserved" },
1458   { 0x8e,        "Reserved" },
1459
1460   { 0x8F,        "Unspecified TP-PID error" },
1461         /* 90 - 9F TP-DCS errors */
1462   { 0x90,        "Data coding scheme (alphabet) not supported" },
1463   { 0x91,        "Message class not supported" },
1464         /* 92 - 9E Reserved */
1465   { 0x92,        "Reserved" },
1466   { 0x93,        "Reserved" },
1467   { 0x94,        "Reserved" },
1468   { 0x95,        "Reserved" },
1469   { 0x96,        "Reserved" },
1470   { 0x97,        "Reserved" },
1471   { 0x98,        "Reserved" },
1472   { 0x99,        "Reserved" },
1473   { 0x9a,        "Reserved" },
1474   { 0x9b,        "Reserved" },
1475   { 0x9c,        "Reserved" },
1476   { 0x9d,        "Reserved" },
1477   { 0x9e,        "Reserved" },
1478
1479   { 0x9F,        "Unspecified TP-DCS error" },
1480         /* A0 - AF TP-Command Errors */
1481   { 0xA0,        "Command cannot be actioned" },
1482   { 0xA1,        "Command unsupported" },
1483         /* A2 - AE Reserved */
1484   { 0xa2,        "Reserved" },
1485   { 0xa3,        "Reserved" },
1486   { 0xa4,        "Reserved" },
1487   { 0xa5,        "Reserved" },
1488   { 0xa6,        "Reserved" },
1489   { 0xa7,        "Reserved" },
1490   { 0xa8,        "Reserved" },
1491   { 0xa9,        "Reserved" },
1492   { 0xaa,        "Reserved" },
1493   { 0xab,        "Reserved" },
1494   { 0xac,        "Reserved" },
1495   { 0xad,        "Reserved" },
1496   { 0xae,        "Reserved" },
1497
1498   { 0xAF,        "Unspecified TP-Command error" },
1499   { 0xB0,        "TPDU not supported" },
1500         /* B1 - BF Reserved */
1501   { 0xb1,        "Reserved" },
1502   { 0xb2,        "Reserved" },
1503   { 0xb3,        "Reserved" },
1504   { 0xb4,        "Reserved" },
1505   { 0xb5,        "Reserved" },
1506   { 0xb6,        "Reserved" },
1507   { 0xb7,        "Reserved" },
1508   { 0xb8,        "Reserved" },
1509   { 0xb9,        "Reserved" },
1510   { 0xba,        "Reserved" },
1511   { 0xbb,        "Reserved" },
1512   { 0xbc,        "Reserved" },
1513   { 0xbd,        "Reserved" },
1514   { 0xbe,        "Reserved" },
1515   { 0xbf,        "Reserved" },
1516
1517   { 0xC0,        "SC busy" },
1518   { 0xC1,        "No SC subscription" },
1519   { 0xC2,        "SC system failure" },
1520   { 0xC3,        "Invalid SME address" },
1521   { 0xC4,        "Destination SME barred" },
1522   { 0xC5,        "SM Rejected-Duplicate SM" },
1523   { 0xC6,        "TP-VPF not supported" },
1524   { 0xC7,        "TP-VP not supported" },
1525         /* C8 - CF Reserved */
1526   { 0xc8,        "Reserved" },
1527   { 0xc9,        "Reserved" },
1528   { 0xca,        "Reserved" },
1529   { 0xcb,        "Reserved" },
1530   { 0xcc,        "Reserved" },
1531   { 0xcd,        "Reserved" },
1532   { 0xce,        "Reserved" },
1533   { 0xcf,        "Reserved" },
1534
1535   { 0xD0,        "(U)SIM SMS storage full" },
1536   { 0xD1,        "No SMS storage capability in (U)SIM" },
1537   { 0xD2,        "Error in MS" },
1538   { 0xD3,        "Memory Capacity Exceeded" },
1539   { 0xD4,        "(U)SIM Application Toolkit Busy" },
1540   { 0xD5,        "(U)SIM data download error" },
1541         /* D6 - DF Reserved */
1542   { 0xd6,        "Reserved" },
1543   { 0xd7,        "Reserved" },
1544   { 0xd8,        "Reserved" },
1545   { 0xd9,        "Reserved" },
1546   { 0xda,        "Reserved" },
1547   { 0xdb,        "Reserved" },
1548   { 0xdc,        "Reserved" },
1549   { 0xdd,        "Reserved" },
1550   { 0xde,        "Reserved" },
1551   { 0xdf,        "Reserved" },
1552
1553   /* E0 - FE Values specific to an application */
1554   { 0xe0,        "Value specific to an application" },
1555   { 0xe1,        "Value specific to an application" },
1556   { 0xe2,        "Value specific to an application" },
1557   { 0xe3,        "Value specific to an application" },
1558   { 0xe4,        "Value specific to an application" },
1559   { 0xe5,        "Value specific to an application" },
1560   { 0xe6,        "Value specific to an application" },
1561   { 0xe7,        "Value specific to an application" },
1562   { 0xe8,        "Value specific to an application" },
1563   { 0xe9,        "Value specific to an application" },
1564   { 0xea,        "Value specific to an application" },
1565   { 0xeb,        "Value specific to an application" },
1566   { 0xec,        "Value specific to an application" },
1567   { 0xed,        "Value specific to an application" },
1568   { 0xee,        "Value specific to an application" },
1569   { 0xef,        "Value specific to an application" },
1570   { 0xf0,        "Value specific to an application" },
1571   { 0xf1,        "Value specific to an application" },
1572   { 0xf2,        "Value specific to an application" },
1573   { 0xf3,        "Value specific to an application" },
1574   { 0xf4,        "Value specific to an application" },
1575   { 0xf5,        "Value specific to an application" },
1576   { 0xf6,        "Value specific to an application" },
1577   { 0xf7,        "Value specific to an application" },
1578   { 0xf8,        "Value specific to an application" },
1579   { 0xf9,        "Value specific to an application" },
1580   { 0xfa,        "Value specific to an application" },
1581   { 0xfb,        "Value specific to an application" },
1582   { 0xfc,        "Value specific to an application" },
1583   { 0xfd,        "Value specific to an application" },
1584   { 0xfe,        "Value specific to an application" },
1585
1586   { 0xFF,        "Unspecified error cause" },
1587   { 0,           NULL }
1588  };
1589 static value_string_ext gsm_sms_tp_failure_cause_values_ext = VALUE_STRING_EXT_INIT(gsm_sms_tp_failure_cause_values);
1590
1591 static void
1592 dis_field_fcs(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 oct _U_)
1593 {
1594         proto_tree_add_item(tree, hf_gsm_sms_tp_fail_cause, tvb, offset, 1, ENC_BIG_ENDIAN);
1595 }
1596
1597 /* 9.2.3.23 */
1598 #define DIS_FIELD_UDHI(m_tree, m_bitmask, m_offset, m_udhi) \
1599 { \
1600     SMS_SHIFTMASK(oct & m_bitmask, m_bitmask, m_udhi); \
1601     other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
1602     proto_tree_add_text(m_tree, tvb, \
1603         m_offset, 1, \
1604         "%s :  TP-User-Data-Header-Indicator: %s short message", \
1605         bigbuf, \
1606         m_udhi ? \
1607         "The beginning of the TP-UD field contains a Header in addition to the" : \
1608         "The TP-UD field contains only the"); \
1609 }
1610
1611 /*
1612  * FROM GNOKII
1613  * gsm-encoding.c
1614  * gsm-sms.c
1615  */
1616 #define GN_BYTE_MASK ((1 << bits) - 1)
1617
1618 int
1619 gsm_sms_char_7bit_unpack(unsigned int offset, unsigned int in_length, unsigned int out_length,
1620                          const guint8 *input, unsigned char *output)
1621 {
1622     unsigned char *out_num = output; /* Current pointer to the output buffer */
1623     const guint8 *in_num = input;    /* Current pointer to the input buffer */
1624     unsigned char rest = 0x00;
1625     int bits;
1626
1627     bits = offset ? offset : 7;
1628
1629     while ((unsigned int)(in_num - input) < in_length)
1630     {
1631         *out_num = ((*in_num & GN_BYTE_MASK) << (7 - bits)) | rest;
1632         rest = *in_num >> bits;
1633
1634         /* If we don't start from 0th bit, we shouldn't go to the
1635            next char. Under *out_num we have now 0 and under Rest -
1636            _first_ part of the char. */
1637         if ((in_num != input) || (bits == 7)) out_num++;
1638         in_num++;
1639
1640         if ((unsigned int)(out_num - output) >= out_length) break;
1641
1642         /* After reading 7 octets we have read 7 full characters but
1643            we have 7 bits as well. This is the next character */
1644         if (bits == 1)
1645         {
1646             *out_num = rest;
1647             out_num++;
1648             bits = 7;
1649             rest = 0x00;
1650         }
1651         else
1652         {
1653             bits--;
1654         }
1655     }
1656
1657     return (int)(out_num - output);
1658 }
1659
1660 #define GN_CHAR_ALPHABET_SIZE 128
1661
1662 #define GN_CHAR_ESCAPE 0x1b
1663
1664 static gunichar gsm_default_alphabet[GN_CHAR_ALPHABET_SIZE] = {
1665
1666     /* ETSI GSM 03.38, version 6.0.1, section 6.2.1; Default alphabet */
1667     /* Fixed to use unicode */
1668     /* Characters in hex position 10, [12 to 1a] and 24 are not present on
1669        latin1 charset, so we cannot reproduce on the screen, however they are
1670        greek symbol not present even on my Nokia */
1671
1672     '@',   0xa3,  '$',   0xa5,  0xe8,  0xe9,  0xf9,  0xec,
1673     0xf2,  0xc7,  '\n',  0xd8,  0xf8,  '\r',  0xc5,  0xe5,
1674     0x394, '_',   0x3a6, 0x393, 0x39b, 0x3a9, 0x3a0, 0x3a8,
1675     0x3a3, 0x398, 0x39e, 0xa0,  0xc6,  0xe6,  0xdf,  0xc9,
1676     ' ',   '!',   '\"',  '#',   0xa4,  '%',   '&',   '\'',
1677     '(',   ')',   '*',   '+',   ',',   '-',   '.',   '/',
1678     '0',   '1',   '2',   '3',   '4',   '5',   '6',   '7',
1679     '8',   '9',   ':',   ';',   '<',   '=',   '>',   '?',
1680     0xa1,  'A',   'B',   'C',   'D',   'E',   'F',   'G',
1681     'H',   'I',   'J',   'K',   'L',   'M',   'N',   'O',
1682     'P',   'Q',   'R',   'S',   'T',   'U',   'V',   'W',
1683     'X',   'Y',   'Z',   0xc4,  0xd6,  0xd1,  0xdc,  0xa7,
1684     0xbf,  'a',   'b',   'c',   'd',   'e',   'f',   'g',
1685     'h',   'i',   'j',   'k',   'l',   'm',   'n',   'o',
1686     'p',   'q',   'r',   's',   't',   'u',   'v',   'w',
1687     'x',   'y',   'z',   0xe4,  0xf6,  0xf1,  0xfc,  0xe0
1688 };
1689
1690 static gboolean
1691 char_is_escape(unsigned char value)
1692 {
1693     return (value == GN_CHAR_ESCAPE);
1694 }
1695
1696 static gunichar
1697 char_def_alphabet_ext_decode(unsigned char value)
1698 {
1699     switch (value)
1700     {
1701     case 0x0a: return 0x0c; /* form feed */
1702     case 0x14: return '^';
1703     case 0x28: return '{';
1704     case 0x29: return '}';
1705     case 0x2f: return '\\';
1706     case 0x3c: return '[';
1707     case 0x3d: return '~';
1708     case 0x3e: return ']';
1709     case 0x40: return '|';
1710     case 0x65: return 0x20ac; /* euro */
1711     default: return '?'; /* invalid character */
1712     }
1713 }
1714
1715 static gunichar
1716 char_def_alphabet_decode(unsigned char value)
1717 {
1718     if (value < GN_CHAR_ALPHABET_SIZE)
1719     {
1720         return gsm_default_alphabet[value];
1721     }
1722     else
1723     {
1724         return '?';
1725     }
1726 }
1727
1728 gchar *
1729 gsm_sms_chars_to_utf8(const unsigned char* src, int len)
1730 {
1731     gint outlen, i, j;
1732     gunichar c;
1733     gchar *outbuf;
1734
1735     /* Scan the input string to see how long the output string will be */
1736     for (outlen = 0, j = 0; j < len;  j++)
1737     {
1738         if (char_is_escape(src[j])) {
1739             j++;
1740             if (j == len)
1741                 c = '?';        /* escape with nothing following it - error */
1742             else
1743                 c = char_def_alphabet_ext_decode(src[j]);
1744         }
1745         else
1746             c = char_def_alphabet_decode(src[j]);
1747         outlen += g_unichar_to_utf8(c,NULL);
1748     }
1749
1750     /* Now allocate a buffer for the output string and fill it in */
1751     outbuf = ep_alloc(outlen + 1);
1752     for (i = 0, j = 0; j < len;  j++)
1753     {
1754         if (char_is_escape(src[j])) {
1755             j++;
1756             if (j == len)
1757                 c = '?';        /* escape with nothing following it - error */
1758             else
1759                 c = char_def_alphabet_ext_decode(src[j]);
1760         }
1761         else
1762             c = char_def_alphabet_decode(src[j]);
1763         i += g_unichar_to_utf8(c,&(outbuf[i]));
1764     }
1765     outbuf[i] = '\0';
1766     return outbuf;
1767 }
1768
1769 /*
1770  * END FROM GNOKII
1771  */
1772
1773 /* 9.2.3.24.1 */
1774 static void
1775 dis_iei_csm8(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
1776 {
1777     guint8        oct;
1778
1779     EXACT_DATA_CHECK(length, 3);
1780     oct = tvb_get_guint8(tvb, offset);
1781     g_sm_id = oct;
1782     proto_tree_add_uint (tree,
1783                          hf_gsm_sms_ud_multiple_messages_msg_id,
1784                          tvb, offset, 1, g_sm_id);
1785     offset++;
1786
1787     oct = tvb_get_guint8(tvb, offset);
1788     g_frags = oct;
1789     proto_tree_add_uint (tree,
1790                          hf_gsm_sms_ud_multiple_messages_msg_parts,
1791                          tvb , offset , 1, g_frags);
1792     offset++;
1793     oct = tvb_get_guint8(tvb, offset);
1794     g_frag = oct;
1795     proto_tree_add_uint (tree,
1796                          hf_gsm_sms_ud_multiple_messages_msg_part,
1797                          tvb, offset, 1, g_frag);
1798
1799 }
1800
1801 /* TODO 9.2.3.24.2 Special SMS Message Indication */
1802
1803 /* 9.2.3.24.3 */
1804 static void
1805 dis_iei_apa_8bit(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
1806 {
1807     const gchar   *str = NULL;
1808     guint8        oct;
1809
1810
1811     EXACT_DATA_CHECK(length, 2);
1812
1813     oct = tvb_get_guint8(tvb, offset);
1814     g_port_dst = oct;
1815     if (oct < 240)
1816     {
1817         str = "Reserved";
1818     }
1819     else
1820     {
1821         str = "Available for allocation by applications";
1822     }
1823
1824     proto_tree_add_text(tree,
1825         tvb, offset, 1,
1826         "Destination port: %d, %s",
1827         oct,
1828         str);
1829
1830     offset++;
1831     oct = tvb_get_guint8(tvb, offset);
1832     g_port_src = oct;
1833     if (oct < 240)
1834     {
1835         str = "Reserved";
1836     }
1837     else
1838     {
1839         str = "Available for allocation by applications";
1840     }
1841
1842     proto_tree_add_text(tree,
1843         tvb, offset, 1,
1844         "Originator port: %d, %s",
1845         oct,
1846         str);
1847 }
1848
1849 /* 9.2.3.24.4 */
1850 static void
1851 dis_iei_apa_16bit(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
1852 {
1853     const gchar    *str = NULL;
1854     guint32        value;
1855
1856
1857     EXACT_DATA_CHECK(length, 4);
1858
1859     value = tvb_get_ntohs(tvb, offset);
1860     g_port_dst = value;
1861     if (value < 16000)
1862     {
1863         str = "As allocated by IANA (http://www.IANA.com/)";
1864     }
1865     else if (value < 17000)
1866     {
1867         str = "Available for allocation by applications";
1868     }
1869     else
1870     {
1871         str = "Reserved";
1872     }
1873
1874     proto_tree_add_text(tree,
1875         tvb, offset, 2,
1876         "Destination port: %d, %s",
1877         value,
1878         str);
1879
1880     offset += 2;
1881     value = tvb_get_ntohs(tvb, offset);
1882     g_port_src = value;
1883     if (value < 16000)
1884     {
1885         str = "As allocated by IANA (http://www.IANA.com/)";
1886     }
1887     else if (value < 17000)
1888     {
1889         str = "Available for allocation by applications";
1890     }
1891     else
1892     {
1893         str = "Reserved";
1894     }
1895
1896     proto_tree_add_text(tree,
1897         tvb, offset, 2,
1898         "Originator port: %d, %s",
1899         value,
1900         str);
1901
1902         g_is_wsp = 1;
1903 }
1904
1905 /* 9.2.3.24.5 */
1906 static void
1907 dis_iei_scp(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
1908 {
1909     guint8        oct;
1910
1911     EXACT_DATA_CHECK(length, 1);
1912
1913     oct = tvb_get_guint8(tvb, offset);
1914
1915     if (oct & 0x01)
1916     {
1917         proto_tree_add_text(tree,
1918                             tvb, offset, 1,
1919                             "Status Report for short message transaction completed");
1920     }
1921     else
1922     {
1923         proto_tree_add_text(tree,
1924                             tvb, offset, 1,
1925                             "No Status Report for short message transaction completed");
1926     }
1927
1928     if (oct & 0x02)
1929     {
1930         proto_tree_add_text(tree,
1931                             tvb, offset, 1,
1932                             "Status Report for permanent error when SC is not making any more transfer attempts");
1933     }
1934     else
1935     {
1936         proto_tree_add_text(tree,
1937                             tvb, offset, 1,
1938                             "No Status Report for permanent error when SC is not making any more transfer attempts");
1939     }
1940
1941     if (oct & 0x04)
1942     {
1943         proto_tree_add_text(tree,
1944                             tvb, offset, 1,
1945                             "Status Report for temporary error when SC is not making any more transfer attempts");
1946     }
1947     else
1948     {
1949         proto_tree_add_text(tree,
1950                             tvb, offset, 1,
1951                             "No Status Report for temporary error when SC is not making any more transfer attempts");
1952     }
1953
1954     if (oct & 0x08)
1955     {
1956
1957         proto_tree_add_text(tree,
1958                             tvb, offset, 1,
1959                             "Status Report for temporary error when SC is still trying to transfer SM");
1960     }
1961     else
1962     {
1963         proto_tree_add_text(tree,
1964                             tvb, offset, 1,
1965                             "No Status Report for temporary error when SC is still trying to transfer SM");
1966     }
1967
1968     if (oct & 0x40)
1969     {
1970
1971         proto_tree_add_text(tree,
1972                             tvb, offset, 1,
1973                             "A Status Report generated by this Short Message, due to a permanent error or last temporary error, cancels the SRR of the rest of the Short Messages in a concatenated message");
1974     }
1975     else
1976     {
1977         proto_tree_add_text(tree,
1978                             tvb, offset, 1,
1979                             "No activation");
1980     }
1981
1982     if (oct & 0x80)
1983     {
1984
1985         proto_tree_add_text(tree,
1986                             tvb, offset, 1,
1987                             "Include original UDH into the Status Report");
1988     }
1989     else
1990     {
1991         proto_tree_add_text(tree,
1992                             tvb, offset, 1,
1993                             "Do not include original UDH into the Status Report");
1994     }
1995
1996 }
1997
1998 /* 9.2.3.24.6 */
1999 static void
2000 dis_iei_udh_si(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
2001 {
2002     guint8        oct;
2003
2004     EXACT_DATA_CHECK(length, 1);
2005
2006     oct = tvb_get_guint8(tvb, offset);
2007
2008     switch (oct)
2009     {
2010         case 1:
2011             proto_tree_add_text(tree,
2012                                 tvb, offset, 1,
2013                                 "The following part of the UDH is created by the original sender (valid in case of Status Report)");
2014             break;
2015         case 2:
2016             proto_tree_add_text(tree,
2017                                 tvb, offset, 1,
2018                                 "The following part of the UDH is created by the original receiver (valid in case of Status Report)");
2019             break;
2020         case 3:
2021             proto_tree_add_text(tree,
2022                                 tvb, offset, 1,
2023                                 "The following part of the UDH is created by the SMSC (can occur in any message or report)");
2024             break;
2025         default:
2026             proto_tree_add_text(tree,
2027                                 tvb, offset, 1,
2028                                 "The following part of the UDH is created by %d" , oct);
2029             break;
2030     }
2031 }
2032 /* 9.2.3.24.8 */
2033 static void
2034 dis_iei_csm16(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
2035 {
2036     guint8        oct;
2037     guint16        oct_ref;
2038
2039     EXACT_DATA_CHECK(length, 4);
2040     oct_ref = tvb_get_ntohs(tvb, offset);
2041     g_sm_id = oct_ref;
2042     proto_tree_add_uint (tree,
2043                          hf_gsm_sms_ud_multiple_messages_msg_id,
2044                          tvb, offset, 2, g_sm_id);
2045     offset+=2;
2046     oct = tvb_get_guint8(tvb, offset);
2047     g_frags = oct;
2048     proto_tree_add_uint (tree,
2049                          hf_gsm_sms_ud_multiple_messages_msg_parts,
2050                          tvb , offset , 1, g_frags);
2051
2052     offset++;
2053     oct = tvb_get_guint8(tvb, offset);
2054     g_frag = oct;
2055     proto_tree_add_uint (tree,
2056                          hf_gsm_sms_ud_multiple_messages_msg_part,
2057                          tvb, offset, 1, g_frag);
2058 }
2059
2060 static const value_string text_color_values[] = {
2061   { 0x00,        "Black" },
2062   { 0x01,        "Dark Grey" },
2063   { 0x02,        "Dark Red" },
2064   { 0x03,        "Dark Yellow" },
2065   { 0x04,        "Dark Green" },
2066   { 0x05,        "Dark Cyan" },
2067   { 0x06,        "Dark Blue" },
2068   { 0x07,        "Dark Magenta" },
2069   { 0x08,        "Grey" },
2070   { 0x09,        "White" },
2071   { 0x0A,        "Bright Red" },
2072   { 0x0B,        "Bright Yellow" },
2073   { 0x0C,        "Bright Green" },
2074   { 0x0D,        "Bright Cyan" },
2075   { 0x0E,        "Bright Blue" },
2076   { 0x0F,        "Bright Magenta" },
2077   { 0,           NULL }
2078 };
2079
2080 /* 9.2.3.24.10.1.1 */
2081 static void
2082 dis_iei_tf(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
2083 {
2084     const gchar *str = NULL;
2085     guint8      oct;
2086     proto_item  *item;
2087     proto_item  *item_colour;
2088     proto_tree  *subtree = NULL;
2089     proto_tree  *subtree_colour = NULL;
2090
2091
2092     EXACT_DATA_CHECK(length, 4);
2093     oct = tvb_get_guint8(tvb, offset);
2094
2095     proto_tree_add_text(tree, tvb, offset, 1,
2096                         "Start position of the text formatting: %d", oct);
2097     offset++;
2098
2099     oct = tvb_get_guint8(tvb, offset);
2100
2101     proto_tree_add_text(tree, tvb, offset, 1, "Text formatting length: %d",
2102                         oct);
2103     offset++;
2104
2105     oct = tvb_get_guint8(tvb, offset);
2106
2107     item = proto_tree_add_text(tree, tvb, offset, 1, "formatting mode");
2108
2109     subtree = proto_item_add_subtree(item, ett_udh_tfm);
2110     switch(oct & 0x03)
2111     {
2112         case 0x00:
2113             str = "Left";
2114             break;
2115         case 0x01:
2116             str = "Center";
2117             break;
2118         case 0x02:
2119             str = "Right";
2120             break;
2121         case 0x03:
2122             str = "Language dependent";
2123             break;
2124     }
2125
2126     proto_tree_add_text(subtree, tvb, offset, 1, "Alignment : %d %s",
2127                         oct & 0x03 , str);
2128
2129     switch((oct >> 2) & 0x03)
2130     {
2131         case 0x00:
2132             str = "Normal";
2133             break;
2134         case 0x01:
2135             str = "Large";
2136             break;
2137         case 0x02:
2138             str = "Small";
2139             break;
2140         case 0x03:
2141             str = "reserved";
2142             break;
2143     }
2144
2145     proto_tree_add_text(subtree, tvb, offset, 1, "Font Size : %d %s",
2146                         (oct >> 2) & 0x03 , str);
2147
2148     if(oct & 0x10)
2149         str = "on";
2150     else
2151         str = "off";
2152     proto_tree_add_text(subtree, tvb, offset, 1, "Style bold : %d %s",
2153                         oct & 0x10 , str);
2154
2155     if(oct & 0x20)
2156         str = "on";
2157     else
2158         str = "off";
2159     proto_tree_add_text(subtree, tvb, offset, 1, "Style Italic : %d %s",
2160                         oct & 0x20 , str);
2161
2162     if(oct & 0x40)
2163         str = "on";
2164     else
2165         str = "off";
2166     proto_tree_add_text(subtree, tvb, offset, 1, "Style Underlined : %d %s",
2167                         oct & 0x40 , str);
2168
2169     if(oct & 0x80)
2170         str = "on";
2171     else
2172         str = "off";
2173     proto_tree_add_text(subtree, tvb, offset, 1, "Style Strikethrough : %d %s",
2174                         oct & 0x80 , str);
2175
2176     offset++;
2177     oct = tvb_get_guint8(tvb, offset);
2178     item_colour = proto_tree_add_text(tree, tvb, offset, 1, "Text Colour");
2179
2180     subtree_colour = proto_item_add_subtree(item_colour, ett_udh_tfc);
2181
2182
2183     str = val_to_str_const(oct & 0x0f, text_color_values, "Unknown");
2184     proto_tree_add_text(subtree_colour, tvb, offset, 1,
2185                         "Foreground Colour : 0x%x %s",
2186                         oct & 0x0f , str);
2187
2188     str = val_to_str_const((oct >> 4) & 0x0f, text_color_values, "Unknown");
2189     proto_tree_add_text(subtree_colour,
2190                         tvb, offset, 1,
2191                         "Background Colour : 0x%x %s",
2192                         (oct >> 4) & 0x0f , str);
2193
2194 }
2195
2196 /* 9.2.3.24.10.1.2 */
2197 static void
2198 dis_iei_ps(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
2199 {
2200     guint8        oct;
2201
2202     EXACT_DATA_CHECK(length, 2);
2203     oct = tvb_get_guint8(tvb, offset);
2204
2205     proto_tree_add_text(tree,
2206                         tvb, offset, 1,
2207                         "position: %d",
2208                         oct);
2209     offset++;
2210
2211     oct = tvb_get_guint8(tvb, offset);
2212
2213     proto_tree_add_text(tree,
2214                         tvb, offset, 1,
2215                         "sound number: %d",
2216                         oct);
2217 }
2218
2219 /* 9.2.3.24.10.1.3 */
2220 static void
2221 dis_iei_uds(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
2222 {
2223     guint8        oct;
2224
2225     SHORT_DATA_CHECK(length, 2);
2226     oct = tvb_get_guint8(tvb, offset);
2227
2228     proto_tree_add_text(tree,
2229                         tvb, offset, 1,
2230                         "position: %d",
2231                         oct);
2232     offset++;
2233
2234     proto_tree_add_text(tree,
2235                         tvb, offset, length - 1,
2236                         "User Defined Sound ");
2237 }
2238
2239
2240 /* 9.2.3.24.10.1.4 */
2241 static void
2242 dis_iei_pa(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
2243 {
2244     guint8        oct;
2245
2246     EXACT_DATA_CHECK(length, 2);
2247     oct = tvb_get_guint8(tvb, offset);
2248
2249     proto_tree_add_text(tree,
2250                         tvb, offset, 1,
2251                         "position: %d",
2252                         oct);
2253     offset++;
2254
2255     oct = tvb_get_guint8(tvb, offset);
2256
2257     proto_tree_add_text(tree,
2258                         tvb, offset, 1,
2259                         "animation number: %d",
2260                         oct);
2261 }
2262
2263
2264 /* 9.2.3.24.10.1.5 */
2265 static void
2266 dis_iei_la(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
2267 {
2268     guint8        oct;
2269
2270     SHORT_DATA_CHECK(length, 2);
2271     oct = tvb_get_guint8(tvb, offset);
2272
2273     proto_tree_add_text(tree,
2274                         tvb, offset, 1,
2275                         "position: %d",
2276                         oct);
2277     offset++;
2278
2279     proto_tree_add_text(tree,
2280                         tvb, offset, length - 1,
2281                         "Large Animation ");
2282 }
2283
2284 /* 9.2.3.24.10.1.6 */
2285 static void
2286 dis_iei_sa(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
2287 {
2288     guint8        oct;
2289
2290     SHORT_DATA_CHECK(length, 2);
2291     oct = tvb_get_guint8(tvb, offset);
2292
2293     proto_tree_add_text(tree,
2294                         tvb, offset, 1,
2295                         "position: %d",
2296                         oct);
2297     offset++;
2298
2299     proto_tree_add_text(tree,
2300                         tvb, offset, length - 1,
2301                         "Small Animation ");
2302 }
2303
2304
2305 /* 9.2.3.24.10.1.7 */
2306 static void
2307 dis_iei_lp(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
2308 {
2309     guint8        oct;
2310
2311     SHORT_DATA_CHECK(length, 2);
2312     oct = tvb_get_guint8(tvb, offset);
2313
2314     proto_tree_add_text(tree,
2315                         tvb, offset, 1,
2316                         "position: %d",
2317                         oct);
2318     offset++;
2319
2320     proto_tree_add_text(tree,
2321                         tvb, offset, length - 1,
2322                         "Large Picture ");
2323 }
2324
2325 /* 9.2.3.24.10.1.8 */
2326 static void
2327 dis_iei_sp(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
2328 {
2329     guint8        oct;
2330
2331     SHORT_DATA_CHECK(length, 2);
2332     oct = tvb_get_guint8(tvb, offset);
2333
2334     proto_tree_add_text(tree,
2335                         tvb, offset, 1,
2336                         "position: %d",
2337                         oct);
2338     offset++;
2339
2340     proto_tree_add_text(tree,
2341                         tvb, offset, length - 1,
2342                         "Small Picture ");
2343 }
2344
2345
2346 /* 9.2.3.24.10.1.9 */
2347 static void
2348 dis_iei_vp(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
2349 {
2350     guint8        oct;
2351
2352     SHORT_DATA_CHECK(length, 4);
2353     oct = tvb_get_guint8(tvb, offset);
2354
2355     proto_tree_add_text(tree,
2356                         tvb, offset, 1,
2357                         "position: %d",
2358                         oct);
2359     offset++;
2360
2361     oct = tvb_get_guint8(tvb, offset);
2362     proto_tree_add_text(tree,
2363                         tvb, offset, 1,
2364                         "Horizontal dimension: %d",
2365                         oct);
2366     offset++;
2367
2368     oct = tvb_get_guint8(tvb, offset);
2369     proto_tree_add_text(tree,
2370                         tvb, offset, 1,
2371                         "Vertical dimension: %d",
2372                         oct);
2373     offset++;
2374
2375     proto_tree_add_text(tree,
2376                         tvb, offset, length - 3,
2377                         "Variable Picture ");
2378 }
2379
2380 /* 9.2.3.24.10.1.10 */
2381 static void
2382 dis_iei_upi(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
2383 {
2384     guint8        oct;
2385
2386     EXACT_DATA_CHECK(length, 1);
2387     oct = tvb_get_guint8(tvb, offset);
2388
2389     proto_tree_add_text(tree,
2390                         tvb, offset, 1,
2391                         "Number of corresponding objects: %d",
2392                         oct);
2393     offset++;
2394 }
2395
2396
2397 /*
2398  * 9.2.3.24 TP-User Data (TP-UD)
2399  * Information Element Identifier octet
2400  */
2401
2402 #if 0
2403 /* TS 123 040 V9.3.0 (2010-10) */
2404 static const value_string gsm_sms_tp_ud_ie_id_vals[] = {
2405     { 0x00,  "Concatenated short messages, 8-bit reference number (SMS Control)" },
2406     { 0x01,  "Special SMS Message Indication (SMS Control)" },
2407     { 0x02,  "Reserved" },
2408     { 0x03,  "Value not used to avoid misinterpretation as <LF> character" },
2409     { 0x04,  "Application port addressing scheme, 8 bit address (SMS Control)" },
2410     { 0x05,  "Application port addressing scheme, 16 bit address (SMS Control)" },
2411     { 0x06,  "SMSC Control Parameters (SMS Control)" },
2412     { 0x07,  "UDH Source Indicator (SMS Control)" },
2413     { 0x08,  "Concatenated short message, 16-bit reference number (SMS Control)" },
2414     { 0x09,  "Wireless Control Message Protocol (SMS Control)" },
2415     { 0x0A,  "Text Formatting (EMS Control)" },
2416     { 0x0B,  "Predefined Sound (EMS Content)" },
2417     { 0x0C,  "User Defined Sound (iMelody max 128 bytes) (EMS Content)" },
2418     { 0x0D,  "Predefined Animation (EMS Content)" },
2419     { 0x0E,  "Large Animation (16*16 times 4 = 32*4 =128 bytes) (EMS Content)" },
2420     { 0x0F,  "Small Animation (8*8 times 4 = 8*4 =32 bytes) (EMS Content)" },
2421     { 0x10,  "Large Picture (32*32 = 128 bytes) (EMS Content)" },
2422     { 0x11,  "Small Picture (16*16 = 32 bytes) (EMS Content)" },
2423     { 0x12,  "Variable Picture (EMS Content)" },
2424     { 0x13,  "User prompt indicator (EMS Control)" },
2425     { 0x14,  "Extended Object (EMS Content)" },
2426     { 0x15,  "Reused Extended Object (EMS Control)" },
2427     { 0x16,  "Compression Control (EMS Control)" },
2428     { 0x17,  "Object Distribution Indicator (EMS Control)" },
2429     { 0x18,  "Standard WVG object (EMS Content)" },
2430     { 0x19,  "Character Size WVG object (EMS Content)" },
2431     { 0x1A,  "Extended Object Data Request Command (EMS Control)" },
2432     /*1B-1F Reserved for future EMS features (see subclause 3.10) */
2433     { 0x20,  "RFC 822 E-Mail Header (SMS Control)" },
2434     { 0x21,  "Hyperlink format element (SMS Control)" },s
2435     { 0x22,  "Reply Address Element (SMS Control)" },
2436     { 0x23,  "Enhanced Voice Mail Information (SMS Control)" },
2437     { 0x24,  "National Language Single Shift (SMS Control)" },
2438     { 0x25,  "National Language Locking Shift (SMS Control)" },
2439     /*26-6F Reserved for future use */
2440     /*70-7F (U)SIM Toolkit Security Headers (SMS Control) */
2441     /*80-9F SME to SME specific use (SMS Control) */
2442     /*A0-BF Reserved for future use */
2443     /*C0-DF SC specific use (SMS Control) */
2444     /*E0-FF Reserved for future use */
2445     { 0, NULL },
2446 };
2447
2448 #endif
2449 static void
2450 dis_field_ud_iei(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
2451 {
2452     void (*iei_fcn)(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length);
2453     guint8        oct;
2454     proto_item    *item;
2455     proto_tree    *subtree = NULL;
2456     const gchar   *str = NULL;
2457     guint8        iei_len;
2458
2459
2460     while (length >= 2)
2461     {
2462         iei_fcn = NULL;
2463
2464         oct = tvb_get_guint8(tvb, offset);
2465
2466         switch (oct)
2467         {
2468             case 0x00: str = "Concatenated short messages, 8-bit reference number (SMS Control)"; iei_fcn = dis_iei_csm8; break;
2469             case 0x01: str = "Special SMS Message Indication (SMS Control)"; break;
2470             case 0x02: str = "Reserved N/A"; break;
2471             case 0x03: str = "Value not used to avoid misinterpretation as <LF> character N/A"; break;
2472             case 0x04: str = "Application port addressing scheme, 8 bit address (SMS Control)"; iei_fcn = dis_iei_apa_8bit; break;
2473             case 0x05: str = "Application port addressing scheme, 16 bit address (SMS Control)"; iei_fcn = dis_iei_apa_16bit; break;
2474             case 0x06: str = "SMSC Control Parameters (SMS Control)"; iei_fcn = dis_iei_scp; break;
2475             case 0x07: str = "UDH Source Indicator (SMS Control)"; iei_fcn  = dis_iei_udh_si; break;
2476             case 0x08: str = "Concatenated short message, 16-bit reference number (SMS Control)"; iei_fcn = dis_iei_csm16; break;
2477             case 0x09: str = "Wireless Control Message Protocol (SMS Control)"; break;
2478             case 0x0A: str = "Text Formatting (EMS Control)"; iei_fcn = dis_iei_tf;break;
2479             case 0x0B: str = "Predefined Sound (EMS Content)"; iei_fcn = dis_iei_ps;break;
2480             case 0x0C: str = "User Defined Sound (iMelody max 128 bytes) (EMS Content)"; iei_fcn = dis_iei_uds;break;
2481             case 0x0D: str = "Predefined Animation (EMS Content)"; iei_fcn = dis_iei_pa;break;
2482             case 0x0E: str = "Large Animation (16*16 times 4 = 32*4 =128 bytes) (EMS Content)"; iei_fcn = dis_iei_la;break;
2483             case 0x0F: str = "Small Animation (8*8 times 4 = 8*4 =32 bytes) (EMS Content)"; iei_fcn = dis_iei_sa;break;
2484             case 0x10: str = "Large Picture (32*32 = 128 bytes) (EMS Content)"; iei_fcn = dis_iei_lp;break;
2485             case 0x11: str = "Small Picture (16*16 = 32 bytes) (EMS Content)"; iei_fcn = dis_iei_sp;break;
2486             case 0x12: str = "Variable Picture (EMS Content)"; iei_fcn = dis_iei_vp;break;
2487             case 0x13: str = "User prompt indicator (EMS Control)"; iei_fcn = dis_iei_upi;break;
2488             case 0x14: str = "Extended Object (EMS Content)"; break;
2489             case 0x15: str = "Reused Extended Object (EMS Control)"; break;
2490             case 0x16: str = "Compression Control (EMS Control)"; break;
2491             case 0x17: str = "Object Distribution Indicator (EMS Control)"; break;
2492             case 0x18: str = "Standard WVG object (EMS Content)"; break;
2493             case 0x19: str = "Character Size WVG object (EMS Content)"; break;
2494             case 0x1A: str = "Extended Object Data Request Command (EMS Control)"; break;
2495             case 0x20: str = "RFC 822 E-Mail Header (SMS Control)"; break;
2496             case 0x21: str = "Hyperlink format element (SMS Control)"; break;
2497             case 0x22: str = "Reply Address Element (SMS Control)"; break;
2498             default:
2499                 if ((oct >= 0x1b) &&
2500                     (oct <= 0x1f))
2501                 {
2502                     str = "Reserved for future EMS features (see subclause 3.10) N/A"; break;
2503                 }
2504                 else if ((oct >= 0x23) &&
2505                          (oct <= 0x6f))
2506                 {
2507                     str = "Reserved for future use N/A"; break;
2508                 }
2509                 else if ((oct >= 0x70) &&
2510                          (oct <= 0x7f))
2511                 {
2512                     str = "(U)SIM Toolkit Security Headers (SMS Control)"; break;
2513                 }
2514                 else if ((oct >= 0x80) &&
2515                          (oct <= 0x9f))
2516                 {
2517                     str = "SME to SME specific use (SMS Control)"; break;
2518                 }
2519                 else if ((oct >= 0xa0) &&
2520                          (oct <= 0xbf))
2521                 {
2522                     str = "Reserved for future use N/A"; break;
2523                 }
2524                 else if ((oct >= 0xc0) &&
2525                          (oct <= 0xdf))
2526                 {
2527                     str = "SC specific use (SMS Control)"; break;
2528                 }
2529                 else
2530                 {
2531                     str = "Reserved for future use N/A"; break;
2532                 }
2533         }
2534
2535         iei_len = tvb_get_guint8(tvb, offset + 1);
2536
2537         item =
2538             proto_tree_add_text(tree,
2539                                 tvb, offset, iei_len + 2,
2540                                 "IE: %s",
2541                                 str);
2542
2543         subtree = proto_item_add_subtree(item, ett_udh_ieis[oct]);
2544
2545         proto_tree_add_text(subtree,
2546                             tvb, offset, 1,
2547                             "Information Element Identifier: 0x%02X",
2548                             oct);
2549
2550         offset++;
2551
2552         proto_tree_add_text(subtree,
2553                             tvb, offset, 1,
2554                             "Length: %d",
2555                             iei_len);
2556
2557         offset++;
2558
2559         if (iei_len > 0)
2560         {
2561             if (iei_fcn == NULL)
2562             {
2563                 proto_tree_add_text(subtree,
2564                                     tvb, offset, iei_len,
2565                                     "IE Data");
2566             }
2567             else
2568             {
2569                 iei_fcn(tvb, subtree, offset, iei_len);
2570             }
2571         }
2572
2573         length -= 2 + iei_len;
2574         offset += iei_len;
2575     }
2576 }
2577
2578 /* 9.2.3.24 */
2579 #define SMS_MAX_MESSAGE_SIZE 160
2580 static char    messagebuf[SMS_MAX_MESSAGE_SIZE+1];
2581 static void
2582 dis_field_ud(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint32 length, gboolean udhi, guint8 udl,
2583     gboolean seven_bit, gboolean eight_bit, gboolean ucs2, gboolean compressed)
2584 {
2585     static guint8     fill_bits_mask[7] =
2586         { 0x0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f };
2587     proto_item        *item;
2588     proto_item        *udh_item;
2589     proto_tree        *subtree = NULL;
2590     proto_tree        *udh_subtree = NULL;
2591     tvbuff_t          *sm_tvb = NULL;
2592     fragment_data     *fd_sm = NULL;
2593     guint8            oct;
2594     guint             fill_bits;
2595     guint32           out_len, total_sms_len, len_sms, length_ucs2, i;
2596     char              *ustr;
2597     proto_item        *ucs2_item;
2598     gchar             *utf8_text = NULL;
2599     gchar             save_byte = 0, save_byte2 = 0;
2600     GIConv            cd;
2601     GError            *l_conv_error = NULL;
2602
2603     gboolean    reassembled = FALSE;
2604     guint32     reassembled_in = 0;
2605     gboolean    is_fragmented = FALSE;
2606     gboolean    save_fragmented = FALSE, try_gsm_sms_ud_reassemble = FALSE;
2607     guint32     num_labels;
2608
2609     sm_fragment_params *p_frag_params;
2610
2611     fill_bits = 0;
2612
2613     item =
2614         proto_tree_add_text(tree, tvb,
2615                             offset, length,
2616                             "TP-User-Data");
2617     subtree = proto_item_add_subtree(item, ett_ud);
2618
2619     oct = tvb_get_guint8(tvb, offset);
2620
2621     if (udhi)
2622     {
2623
2624         /* step over header */
2625
2626         udh_item =
2627             proto_tree_add_text(subtree, tvb,
2628                                 offset, oct + 1,
2629                                 "User-Data Header");
2630
2631         udh_subtree = proto_item_add_subtree(udh_item, ett_udh);
2632
2633         proto_tree_add_text(udh_subtree,
2634                             tvb, offset, 1,
2635                             "User Data Header Length (%u)",
2636                             oct);
2637
2638         offset++;
2639         udl--;
2640         length--;
2641
2642         dis_field_ud_iei(tvb, udh_subtree, offset, oct);
2643
2644         offset += oct;
2645         udl -= oct;
2646         length -= oct;
2647
2648         if (seven_bit)
2649         {
2650             /* step over fill bits ? */
2651
2652             fill_bits = 6 - ((oct * 8) % 7);
2653             if (fill_bits)
2654             {
2655                 oct = tvb_get_guint8(tvb, offset);
2656
2657                 other_decode_bitfield_value(bigbuf, oct, fill_bits_mask[fill_bits], 8);
2658                 proto_tree_add_text(udh_subtree,
2659                                     tvb, offset, 1,
2660                                     "%s :  Fill bits",
2661                                     bigbuf);
2662                 /* Note: Could add an expert item here if ((oct & fill_bits_mask[fill_bits]) != 0) */
2663             }
2664         }
2665     }
2666
2667     if (g_frags > 1)
2668         is_fragmented = TRUE;
2669
2670     if ( is_fragmented && reassemble_sms)
2671     {
2672         try_gsm_sms_ud_reassemble = TRUE;
2673         save_fragmented = g_pinfo->fragmented;
2674         g_pinfo->fragmented = TRUE;
2675         fd_sm = fragment_add_seq_check (tvb, offset, g_pinfo,
2676                                         g_sm_id, /* guint32 ID for fragments belonging together */
2677                                         g_sm_fragment_table, /* list of message fragments */
2678                                         g_sm_reassembled_table, /* list of reassembled messages */
2679                                         g_frag-1, /* guint32 fragment sequence number */
2680                                         length, /* guint32 fragment length */
2681                                         (g_frag != g_frags)); /* More fragments? */
2682         if (fd_sm)
2683         {
2684             reassembled = TRUE;
2685             reassembled_in = fd_sm->reassembled_in;
2686         }
2687
2688         sm_tvb = process_reassembled_data(tvb, offset, g_pinfo,
2689                                           "Reassembled Short Message", fd_sm, &sm_frag_items,
2690                                           NULL, tree);
2691
2692         if(reassembled && g_pinfo->fd->num == reassembled_in)
2693         {
2694             /* Reassembled */
2695             col_append_str (g_pinfo->cinfo, COL_INFO,
2696                             " (Short Message Reassembled)");
2697         }
2698         else
2699         {
2700             /* Not last packet of reassembled Short Message */
2701             col_append_fstr (g_pinfo->cinfo, COL_INFO,
2702                              " (Short Message fragment %u of %u)", g_frag, g_frags);
2703         }
2704
2705         /* Store udl and length for later decoding of reassembled SMS */
2706         p_frag_params = se_alloc0(sizeof(sm_fragment_params));
2707         p_frag_params->udl = udl;
2708         p_frag_params->length = length;
2709         g_hash_table_insert(g_sm_fragment_params_table,
2710                             GUINT_TO_POINTER((guint)((g_sm_id<<16)|(g_frag-1))),
2711                             p_frag_params);
2712     } /* Else: not fragmented */
2713     if (! sm_tvb) /* One single Short Message, or not reassembled */
2714         sm_tvb = tvb_new_subset_remaining (tvb, offset);
2715
2716     if (compressed)
2717     {
2718         proto_tree_add_text(subtree, tvb, offset, length, "Compressed data");
2719     }
2720     else
2721     {
2722         if (seven_bit)
2723         {
2724             if(!(reassembled && g_pinfo->fd->num == reassembled_in))
2725             {
2726                 /* Show unassembled SMS */
2727                 out_len =
2728                     gsm_sms_char_7bit_unpack(fill_bits, length ,
2729                                              (udl > SMS_MAX_MESSAGE_SIZE ? SMS_MAX_MESSAGE_SIZE : udl),
2730                                              tvb_get_ptr(tvb , offset , length) , messagebuf);
2731                 messagebuf[out_len] = '\0';
2732                 proto_tree_add_unicode_string(subtree, hf_gsm_sms_text, tvb, offset,
2733                                               length,
2734                                               gsm_sms_chars_to_utf8(messagebuf, out_len));
2735             }
2736             else
2737             {
2738                 /*  Show reassembled SMS.  We show each fragment separately
2739                  *  so that the text doesn't get truncated when we add it to
2740                  *  the tree.
2741                  */
2742                 total_sms_len = 0;
2743                 for(i = 0 ; i < g_frags; i++)
2744                 {
2745                     p_frag_params = (sm_fragment_params*)g_hash_table_lookup(g_sm_fragment_params_table,
2746                                                             GUINT_TO_POINTER((guint)((g_sm_id<<16)|i)));
2747
2748                     if (p_frag_params) {
2749                         out_len =
2750                             gsm_sms_char_7bit_unpack(fill_bits, p_frag_params->length,
2751                                 (p_frag_params->udl > SMS_MAX_MESSAGE_SIZE ? SMS_MAX_MESSAGE_SIZE : p_frag_params->udl),
2752                                 tvb_get_ptr(sm_tvb, total_sms_len, p_frag_params->length), messagebuf);
2753
2754                         messagebuf[out_len] = '\0';
2755                         proto_tree_add_unicode_string(subtree, hf_gsm_sms_text, sm_tvb,
2756                                                       total_sms_len, p_frag_params->length,
2757                                                       gsm_sms_chars_to_utf8(messagebuf, out_len));
2758
2759                         total_sms_len += p_frag_params->length;
2760                     }
2761                 }
2762             }
2763         }
2764         else if (eight_bit)
2765         {
2766             /*proto_tree_add_text(subtree, tvb , offset , length, "%s",
2767               tvb_format_text(tvb, offset, length));                                */
2768             if (! dissector_try_uint(gsm_sms_dissector_tbl, g_port_src, sm_tvb, g_pinfo, subtree))
2769             {
2770                 if (! dissector_try_uint(gsm_sms_dissector_tbl, g_port_dst,sm_tvb, g_pinfo, subtree))
2771                 {
2772                     if (subtree)
2773                     { /* Only display if needed */
2774                         proto_tree_add_text (subtree, sm_tvb, 0, -1,
2775                                              "Short Message body");
2776                     }
2777                 }
2778             }
2779         }
2780         else if (ucs2)
2781         {
2782             /* XXX, use tvb_get_ephemeral_unicode_string(.., ENC_BIG_ENDIAN); */
2783             if ((cd = g_iconv_open("UTF-8","UCS-2BE")) != (GIConv)-1)
2784             {
2785                 guint8 rep_len = tvb_reported_length(sm_tvb);
2786
2787                 if(!(reassembled && g_pinfo->fd->num == reassembled_in))
2788                 {
2789                     /* Show unreassembled SMS */
2790                     utf8_text = g_convert_with_iconv(tvb_get_ptr(sm_tvb, 0, rep_len), rep_len , cd , NULL , NULL , &l_conv_error);
2791                     if(!l_conv_error) {
2792                         ucs2_item = proto_tree_add_unicode_string(subtree, hf_gsm_sms_text, tvb,
2793                                                                   offset, length, utf8_text);
2794                     } else {
2795                         ucs2_item = proto_tree_add_text(subtree, tvb, offset, length, "Failed to decode UCS2!");
2796                     }
2797                     PROTO_ITEM_SET_GENERATED(ucs2_item);
2798                 } else {
2799                     /*  Show reassembled SMS.  We show each fragment separately
2800                      *  so that the text doesn't get truncated when we add it to
2801                      *  the tree.
2802                      */
2803                     utf8_text = g_convert_with_iconv(tvb_get_ptr(sm_tvb, 0, rep_len), rep_len , cd , NULL , NULL , &l_conv_error);
2804                     if(!l_conv_error)
2805                     {
2806                         len_sms = (int)strlen(utf8_text);
2807                         num_labels = len_sms / MAX_SMS_FRAG_LEN;
2808                         num_labels += (len_sms % MAX_SMS_FRAG_LEN) ? 1 : 0;
2809                         for(i = 0; i < num_labels;i++) {
2810                             if(i * MAX_SMS_FRAG_LEN < len_sms) {
2811                                 /* set '\0' to byte number 134 text_node MAX size*/
2812                                 save_byte =  utf8_text[i * MAX_SMS_FRAG_LEN];
2813                                 save_byte2 =  utf8_text[i * MAX_SMS_FRAG_LEN + 1];
2814                                 if(i > 0)
2815                                 {
2816                                     utf8_text[i * MAX_SMS_FRAG_LEN] = '\0';
2817                                     utf8_text[i * MAX_SMS_FRAG_LEN + 1] = '\0';
2818                                 }
2819
2820                                 length_ucs2 = MAX_SMS_FRAG_LEN;
2821                             } else
2822                                 length_ucs2 = len_sms % MAX_SMS_FRAG_LEN;
2823
2824                             ucs2_item = proto_tree_add_unicode_string(subtree, hf_gsm_sms_text, sm_tvb,
2825                                                                       i * MAX_SMS_FRAG_LEN, length_ucs2,
2826                                                                       &utf8_text[i * MAX_SMS_FRAG_LEN]);
2827                             PROTO_ITEM_SET_GENERATED(ucs2_item);
2828
2829                             /* return the save byte to utf8 buffer*/
2830                             if(i * MAX_SMS_FRAG_LEN < len_sms) {
2831                                 utf8_text[i * MAX_SMS_FRAG_LEN] = save_byte;
2832                                 utf8_text[i * MAX_SMS_FRAG_LEN + 1] = save_byte2;
2833                             }
2834                         }
2835                     } else {
2836                         ucs2_item = proto_tree_add_text(subtree, tvb, offset, length, "Failed to decode UCS2!");
2837                         PROTO_ITEM_SET_GENERATED(ucs2_item);
2838                     }
2839                 }
2840
2841                 g_free(utf8_text);
2842                 g_iconv_close(cd);
2843             } else {
2844                 ustr = tvb_get_ephemeral_unicode_string(tvb, offset, length, ENC_BIG_ENDIAN);
2845                 proto_tree_add_text(subtree, tvb, offset, length, "%s", ustr);
2846             }
2847         }
2848     }
2849
2850     if (try_gsm_sms_ud_reassemble) /* Clean up defragmentation */
2851         g_pinfo->fragmented = save_fragmented;
2852 }
2853
2854 /* 9.2.3.27 */
2855 static void
2856 dis_field_pi(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 oct)
2857 {
2858     proto_item        *item;
2859     proto_tree        *subtree = NULL;
2860
2861
2862     item =
2863         proto_tree_add_text(tree, tvb,
2864             offset, 1,
2865             "TP-Parameter-Indicator");
2866
2867     subtree = proto_item_add_subtree(item, ett_pi);
2868
2869     other_decode_bitfield_value(bigbuf, oct, 0x80, 8);
2870     proto_tree_add_text(subtree, tvb,
2871         offset, 1,
2872         "%s :  %s",
2873         bigbuf,
2874         (oct & 0x80) ? "Extended" : "No extension");
2875
2876     other_decode_bitfield_value(bigbuf, oct, 0x78, 8);
2877     proto_tree_add_text(subtree, tvb,
2878         offset, 1,
2879         "%s :  Reserved",
2880         bigbuf);
2881
2882     other_decode_bitfield_value(bigbuf, oct, 0x04, 8);
2883     proto_tree_add_text(subtree, tvb,
2884         offset, 1,
2885         "%s :  TP-UDL %spresent",
2886         bigbuf,
2887         (oct & 0x04) ? "" : "not ");
2888
2889     other_decode_bitfield_value(bigbuf, oct, 0x02, 8);
2890     proto_tree_add_text(subtree, tvb,
2891         offset, 1,
2892         "%s :  TP-DCS %spresent",
2893         bigbuf,
2894         (oct & 0x02) ? "" : "not ");
2895
2896     other_decode_bitfield_value(bigbuf, oct, 0x01, 8);
2897     proto_tree_add_text(subtree, tvb,
2898         offset, 1,
2899         "%s :  TP-PID %spresent",
2900         bigbuf,
2901         (oct & 0x01) ? "" : "not ");
2902 }
2903
2904 /*
2905  * Ref. GSM 03.40
2906  * Section 9.2.2
2907  */
2908 static void
2909 dis_msg_deliver(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
2910 {
2911     guint32        saved_offset;
2912     guint32        length;
2913     guint8         oct;
2914     guint8         udl;
2915     gboolean       seven_bit;
2916     gboolean       eight_bit;
2917     gboolean       ucs2;
2918     gboolean       compressed;
2919     gboolean       udhi;
2920
2921     saved_offset = offset;
2922     length = tvb_length_remaining(tvb, offset);
2923
2924     oct = tvb_get_guint8(tvb, offset);
2925     udhi = oct & 0x40;
2926
2927     proto_tree_add_item(tree, hf_gsm_sms_tp_rp, tvb, offset, 1, ENC_BIG_ENDIAN);
2928     proto_tree_add_item(tree, hf_gsm_sms_tp_udhi, tvb, offset, 1, ENC_BIG_ENDIAN);
2929     proto_tree_add_item(tree, hf_gsm_sms_tp_sri, tvb, offset, 1, ENC_BIG_ENDIAN);
2930     proto_tree_add_item(tree, hf_gsm_sms_tp_mms, tvb, offset, 1, ENC_BIG_ENDIAN);
2931     proto_tree_add_item(tree, hf_gsm_sms_tp_mti_down, tvb, offset, 1, ENC_BIG_ENDIAN);
2932
2933     offset++;
2934
2935     dis_field_addr(tvb, tree, &offset, "TP-Originating-Address");
2936
2937     oct = tvb_get_guint8(tvb, offset);
2938
2939     dis_field_pid(tvb, tree, offset, oct);
2940
2941     offset++;
2942     oct = tvb_get_guint8(tvb, offset);
2943
2944     dis_field_dcs(tvb, tree, offset, oct, &seven_bit, &eight_bit, &ucs2, &compressed);
2945
2946     offset++;
2947     dis_field_scts(tvb, tree, &offset);
2948
2949     oct = tvb_get_guint8(tvb, offset);
2950     udl = oct;
2951
2952     DIS_FIELD_UDL(tree, offset);
2953
2954     if (udl > 0)
2955     {
2956         offset++;
2957
2958         dis_field_ud(tvb, tree, offset, length - (offset - saved_offset), udhi, udl,
2959             seven_bit, eight_bit, ucs2, compressed);
2960     }
2961 }
2962
2963 /*
2964  * Ref. GSM 03.40
2965  * Section 9.2.2
2966  */
2967 static void
2968 dis_msg_deliver_report(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
2969 {
2970     guint32        saved_offset;
2971     guint32        length;
2972     guint8         oct;
2973     guint8         pi;
2974     guint8         udl;
2975     gboolean       seven_bit = FALSE;
2976     gboolean       eight_bit = FALSE;
2977     gboolean       ucs2 = FALSE;
2978     gboolean       compressed = FALSE;
2979     gboolean       udhi;
2980
2981
2982     udl = 0;
2983     saved_offset = offset;
2984     length = tvb_length_remaining(tvb, offset);
2985
2986     oct = tvb_get_guint8(tvb, offset);
2987     udhi = oct & 0x40;
2988
2989     proto_tree_add_item(tree, hf_gsm_sms_tp_udhi, tvb, offset, 1, ENC_BIG_ENDIAN);
2990     proto_tree_add_item(tree, hf_gsm_sms_tp_mms, tvb, offset, 1, ENC_BIG_ENDIAN);
2991     proto_tree_add_item(tree, hf_gsm_sms_tp_mti_up, tvb, offset, 1, ENC_BIG_ENDIAN);
2992
2993     if (length < 2)
2994     {
2995         proto_tree_add_text(tree,
2996             tvb, offset, length,
2997             "Short Data (?)");
2998         return;
2999     }
3000
3001     /*
3002      * there does not seem to be a way to determine that this
3003      * deliver report is from an RP-ERROR or RP-ACK other
3004      * than to look at the next octet
3005      *
3006      * FCS values are 0x80 and higher
3007      * PI uses bit 7 as an extension indicator
3008      *
3009      * will assume that if bit 7 is set then this octet
3010      * is an FCS otherwise PI
3011      */
3012     offset++;
3013     oct = tvb_get_guint8(tvb, offset);
3014
3015     if (oct & 0x80)
3016     {
3017         dis_field_fcs(tvb, tree, offset, oct);
3018         offset++;
3019     }
3020
3021     pi = tvb_get_guint8(tvb, offset);
3022
3023     dis_field_pi(tvb, tree, offset, pi);
3024
3025     if (pi & 0x01)
3026     {
3027         if (length <= (offset - saved_offset))
3028         {
3029             proto_tree_add_text(tree,
3030                 tvb, offset, -1,
3031                 "Short Data (?)");
3032             return;
3033         }
3034
3035         offset++;
3036         oct = tvb_get_guint8(tvb, offset);
3037
3038         dis_field_pid(tvb, tree, offset, oct);
3039     }
3040
3041     if (pi & 0x02)
3042     {
3043         if (length <= (offset - saved_offset))
3044         {
3045             proto_tree_add_text(tree,
3046                 tvb, offset, -1,
3047                 "Short Data (?)");
3048             return;
3049         }
3050
3051         offset++;
3052         oct = tvb_get_guint8(tvb, offset);
3053
3054         dis_field_dcs(tvb, tree, offset, oct, &seven_bit, &eight_bit, &ucs2, &compressed);
3055     }
3056
3057     if (pi & 0x04)
3058     {
3059         if (length <= (offset - saved_offset))
3060         {
3061             proto_tree_add_text(tree,
3062                 tvb, offset, -1,
3063                 "Short Data (?)");
3064             return;
3065         }
3066
3067         offset++;
3068         oct = tvb_get_guint8(tvb, offset);
3069         udl = oct;
3070
3071         DIS_FIELD_UDL(tree, offset);
3072     }
3073
3074     if (udl > 0)
3075     {
3076         offset++;
3077
3078         dis_field_ud(tvb, tree, offset, length - (offset - saved_offset), udhi, udl,
3079             seven_bit, eight_bit, ucs2, compressed);
3080     }
3081 }
3082
3083 /*
3084  * Ref. GSM 03.40
3085  * Section 9.2.2
3086  */
3087 static void
3088 dis_msg_submit(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
3089 {
3090     guint32        saved_offset;
3091     guint32        length;
3092     guint8         oct;
3093     guint8         vp_form;
3094     guint8         udl;
3095     gboolean       seven_bit;
3096     gboolean       eight_bit;
3097     gboolean       ucs2;
3098     gboolean       compressed;
3099     gboolean       udhi;
3100
3101
3102     saved_offset = offset;
3103     length = tvb_length_remaining(tvb, offset);
3104
3105     oct = tvb_get_guint8(tvb, offset);
3106     udhi = oct & 0x40;
3107     vp_form = ((oct & 0x18) >> 3);
3108
3109     proto_tree_add_item(tree, hf_gsm_sms_tp_rp, tvb, offset, 1, ENC_BIG_ENDIAN);
3110     proto_tree_add_item(tree, hf_gsm_sms_tp_udhi, tvb, offset, 1, ENC_BIG_ENDIAN);
3111     proto_tree_add_item(tree, hf_gsm_sms_tp_srr, tvb, offset, 1, ENC_BIG_ENDIAN);
3112     proto_tree_add_item(tree, hf_gsm_sms_tp_vpf, tvb, offset, 1, ENC_BIG_ENDIAN);
3113     proto_tree_add_item(tree, hf_gsm_sms_tp_rd, tvb, offset, 1, ENC_BIG_ENDIAN);
3114     proto_tree_add_item(tree, hf_gsm_sms_tp_mti_up, tvb, offset, 1, ENC_BIG_ENDIAN);
3115
3116     offset++;
3117
3118     proto_tree_add_item(tree, hf_gsm_sms_tp_mr, tvb, offset, 1, ENC_BIG_ENDIAN);
3119
3120     offset++;
3121
3122     dis_field_addr(tvb, tree, &offset, "TP-Destination-Address");
3123
3124     oct = tvb_get_guint8(tvb, offset);
3125
3126     dis_field_pid(tvb, tree, offset, oct);
3127
3128     offset++;
3129     oct = tvb_get_guint8(tvb, offset);
3130
3131     dis_field_dcs(tvb, tree, offset, oct, &seven_bit, &eight_bit, &ucs2, &compressed);
3132
3133     offset++;
3134     dis_field_vp(tvb, tree, &offset, vp_form);
3135
3136     oct = tvb_get_guint8(tvb, offset);
3137     udl = oct;
3138
3139     DIS_FIELD_UDL(tree, offset);
3140
3141     if (udl > 0)
3142     {
3143         offset++;
3144
3145         dis_field_ud(tvb, tree, offset, length - (offset - saved_offset), udhi, udl,
3146             seven_bit, eight_bit, ucs2, compressed);
3147     }
3148 }
3149
3150 /*
3151  * Ref. GSM 03.40
3152  * Section 9.2.2
3153  */
3154 static void
3155 dis_msg_submit_report(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
3156 {
3157     guint32        saved_offset;
3158     guint32        length;
3159     guint8         oct;
3160     guint8         pi;
3161     guint8         udl;
3162     gboolean       seven_bit = FALSE;
3163     gboolean       eight_bit = FALSE;
3164     gboolean       ucs2 = FALSE;
3165     gboolean       compressed = FALSE;
3166     gboolean       udhi;
3167
3168
3169     udl = 0;
3170     saved_offset = offset;
3171     length = tvb_length_remaining(tvb, offset);
3172
3173     oct = tvb_get_guint8(tvb, offset);
3174     udhi = oct & 0x40;
3175
3176     proto_tree_add_item(tree, hf_gsm_sms_tp_udhi, tvb, offset, 1, ENC_BIG_ENDIAN);
3177     proto_tree_add_item(tree, hf_gsm_sms_tp_mti_down, tvb, offset, 1, ENC_BIG_ENDIAN);
3178
3179     /*
3180      * there does not seem to be a way to determine that this
3181      * deliver report is from an RP-ERROR or RP-ACK other
3182      * than to look at the next octet
3183      *
3184      * FCS values are 0x80 and higher
3185      * PI uses bit 7 as an extension indicator
3186      *
3187      * will assume that if bit 7 is set then this octet
3188      * is an FCS otherwise PI
3189      */
3190     offset++;
3191     oct = tvb_get_guint8(tvb, offset);
3192
3193     if (oct & 0x80)
3194     {
3195         dis_field_fcs(tvb, tree, offset, oct);
3196         offset++;
3197     }
3198
3199     pi = tvb_get_guint8(tvb, offset);
3200
3201     dis_field_pi(tvb, tree, offset, pi);
3202     offset++;
3203
3204     dis_field_scts(tvb, tree, &offset);
3205
3206     if (pi & 0x01) {
3207         if (length <= (offset - saved_offset)) {
3208             proto_tree_add_text(tree,
3209                 tvb, offset, -1,
3210                 "Short Data (?)");
3211             return;
3212         }
3213
3214         oct = tvb_get_guint8(tvb, offset);
3215
3216         dis_field_pid(tvb, tree, offset, oct);
3217         offset++;
3218     }
3219
3220     if (pi & 0x02)
3221     {
3222         if (length <= (offset - saved_offset))
3223         {
3224             proto_tree_add_text(tree,
3225                 tvb, offset, -1,
3226                 "Short Data (?)");
3227             return;
3228         }
3229
3230         oct = tvb_get_guint8(tvb, offset);
3231
3232         dis_field_dcs(tvb, tree, offset, oct, &seven_bit, &eight_bit, &ucs2, &compressed);
3233         offset++;
3234     }
3235
3236     if (pi & 0x04)
3237     {
3238         if (length <= (offset - saved_offset))
3239         {
3240             proto_tree_add_text(tree,
3241                 tvb, offset, -1,
3242                 "Short Data (?)");
3243             return;
3244         }
3245
3246         oct = tvb_get_guint8(tvb, offset);
3247         udl = oct;
3248
3249         DIS_FIELD_UDL(tree, offset);
3250         offset++;
3251     }
3252
3253     if (udl > 0)
3254     {
3255         dis_field_ud(tvb, tree, offset, length - (offset - saved_offset), udhi, udl,
3256             seven_bit, eight_bit, ucs2, compressed);
3257     }
3258 }
3259
3260 /*
3261  * Ref. GSM 03.40
3262  * Section 9.2.2
3263  */
3264 static void
3265 dis_msg_status_report(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
3266 {
3267     guint32        saved_offset;
3268     guint32        length;
3269     guint8         oct;
3270     guint8         pi;
3271     guint8         udl;
3272     gboolean       seven_bit = FALSE;
3273     gboolean       eight_bit = FALSE;
3274     gboolean       ucs2 = FALSE;
3275     gboolean       compressed = FALSE;
3276     gboolean       udhi;
3277
3278
3279     udl = 0;
3280     saved_offset = offset;
3281     length = tvb_length_remaining(tvb, offset);
3282
3283     oct = tvb_get_guint8(tvb, offset);
3284     udhi = oct & 0x40;
3285
3286     proto_tree_add_item(tree, hf_gsm_sms_tp_udhi, tvb, offset, 1, ENC_BIG_ENDIAN);
3287     proto_tree_add_item(tree, hf_gsm_sms_tp_srq, tvb, offset, 1, ENC_BIG_ENDIAN);
3288     proto_tree_add_item(tree, hf_gsm_sms_tp_mms, tvb, offset, 1, ENC_BIG_ENDIAN);
3289     proto_tree_add_item(tree, hf_gsm_sms_tp_mti_down, tvb, offset, 1, ENC_BIG_ENDIAN);
3290
3291     offset++;
3292
3293     proto_tree_add_item(tree, hf_gsm_sms_tp_mr, tvb, offset, 1, ENC_BIG_ENDIAN);
3294
3295     offset++;
3296
3297     dis_field_addr(tvb, tree, &offset, "TP-Recipient-Address");
3298
3299     dis_field_scts(tvb, tree, &offset);
3300
3301     dis_field_dt(tvb, tree, &offset);
3302
3303     oct = tvb_get_guint8(tvb, offset);
3304
3305     dis_field_st(tvb, tree, offset, oct);
3306
3307     offset++;
3308     /* Parameter indicating the presence of any of
3309      * the optional parameters which follow
3310      * 4) Mandatory if any of the optional parameters following TP-PI is present,
3311      * otherwise optional.
3312      */
3313     if (length <= (offset - saved_offset))
3314     {
3315         return;
3316     }
3317     pi = tvb_get_guint8(tvb, offset);
3318
3319     dis_field_pi(tvb, tree, offset, pi);
3320
3321     if (pi & 0x01)
3322     {
3323         if (length <= (offset - saved_offset))
3324         {
3325             proto_tree_add_text(tree,
3326                 tvb, offset, -1,
3327                 "Short Data (?)");
3328             return;
3329         }
3330
3331         offset++;
3332         oct = tvb_get_guint8(tvb, offset);
3333
3334         dis_field_pid(tvb, tree, offset, oct);
3335     }
3336
3337     if (pi & 0x02)
3338     {
3339         if (length <= (offset - saved_offset))
3340         {
3341             proto_tree_add_text(tree,
3342                 tvb, offset, -1,
3343                 "Short Data (?)");
3344             return;
3345         }
3346
3347         offset++;
3348         oct = tvb_get_guint8(tvb, offset);
3349
3350         dis_field_dcs(tvb, tree, offset, oct, &seven_bit, &eight_bit, &ucs2, &compressed);
3351     }
3352
3353     if (pi & 0x04)
3354     {
3355         if (length <= (offset - saved_offset))
3356         {
3357             proto_tree_add_text(tree,
3358                 tvb, offset, -1,
3359                 "Short Data (?)");
3360             return;
3361         }
3362
3363         offset++;
3364         oct = tvb_get_guint8(tvb, offset);
3365         udl = oct;
3366
3367         DIS_FIELD_UDL(tree, offset);
3368     }
3369
3370     if (udl > 0)
3371     {
3372         offset++;
3373
3374         dis_field_ud(tvb, tree, offset, length - (offset - saved_offset), udhi, udl,
3375             seven_bit, eight_bit, ucs2, compressed);
3376     }
3377 }
3378
3379 /*
3380  * Ref. GSM 03.40
3381  * Section 9.2.2
3382  */
3383 static void
3384 dis_msg_command(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
3385 {
3386     guint8        oct;
3387     guint8        cdl;
3388     const gchar   *str = NULL;
3389
3390     proto_tree_add_item(tree, hf_gsm_sms_tp_udhi, tvb, offset, 1, ENC_BIG_ENDIAN);
3391     proto_tree_add_item(tree, hf_gsm_sms_tp_srr, tvb, offset, 1, ENC_BIG_ENDIAN);
3392     proto_tree_add_item(tree, hf_gsm_sms_tp_mti_up, tvb, offset, 1, ENC_BIG_ENDIAN);
3393
3394     offset++;
3395
3396     proto_tree_add_item(tree, hf_gsm_sms_tp_mr, tvb, offset, 1, ENC_BIG_ENDIAN);
3397
3398     offset++;
3399     oct = tvb_get_guint8(tvb, offset);
3400
3401     dis_field_pid(tvb, tree, offset, oct);
3402
3403     offset++;
3404     oct = tvb_get_guint8(tvb, offset);
3405
3406     DIS_FIELD_CT(tree, offset);
3407
3408     offset++;
3409     oct = tvb_get_guint8(tvb, offset);
3410
3411     DIS_FIELD_MN(tree, offset);
3412
3413     offset++;
3414
3415     dis_field_addr(tvb, tree, &offset, "TP-Destination-Address");
3416
3417     oct = tvb_get_guint8(tvb, offset);
3418     cdl = oct;
3419
3420     DIS_FIELD_CDL(tree, offset);
3421
3422     if (cdl > 0)
3423     {
3424         offset++;
3425
3426         proto_tree_add_text(tree,
3427             tvb, offset, cdl,
3428             "TP-Command-Data");
3429     }
3430 }
3431
3432 #if 0
3433 #define NUM_MSGS (sizeof(msg_type_strings)/sizeof(value_string))
3434 static gint ett_msgs[NUM_MSGS];
3435 #endif
3436
3437 static void (*gsm_sms_msg_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset) = {
3438     dis_msg_deliver,        /* SMS-DELIVER */
3439     dis_msg_deliver_report, /* SMS-DELIVER REPORT */
3440     dis_msg_submit,         /* SMS-SUBMIT */
3441     dis_msg_submit_report,  /* SMS-SUBMIT REPORT */
3442     dis_msg_status_report,  /* SMS-STATUS REPORT */
3443     dis_msg_command,        /* SMS-COMMAND */
3444     NULL,                   /* Reserved */
3445     NULL,                   /* Reserved */
3446     NULL,                   /* NONE */
3447 };
3448
3449 /* GENERIC DISSECTOR FUNCTIONS */
3450
3451 static void
3452 dissect_gsm_sms(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3453 {
3454     void (*msg_fcn)(tvbuff_t *tvb, proto_tree *tree, guint32 offset) = NULL;
3455     proto_item *gsm_sms_item;
3456     proto_tree *gsm_sms_tree = NULL;
3457     guint32    offset;
3458     guint8      msg_type;
3459     guint8      oct;
3460     gint        idx;
3461     const gchar *str = NULL;
3462     /*gint      ett_msg_idx;*/
3463
3464
3465     g_pinfo = pinfo;
3466     g_is_wsp = 0;
3467     g_sm_id = 0;
3468     g_frags = 0;
3469     g_frag = 0;
3470     g_port_src = 0;
3471     g_port_dst = 0;
3472
3473     col_set_str(pinfo->cinfo, COL_PROTOCOL, gsm_sms_proto_name_short);
3474
3475     /* In the interest of speed, if "tree" is NULL, don't do any work not
3476      * necessary to generate protocol tree items.
3477      */
3478     if (tree || reassemble_sms)
3479     {
3480         g_tree = tree;
3481
3482         offset = 0;
3483
3484         oct = tvb_get_guint8(tvb, offset);
3485
3486         oct &= 0x03;
3487         msg_type = oct;
3488
3489         /*
3490          * convert the 2 bit value to one based on direction
3491          */
3492         msg_type |= ((pinfo->p2p_dir == P2P_DIR_RECV) ? 0x04 : 0x00);
3493
3494         str = match_strval_idx(msg_type, msg_type_strings, &idx);
3495
3496         /*
3497          * create the GSM_SMS protocol tree
3498          */
3499         gsm_sms_item =
3500             proto_tree_add_protocol_format(tree, proto_gsm_sms, tvb, 0, -1,
3501                 "%s %s",
3502                 gsm_sms_proto_name,
3503                 (str == NULL) ? "Unknown message identifier" : str);
3504
3505         gsm_sms_tree =
3506             proto_item_add_subtree(gsm_sms_item, ett_gsm_sms);
3507
3508         if ((str == NULL) ||
3509             (msg_type == 0x03) ||
3510             (msg_type == 0x07))
3511         {
3512             return;
3513         }
3514         else
3515         {
3516             /*ett_msg_idx = ett_msgs[idx];*/ /* XXX: Not actually used */
3517             msg_fcn = gsm_sms_msg_fcn[idx];
3518         }
3519
3520         if (msg_fcn == NULL)
3521         {
3522             proto_tree_add_text(gsm_sms_tree,
3523                 tvb, offset, -1,
3524                 "Message dissector not implemented");
3525         }
3526         else
3527         {
3528             (*msg_fcn)(tvb, gsm_sms_tree, offset);
3529         }
3530     }
3531 }
3532
3533
3534 /* Register the protocol with Wireshark */
3535 void
3536 proto_register_gsm_sms(void)
3537 {
3538     guint     i;
3539     guint     last_offset;
3540     module_t  *gsm_sms_module; /* Preferences for GSM SMS UD */
3541
3542     /* Setup list of header fields */
3543     static hf_register_info hf[] =
3544         {
3545             { &hf_gsm_sms_coding_group_bits2,
3546               { "Coding Group Bits", "gsm_sms.coding_group_bits2",
3547                 FT_UINT8, BASE_DEC, VALS(gsm_sms_coding_group_bits_vals), 0xc0,
3548                 NULL, HFILL }
3549             },
3550             { &hf_gsm_sms_coding_group_bits4,
3551               { "Coding Group Bits", "gsm_sms.coding_group_bits4",
3552                 FT_UINT8, BASE_DEC, VALS(gsm_sms_coding_group_bits_vals), 0xf0,
3553                 NULL, HFILL }
3554             },
3555
3556             /*
3557              * Short Message fragment reassembly
3558              */
3559             { &hf_gsm_sms_ud_fragments,
3560               { "Short Message fragments", "gsm_sms.fragments",
3561                  FT_NONE, BASE_NONE, NULL, 0x00,
3562                  "GSM Short Message fragments", HFILL }
3563             },
3564             { &hf_gsm_sms_ud_fragment,
3565               { "Short Message fragment", "gsm_sms.fragment",
3566                 FT_FRAMENUM, BASE_NONE, NULL, 0x00,
3567                 "GSM Short Message fragment", HFILL }
3568             },
3569             { &hf_gsm_sms_ud_fragment_overlap,
3570               { "Short Message fragment overlap", "gsm_sms.fragment.overlap",
3571                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
3572                 "GSM Short Message fragment overlaps with other fragment(s)", HFILL }
3573             },
3574             { &hf_gsm_sms_ud_fragment_overlap_conflicts,
3575               { "Short Message fragment overlapping with conflicting data", "gsm_sms.fragment.overlap.conflicts",
3576                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
3577                 "GSM Short Message fragment overlaps with conflicting data", HFILL }
3578             },
3579             { &hf_gsm_sms_ud_fragment_multiple_tails,
3580               { "Short Message has multiple tail fragments", "gsm_sms.fragment.multiple_tails",
3581                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
3582                 "GSM Short Message fragment has multiple tail fragments", HFILL }
3583             },
3584             { &hf_gsm_sms_ud_fragment_too_long_fragment,
3585               { "Short Message fragment too long", "gsm_sms.fragment.too_long_fragment",
3586                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
3587                 "GSM Short Message fragment data goes beyond the packet end", HFILL }
3588             },
3589             { &hf_gsm_sms_ud_fragment_error,
3590               { "Short Message defragmentation error", "gsm_sms.fragment.error",
3591                 FT_FRAMENUM, BASE_NONE, NULL, 0x00,
3592                 "GSM Short Message defragmentation error due to illegal fragments", HFILL }
3593             },
3594             { &hf_gsm_sms_ud_fragment_count,
3595               { "Short Message fragment count", "gsm_sms.fragment.count",
3596                 FT_UINT32, BASE_DEC, NULL, 0x00,
3597                 NULL, HFILL }
3598             },
3599             { &hf_gsm_sms_ud_reassembled_in,
3600               { "Reassembled in", "gsm_sms.reassembled.in",
3601                 FT_FRAMENUM, BASE_NONE, NULL, 0x00,
3602                 "GSM Short Message has been reassembled in this packet.", HFILL }
3603             },
3604             { &hf_gsm_sms_ud_reassembled_length,
3605               { "Reassembled Short Message length", "gsm_sms.reassembled.length",
3606                 FT_UINT32, BASE_DEC, NULL, 0x00,
3607                 "The total length of the reassembled payload", HFILL }
3608             },
3609             { &hf_gsm_sms_ud_multiple_messages_msg_id,
3610               { "Message identifier", "gsm_sms.udh.mm.msg_id",
3611                 FT_UINT16, BASE_DEC, NULL, 0x00,
3612                 "Identification of the message", HFILL }
3613             },
3614             { &hf_gsm_sms_ud_multiple_messages_msg_parts,
3615               { "Message parts", "gsm_sms.udh.mm.msg_parts",
3616                 FT_UINT8, BASE_DEC, NULL, 0x00,
3617                 "Total number of message parts (fragments)", HFILL }
3618             },
3619             { &hf_gsm_sms_ud_multiple_messages_msg_part,
3620               { "Message part number", "gsm_sms.udh.mm.msg_part",
3621                 FT_UINT8, BASE_DEC, NULL, 0x00,
3622                 "Message part (fragment) sequence number", HFILL }
3623             },
3624             /* TPDU parameters */
3625             { &hf_gsm_sms_tp_mti_up,
3626               { "TP-MTI", "gsm_sms.tp-mti",
3627                 FT_UINT8, BASE_DEC, VALS(msg_type_strings_ms_to_sc), 0x03,
3628                 "TP-Message-Type-Indicator (in the direction MS to SC)", HFILL }
3629             },
3630             { &hf_gsm_sms_tp_mti_down,
3631               { "TP-MTI", "gsm_sms.tp-mti",
3632                 FT_UINT8, BASE_DEC, VALS(msg_type_strings_sc_to_ms), 0x03,
3633                 "TP-Message-Type-Indicator (in the direction SC to MS)", HFILL }
3634             },
3635             { &hf_gsm_sms_tp_oa,
3636               { "TP-OA Digits", "gsm_sms.tp-oa",
3637                 FT_STRING, BASE_NONE, NULL, 0x00,
3638                 "TP-Originating-Address Digits", HFILL }
3639             },
3640             { &hf_gsm_sms_tp_da,
3641               { "TP-DA Digits", "gsm_sms.tp-da",
3642                 FT_STRING, BASE_NONE, NULL, 0x00,
3643                 "TP-Destination-Address Digits", HFILL }
3644             },
3645             { &hf_gsm_sms_tp_ra,
3646               { "TP-RA Digits", "gsm_sms.tp-ra",
3647                 FT_STRING, BASE_NONE, NULL, 0x00,
3648                 "TP-Recipient-Address Digits", HFILL }
3649             },
3650             { &hf_gsm_sms_tp_pid,
3651               { "TP-PID", "gsm_sms.tp-pid",
3652                 FT_UINT8, BASE_DEC, NULL, 0x00,
3653                 "TP-Protocol-Identifier", HFILL }
3654             },
3655             { &hf_gsm_sms_tp_dcs,
3656               { "TP-DCS", "gsm_sms.tp-dcs",
3657                 FT_UINT8, BASE_DEC, NULL, 0x00,
3658                 "TP-Data-Coding-Scheme", HFILL }
3659             },
3660             { &hf_gsm_sms_tp_mr,
3661               { "TP-MR", "gsm_sms.tp-mr",
3662                 FT_UINT8, BASE_DEC, NULL, 0x00,
3663                 "TP-Message-Reference", HFILL }
3664             },
3665             { &hf_gsm_sms_tp_mms,
3666               { "TP-MMS", "gsm_sms.tp-mms",
3667                 FT_BOOLEAN, 8, TFS(&mms_bool_strings), 0x04,
3668                 "TP-More-Messages-to-Send", HFILL }
3669             },
3670             { &hf_gsm_sms_tp_sri,
3671               { "TP-SRI", "gsm_sms.tp-sri",
3672                 FT_BOOLEAN, 8, TFS(&sri_bool_strings), 0x20,
3673                 "TP-Status-Report-Indication", HFILL }
3674             },
3675             { &hf_gsm_sms_tp_srr,
3676               { "TP-SRR", "gsm_sms.tp-srr",
3677                 FT_BOOLEAN, 8, TFS(&srr_bool_strings), 0x20,
3678                 "TP-Status-Report-Request", HFILL }
3679             },
3680             { &hf_gsm_sms_tp_udhi,
3681               { "TP-UDHI", "gsm_sms.tp-udhi",
3682                 FT_BOOLEAN, 8, TFS(&udhi_bool_strings), 0x40,
3683                 "TP-User-Data-Header-Indicator", HFILL }
3684             },
3685             { &hf_gsm_sms_tp_rp,
3686               { "TP-RP", "gsm_sms.tp-rp",
3687                 FT_BOOLEAN, 8, TFS(&rp_bool_strings), 0x80,
3688                 "TP-Reply-Path", HFILL }
3689             },
3690             { &hf_gsm_sms_tp_vpf,
3691               { "TP-VPF", "gsm_sms.tp-vpf",
3692                 FT_UINT8, BASE_DEC, VALS(vp_type_strings), 0x18,
3693                 "TP-Validity-Period-Format", HFILL }
3694             },
3695             { &hf_gsm_sms_tp_rd,
3696               { "TP-RD", "gsm_sms.tp-rd",
3697                 FT_BOOLEAN, 8, TFS(&rd_bool_strings), 0x04,
3698                 "TP-Reject-Duplicates", HFILL }
3699             },
3700             { &hf_gsm_sms_tp_srq,
3701               { "TP-SRQ", "gsm_sms.tp-srq",
3702                 FT_BOOLEAN, 8, TFS(&srq_bool_strings), 0x20,
3703                 "TP-Status-Report-Qualifier", HFILL }
3704             },
3705             { &hf_gsm_sms_text,
3706               { "SMS text", "gsm_sms.sms_text",
3707                 FT_STRING, BASE_NONE, NULL, 0x00,
3708                 "The text of the SMS", HFILL }
3709             },
3710             { &hf_gsm_sms_tp_fail_cause,
3711               { "TP-Failure-Cause (TP-FCS)", "gsm_sms.tp-fcs",
3712                 FT_UINT8, BASE_HEX_DEC|BASE_EXT_STRING, &gsm_sms_tp_failure_cause_values_ext, 0x0,
3713                 "TP-Validity-Period-Format", HFILL }
3714             },
3715         };
3716
3717     /* Setup protocol subtree array */
3718 #define NUM_INDIVIDUAL_PARMS        12
3719     gint *ett[NUM_INDIVIDUAL_PARMS/*+NUM_MSGS*/+NUM_UDH_IEIS+2];
3720
3721     ett[0]  = &ett_gsm_sms;
3722     ett[1]  = &ett_pid;
3723     ett[2]  = &ett_pi;
3724     ett[3]  = &ett_fcs;
3725     ett[4]  = &ett_vp;
3726     ett[5]  = &ett_scts;
3727     ett[6]  = &ett_dt;
3728     ett[7]  = &ett_st;
3729     ett[8]  = &ett_addr;
3730     ett[9]  = &ett_dcs;
3731     ett[10] = &ett_ud;
3732     ett[11] = &ett_udh;
3733
3734     last_offset = NUM_INDIVIDUAL_PARMS;
3735
3736 #if 0
3737     for (i=0; i < NUM_MSGS; i++, last_offset++)
3738     {
3739         ett_msgs[i] = -1;
3740         ett[last_offset] = &ett_msgs[i];
3741     }
3742 #endif
3743
3744     for (i=0; i < NUM_UDH_IEIS; i++, last_offset++)
3745     {
3746         ett_udh_ieis[i] = -1;
3747         ett[last_offset] = &ett_udh_ieis[i];
3748     }
3749
3750     ett[last_offset++] = &ett_gsm_sms_ud_fragment;
3751     ett[last_offset] = &ett_gsm_sms_ud_fragments;
3752
3753     /* Register the protocol name and description */
3754
3755     proto_gsm_sms =
3756         proto_register_protocol(gsm_sms_proto_name, gsm_sms_proto_name_short, "gsm_sms");
3757
3758
3759     proto_register_field_array(proto_gsm_sms, hf, array_length(hf));
3760
3761     proto_register_subtree_array(ett, array_length(ett));
3762
3763     gsm_sms_dissector_tbl = register_dissector_table("gsm_sms.udh.port",
3764         "GSM SMS port IE in UDH", FT_UINT16, BASE_DEC);
3765
3766     gsm_sms_module = prefs_register_protocol (proto_gsm_sms, NULL);
3767
3768     prefs_register_obsolete_preference(gsm_sms_module,
3769                                        "try_dissect_message_fragment");
3770     prefs_register_bool_preference (gsm_sms_module, "reassemble",
3771                                     "Reassemble fragmented SMS",
3772                                     "Whether the dissector should reassemble SMS spanning multiple packets",
3773                                     &reassemble_sms);
3774
3775     /* register_dissector("gsm_sms", dissect_gsm_sms, proto_gsm_sms); */
3776
3777     /* GSM SMS UD dissector initialization routines */
3778     register_init_routine (gsm_sms_defragment_init);
3779 }
3780
3781
3782 void
3783 proto_reg_handoff_gsm_sms(void)
3784 {
3785     dissector_handle_t             gsm_sms_handle;
3786
3787     gsm_sms_handle = create_dissector_handle(dissect_gsm_sms, proto_gsm_sms);
3788
3789     dissector_add_uint("gsm_a.sms_tpdu", 0, gsm_sms_handle);
3790     dissector_add_uint("gsm_map.sms_tpdu", 0, gsm_sms_handle);
3791     dissector_add_uint("etsi_cat.sms_tpdu", 0, gsm_sms_handle);
3792 }