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