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