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