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