From Graeme Hewson:
[obnox/wireshark/wip.git] / 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  * $Id: packet-gsm_sms.c,v 1.12 2004/04/21 05:53:56 guy Exp $
15  *
16  * Ethereal - Network traffic analyzer
17  * By Gerald Combs <gerald@ethereal.com>
18  * Copyright 1998 Gerald Combs
19  *
20  * This program is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU General Public License
22  * as published by the Free Software Foundation; either version 2
23  * of the License, or (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  * GNU General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with this program; if not, write to the Free Software
32  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33  */
34
35 #ifdef HAVE_CONFIG_H
36 # include "config.h"
37 #endif
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <gmodule.h>
42
43 #ifdef HAVE_SYS_TYPES_H
44 # include <sys/types.h>
45 #endif
46
47 #ifdef HAVE_NETINET_IN_H
48 # include <netinet/in.h>
49 #endif
50
51 #include <string.h>
52
53 #include "epan/packet.h"
54 #include "prefs.h"
55
56 #include "packet-gsm_sms.h"
57
58
59 /* PROTOTYPES/FORWARDS */
60
61 #define EXTRANEOUS_DATA_CHECK(edc_len, edc_max_len) \
62     if ((edc_len) > (edc_max_len)) \
63     { \
64         proto_tree_add_text(tree, tvb, \
65             offset, (edc_len) - (edc_max_len), "Extraneous Data"); \
66     }
67
68 #define SHORT_DATA_CHECK(sdc_len, sdc_min_len) \
69     if ((sdc_len) < (sdc_min_len)) \
70     { \
71         proto_tree_add_text(tree, tvb, \
72             offset, (sdc_len), "Short Data (?)"); \
73         return; \
74     }
75
76 #define EXACT_DATA_CHECK(edc_len, edc_eq_len) \
77     if ((edc_len) != (edc_eq_len)) \
78     { \
79         proto_tree_add_text(tree, tvb, \
80             offset, (edc_len), "Unexpected Data Length"); \
81         return; \
82     }
83
84 #define SMS_SHIFTMASK(m_val, m_bitmask, m_sval); \
85     { \
86         int     _temp_val = m_val; \
87         int     _temp_bm = m_bitmask; \
88         while (_temp_bm && !(_temp_bm & 0x01)) \
89         { \
90             _temp_bm = _temp_bm >> 1; \
91             _temp_val = _temp_val >> 1; \
92         } \
93         m_sval = _temp_val; \
94     }
95
96
97 static char *gsm_sms_proto_name = "GSM SMS TPDU (GSM 03.40)";
98 static char *gsm_sms_proto_name_short = "GSM SMS";
99
100 /* Initialize the subtree pointers */
101 static gint ett_gsm_sms = -1;
102 static gint ett_pid = -1;
103 static gint ett_pi = -1;
104 static gint ett_fcs = -1;
105 static gint ett_vp = -1;
106 static gint ett_scts = -1;
107 static gint ett_dt = -1;
108 static gint ett_st = -1;
109 static gint ett_addr = -1;
110 static gint ett_dcs = -1;
111 static gint ett_ud = -1;
112 static gint ett_udh = -1;
113
114 /* Initialize the protocol and registered fields */
115 static int proto_gsm_sms = -1;
116
117 static char bigbuf[1024];
118 static dissector_handle_t data_handle;
119 static packet_info *g_pinfo;
120 static proto_tree *g_tree;
121
122 /*
123  * this is the GSM 03.40 definition with the bit 2
124  * set to 1 for uplink messages
125  */
126 static const value_string msg_type_strings[] = {
127     { 0,        "SMS-DELIVER" },
128     { 4,        "SMS-DELIVER REPORT" },
129     { 5,        "SMS-SUBMIT" },
130     { 1,        "SMS-SUBMIT REPORT" },
131     { 2,        "SMS-STATUS REPORT" },
132     { 6,        "SMS-COMMAND" },
133     { 3,        "Reserved" },
134     { 7,        "Reserved" },
135     { 0, NULL },
136 };
137
138 #define NUM_UDH_IEIS    256
139 static gint ett_udh_ieis[NUM_UDH_IEIS];
140
141 /* FUNCTIONS */
142
143 gchar *
144 my_match_strval(guint32 val, const value_string *vs, gint *idx)
145 {
146     gint i = 0;
147
148     while (vs[i].strptr) {
149         if (vs[i].value == val)
150         {
151             *idx = i;
152             return(vs[i].strptr);
153         }
154
155         i++;
156     }
157
158     *idx = -1;
159     return(NULL);
160 }
161
162 /* 9.2.3.1 */
163 #define DIS_FIELD_MTI(m_tree, m_bitmask, m_offset) \
164 { \
165     other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
166     proto_tree_add_text(m_tree, tvb, \
167         m_offset, 1, \
168         "%s :  TP-Message-Type-Indicator", \
169         bigbuf); \
170 }
171
172 /* 9.2.3.2 */
173 #define DIS_FIELD_MMS(m_tree, m_bitmask, m_offset) \
174 { \
175     other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
176     proto_tree_add_text(m_tree, tvb, \
177         m_offset, 1, \
178         "%s :  TP-More-Messages-to-Send: %s messages are waiting for the MS in this SC", \
179         bigbuf, \
180         (oct & m_bitmask) ? "No more" : "More"); \
181 }
182
183 /* 9.2.3.3 */
184 #define DIS_FIELD_VPF(m_tree, m_bitmask, m_offset, m_form) \
185 { \
186     SMS_SHIFTMASK(oct & m_bitmask, m_bitmask, *m_form); \
187     switch (*m_form) \
188     { \
189     case 0: str = "TP-VP field not present"; break; \
190     case 1: str = "TP-VP field present - enhanced format"; break; \
191     case 2: str = "TP-VP field present - relative format"; break; \
192     case 3: str = "TP-VP field present - absolute format"; break; \
193     } \
194     other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
195     proto_tree_add_text(m_tree, tvb, \
196         m_offset, 1, \
197         "%s :  TP-Validity-Period-Format: %s", \
198         bigbuf, \
199         str); \
200 }
201
202 /* 9.2.3.4 */
203 #define DIS_FIELD_SRI(m_tree, m_bitmask, m_offset) \
204 { \
205     other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
206     proto_tree_add_text(m_tree, tvb, \
207         m_offset, 1, \
208         "%s :  TP-Status-Report-Indication: A status report shall %sbe returned to the SME", \
209         bigbuf, \
210         (oct & m_bitmask) ? "" : "not "); \
211 }
212
213 /* 9.2.3.5 */
214 #define DIS_FIELD_SRR(m_tree, m_bitmask, m_offset) \
215 { \
216     other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
217     proto_tree_add_text(m_tree, tvb, \
218         m_offset, 1, \
219         "%s :  TP-Status-Report-Request: A status report is %srequested", \
220         bigbuf, \
221         (oct & m_bitmask) ? "" : "not "); \
222 }
223
224 /* 9.2.3.6 */
225 #define DIS_FIELD_MR(m_tree, m_offset) \
226 { \
227     proto_tree_add_text(m_tree, tvb, \
228         m_offset, 1, \
229         "TP-Message-Reference %d", \
230         oct); \
231 }
232
233 static void
234 dis_field_addr(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p, gchar *title)
235 {
236     static gchar        digit_table[] = {"0123456789*#abc\0"};
237     proto_item          *item;
238     proto_tree          *subtree = NULL;
239     gchar               *str = NULL;
240     guint8              oct;
241     guint32             offset;
242     guint32             numdigocts;
243     guint32             length;
244     guint32             i, j;
245
246
247     offset = *offset_p;
248
249     oct = tvb_get_guint8(tvb, offset);
250     numdigocts = (oct + 1) / 2;
251
252     length = tvb_length_remaining(tvb, offset);
253
254     if (length <= numdigocts)
255     {
256         proto_tree_add_text(tree,
257             tvb, offset, length,
258             "%s: Short Data (?)",
259             title);
260
261         *offset_p += length;
262         return;
263     }
264
265     item =
266         proto_tree_add_text(tree, tvb,
267             offset, numdigocts + 2,
268             title);
269
270     subtree = proto_item_add_subtree(item, ett_addr);
271
272     proto_tree_add_text(subtree,
273         tvb, offset, 1,
274         "Length: %d address digits",
275         oct);
276
277     offset++;
278     oct = tvb_get_guint8(tvb, offset);
279
280     other_decode_bitfield_value(bigbuf, oct, 0x80, 8);
281     proto_tree_add_text(subtree, tvb,
282         offset, 1,
283         "%s :  %s",
284         bigbuf,
285         (oct & 0x80) ? "No extension" : "Extended");
286
287     switch ((oct & 0x70) >> 4)
288     {
289     case 0x00: str = "Unknown"; break;
290     case 0x01: str = "International"; break;
291     case 0x02: str = "National"; break;
292     case 0x07: str = "Reserved for extension"; break;
293     default: str = "Unknown, reserved (?)"; break;
294     }
295
296     other_decode_bitfield_value(bigbuf, oct, 0x70, 8);
297     proto_tree_add_text(subtree,
298         tvb, offset, 1,
299         "%s :  Type of number: (%d) %s",
300         bigbuf,
301         (oct & 0x70) >> 4,
302         str);
303
304     switch (oct & 0x0f)
305     {
306     case 0x00: str = "Unknown"; break;
307     case 0x01: str = "ISDN/telephone"; break;
308     case 0x0f: str = "Reserved for extension"; break;
309     default: str = "Unknown, reserved (?)"; break;
310     }
311
312     other_decode_bitfield_value(bigbuf, oct, 0x0f, 8);
313     proto_tree_add_text(subtree,
314         tvb, offset, 1,
315         "%s :  Numbering plan: (%d) %s",
316         bigbuf,
317         oct & 0x0f,
318         str);
319
320     offset++;
321
322     j = 0;
323     for (i = 0; i < numdigocts; i++)
324     {
325         oct = tvb_get_guint8(tvb, offset + i);
326
327         bigbuf[j++] = digit_table[oct & 0x0f];
328         bigbuf[j++] = digit_table[(oct & 0xf0) >> 4];
329     }
330
331     bigbuf[j++] = '\0';
332
333     proto_tree_add_text(subtree,
334         tvb, offset, numdigocts,
335         "Digits: %s",
336         bigbuf);
337
338     proto_item_append_text(item, " - (%s)", bigbuf);
339
340     *offset_p = offset + i;
341 }
342
343 /* 9.2.3.7 */
344 /* use dis_field_addr() */
345
346 /* 9.2.3.8 */
347 /* use dis_field_addr() */
348
349 /* 9.2.3.9 */
350 static void
351 dis_field_pid(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 oct)
352 {
353     proto_item  *item;
354     proto_tree  *subtree = NULL;
355     guint8      form;
356     guint8      telematic;
357     gchar       *str = NULL;
358
359
360     item =
361         proto_tree_add_text(tree, tvb,
362             offset, 1,
363             "TP-Protocol-Identifier");
364
365     subtree = proto_item_add_subtree(item, ett_pid);
366
367     form = (oct & 0xc0) >> 6;
368
369     switch (form)
370     {
371     case 0:
372         other_decode_bitfield_value(bigbuf, oct, 0xc0, 8);
373         proto_tree_add_text(subtree, tvb,
374             offset, 1,
375             "%s :  defines formatting for subsequent bits",
376             bigbuf);
377
378         other_decode_bitfield_value(bigbuf, oct, 0x20, 8);
379         proto_tree_add_text(subtree, tvb,
380             offset, 1,
381             "%s :  %s",
382             bigbuf,
383             (oct & 0x20) ?
384             "telematic interworking" :
385             "no telematic interworking, but SME-to-SME protocol");
386
387         if (oct & 0x20)
388         {
389             telematic = oct & 0x1f;
390
391             switch (telematic)
392             {
393             case 0x00: str = "implicit - device type is specific to this SC, or can be concluded on the basis of the address"; break;
394             case 0x01: str = "telex (or teletex reduced to telex format)"; break;
395             case 0x02: str = "group 3 telefax"; break;
396             case 0x03: str = "group 4 telefax"; break;
397             case 0x04: str = "voice telephone (i.e. conversion to speech)"; break;
398             case 0x05: str = "ERMES (European Radio Messaging System)"; break;
399             case 0x06: str = "National Paging system (known to the SC)"; break;
400             case 0x07: str = "Videotex (T.100 [20] /T.101 [21])"; break;
401             case 0x08: str = "teletex, carrier unspecified"; break;
402             case 0x09: str = "teletex, in PSPDN"; break;
403             case 0x0a: str = "teletex, in CSPDN"; break;
404             case 0x0b: str = "teletex, in analog PSTN"; break;
405             case 0x0c: str = "teletex, in digital ISDN"; break;
406             case 0x0d: str = "UCI (Universal Computer Interface, ETSI DE/PS 3 01-3)"; break;
407             case 0x10: str = "a message handling facility (known to the SC)"; break;
408             case 0x11: str = "any public X.400-based message handling system"; break;
409             case 0x12: str = "Internet Electronic Mail"; break;
410             case 0x1f: str = "A GSM/UMTS mobile station"; break;
411             default:
412                 if ((telematic >= 0x18) &&
413                     (telematic <= 0x1e))
414                 {
415                     str = "values specific to each SC";
416                 }
417                 else
418                 {
419                     str = "reserved";
420                 }
421                 break;
422             }
423
424             other_decode_bitfield_value(bigbuf, oct, 0x1f, 8);
425             proto_tree_add_text(subtree, tvb,
426                 offset, 1,
427                 "%s :  device type: (%d) %s",
428                 bigbuf,
429                 telematic,
430                 str);
431         }
432         else
433         {
434             other_decode_bitfield_value(bigbuf, oct, 0x1f, 8);
435             proto_tree_add_text(subtree, tvb,
436                 offset, 1,
437                 "%s :  the SM-AL protocol being used between the SME and the MS (%d)",
438                 bigbuf,
439                 oct & 0x1f);
440         }
441         break;
442
443     case 1:
444         other_decode_bitfield_value(bigbuf, oct, 0xc0, 8);
445         proto_tree_add_text(subtree, tvb,
446             offset, 1,
447             "%s :  defines formatting for subsequent bits",
448             bigbuf);
449
450         switch (oct & 0x3f)
451         {
452         case 0x00: str = "Short Message Type 0"; break;
453         case 0x01: str = "Replace Short Message Type 1"; break;
454         case 0x02: str = "Replace Short Message Type 2"; break;
455         case 0x03: str = "Replace Short Message Type 3"; break;
456         case 0x04: str = "Replace Short Message Type 4"; break;
457         case 0x05: str = "Replace Short Message Type 5"; break;
458         case 0x06: str = "Replace Short Message Type 6"; break;
459         case 0x07: str = "Replace Short Message Type 7"; break;
460         case 0x1e: str = "Enhanced Message Service (Obsolete)"; break;
461         case 0x1f: str = "Return Call Message"; break;
462         case 0x3c: str = "ANSI-136 R-DATA"; break;
463         case 0x3d: str = "ME Data download"; break;
464         case 0x3e: str = "ME De-personalization Short Message"; break;
465         case 0x3f: str = "(U)SIM Data download"; break;
466         default:
467             str = "Reserved"; break;
468         }
469
470         other_decode_bitfield_value(bigbuf, oct, 0x3f, 8);
471         proto_tree_add_text(subtree, tvb,
472             offset, 1,
473             "%s :  (%d) %s",
474             bigbuf,
475             oct & 0x3f,
476             str);
477         break;
478
479     case 2:
480         other_decode_bitfield_value(bigbuf, oct, 0xc0, 8);
481         proto_tree_add_text(subtree, tvb,
482             offset, 1,
483             "%s :  Reserved",
484             bigbuf);
485
486         other_decode_bitfield_value(bigbuf, oct, 0x3f, 8);
487         proto_tree_add_text(subtree, tvb,
488             offset, 1,
489             "%s :  undefined",
490             bigbuf);
491         break;
492
493     case 3:
494         other_decode_bitfield_value(bigbuf, oct, 0xc0, 8);
495         proto_tree_add_text(subtree, tvb,
496             offset, 1,
497             "%s :  bits 0-5 for SC specific use",
498             bigbuf);
499
500         other_decode_bitfield_value(bigbuf, oct, 0x3f, 8);
501         proto_tree_add_text(subtree, tvb,
502             offset, 1,
503             "%s :  SC specific",
504             bigbuf);
505         break;
506     }
507 }
508
509 /* 9.2.3.10 */
510 static void
511 dis_field_dcs(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 oct,
512     gboolean *seven_bit, gboolean *eight_bit, gboolean *ucs2, gboolean *compressed)
513 {
514     proto_item  *item;
515     proto_tree  *subtree = NULL;
516     guint8      form;
517     gchar       *str = NULL;
518     gboolean    default_5_bits;
519     gboolean    default_3_bits;
520     gboolean    default_data;
521
522
523     *seven_bit = FALSE;
524     *eight_bit = FALSE;
525     *ucs2 = FALSE;
526     *compressed = FALSE;
527
528     item =
529         proto_tree_add_text(tree, tvb,
530             offset, 1,
531             "TP-Data-Coding-Scheme (%d)",
532             oct);
533
534     subtree = proto_item_add_subtree(item, ett_dcs);
535
536     if (oct == 0x00)
537     {
538         proto_tree_add_text(subtree, tvb,
539             offset, 1,
540             "Special case, GSM 7 bit default alphabet");
541
542         *seven_bit = TRUE;
543         return;
544     }
545
546     default_5_bits = FALSE;
547     default_3_bits = FALSE;
548     default_data = FALSE;
549     form = (oct & 0xc0) >> 6;
550
551     switch (form)
552     {
553     case 0:
554         other_decode_bitfield_value(bigbuf, oct, 0xc0, 8);
555         proto_tree_add_text(subtree, tvb,
556             offset, 1,
557             "%s :  General Data Coding indication",
558             bigbuf);
559
560         default_5_bits = TRUE;
561         break;
562
563     case 1:
564         other_decode_bitfield_value(bigbuf, oct, 0xc0, 8);
565         proto_tree_add_text(subtree, tvb,
566             offset, 1,
567             "%s :  Message Marked for Automatic Deletion Group",
568             bigbuf);
569
570         default_5_bits = TRUE;
571         break;
572
573     case 2:
574         /* use top four bits */
575         other_decode_bitfield_value(bigbuf, oct, 0xf0, 8);
576         proto_tree_add_text(subtree, tvb,
577             offset, 1,
578             "%s :  Reserved coding groups",
579             bigbuf);
580         return;
581
582     case 3:
583         switch ((oct & 0x30) >> 4)
584         {
585         case 0x00: str = "Message Waiting Indication Group: Discard Message (GSM 7 bit default alphabet)";
586             default_3_bits = TRUE;
587             *seven_bit = TRUE;
588             break;
589         case 0x01: str = "Message Waiting Indication Group: Store Message (GSM 7 bit default alphabet)";
590             default_3_bits = TRUE;
591             *seven_bit = TRUE;
592             break;
593         case 0x02: str = "Message Waiting Indication Group: Store Message (uncompressed UCS2 alphabet)";
594             default_3_bits = TRUE;
595             break;
596         case 0x03: str = "Data coding/message class";
597             default_data = TRUE;
598             break;
599         }
600
601         /* use top four bits */
602         other_decode_bitfield_value(bigbuf, oct, 0xf0, 8);
603         proto_tree_add_text(subtree, tvb,
604             offset, 1,
605             "%s :  %s",
606             bigbuf,
607             str);
608         break;
609     }
610
611     if (default_5_bits)
612     {
613         other_decode_bitfield_value(bigbuf, oct, 0x20, 8);
614         proto_tree_add_text(subtree, tvb,
615             offset, 1,
616             "%s :  Text is %scompressed",
617             bigbuf,
618             (oct & 0x20) ?  "" : "not ");
619
620         *compressed = (oct & 0x20) >> 5;
621
622         other_decode_bitfield_value(bigbuf, oct, 0x10, 8);
623         proto_tree_add_text(subtree, tvb,
624             offset, 1,
625             "%s :  %s",
626             bigbuf,
627             (oct & 0x10) ?  "Message class is defined below" :
628                 "Reserved, no message class");
629
630         switch ((oct & 0x0c) >> 2)
631         {
632         case 0x00: str = "GSM 7 bit default alphabet";
633             *seven_bit = TRUE;
634             break;
635         case 0x01: str = "8 bit data"; break;
636         case 0x02: str = "UCS2 (16 bit)";
637             *ucs2 = TRUE;
638             break;
639         case 0x03: str = "Reserved"; break;
640         }
641
642         other_decode_bitfield_value(bigbuf, oct, 0x0c, 8);
643         proto_tree_add_text(subtree, tvb,
644             offset, 1,
645             "%s :  Character set: %s",
646             bigbuf,
647             str);
648
649         switch (oct & 0x03)
650         {
651         case 0x00: str = "Class 0"; break;
652         case 0x01: str = "Class 1 Default meaning: ME-specific"; break;
653         case 0x02: str = "Class 2 (U)SIM specific message"; break;
654         case 0x03: str = "Class 3 Default meaning: TE-specific"; break;
655         }
656
657         other_decode_bitfield_value(bigbuf, oct, 0x03, 8);
658         proto_tree_add_text(subtree, tvb,
659             offset, 1,
660             "%s :  Message Class: %s%s",
661             bigbuf,
662             str,
663             (oct & 0x10) ?  "" : " (reserved)");
664     }
665     else if (default_3_bits)
666     {
667         other_decode_bitfield_value(bigbuf, oct, 0x08, 8);
668         proto_tree_add_text(subtree, tvb,
669             offset, 1,
670             "%s :  Indication Sense: %s",
671             bigbuf,
672             (oct & 0x08) ?  "Set Indication Active" : "Set Indication Inactive");
673
674         other_decode_bitfield_value(bigbuf, oct, 0x04, 8);
675         proto_tree_add_text(subtree, tvb,
676             offset, 1,
677             "%s :  Reserved",
678             bigbuf);
679
680         switch (oct & 0x03)
681         {
682         case 0x00: str = "Voicemail Message Waiting"; break;
683         case 0x01: str = "Fax Message Waiting"; break;
684         case 0x02: str = "Electronic Mail Message Waiting"; break;
685         case 0x03: str = "Other Message Waiting"; break;
686         }
687
688         other_decode_bitfield_value(bigbuf, oct, 0x03, 8);
689         proto_tree_add_text(subtree, tvb,
690             offset, 1,
691             "%s :  %s",
692             bigbuf,
693             str);
694     }
695     else if (default_data)
696     {
697         other_decode_bitfield_value(bigbuf, oct, 0x08, 8);
698         proto_tree_add_text(subtree, tvb,
699             offset, 1,
700             "%s :  Reserved",
701             bigbuf);
702
703         *seven_bit = !(*eight_bit = (oct & 0x04) ? TRUE : FALSE);
704
705         other_decode_bitfield_value(bigbuf, oct, 0x04, 8);
706         proto_tree_add_text(subtree, tvb,
707             offset, 1,
708             "%s :  Message coding: %s",
709             bigbuf,
710             (*eight_bit) ? "8 bit data" : "GSM 7 bit default alphabet");
711
712         switch (oct & 0x03)
713         {
714         case 0x00: str = "Class 0"; break;
715         case 0x01: str = "Class 1 Default meaning: ME-specific"; break;
716         case 0x02: str = "Class 2 (U)SIM specific message"; break;
717         case 0x03: str = "Class 3 Default meaning: TE-specific"; break;
718         }
719
720         other_decode_bitfield_value(bigbuf, oct, 0x03, 8);
721         proto_tree_add_text(subtree, tvb,
722             offset, 1,
723             "%s :  Message Class: %s",
724             bigbuf,
725             str);
726     }
727 }
728
729 static void
730 dis_field_scts_aux(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
731 {
732     guint8      oct, oct2, oct3;
733
734
735     oct = tvb_get_guint8(tvb, offset);
736     oct2 = tvb_get_guint8(tvb, offset+1);
737     oct3 = tvb_get_guint8(tvb, offset+2);
738
739     proto_tree_add_text(tree,
740         tvb, offset, 3,
741         "Year %d%d, Month %d%d, Day %d%d",
742         oct & 0x0f,
743         (oct & 0xf0) >> 4,
744         oct2 & 0x0f,
745         (oct2 & 0xf0) >> 4,
746         oct3 & 0x0f,
747         (oct3 & 0xf0) >> 4);
748
749     offset += 3;
750
751     oct = tvb_get_guint8(tvb, offset);
752     oct2 = tvb_get_guint8(tvb, offset+1);
753     oct3 = tvb_get_guint8(tvb, offset+2);
754
755     proto_tree_add_text(tree,
756         tvb, offset, 3,
757         "Hour %d%d, Minutes %d%d, Seconds %d%d",
758         oct & 0x0f,
759         (oct & 0xf0) >> 4,
760         oct2 & 0x0f,
761         (oct2 & 0xf0) >> 4,
762         oct3 & 0x0f,
763         (oct3 & 0xf0) >> 4);
764
765     offset += 3;
766
767     oct = tvb_get_guint8(tvb, offset);
768
769     proto_tree_add_text(tree,
770         tvb, offset, 1,
771         "Timezone %d",
772         oct);
773 }
774
775 /* 9.2.3.11 */
776 static void
777 dis_field_scts(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p)
778 {
779     proto_item  *item;
780     proto_tree  *subtree = NULL;
781     guint32     offset;
782     guint32     length;
783
784
785     offset = *offset_p;
786
787     length = tvb_length_remaining(tvb, offset);
788
789     if (length < 7)
790     {
791         proto_tree_add_text(tree,
792             tvb, offset, length,
793             "TP-Service-Centre-Time-Stamp: Short Data (?)");
794
795         *offset_p += length;
796         return;
797     }
798
799     item =
800         proto_tree_add_text(tree, tvb,
801             offset, 7,
802             "TP-Service-Centre-Time-Stamp");
803
804     subtree = proto_item_add_subtree(item, ett_scts);
805
806     dis_field_scts_aux(tvb, subtree, *offset_p);
807
808     *offset_p += 7;
809 }
810
811 /* 9.2.3.12 */
812 static void
813 dis_field_vp(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p, guint8 vp_form)
814 {
815     proto_item  *item;
816     proto_tree  *subtree = NULL;
817     guint32     offset;
818     guint32     length;
819     guint8      oct, oct2, oct3;
820     guint8      loc_form;
821     guint32     mins, hours;
822     gboolean    done;
823
824
825     if (vp_form == 0x00) return;
826
827     offset = *offset_p;
828     subtree = tree;
829
830     done = FALSE;
831     do
832     {
833         switch (vp_form)
834         {
835         case 1:
836             length = tvb_length_remaining(tvb, offset);
837
838             if (length < 7)
839             {
840                 proto_tree_add_text(tree,
841                     tvb, offset, length,
842                     "TP-Validity-Period: Short Data (?)");
843
844                 *offset_p += length;
845                 return;
846             }
847
848             item =
849                 proto_tree_add_text(tree, tvb,
850                     offset, 7,
851                     "TP-Validity-Period");
852
853             subtree = proto_item_add_subtree(item, ett_vp);
854
855             oct = tvb_get_guint8(tvb, offset);
856
857             other_decode_bitfield_value(bigbuf, oct, 0x80, 8);
858             proto_tree_add_text(subtree, tvb,
859                 offset, 1,
860                 "%s :  %s",
861                 bigbuf,
862                 (oct & 0x80) ? "Extended" : "No extension");
863
864             if (oct & 0x80)
865             {
866                 proto_tree_add_text(subtree,
867                     tvb, offset + 1, 6,
868                     "Extension not implemented, ignored");
869
870                 *offset_p += 7;
871                 return;
872             }
873
874             other_decode_bitfield_value(bigbuf, oct, 0x40, 8);
875             proto_tree_add_text(subtree, tvb,
876                 offset, 1,
877                 "%s :  %s",
878                 bigbuf,
879                 (oct & 0x40) ? "Single shot SM" : "Not single shot SM");
880
881             other_decode_bitfield_value(bigbuf, oct, 0x38, 8);
882             proto_tree_add_text(subtree, tvb,
883                 offset, 1,
884                 "%s :  Reserved",
885                 bigbuf);
886
887             loc_form = oct & 0x7;
888
889             switch (loc_form)
890             {
891             case 0x00:
892                 other_decode_bitfield_value(bigbuf, oct, 0x07, 8);
893                 proto_tree_add_text(subtree, tvb,
894                     offset, 1,
895                     "%s :  No Validity Period specified",
896                     bigbuf);
897
898                 done = TRUE;
899                 break;
900
901             case 0x01:
902                 other_decode_bitfield_value(bigbuf, oct, 0x07, 8);
903                 proto_tree_add_text(subtree, tvb,
904                     offset, 1,
905                     "%s :  Validity Period Format: relative",
906                     bigbuf);
907
908                 /* go around again */
909                 vp_form = 2;
910                 break;
911
912             case 0x02:
913                 other_decode_bitfield_value(bigbuf, oct, 0x07, 8);
914                 proto_tree_add_text(subtree, tvb,
915                     offset, 1,
916                     "%s :  Validity Period Format: relative",
917                     bigbuf);
918
919                 offset++;
920                 oct = tvb_get_guint8(tvb, offset);
921
922                 proto_tree_add_text(subtree, tvb,
923                     offset, 1,
924                     "%d seconds",
925                     oct);
926
927                 done = TRUE;
928                 break;
929
930             case 0x03:
931                 other_decode_bitfield_value(bigbuf, oct, 0x07, 8);
932                 proto_tree_add_text(subtree, tvb,
933                     offset, 1,
934                     "%s :  Validity Period Format: relative",
935                     bigbuf);
936
937                 offset++;
938                 oct = tvb_get_guint8(tvb, offset);
939                 oct2 = tvb_get_guint8(tvb, offset+1);
940                 oct3 = tvb_get_guint8(tvb, offset+2);
941
942                 proto_tree_add_text(subtree,
943                     tvb, offset, 3,
944                     "Hour %d%d, Minutes %d%d, Seconds %d%d",
945                     (oct & 0xf0) >> 4,
946                     oct & 0x0f,
947                     (oct2 & 0xf0) >> 4,
948                     oct2 & 0x0f,
949                     (oct3 & 0xf0) >> 4,
950                     oct3 & 0x0f);
951
952                 done = TRUE;
953                 break;
954
955             default:
956                 other_decode_bitfield_value(bigbuf, oct, 0x07, 8);
957                 proto_tree_add_text(subtree, tvb,
958                     offset, 1,
959                     "%s :  Validity Period Format: Reserved",
960                     bigbuf);
961
962                 done = TRUE;
963                 break;
964             }
965             break;
966
967         case 2:
968             oct = tvb_get_guint8(tvb, offset);
969
970             if (oct <= 143)
971             {
972                 mins = (oct + 1) * 5;
973                 if (mins >= 60)
974                 {
975                     hours = mins / 60;
976                     mins %= 60;
977
978                     proto_tree_add_text(subtree, tvb,
979                         offset, 1,
980                         "TP-Validity-Period: %d hours %d minutes",
981                         hours,
982                         mins);
983                 }
984                 else
985                 {
986                     proto_tree_add_text(subtree, tvb,
987                         offset, 1,
988                         "TP-Validity-Period: %d minutes",
989                         mins);
990                 }
991             }
992             else if ((oct >= 144) &&
993                 (oct <= 167))
994             {
995                 mins = (oct - 143) * 30;
996                 hours = 12 + (mins / 60);
997                 mins %= 60;
998
999                 proto_tree_add_text(subtree, tvb,
1000                     offset, 1,
1001                     "TP-Validity-Period: %d hours %d minutes",
1002                     hours,
1003                     mins);
1004             }
1005             else if ((oct >= 168) &&
1006                 (oct <= 196))
1007             {
1008                 proto_tree_add_text(subtree, tvb,
1009                     offset, 1,
1010                     "TP-Validity-Period: %d day(s)",
1011                     oct - 166);
1012             }
1013             else if (oct >= 197)
1014             {
1015                 proto_tree_add_text(subtree, tvb,
1016                     offset, 1,
1017                     "TP-Validity-Period: %d week(s)",
1018                     oct - 192);
1019             }
1020
1021             done = TRUE;
1022             break;
1023
1024         case 3:
1025             length = tvb_length_remaining(tvb, offset);
1026
1027             if (length < 7)
1028             {
1029                 proto_tree_add_text(tree,
1030                     tvb, offset, length,
1031                     "TP-Validity-Period: Short Data (?)");
1032
1033                 *offset_p += length;
1034                 return;
1035             }
1036
1037             item =
1038                 proto_tree_add_text(tree, tvb,
1039                     offset, 7,
1040                     "TP-Validity-Period: absolute");
1041
1042             subtree = proto_item_add_subtree(item, ett_vp);
1043
1044             dis_field_scts_aux(tvb, subtree, *offset_p);
1045
1046             done = TRUE;
1047             break;
1048         }
1049     }
1050     while (!done);
1051
1052     if (vp_form == 2)
1053     {
1054         (*offset_p)++;
1055     }
1056     else
1057     {
1058         *offset_p += 7;
1059     }
1060 }
1061
1062 /* 9.2.3.13 */
1063 static void
1064 dis_field_dt(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p)
1065 {
1066     proto_item  *item;
1067     proto_tree  *subtree = NULL;
1068     guint32     offset;
1069     guint32     length;
1070
1071
1072     offset = *offset_p;
1073
1074     length = tvb_length_remaining(tvb, offset);
1075
1076     if (length < 7)
1077     {
1078         proto_tree_add_text(tree,
1079             tvb, offset, length,
1080             "TP-Discharge-Time: Short Data (?)");
1081
1082         *offset_p += length;
1083         return;
1084     }
1085
1086     item =
1087         proto_tree_add_text(tree, tvb,
1088             offset, 7,
1089             "TP-Discharge-Time");
1090
1091     subtree = proto_item_add_subtree(item, ett_dt);
1092
1093     dis_field_scts_aux(tvb, subtree, *offset_p);
1094
1095     *offset_p += 7;
1096 }
1097
1098 /* 9.2.3.14 */
1099 /* use dis_field_addr() */
1100
1101 /* 9.2.3.15 */
1102 static void
1103 dis_field_st(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 oct)
1104 {
1105     static gchar        *sc_complete = "Short message transaction completed";
1106     static gchar        *sc_temporary = "Temporary error, SC still trying to transfer SM";
1107     static gchar        *sc_perm = "Permanent error, SC is not making any more transfer attempts";
1108     static gchar        *sc_tempfin = "Temporary error, SC is not making any more transfer attempts";
1109     proto_item          *item;
1110     proto_tree          *subtree = NULL;
1111     guint8              value;
1112     gchar               *str = NULL;
1113     gchar               *str2 = NULL;
1114
1115
1116     item =
1117         proto_tree_add_text(tree, tvb,
1118             offset, 1,
1119             "TP-Status");
1120
1121     subtree = proto_item_add_subtree(item, ett_st);
1122
1123     other_decode_bitfield_value(bigbuf, oct, 0x80, 8);
1124     proto_tree_add_text(subtree, tvb,
1125         offset, 1,
1126         "%s :  Definition of bits 0-6: %s",
1127         bigbuf,
1128         (oct & 0x80) ?  "Reserved" : "as follows");
1129
1130     value = oct & 0x7f;
1131
1132     switch (value)
1133     {
1134     case 0x00: str2 = sc_complete; str = "Short message received by the SME"; break;
1135     case 0x01: str2 = sc_complete; str = "Short message forwarded by the SC to the SME but the SC is unable to confirm delivery"; break;
1136     case 0x02: str2 = sc_complete; str = "Short message replaced by the SC Reserved values"; break;
1137
1138     case 0x20: str2 = sc_temporary; str = "Congestion"; break;
1139     case 0x21: str2 = sc_temporary; str = "SME busy"; break;
1140     case 0x22: str2 = sc_temporary; str = "No response from SME"; break;
1141     case 0x23: str2 = sc_temporary; str = "Service rejected"; break;
1142     case 0x24: str2 = sc_temporary; str = "Quality of service not available"; break;
1143     case 0x25: str2 = sc_temporary; str = "Error in SME"; break;
1144
1145     case 0x40: str2 = sc_perm; str = "Remote procedure error"; break;
1146     case 0x41: str2 = sc_perm; str = "Incompatible destination"; break;
1147     case 0x42: str2 = sc_perm; str = "Connection rejected by SME"; break;
1148     case 0x43: str2 = sc_perm; str = "Not obtainable"; break;
1149     case 0x44: str2 = sc_perm; str = "Quality of service not available"; break;
1150     case 0x45: str2 = sc_perm; str = "No interworking available"; break;
1151     case 0x46: str2 = sc_perm; str = "SM Validity Period Expired"; break;
1152     case 0x47: str2 = sc_perm; str = "SM Deleted by originating SME"; break;
1153     case 0x48: str2 = sc_perm; str = "SM Deleted by SC Administration"; break;
1154     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;
1155
1156     case 0x60: str2 = sc_tempfin; str = "Congestion"; break;
1157     case 0x61: str2 = sc_tempfin; str = "SME busy"; break;
1158     case 0x62: str2 = sc_tempfin; str = "No response from SME"; break;
1159     case 0x63: str2 = sc_tempfin; str = "Service rejected"; break;
1160     case 0x64: str2 = sc_tempfin; str = "Quality of service not available"; break;
1161     case 0x65: str2 = sc_tempfin; str = "Error in SME"; break;
1162
1163     default:
1164         if ((value >= 0x03) &&
1165             (value <= 0x0f))
1166         {
1167             str2 = sc_complete;
1168             str = "Reserved";
1169         }
1170         else if ((value >= 0x10) &&
1171             (value <= 0x1f))
1172         {
1173             str2 = sc_complete;
1174             str = "Values specific to each SC";
1175         }
1176         else if ((value >= 0x26) &&
1177             (value <= 0x2f))
1178         {
1179             str2 = sc_temporary;
1180             str = "Reserved";
1181         }
1182         else if ((value >= 0x30) &&
1183             (value <= 0x3f))
1184         {
1185             str2 = sc_temporary;
1186             str = "Values specific to each SC";
1187         }
1188         else if ((value >= 0x4a) &&
1189             (value <= 0x4f))
1190         {
1191             str2 = sc_perm;
1192             str = "Reserved";
1193         }
1194         else if ((value >= 0x50) &&
1195             (value <= 0x5f))
1196         {
1197             str2 = sc_perm;
1198             str = "Values specific to each SC";
1199         }
1200         else if ((value >= 0x66) &&
1201             (value <= 0x6f))
1202         {
1203             str2 = sc_tempfin;
1204             str = "Reserved";
1205         }
1206         else if ((value >= 0x70) &&
1207             (value <= 0x7f))
1208         {
1209             str2 = sc_tempfin;
1210             str = "Values specific to each SC";
1211         }
1212         break;
1213     }
1214
1215     other_decode_bitfield_value(bigbuf, oct, 0x7f, 8);
1216     proto_tree_add_text(subtree, tvb,
1217         offset, 1,
1218         "%s :  (%d) %s, %s",
1219         bigbuf,
1220         value,
1221         str2,
1222         str);
1223 }
1224
1225 /* 9.2.3.16 */
1226 #define DIS_FIELD_UDL(m_tree, m_offset) \
1227 { \
1228     proto_tree_add_text(m_tree, tvb, \
1229         m_offset, 1, \
1230         "TP-User-Data-Length: (%d) %s", \
1231         oct, \
1232         oct ? "depends on Data-Coding-Scheme" : "no User-Data");\
1233 }
1234
1235 /* 9.2.3.17 */
1236 #define DIS_FIELD_RP(m_tree, m_bitmask, m_offset) \
1237 { \
1238     other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
1239     proto_tree_add_text(m_tree, tvb, \
1240         m_offset, 1, \
1241         "%s :  TP-Reply-Path: parameter is %sset in this SMS-SUBMIT/DELIVER", \
1242         bigbuf, \
1243         (oct & m_bitmask) ? "" : "not "); \
1244 }
1245
1246 /* 9.2.3.18 */
1247 #define DIS_FIELD_MN(m_tree, m_offset) \
1248 { \
1249     proto_tree_add_text(m_tree, tvb, \
1250         m_offset, 1, \
1251         "TP-Message-Number: %d", \
1252         oct); \
1253 }
1254
1255 /* 9.2.3.19 */
1256 #define DIS_FIELD_CT(m_tree, m_offset) \
1257 { \
1258     switch (oct) \
1259     { \
1260     case 0: str = "Enquiry relating to previously submitted short message"; break; \
1261     case 1: str = "Cancel Status Report Request relating to previously submitted short message"; break; \
1262     case 2: str = "Delete previously submitted Short Message"; break; \
1263     case 3: str = "Enable Status Report Request relating to previously submitted short message"; break; \
1264     default: \
1265         if ((oct >= 0x04) && \
1266             (oct <= 0x1f)) \
1267         { \
1268             str = "Reserved unspecified"; \
1269         } \
1270         else if (oct >= 0xe0) \
1271         { \
1272             str = "Values specific for each SC"; \
1273         } \
1274         else \
1275         { \
1276             str = "undefined"; \
1277         } \
1278         break; \
1279     } \
1280     proto_tree_add_text(m_tree, tvb, \
1281         m_offset, 1, \
1282         "TP-Command-Type: (%d), %s", \
1283         oct, \
1284         str); \
1285 }
1286
1287 /* 9.2.3.20 */
1288 #define DIS_FIELD_CDL(m_tree, m_offset) \
1289 { \
1290     proto_tree_add_text(m_tree, tvb, \
1291         m_offset, 1, \
1292         "TP-Command-Data-Length: (%d)%s", \
1293         oct, \
1294         oct ? "" : " no Command-Data");\
1295 }
1296
1297 /* 9.2.3.21 */
1298 /* done in-line in the message functions */
1299
1300 /* 9.2.3.22 */
1301 static void
1302 dis_field_fcs(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 oct)
1303 {
1304     proto_item  *item;
1305     proto_tree  *subtree = NULL;
1306     gchar       *str = NULL;
1307
1308
1309     item =
1310         proto_tree_add_text(tree, tvb,
1311             offset, 1,
1312             "TP-Failure-Cause");
1313
1314     subtree = proto_item_add_subtree(item, ett_fcs);
1315
1316     switch (oct)
1317     {
1318     case 0x80: str = "Telematic interworking not supported"; break;
1319     case 0x81: str = "Short message Type 0 not supported"; break;
1320     case 0x82: str = "Cannot replace short message"; break;
1321     case 0x8F: str = "Unspecified TP-PID error"; break;
1322     case 0x90: str = "Data coding scheme (alphabet) not supported"; break;
1323     case 0x91: str = "Message class not supported"; break;
1324     case 0x9F: str = "Unspecified TP-DCS error"; break;
1325     case 0xA0: str = "Command cannot be actioned"; break;
1326     case 0xA1: str = "Command unsupported"; break;
1327     case 0xAF: str = "Unspecified TP-Command error"; break;
1328     case 0xB0: str = "TPDU not supported"; break;
1329     case 0xC0: str = "SC busy"; break;
1330     case 0xC1: str = "No SC subscription"; break;
1331     case 0xC2: str = "SC system failure"; break;
1332     case 0xC3: str = "Invalid SME address"; break;
1333     case 0xC4: str = "Destination SME barred"; break;
1334     case 0xC5: str = "SM Rejected-Duplicate SM"; break;
1335     case 0xC6: str = "TP-VPF not supported"; break;
1336     case 0xC7: str = "TP-VP not supported"; break;
1337     case 0xD0: str = "(U)SIM SMS storage full"; break;
1338     case 0xD1: str = "No SMS storage capability in (U)SIM"; break;
1339     case 0xD2: str = "Error in MS"; break;
1340     case 0xD3: str = "Memory Capacity Exceeded"; break;
1341     case 0xD4: str = "(U)SIM Application Toolkit Busy"; break;
1342     case 0xD5: str = "(U)SIM data download error"; break;
1343     case 0xFF: str = "Unspecified error cause"; break;
1344     default:
1345         if ((oct >= 0x80) &&
1346             (oct <= 0x8F))
1347         {
1348             str = "TP-PID errors"; break;
1349         }
1350         else if ((oct >= 0x90) &&
1351             (oct <= 0x9F))
1352         {
1353             str = "TP-DCS errors"; break;
1354         }
1355         else if ((oct >= 0xA0) &&
1356             (oct <= 0xAF))
1357         {
1358             str = "TP-Command errors"; break;
1359         }
1360         else if ((oct >= 0xE0) &&
1361             (oct <= 0xFE))
1362         {
1363             str = "Values specific to an application"; break;
1364         }
1365         else
1366         {
1367             str = "Reserved"; break;
1368         }
1369     }
1370
1371     proto_tree_add_text(subtree, tvb,
1372         offset, 1,
1373         str);
1374 }
1375
1376 /* 9.2.3.23 */
1377 #define DIS_FIELD_UDHI(m_tree, m_bitmask, m_offset, m_udhi) \
1378 { \
1379     SMS_SHIFTMASK(oct & m_bitmask, m_bitmask, m_udhi); \
1380     other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
1381     proto_tree_add_text(m_tree, tvb, \
1382         m_offset, 1, \
1383         "%s :  TP-User-Data-Header-Indicator: %s short message", \
1384         bigbuf, \
1385         m_udhi ? \
1386         "The beginning of the TP-UD field contains a Header in addition to the" : \
1387         "The TP-UD field contains only the"); \
1388 }
1389
1390 /*
1391  * FROM GNOKII
1392  * gsm-encoding.c
1393  * gsm-sms.c
1394  */
1395 #define GN_BYTE_MASK ((1 << bits) - 1)
1396
1397 int
1398 gsm_sms_char_7bit_unpack(unsigned int offset, unsigned int in_length, unsigned int out_length,
1399                      const guint8 *input, unsigned char *output)
1400 {
1401     unsigned char *out_num = output; /* Current pointer to the output buffer */
1402     const guint8 *in_num = input;    /* Current pointer to the input buffer */
1403     unsigned char rest = 0x00;
1404     int bits;
1405
1406     bits = offset ? offset : 7;
1407
1408     while ((unsigned int)(in_num - input) < in_length)
1409     {
1410         *out_num = ((*in_num & GN_BYTE_MASK) << (7 - bits)) | rest;
1411         rest = *in_num >> bits;
1412
1413         /* If we don't start from 0th bit, we shouldn't go to the
1414            next char. Under *out_num we have now 0 and under Rest -
1415            _first_ part of the char. */
1416         if ((in_num != input) || (bits == 7)) out_num++;
1417         in_num++;
1418
1419         if ((unsigned int)(out_num - output) >= out_length) break;
1420
1421         /* After reading 7 octets we have read 7 full characters but
1422            we have 7 bits as well. This is the next character */
1423         if (bits == 1)
1424         {
1425             *out_num = rest;
1426             out_num++;
1427             bits = 7;
1428             rest = 0x00;
1429         }
1430         else
1431         {
1432             bits--;
1433         }
1434     }
1435
1436     return out_num - output;
1437 }
1438
1439 #define GN_CHAR_ALPHABET_SIZE 128
1440
1441 #define GN_CHAR_ESCAPE 0x1b
1442
1443 static unsigned char gsm_default_alphabet[GN_CHAR_ALPHABET_SIZE] = {
1444
1445     /* ETSI GSM 03.38, version 6.0.1, section 6.2.1; Default alphabet */
1446     /* Characters in hex position 10, [12 to 1a] and 24 are not present on
1447        latin1 charset, so we cannot reproduce on the screen, however they are
1448        greek symbol not present even on my Nokia */
1449
1450     '@',  0xa3, '$',  0xa5, 0xe8, 0xe9, 0xf9, 0xec,
1451     0xf2, 0xc7, '\n', 0xd8, 0xf8, '\r', 0xc5, 0xe5,
1452     '?',  '_',  '?',  '?',  '?',  '?',  '?',  '?',
1453     '?',  '?',  '?',  '?',  0xc6, 0xe6, 0xdf, 0xc9,
1454     ' ',  '!',  '\"', '#',  0xa4,  '%',  '&',  '\'',
1455     '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
1456     '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
1457     '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',
1458     0xa1, 'A',  'B',  'C',  'D',  'E',  'F',  'G',
1459     'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',
1460     'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',
1461     'X',  'Y',  'Z',  0xc4, 0xd6, 0xd1, 0xdc, 0xa7,
1462     0xbf, 'a',  'b',  'c',  'd',  'e',  'f',  'g',
1463     'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
1464     'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
1465     'x',  'y',  'z',  0xe4, 0xf6, 0xf1, 0xfc, 0xe0
1466 };
1467
1468 static gboolean
1469 char_is_escape(unsigned char value)
1470 {
1471     return (value == GN_CHAR_ESCAPE);
1472 }
1473
1474 static unsigned char
1475 char_def_alphabet_ext_decode(unsigned char value)
1476 {
1477     switch (value)
1478     {
1479     case 0x0a: return 0x0c; break; /* form feed */
1480     case 0x14: return '^';  break;
1481     case 0x28: return '{';  break;
1482     case 0x29: return '}';  break;
1483     case 0x2f: return '\\'; break;
1484     case 0x3c: return '[';  break;
1485     case 0x3d: return '~';  break;
1486     case 0x3e: return ']';  break;
1487     case 0x40: return '|';  break;
1488     case 0x65: return 0xa4; break; /* euro */
1489     default: return '?';    break; /* invalid character */
1490     }
1491 }
1492
1493 static unsigned char
1494 char_def_alphabet_decode(unsigned char value)
1495 {
1496     if (value < GN_CHAR_ALPHABET_SIZE)
1497     {
1498         return gsm_default_alphabet[value];
1499     }
1500     else
1501     {
1502         return '?';
1503     }
1504 }
1505
1506 void
1507 gsm_sms_char_ascii_decode(unsigned char* dest, const unsigned char* src, int len)
1508 {
1509     int i, j;
1510
1511     for (i = 0, j = 0; j < len; i++, j++)
1512     {
1513         if (char_is_escape(src[j]))
1514             dest[i] = char_def_alphabet_ext_decode(src[++j]);
1515         else
1516             dest[i] = char_def_alphabet_decode(src[j]);
1517     }
1518     dest[i] = 0;
1519     return;
1520 }
1521
1522 /*
1523  * END FROM GNOKII
1524  */
1525
1526 static void
1527 dis_iei_apa_8bit(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
1528 {
1529     gchar       *str = NULL;
1530     guint8      oct;
1531
1532
1533     EXACT_DATA_CHECK(length, 2);
1534
1535     oct = tvb_get_guint8(tvb, offset);
1536
1537     if (oct < 240)
1538     {
1539         str = "Reserved";
1540     }
1541     else
1542     {
1543         str = "Available for allocation by applications";
1544     }
1545
1546     proto_tree_add_text(tree,
1547         tvb, offset, 1,
1548         "Destination port: %d, %s",
1549         oct,
1550         str);
1551
1552     offset++;
1553     oct = tvb_get_guint8(tvb, offset);
1554
1555     if (oct < 240)
1556     {
1557         str = "Reserved";
1558     }
1559     else
1560     {
1561         str = "Available for allocation by applications";
1562     }
1563
1564     proto_tree_add_text(tree,
1565         tvb, offset, 1,
1566         "Originator port: %d, %s",
1567         oct,
1568         str);
1569 }
1570
1571 static void
1572 dis_iei_apa_16bit(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
1573 {
1574     gchar       *str = NULL;
1575     guint32     value;
1576
1577
1578     EXACT_DATA_CHECK(length, 4);
1579
1580     value = tvb_get_ntohs(tvb, offset);
1581
1582     if (value < 16000)
1583     {
1584         str = "As allocated by IANA (http://www.IANA.com/)";
1585     }
1586     else if (value < 17000)
1587     {
1588         str = "Available for allocation by applications";
1589     }
1590     else
1591     {
1592         str = "Reserved";
1593     }
1594
1595     proto_tree_add_text(tree,
1596         tvb, offset, 2,
1597         "Destination port: %d, %s",
1598         value,
1599         str);
1600
1601     offset += 2;
1602     value = tvb_get_ntohs(tvb, offset);
1603
1604     if (value < 16000)
1605     {
1606         str = "As allocated by IANA (http://www.IANA.com/)";
1607     }
1608     else if (value < 17000)
1609     {
1610         str = "Available for allocation by applications";
1611     }
1612     else
1613     {
1614         str = "Reserved";
1615     }
1616
1617     proto_tree_add_text(tree,
1618         tvb, offset, 2,
1619         "Originator port: %d, %s",
1620         value,
1621         str);
1622 }
1623
1624 static void
1625 dis_field_ud_iei(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
1626 {
1627     void (*iei_fcn)(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length);
1628     guint8      oct;
1629     proto_item  *item;
1630     proto_tree  *subtree = NULL;
1631     gchar       *str = NULL;
1632     guint8      iei_len;
1633
1634
1635     while (length > 2)
1636     {
1637         iei_fcn = NULL;
1638
1639         oct = tvb_get_guint8(tvb, offset);
1640
1641         switch (oct)
1642         {
1643         case 0x00: str = "Concatenated short messages, 8-bit reference number (SMS Control)"; break;
1644         case 0x01: str = "Special SMS Message Indication (SMS Control)"; break;
1645         case 0x02: str = "Reserved N/A"; break;
1646         case 0x03: str = "Value not used to avoid misinterpretation as <LF> character N/A"; break;
1647         case 0x04: str = "Application port addressing scheme, 8 bit address (SMS Control)"; iei_fcn = dis_iei_apa_8bit; break;
1648         case 0x05: str = "Application port addressing scheme, 16 bit address (SMS Control)"; iei_fcn = dis_iei_apa_16bit; break;
1649         case 0x06: str = "SMSC Control Parameters (SMS Control)"; break;
1650         case 0x07: str = "UDH Source Indicator (SMS Control)"; break;
1651         case 0x08: str = "Concatenated short message, 16-bit reference number (SMS Control)"; break;
1652         case 0x09: str = "Wireless Control Message Protocol (SMS Control)"; break;
1653         case 0x0A: str = "Text Formatting (EMS Control)"; break;
1654         case 0x0B: str = "Predefined Sound (EMS Content)"; break;
1655         case 0x0C: str = "User Defined Sound (iMelody max 128 bytes) (EMS Content)"; break;
1656         case 0x0D: str = "Predefined Animation (EMS Content)"; break;
1657         case 0x0E: str = "Large Animation (16*16 times 4 = 32*4 =128 bytes) (EMS Content)"; break;
1658         case 0x0F: str = "Small Animation (8*8 times 4 = 8*4 =32 bytes) (EMS Content)"; break;
1659         case 0x10: str = "Large Picture (32*32 = 128 bytes) (EMS Content)"; break;
1660         case 0x11: str = "Small Picture (16*16 = 32 bytes) (EMS Content)"; break;
1661         case 0x12: str = "Variable Picture (EMS Content)"; break;
1662         case 0x13: str = "User prompt indicator (EMS Control)"; break;
1663         case 0x14: str = "Extended Object (EMS Content)"; break;
1664         case 0x15: str = "Reused Extended Object (EMS Control)"; break;
1665         case 0x16: str = "Compression Control (EMS Control)"; break;
1666         case 0x17: str = "Object Distribution Indicator (EMS Control)"; break;
1667         case 0x18: str = "Standard WVG object (EMS Content)"; break;
1668         case 0x19: str = "Character Size WVG object (EMS Content)"; break;
1669         case 0x1A: str = "Extended Object Data Request Command (EMS Control)"; break;
1670         case 0x20: str = "RFC 822 E-Mail Header (SMS Control)"; break;
1671         case 0x21: str = "Hyperlink format element (SMS Control)"; break;
1672         case 0x22: str = "Reply Address Element (SMS Control)"; break;
1673         default:
1674             if ((oct >= 0x1b) &&
1675                 (oct <= 0x1f))
1676             {
1677                 str = "Reserved for future EMS features (see subclause 3.10) N/A"; break;
1678             }
1679             else if ((oct >= 0x23) &&
1680                 (oct <= 0x6f))
1681             {
1682                 str = "Reserved for future use N/A"; break;
1683             }
1684             else if ((oct >= 0x70) &&
1685                 (oct <= 0x7f))
1686             {
1687                 str = "(U)SIM Toolkit Security Headers (SMS Control)"; break;
1688             }
1689             else if ((oct >= 0x80) &&
1690                 (oct <= 0x9f))
1691             {
1692                 str = "SME to SME specific use (SMS Control)"; break;
1693             }
1694             else if ((oct >= 0xa0) &&
1695                 (oct <= 0xbf))
1696             {
1697                 str = "Reserved for future use N/A"; break;
1698             }
1699             else if ((oct >= 0xc0) &&
1700                 (oct <= 0xdf))
1701             {
1702                 str = "SC specific use (SMS Control)"; break;
1703             }
1704             else
1705             {
1706                 str = "Reserved for future use N/A"; break;
1707             }
1708         }
1709
1710         iei_len = tvb_get_guint8(tvb, offset + 1);
1711
1712         item =
1713             proto_tree_add_text(tree,
1714                 tvb, offset, iei_len + 2,
1715                 "IE: %s",
1716                 str);
1717
1718         subtree = proto_item_add_subtree(item, ett_udh_ieis[oct]);
1719
1720         proto_tree_add_text(subtree,
1721             tvb, offset, 1,
1722             "Information Element Identifier: %d",
1723             oct);
1724
1725         offset++;
1726
1727         proto_tree_add_text(subtree,
1728             tvb, offset, 1,
1729             "Length: %d",
1730             iei_len);
1731
1732         offset++;
1733
1734         if (iei_len > 0)
1735         {
1736             if (iei_fcn == NULL)
1737             {
1738                 proto_tree_add_text(subtree,
1739                     tvb, offset, iei_len,
1740                     "IE Data");
1741             }
1742             else
1743             {
1744                 iei_fcn(tvb, subtree, offset, iei_len);
1745             }
1746         }
1747
1748         length -= 2 + iei_len;
1749         offset += iei_len;
1750     }
1751 }
1752
1753 /* 9.2.3.24 */
1754 static void
1755 dis_field_ud(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint32 length, gboolean udhi, guint8 udl,
1756     gboolean seven_bit, gboolean eight_bit, gboolean ucs2, gboolean compressed)
1757 {
1758     static guint8       fill_bits_mask[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc };
1759     proto_item  *item;
1760     proto_item  *udh_item;
1761     proto_tree  *subtree = NULL;
1762     proto_tree  *udh_subtree = NULL;
1763     guint8      oct;
1764     guint8      fill_bits;
1765     guint32     out_len;
1766     char        *ustr;
1767
1768     fill_bits = 0;
1769
1770     item =
1771         proto_tree_add_text(tree, tvb,
1772             offset, length,
1773             "TP-User-Data");
1774
1775     subtree = proto_item_add_subtree(item, ett_ud);
1776
1777     oct = tvb_get_guint8(tvb, offset);
1778
1779     if (udhi)
1780     {
1781         /* step over header */
1782
1783         udh_item =
1784             proto_tree_add_text(subtree, tvb,
1785                 offset, oct + 1,
1786                 "User-Data Header");
1787
1788         udh_subtree = proto_item_add_subtree(udh_item, ett_udh);
1789
1790         proto_tree_add_text(udh_subtree,
1791             tvb, offset, 1,
1792             "User Data Header Length (%d)",
1793             oct);
1794
1795         offset++;
1796         udl--;
1797         length--;
1798
1799         dis_field_ud_iei(tvb, udh_subtree, offset, oct);
1800
1801         offset += oct;
1802         udl -= oct;
1803         length -= oct;
1804
1805         if (seven_bit)
1806         {
1807             /* step over fill bits ? */
1808
1809             fill_bits = 7 - (((oct + 1) * 8) % 7);
1810             if (fill_bits != 7)
1811             {
1812                 oct = tvb_get_guint8(tvb, offset);
1813
1814                 other_decode_bitfield_value(bigbuf, oct, fill_bits_mask[fill_bits], 8);
1815                 proto_tree_add_text(udh_subtree,
1816                     tvb, offset, 1,
1817                     "%s :  Fill bits",
1818                     bigbuf);
1819             }
1820         }
1821     }
1822
1823     if (compressed)
1824     {
1825         proto_tree_add_text(subtree, tvb,
1826             offset, length,
1827             "Compressed data");
1828     }
1829     else
1830     {
1831         if (seven_bit)
1832         {
1833             out_len =
1834                 gsm_sms_char_7bit_unpack(fill_bits, length, sizeof(bigbuf),
1835                     tvb_get_ptr(tvb, offset, length), bigbuf);
1836             bigbuf[out_len] = '\0';
1837             gsm_sms_char_ascii_decode(bigbuf, bigbuf, out_len);
1838             bigbuf[udl] = '\0';
1839
1840             proto_tree_add_text(subtree, tvb, offset, length, "%s", bigbuf);
1841         }
1842         else if (eight_bit)
1843         {
1844             proto_tree_add_text(subtree, tvb, offset, length, "%s",
1845                 tvb_format_text(tvb, offset, length));
1846         }
1847         else if (ucs2)
1848         {
1849             ustr = tvb_fake_unicode(tvb, offset, length, FALSE);
1850             proto_tree_add_text(subtree, tvb, offset, length, "%s", ustr);
1851             g_free(ustr);
1852         }
1853     }
1854 }
1855
1856 /* 9.2.3.25 */
1857 #define DIS_FIELD_RD(m_tree, m_bitmask, m_offset) \
1858 { \
1859     other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
1860     proto_tree_add_text(m_tree, tvb, \
1861         m_offset, 1, \
1862         "%s :  TP-Reject-Duplicates: Instruct SC to %s duplicates", \
1863         bigbuf, \
1864         (oct & m_bitmask) ? \
1865         "reject" : \
1866         "accept"); \
1867 }
1868
1869 /* 9.2.3.26 */
1870 #define DIS_FIELD_SRQ(m_tree, m_bitmask, m_offset) \
1871 { \
1872     other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
1873     proto_tree_add_text(m_tree, tvb, \
1874         m_offset, 1, \
1875         "%s :  TP-Status-Report-Qualifier: The SMS-STATUS-REPORT is the result of %s", \
1876         bigbuf, \
1877         (oct & m_bitmask) ? \
1878         "an SMS-COMMAND e.g. an Enquiry" : \
1879         "a SMS-SUBMIT"); \
1880 }
1881
1882 /* 9.2.3.27 */
1883 static void
1884 dis_field_pi(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 oct)
1885 {
1886     proto_item  *item;
1887     proto_tree  *subtree = NULL;
1888
1889
1890     item =
1891         proto_tree_add_text(tree, tvb,
1892             offset, 1,
1893             "TP-Parameter-Indicator");
1894
1895     subtree = proto_item_add_subtree(item, ett_pi);
1896
1897     other_decode_bitfield_value(bigbuf, oct, 0x80, 8);
1898     proto_tree_add_text(subtree, tvb,
1899         offset, 1,
1900         "%s :  %s",
1901         bigbuf,
1902         (oct & 0x80) ? "Extended" : "No extension");
1903
1904     other_decode_bitfield_value(bigbuf, oct, 0x78, 8);
1905     proto_tree_add_text(subtree, tvb,
1906         offset, 1,
1907         "%s :  Reserved",
1908         bigbuf);
1909
1910     other_decode_bitfield_value(bigbuf, oct, 0x04, 8);
1911     proto_tree_add_text(subtree, tvb,
1912         offset, 1,
1913         "%s :  TP-UDL %spresent",
1914         bigbuf,
1915         (oct & 0x04) ? "" : "not ");
1916
1917     other_decode_bitfield_value(bigbuf, oct, 0x02, 8);
1918     proto_tree_add_text(subtree, tvb,
1919         offset, 1,
1920         "%s :  TP-DCS %spresent",
1921         bigbuf,
1922         (oct & 0x02) ? "" : "not ");
1923
1924     other_decode_bitfield_value(bigbuf, oct, 0x01, 8);
1925     proto_tree_add_text(subtree, tvb,
1926         offset, 1,
1927         "%s :  TP-PID %spresent",
1928         bigbuf,
1929         (oct & 0x01) ? "" : "not ");
1930 }
1931
1932 /*
1933  * Ref. GSM 03.40
1934  * Section 9.2.2
1935  */
1936 static void
1937 dis_msg_deliver(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
1938 {
1939     guint32     saved_offset;
1940     guint32     length;
1941     guint8      oct;
1942     guint8      udl;
1943     gboolean    seven_bit;
1944     gboolean    eight_bit;
1945     gboolean    ucs2;
1946     gboolean    compressed;
1947     gboolean    udhi;
1948
1949     udl = 0;
1950     saved_offset = offset;
1951     length = tvb_length_remaining(tvb, offset);
1952
1953     oct = tvb_get_guint8(tvb, offset);
1954
1955     DIS_FIELD_SRI(tree, 0x20, offset);
1956
1957     DIS_FIELD_UDHI(tree, 0x10, offset, udhi);
1958
1959     DIS_FIELD_RP(tree, 0x08, offset);
1960
1961     DIS_FIELD_MMS(tree, 0x04, offset);
1962
1963     DIS_FIELD_MTI(tree, 0x03, offset);
1964
1965     offset++;
1966
1967     dis_field_addr(tvb, tree, &offset, "TP-Originating-Address");
1968
1969     oct = tvb_get_guint8(tvb, offset);
1970
1971     dis_field_pid(tvb, tree, offset, oct);
1972
1973     offset++;
1974     oct = tvb_get_guint8(tvb, offset);
1975
1976     dis_field_dcs(tvb, tree, offset, oct, &seven_bit, &eight_bit, &ucs2, &compressed);
1977
1978     offset++;
1979     dis_field_scts(tvb, tree, &offset);
1980
1981     oct = tvb_get_guint8(tvb, offset);
1982     udl = oct;
1983
1984     DIS_FIELD_UDL(tree, offset);
1985
1986     if (udl > 0)
1987     {
1988         offset++;
1989
1990         dis_field_ud(tvb, tree, offset, length - (offset - saved_offset), udhi, udl,
1991             seven_bit, eight_bit, ucs2, compressed);
1992     }
1993 }
1994
1995 /*
1996  * Ref. GSM 03.40
1997  * Section 9.2.2
1998  */
1999 static void
2000 dis_msg_deliver_report(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
2001 {
2002     guint32     saved_offset;
2003     guint32     length;
2004     guint8      oct;
2005     guint8      pi;
2006     guint8      udl;
2007     gboolean    seven_bit;
2008     gboolean    eight_bit;
2009     gboolean    ucs2;
2010     gboolean    compressed;
2011     gboolean    udhi;
2012
2013
2014     udl = 0;
2015     saved_offset = offset;
2016     length = tvb_length_remaining(tvb, offset);
2017
2018     oct = tvb_get_guint8(tvb, offset);
2019
2020     DIS_FIELD_UDHI(tree, 0x04, offset, udhi);
2021
2022     DIS_FIELD_MTI(tree, 0x03, offset);
2023
2024     if (length < 2)
2025     {
2026         proto_tree_add_text(tree,
2027             tvb, offset, length,
2028             "Short Data (?)");
2029         return;
2030     }
2031
2032     /*
2033      * there does not seem to be a way to determine that this
2034      * deliver report is from an RP-ERROR or RP-ACK other
2035      * than to look at the next octet
2036      *
2037      * FCS values are 0x80 and higher
2038      * PI uses bit 7 as an extension indicator
2039      *
2040      * will assume that if bit 7 is set then this octet
2041      * is an FCS otherwise PI
2042      */
2043     offset++;
2044     oct = tvb_get_guint8(tvb, offset);
2045
2046     if (oct & 0x80)
2047     {
2048         dis_field_fcs(tvb, tree, offset, oct);
2049     }
2050
2051     offset++;
2052     pi = tvb_get_guint8(tvb, offset);
2053
2054     dis_field_pi(tvb, tree, offset, pi);
2055
2056     if (pi & 0x01)
2057     {
2058         if (length <= (offset - saved_offset))
2059         {
2060             proto_tree_add_text(tree,
2061                 tvb, offset, -1,
2062                 "Short Data (?)");
2063             return;
2064         }
2065
2066         offset++;
2067         oct = tvb_get_guint8(tvb, offset);
2068
2069         dis_field_pid(tvb, tree, offset, oct);
2070     }
2071
2072     if (pi & 0x02)
2073     {
2074         if (length <= (offset - saved_offset))
2075         {
2076             proto_tree_add_text(tree,
2077                 tvb, offset, -1,
2078                 "Short Data (?)");
2079             return;
2080         }
2081
2082         offset++;
2083         oct = tvb_get_guint8(tvb, offset);
2084
2085         dis_field_dcs(tvb, tree, offset, oct, &seven_bit, &eight_bit, &ucs2, &compressed);
2086     }
2087
2088     if (pi & 0x04)
2089     {
2090         if (length <= (offset - saved_offset))
2091         {
2092             proto_tree_add_text(tree,
2093                 tvb, offset, -1,
2094                 "Short Data (?)");
2095             return;
2096         }
2097
2098         offset++;
2099         oct = tvb_get_guint8(tvb, offset);
2100         udl = oct;
2101
2102         DIS_FIELD_UDL(tree, offset);
2103     }
2104
2105     if (udl > 0)
2106     {
2107         offset++;
2108
2109         dis_field_ud(tvb, tree, offset, length - (offset - saved_offset), udhi, udl,
2110             seven_bit, eight_bit, ucs2, compressed);
2111     }
2112 }
2113
2114 /*
2115  * Ref. GSM 03.40
2116  * Section 9.2.2
2117  */
2118 static void
2119 dis_msg_submit(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
2120 {
2121     guint32     saved_offset;
2122     guint32     length;
2123     guint8      oct;
2124     guint8      vp_form;
2125     guint8      udl;
2126     gchar       *str = NULL;
2127     gboolean    seven_bit;
2128     gboolean    eight_bit;
2129     gboolean    ucs2;
2130     gboolean    compressed;
2131     gboolean    udhi;
2132
2133
2134     saved_offset = offset;
2135     length = tvb_length_remaining(tvb, offset);
2136
2137     oct = tvb_get_guint8(tvb, offset);
2138
2139     DIS_FIELD_SRR(tree, 0x80, offset);
2140
2141     DIS_FIELD_UDHI(tree, 0x40, offset, udhi);
2142
2143     DIS_FIELD_RP(tree, 0x20, offset);
2144
2145     DIS_FIELD_VPF(tree, 0x18, offset, &vp_form);
2146
2147     DIS_FIELD_RD(tree, 0x04, offset);
2148
2149     DIS_FIELD_MTI(tree, 0x03, offset);
2150
2151     offset++;
2152     oct = tvb_get_guint8(tvb, offset);
2153
2154     DIS_FIELD_MR(tree, offset);
2155
2156     offset++;
2157
2158     dis_field_addr(tvb, tree, &offset, "TP-Destination-Address");
2159
2160     oct = tvb_get_guint8(tvb, offset);
2161
2162     dis_field_pid(tvb, tree, offset, oct);
2163
2164     offset++;
2165     oct = tvb_get_guint8(tvb, offset);
2166
2167     dis_field_dcs(tvb, tree, offset, oct, &seven_bit, &eight_bit, &ucs2, &compressed);
2168
2169     offset++;
2170     dis_field_vp(tvb, tree, &offset, vp_form);
2171
2172     oct = tvb_get_guint8(tvb, offset);
2173     udl = oct;
2174
2175     DIS_FIELD_UDL(tree, offset);
2176
2177     if (udl > 0)
2178     {
2179         offset++;
2180
2181         dis_field_ud(tvb, tree, offset, length - (offset - saved_offset), udhi, udl,
2182             seven_bit, eight_bit, ucs2, compressed);
2183     }
2184 }
2185
2186 /*
2187  * Ref. GSM 03.40
2188  * Section 9.2.2
2189  */
2190 static void
2191 dis_msg_submit_report(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
2192 {
2193     guint32     saved_offset;
2194     guint32     length;
2195     guint8      oct;
2196     guint8      pi;
2197     guint8      udl;
2198     gboolean    seven_bit;
2199     gboolean    eight_bit;
2200     gboolean    ucs2;
2201     gboolean    compressed;
2202     gboolean    udhi;
2203
2204
2205     udl = 0;
2206     saved_offset = offset;
2207     length = tvb_length_remaining(tvb, offset);
2208
2209     oct = tvb_get_guint8(tvb, offset);
2210
2211     DIS_FIELD_UDHI(tree, 0x04, offset, udhi);
2212
2213     DIS_FIELD_MTI(tree, 0x03, offset);
2214
2215     /*
2216      * there does not seem to be a way to determine that this
2217      * deliver report is from an RP-ERROR or RP-ACK other
2218      * than to look at the next octet
2219      *
2220      * FCS values are 0x80 and higher
2221      * PI uses bit 7 as an extension indicator
2222      *
2223      * will assume that if bit 7 is set then this octet
2224      * is an FCS otherwise PI
2225      */
2226     offset++;
2227     oct = tvb_get_guint8(tvb, offset);
2228
2229     if (oct & 0x80)
2230     {
2231         dis_field_fcs(tvb, tree, offset, oct);
2232     }
2233
2234     offset++;
2235     pi = tvb_get_guint8(tvb, offset);
2236
2237     dis_field_pi(tvb, tree, offset, pi);
2238
2239     offset++;
2240     dis_field_scts(tvb, tree, &offset);
2241
2242     if (pi & 0x02)
2243     {
2244         if (length <= (offset - saved_offset))
2245         {
2246             proto_tree_add_text(tree,
2247                 tvb, offset, -1,
2248                 "Short Data (?)");
2249             return;
2250         }
2251
2252         offset++;
2253         oct = tvb_get_guint8(tvb, offset);
2254
2255         dis_field_dcs(tvb, tree, offset, oct, &seven_bit, &eight_bit, &ucs2, &compressed);
2256     }
2257
2258     if (pi & 0x04)
2259     {
2260         if (length <= (offset - saved_offset))
2261         {
2262             proto_tree_add_text(tree,
2263                 tvb, offset, -1,
2264                 "Short Data (?)");
2265             return;
2266         }
2267
2268         offset++;
2269         oct = tvb_get_guint8(tvb, offset);
2270         udl = oct;
2271
2272         DIS_FIELD_UDL(tree, offset);
2273     }
2274
2275     if (udl > 0)
2276     {
2277         offset++;
2278
2279         dis_field_ud(tvb, tree, offset, length - (offset - saved_offset), udhi, udl,
2280             seven_bit, eight_bit, ucs2, compressed);
2281     }
2282 }
2283
2284 /*
2285  * Ref. GSM 03.40
2286  * Section 9.2.2
2287  */
2288 static void
2289 dis_msg_status_report(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
2290 {
2291     guint32     saved_offset;
2292     guint32     length;
2293     guint8      oct;
2294     guint8      pi;
2295     guint8      udl;
2296     gboolean    seven_bit;
2297     gboolean    eight_bit;
2298     gboolean    ucs2;
2299     gboolean    compressed;
2300     gboolean    udhi;
2301
2302
2303     udl = 0;
2304     saved_offset = offset;
2305     length = tvb_length_remaining(tvb, offset);
2306
2307     oct = tvb_get_guint8(tvb, offset);
2308
2309     DIS_FIELD_SRQ(tree, 0x10, offset);
2310
2311     DIS_FIELD_MMS(tree, 0x08, offset);
2312
2313     DIS_FIELD_UDHI(tree, 0x04, offset, udhi);
2314
2315     DIS_FIELD_MTI(tree, 0x03, offset);
2316
2317     offset++;
2318     oct = tvb_get_guint8(tvb, offset);
2319
2320     DIS_FIELD_MR(tree, offset);
2321
2322     offset++;
2323
2324     dis_field_addr(tvb, tree, &offset, "TP-Recipient-Address");
2325
2326     dis_field_scts(tvb, tree, &offset);
2327
2328     dis_field_dt(tvb, tree, &offset);
2329
2330     oct = tvb_get_guint8(tvb, offset);
2331
2332     dis_field_st(tvb, tree, offset, oct);
2333
2334     offset++;
2335     pi = tvb_get_guint8(tvb, offset);
2336
2337     dis_field_pi(tvb, tree, offset, pi);
2338
2339     if (pi & 0x01)
2340     {
2341         if (length <= (offset - saved_offset))
2342         {
2343             proto_tree_add_text(tree,
2344                 tvb, offset, -1,
2345                 "Short Data (?)");
2346             return;
2347         }
2348
2349         offset++;
2350         oct = tvb_get_guint8(tvb, offset);
2351
2352         dis_field_pid(tvb, tree, offset, oct);
2353     }
2354
2355     if (pi & 0x02)
2356     {
2357         if (length <= (offset - saved_offset))
2358         {
2359             proto_tree_add_text(tree,
2360                 tvb, offset, -1,
2361                 "Short Data (?)");
2362             return;
2363         }
2364
2365         offset++;
2366         oct = tvb_get_guint8(tvb, offset);
2367
2368         dis_field_dcs(tvb, tree, offset, oct, &seven_bit, &eight_bit, &ucs2, &compressed);
2369     }
2370
2371     if (pi & 0x04)
2372     {
2373         if (length <= (offset - saved_offset))
2374         {
2375             proto_tree_add_text(tree,
2376                 tvb, offset, -1,
2377                 "Short Data (?)");
2378             return;
2379         }
2380
2381         offset++;
2382         oct = tvb_get_guint8(tvb, offset);
2383         udl = oct;
2384
2385         DIS_FIELD_UDL(tree, offset);
2386     }
2387
2388     if (udl > 0)
2389     {
2390         offset++;
2391
2392         dis_field_ud(tvb, tree, offset, length - (offset - saved_offset), udhi, udl,
2393             seven_bit, eight_bit, ucs2, compressed);
2394     }
2395 }
2396
2397 /*
2398  * Ref. GSM 03.40
2399  * Section 9.2.2
2400  */
2401 static void
2402 dis_msg_command(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
2403 {
2404     guint32     saved_offset;
2405     guint32     length;
2406     guint8      oct;
2407     guint8      cdl;
2408     gchar       *str = NULL;
2409     gboolean    udhi;
2410
2411
2412     cdl = 0;
2413     saved_offset = offset;
2414     length = tvb_length_remaining(tvb, offset);
2415
2416     oct = tvb_get_guint8(tvb, offset);
2417
2418     DIS_FIELD_SRR(tree, 0x08, offset);
2419
2420     DIS_FIELD_UDHI(tree, 0x04, offset, udhi);
2421
2422     DIS_FIELD_MTI(tree, 0x03, offset);
2423
2424     offset++;
2425     oct = tvb_get_guint8(tvb, offset);
2426
2427     DIS_FIELD_MR(tree, offset);
2428
2429     offset++;
2430     oct = tvb_get_guint8(tvb, offset);
2431
2432     dis_field_pid(tvb, tree, offset, oct);
2433
2434     offset++;
2435     oct = tvb_get_guint8(tvb, offset);
2436
2437     DIS_FIELD_CT(tree, offset);
2438
2439     offset++;
2440     oct = tvb_get_guint8(tvb, offset);
2441
2442     DIS_FIELD_MN(tree, offset);
2443
2444     offset++;
2445
2446     dis_field_addr(tvb, tree, &offset, "TP-Destination-Address");
2447
2448     oct = tvb_get_guint8(tvb, offset);
2449     cdl = oct;
2450
2451     DIS_FIELD_CDL(tree, offset);
2452
2453     if (cdl > 0)
2454     {
2455         offset++;
2456
2457         proto_tree_add_text(tree,
2458             tvb, offset, cdl,
2459             "TP-Command-Data");
2460     }
2461 }
2462
2463 #define NUM_MSGS (sizeof(msg_type_strings)/sizeof(value_string))
2464 static gint ett_msgs[NUM_MSGS];
2465 static void (*gsm_sms_msg_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset) = {
2466     dis_msg_deliver,            /* SMS-DELIVER */
2467     dis_msg_deliver_report,     /* SMS-DELIVER REPORT */
2468     dis_msg_submit,             /* SMS-SUBMIT */
2469     dis_msg_submit_report,      /* SMS-SUBMIT REPORT */
2470     dis_msg_status_report,      /* SMS-STATUS REPORT */
2471     dis_msg_command,            /* SMS-COMMAND */
2472     NULL,                       /* Reserved */
2473     NULL,                       /* Reserved */
2474     NULL,       /* NONE */
2475 };
2476
2477 /* GENERIC DISSECTOR FUNCTIONS */
2478
2479 static void
2480 dissect_gsm_sms(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2481 {
2482     void (*msg_fcn)(tvbuff_t *tvb, proto_tree *tree, guint32 offset) = NULL;
2483     proto_item  *gsm_sms_item;
2484     proto_tree  *gsm_sms_tree = NULL;
2485     guint32     offset;
2486     guint8      msg_type;
2487     guint8      oct;
2488     gint        idx;
2489     gchar       *str = NULL;
2490     gint        ett_msg_idx;
2491
2492
2493     g_pinfo = pinfo;
2494
2495     if (check_col(pinfo->cinfo, COL_PROTOCOL))
2496     {
2497         col_set_str(pinfo->cinfo, COL_PROTOCOL, gsm_sms_proto_name_short);
2498     }
2499
2500     /* In the interest of speed, if "tree" is NULL, don't do any work not
2501      * necessary to generate protocol tree items.
2502      */
2503     if (tree)
2504     {
2505         g_tree = tree;
2506
2507         offset = 0;
2508
2509         oct = tvb_get_guint8(tvb, offset);
2510
2511         oct &= 0x03;
2512         msg_type = oct;
2513
2514         /*
2515          * convert the 2 bit value to one based on direction
2516          */
2517         msg_type |= ((pinfo->p2p_dir == P2P_DIR_RECV) ? 0x04 : 0x00);
2518
2519         str = my_match_strval(msg_type, msg_type_strings, &idx);
2520
2521         /*
2522          * create the GSM_SMS protocol tree
2523          */
2524         gsm_sms_item =
2525             proto_tree_add_protocol_format(tree, proto_gsm_sms, tvb, 0, -1,
2526                 "%s %s",
2527                 gsm_sms_proto_name,
2528                 (str == NULL) ? "Unknown message identifier" : str);
2529
2530         gsm_sms_tree =
2531             proto_item_add_subtree(gsm_sms_item, ett_gsm_sms);
2532
2533         if ((str == NULL) ||
2534             (msg_type == 0x03) ||
2535             (msg_type == 0x07))
2536         {
2537             return;
2538         }
2539         else
2540         {
2541             ett_msg_idx = ett_msgs[idx];
2542             msg_fcn = gsm_sms_msg_fcn[idx];
2543         }
2544
2545         if (msg_fcn == NULL)
2546         {
2547             proto_tree_add_text(gsm_sms_tree,
2548                 tvb, offset, -1,
2549                 "Message dissector not implemented");
2550         }
2551         else
2552         {
2553             (*msg_fcn)(tvb, gsm_sms_tree, offset);
2554         }
2555     }
2556 }
2557
2558
2559 /* Register the protocol with Ethereal */
2560 void
2561 proto_register_gsm_sms(void)
2562 {
2563     guint               i;
2564     guint               last_offset;
2565
2566 #if 0
2567     /* Setup list of header fields */
2568     static hf_register_info hf[] =
2569     {
2570     };
2571 #endif
2572
2573     /* Setup protocol subtree array */
2574 #define NUM_INDIVIDUAL_PARMS    12
2575     static gint *ett[NUM_INDIVIDUAL_PARMS+NUM_MSGS+NUM_UDH_IEIS];
2576
2577     ett[0] = &ett_gsm_sms;
2578     ett[1] = &ett_pid;
2579     ett[2] = &ett_pi;
2580     ett[3] = &ett_fcs;
2581     ett[4] = &ett_vp;
2582     ett[5] = &ett_scts;
2583     ett[6] = &ett_dt;
2584     ett[7] = &ett_st;
2585     ett[8] = &ett_addr;
2586     ett[9] = &ett_dcs;
2587     ett[10] = &ett_ud;
2588     ett[11] = &ett_udh;
2589
2590     last_offset = NUM_INDIVIDUAL_PARMS;
2591
2592     for (i=0; i < NUM_MSGS; i++, last_offset++)
2593     {
2594         ett_msgs[i] = -1;
2595         ett[last_offset] = &ett_msgs[i];
2596     }
2597
2598     for (i=0; i < NUM_UDH_IEIS; i++, last_offset++)
2599     {
2600         ett_udh_ieis[i] = -1;
2601         ett[last_offset] = &ett_udh_ieis[i];
2602     }
2603
2604     /* Register the protocol name and description */
2605
2606     proto_gsm_sms =
2607         proto_register_protocol(gsm_sms_proto_name, gsm_sms_proto_name_short, "gsm_sms");
2608
2609 #if 0
2610     proto_register_field_array(proto_gsm_sms, hf, array_length(hf));
2611 #endif
2612
2613     proto_register_subtree_array(ett, array_length(ett));
2614 }
2615
2616
2617 void
2618 proto_reg_handoff_gsm_sms(void)
2619 {
2620     dissector_handle_t  gsm_sms_handle;
2621
2622     gsm_sms_handle = create_dissector_handle(dissect_gsm_sms, proto_gsm_sms);
2623
2624     dissector_add("gsm_a.sms_tpdu", 0, gsm_sms_handle);
2625     dissector_add("gsm_map.sms_tpdu", 0, gsm_sms_handle);
2626
2627     data_handle = find_dissector("data");
2628 }