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