From Didier Gautheron:
[obnox/wireshark/wip.git] / epan / dissectors / packet-gsm_sms.c
index f6dc23db0616941405b117943678be58429abe4c..30fd4a2adca52236ce6511e0f1ecb1d7a6fa10a1 100644 (file)
  *   Technical realization of Short Message Service (SMS)
  *   (3GPP TS 23.040 version 5.4.0 Release 5)
  *
+ * Header field support for TPDU Parameters added by
+ * Abhik Sarkar.
+ *
  * $Id$
  *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
  * This program is free software; you can redistribute it and/or
 
 #include <string.h>
 
-#include "epan/packet.h"
+#include <epan/packet.h>
 #include <epan/prefs.h>
+#include <epan/reassemble.h>
+#include <glib.h>
 
 #include "packet-gsm_sms.h"
 
+#define MAX_SMS_FRAG_LEN               134
 
 /* PROTOTYPES/FORWARDS */
 
@@ -111,14 +117,134 @@ static gint ett_dcs = -1;
 static gint ett_ud = -1;
 static gint ett_udh = -1;
 
+static gint ett_udh_tfm = -1;
+static gint ett_udh_tfc = -1;
+
 /* Initialize the protocol and registered fields */
 static int proto_gsm_sms = -1;
 
+static gint hf_gsm_sms_coding_group_bits2 = -1;
+static gint hf_gsm_sms_coding_group_bits4 = -1;
+static gint  hf_gsm_sms_ud_multiple_messages_msg_id = -1;
+static gint  hf_gsm_sms_ud_multiple_messages_msg_parts = -1;
+static gint  hf_gsm_sms_ud_multiple_messages_msg_part = -1;
+
+/* TPDU Parameters */
+static gint hf_gsm_sms_tp_mti_up = -1;
+static gint hf_gsm_sms_tp_mti_down = -1;
+static gint hf_gsm_sms_tp_mms = -1;
+static gint hf_gsm_sms_tp_vpf = -1;
+static gint hf_gsm_sms_tp_sri = -1;
+static gint hf_gsm_sms_tp_srr = -1;
+static gint hf_gsm_sms_tp_mr = -1;
+static gint hf_gsm_sms_tp_oa = -1;
+static gint hf_gsm_sms_tp_da = -1;
+static gint hf_gsm_sms_tp_pid = -1;
+static gint hf_gsm_sms_tp_dcs = -1;
+static gint hf_gsm_sms_tp_ra = -1;
+static gint hf_gsm_sms_tp_rp = -1;
+static gint hf_gsm_sms_tp_udhi = -1;
+static gint hf_gsm_sms_tp_rd = -1;
+static gint hf_gsm_sms_tp_srq = -1;
+#if 0
+static gint hf_gsm_sms_tp_scts = -1;
+static gint hf_gsm_sms_tp_vp = -1;
+static gint hf_gsm_sms_tp_dt = -1;
+static gint hf_gsm_sms_tp_st = -1;
+static gint hf_gsm_sms_tp_udl = -1;
+static gint hf_gsm_sms_tp_mn = -1;
+static gint hf_gsm_sms_tp_ct = -1;
+static gint hf_gsm_sms_tp_cdl = -1;
+static gint hf_gsm_sms_tp_cd = -1;
+static gint hf_gsm_sms_tp_ud = -1;
+#endif
+static gboolean msg_udh_frag = FALSE;
 static char bigbuf[1024];
-static dissector_handle_t data_handle;
 static packet_info *g_pinfo;
 static proto_tree *g_tree;
 
+/* 3GPP TS 23.038 version 7.0.0 Release 7
+ * The TP-Data-Coding-Scheme field, defined in 3GPP TS 23.040 [4],
+ * indicates the data coding scheme of the TP-UD field, and may indicate a message class.
+ * Any reserved codings shall be assumed to be the GSM 7 bit default alphabet
+ * (the same as codepoint 00000000) by a receiving entity.
+ * The octet is used according to a coding group which is indicated in bits 7..4.
+ */
+
+/* Coding Group Bits */
+static const value_string gsm_sms_coding_group_bits_vals[] = {
+       { 0,    "General Data Coding indication" }, /* 00xx */
+       { 1,    "General Data Coding indication" }, /* 00xx */
+       { 2,    "General Data Coding indication" }, /* 00xx */
+       { 3,    "General Data Coding indication" }, /* 00xx */
+       { 4,    "Message Marked for Automatic Deletion Group" }, /* 01xx */
+       { 5,    "Message Marked for Automatic Deletion Group" }, /* 01xx */
+       { 6,    "Message Marked for Automatic Deletion Group" }, /* 01xx */
+       { 7,    "Message Marked for Automatic Deletion Group" }, /* 01xx */
+       { 8,    "Reserved coding groups" },                     /* 1000..1011  */
+       { 9,    "Reserved coding groups" },                     /* 1000..1011  */
+       { 10,   "Reserved coding groups" },                     /* 1000..1011  */
+       { 11,   "Reserved coding groups" },                     /* 1000..1011  */
+       { 12,   "Message Waiting Indication Group: Discard Message" },/* 1100  */
+       { 13,   "Message Waiting Indication Group: Store Message" },  /* 1101  */
+       { 14,   "Message Waiting Indication Group: Store Message" },  /* 1110  */
+       { 15,   "Data coding/message class" },  /* 1111  */
+    { 0, NULL },
+};
+
+guint16 g_sm_id;
+guint16 g_frags;
+guint16 g_frag;
+
+guint16 g_port_src;
+guint16 g_port_dst;
+static gboolean           g_is_wsp;
+
+static dissector_table_t gsm_sms_dissector_tbl;
+/* Short Message reassembly */
+static GHashTable *g_sm_fragment_table = NULL;
+static GHashTable *g_sm_reassembled_table = NULL;
+static gint ett_gsm_sms_ud_fragment = -1;
+static gint ett_gsm_sms_ud_fragments = -1;
+ /*
+ * Short Message fragment handling
+ */
+static int hf_gsm_sms_ud_fragments = -1;
+static int hf_gsm_sms_ud_fragment = -1;
+static int hf_gsm_sms_ud_fragment_overlap = -1;
+static int hf_gsm_sms_ud_fragment_overlap_conflicts = -1;
+static int hf_gsm_sms_ud_fragment_multiple_tails = -1;
+static int hf_gsm_sms_ud_fragment_too_long_fragment = -1;
+static int hf_gsm_sms_ud_fragment_error = -1;
+static int hf_gsm_sms_ud_reassembled_in = -1;
+
+static const fragment_items sm_frag_items = {
+       /* Fragment subtrees */
+       &ett_gsm_sms_ud_fragment,
+       &ett_gsm_sms_ud_fragments,
+       /* Fragment fields */
+       &hf_gsm_sms_ud_fragments,
+       &hf_gsm_sms_ud_fragment,
+       &hf_gsm_sms_ud_fragment_overlap,
+       &hf_gsm_sms_ud_fragment_overlap_conflicts,
+       &hf_gsm_sms_ud_fragment_multiple_tails,
+       &hf_gsm_sms_ud_fragment_too_long_fragment,
+       &hf_gsm_sms_ud_fragment_error,
+       /* Reassembled in field */
+       &hf_gsm_sms_ud_reassembled_in,
+       /* Tag */
+       "Short Message fragments"
+};
+
+
+static void
+gsm_sms_defragment_init (void)
+{
+       fragment_table_init (&g_sm_fragment_table);
+       reassembled_table_init(&g_sm_reassembled_table);
+}
+
 /*
  * this is the GSM 03.40 definition with the bit 2
  * set to 1 for uplink messages
@@ -135,82 +261,69 @@ static const value_string msg_type_strings[] = {
     { 0, NULL },
 };
 
-#define        NUM_UDH_IEIS    256
-static gint ett_udh_ieis[NUM_UDH_IEIS];
+static const value_string msg_type_strings_sc_to_ms[] = {
+    { 0,       "SMS-DELIVER" },
+    { 1,       "SMS-SUBMIT REPORT" },
+    { 2,       "SMS-STATUS REPORT" },
+    { 3,       "Reserved" },
+    { 0, NULL },
+};
 
-/* FUNCTIONS */
+static const value_string msg_type_strings_ms_to_sc[] = {
+    { 0,       "SMS-DELIVER REPORT" },
+    { 1,       "SMS-SUBMIT" },
+    { 2,       "SMS-COMMAND" },
+    { 3,       "Reserved" },
+    { 0, NULL },
+};
 
-/* 9.2.3.1 */
-#define DIS_FIELD_MTI(m_tree, m_bitmask, m_offset) \
-{ \
-    other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
-    proto_tree_add_text(m_tree, tvb, \
-       m_offset, 1, \
-       "%s :  TP-Message-Type-Indicator", \
-       bigbuf); \
-}
+static const value_string vp_type_strings[] = {
+    { 0,       "TP VP field not present"},
+    { 1,       "TP VP field present - relative format"},
+    { 2,       "TP-VP field present - enhanced format"},
+    { 3,       "TP VP field present - absolute format"},
+    { 0, NULL },
+};
 
-/* 9.2.3.2 */
-#define DIS_FIELD_MMS(m_tree, m_bitmask, m_offset) \
-{ \
-    other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
-    proto_tree_add_text(m_tree, tvb, \
-       m_offset, 1, \
-       "%s :  TP-More-Messages-to-Send: %s messages are waiting for the MS in this SC", \
-       bigbuf, \
-       (oct & m_bitmask) ? "No more" : "More"); \
-}
+static const true_false_string mms_bool_strings = {
+       "No more messages are waiting for the MS in this SC",
+       "More messages are waiting for the MS in this SC"
+};
 
-/* 9.2.3.3 */
-#define DIS_FIELD_VPF(m_tree, m_bitmask, m_offset, m_form) \
-{ \
-    SMS_SHIFTMASK(oct & m_bitmask, m_bitmask, *m_form); \
-    switch (*m_form) \
-    { \
-    case 0: str = "TP-VP field not present"; break; \
-    case 1: str = "TP-VP field present - enhanced format"; break; \
-    case 2: str = "TP-VP field present - relative format"; break; \
-    case 3: str = "TP-VP field present - absolute format"; break; \
-    } \
-    other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
-    proto_tree_add_text(m_tree, tvb, \
-       m_offset, 1, \
-       "%s :  TP-Validity-Period-Format: %s", \
-       bigbuf, \
-       str); \
-}
+static const true_false_string sri_bool_strings = {
+       "A status report shall be returned to the SME",
+       "A status report shall not be returned to the SME"
+};
 
-/* 9.2.3.4 */
-#define DIS_FIELD_SRI(m_tree, m_bitmask, m_offset) \
-{ \
-    other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
-    proto_tree_add_text(m_tree, tvb, \
-       m_offset, 1, \
-       "%s :  TP-Status-Report-Indication: A status report shall %sbe returned to the SME", \
-       bigbuf, \
-       (oct & m_bitmask) ? "" : "not "); \
-}
+static const true_false_string srr_bool_strings = {
+       "A status report is requested",
+       "A status report is not requested"
+};
 
-/* 9.2.3.5 */
-#define DIS_FIELD_SRR(m_tree, m_bitmask, m_offset) \
-{ \
-    other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
-    proto_tree_add_text(m_tree, tvb, \
-       m_offset, 1, \
-       "%s :  TP-Status-Report-Request: A status report is %srequested", \
-       bigbuf, \
-       (oct & m_bitmask) ? "" : "not "); \
-}
+static const true_false_string udhi_bool_strings = {
+       "The beginning of the TP UD field contains a Header in addition to the short message",
+       "The TP UD field contains only the short message"
+};
 
-/* 9.2.3.6 */
-#define DIS_FIELD_MR(m_tree, m_offset) \
-{ \
-    proto_tree_add_text(m_tree, tvb, \
-       m_offset, 1, \
-       "TP-Message-Reference %d", \
-       oct); \
-}
+static const true_false_string rp_bool_strings = {
+       "TP Reply Path parameter is set in this SMS SUBMIT/DELIVER",
+       "TP Reply Path parameter is not set in this SMS SUBMIT/DELIVER"
+};
+
+static const true_false_string rd_bool_strings = {
+       "Instruct SC to reject duplicates",
+       "Instruct SC to accept duplicates"
+};
+
+static const true_false_string srq_bool_strings = {
+       "The SMS STATUS REPORT is the result of an SMS COMMAND e.g. an Enquiry.",
+       "SMS STATUS REPORT is the result of a SMS SUBMIT."
+};
+
+#define        NUM_UDH_IEIS    256
+static gint ett_udh_ieis[NUM_UDH_IEIS];
 
+#define MAX_ADDR_SIZE 20
 static void
 dis_field_addr(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p, const gchar *title)
 {
@@ -223,6 +336,8 @@ dis_field_addr(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p, const gchar *
     guint32            numdigocts;
     guint32            length;
     guint32            i, j;
+    char                addrbuf[MAX_ADDR_SIZE+1];
+    gchar               *addrstr;
 
     offset = *offset_p;
 
@@ -242,9 +357,8 @@ dis_field_addr(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p, const gchar *
        return;
     }
 
-    item =
-       proto_tree_add_text(tree, tvb,
-           offset, numdigocts + 2,
+    item = proto_tree_add_text(tree, tvb,
+           offset, numdigocts + 2, "%s",
            title);
 
     subtree = proto_item_add_subtree(item, ett_addr);
@@ -314,28 +428,40 @@ dis_field_addr(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p, const gchar *
     switch ((oct & 0x70) >> 4)
     {
     case 0x05: /* "Alphanumeric (coded according to 3GPP TS 23.038 GSM 7-bit default alphabet)" */
-       i = gsm_sms_char_7bit_unpack(0, numdigocts, sizeof(bigbuf), tvb_get_ptr(tvb, offset, numdigocts), bigbuf);
-       bigbuf[i] = '\0';
-       gsm_sms_char_ascii_decode(bigbuf, bigbuf, i);
+       i = gsm_sms_char_7bit_unpack(0, numdigocts, MAX_ADDR_SIZE, tvb_get_ptr(tvb, offset, numdigocts), addrbuf);
+       addrbuf[i] = '\0';
+       addrstr = gsm_sms_chars_to_utf8(addrbuf, i);
        break;
     default:
+       addrstr = ep_alloc(numdigocts*2 + 1);
        for (i = 0; i < numdigocts; i++)
        {
            oct = tvb_get_guint8(tvb, offset + i);
 
-           bigbuf[j++] = digit_table[oct & 0x0f];
-           bigbuf[j++] = digit_table[(oct & 0xf0) >> 4];
+           addrstr[j++] = digit_table[oct & 0x0f];
+           addrstr[j++] = digit_table[(oct & 0xf0) >> 4];
        }
-       bigbuf[j++] = '\0';
+       addrstr[j++] = '\0';
        break;
     }
 
-    proto_tree_add_text(subtree,
+    if (g_ascii_strncasecmp(title, "TP-O", 4) == 0) {
+       proto_tree_add_string(subtree, hf_gsm_sms_tp_oa, tvb,
+               offset, numdigocts, addrstr);
+    } else if (g_ascii_strncasecmp(title, "TP-D", 4) == 0) {
+       proto_tree_add_string(subtree, hf_gsm_sms_tp_da, tvb,
+               offset, numdigocts, addrstr);
+    } else if (g_ascii_strncasecmp(title, "TP-R", 4) == 0) {
+       proto_tree_add_string(subtree, hf_gsm_sms_tp_ra, tvb,
+               offset, numdigocts, addrstr);
+    } else {
+       proto_tree_add_text(subtree,
        tvb, offset, numdigocts,
        "Digits: %s",
-       bigbuf);
+       addrstr);
+    }
 
-    proto_item_append_text(item, " - (%s)", bigbuf);
+    proto_item_append_text(item, " - (%s)", addrstr);
 
     *offset_p = offset + numdigocts;
 }
@@ -358,9 +484,8 @@ dis_field_pid(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 oct)
 
 
     item =
-       proto_tree_add_text(tree, tvb,
-           offset, 1,
-           "TP-Protocol-Identifier");
+       proto_tree_add_item(tree, hf_gsm_sms_tp_pid, tvb,
+           offset, 1, FALSE);
 
     subtree = proto_item_add_subtree(item, ett_pid);
 
@@ -526,12 +651,15 @@ dis_field_dcs(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 oct,
     *compressed = FALSE;
 
     item =
-       proto_tree_add_text(tree, tvb,
-           offset, 1,
-           "TP-Data-Coding-Scheme (%d)",
-           oct);
+       proto_tree_add_item(tree, hf_gsm_sms_tp_dcs, tvb,
+           offset, 1, FALSE);
 
     subtree = proto_item_add_subtree(item, ett_dcs);
+       if(oct&0x80){
+               proto_tree_add_item(subtree, hf_gsm_sms_coding_group_bits4, tvb, offset, 1, FALSE);
+       }else{
+               proto_tree_add_item(subtree, hf_gsm_sms_coding_group_bits2, tvb, offset, 1, FALSE);
+       }
 
     if (oct == 0x00)
     {
@@ -632,7 +760,9 @@ dis_field_dcs(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 oct,
        case 0x00: str = "GSM 7 bit default alphabet";
            *seven_bit = TRUE;
            break;
-       case 0x01: str = "8 bit data"; break;
+       case 0x01: str = "8 bit data";
+               *eight_bit = TRUE;
+               break;
        case 0x02: str = "UCS2 (16 bit)";
            *ucs2 = TRUE;
            break;
@@ -1374,7 +1504,7 @@ dis_field_fcs(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 oct)
     }
 
     proto_tree_add_text(subtree, tvb,
-       offset, 1,
+       offset, 1, "%s",
        str);
 }
 
@@ -1438,24 +1568,25 @@ gsm_sms_char_7bit_unpack(unsigned int offset, unsigned int in_length, unsigned i
        }
     }
 
-    return out_num - output;
+    return (int)(out_num - output);
 }
 
 #define GN_CHAR_ALPHABET_SIZE 128
 
 #define GN_CHAR_ESCAPE 0x1b
 
-static unsigned char gsm_default_alphabet[GN_CHAR_ALPHABET_SIZE] = {
+static gunichar gsm_default_alphabet[GN_CHAR_ALPHABET_SIZE] = {
 
     /* ETSI GSM 03.38, version 6.0.1, section 6.2.1; Default alphabet */
+    /* Fixed to use unicode */
     /* Characters in hex position 10, [12 to 1a] and 24 are not present on
        latin1 charset, so we cannot reproduce on the screen, however they are
        greek symbol not present even on my Nokia */
 
-    '@',  0xa3, '$' 0xa5, 0xe8, 0xe9, 0xf9, 0xec,
+    '@',  0xa3, '$' , 0xa5, 0xe8, 0xe9, 0xf9, 0xec,
     0xf2, 0xc7, '\n', 0xd8, 0xf8, '\r', 0xc5, 0xe5,
-    '?',  '_',  '?',  '?',  '?',  '?',  '?',  '?',
-    '?',  '?',  '?',  '?',  0xc6, 0xe6, 0xdf, 0xc9,
+   0x394, '_', 0x3a6,0x393,0x39b,0x3a9,0x3a0,0x3a8,
+   0x3a3,0x398,0x39e, 0xa0, 0xc6, 0xe6, 0xdf, 0xc9,
     ' ',  '!',  '\"', '#',  0xa4,  '%',  '&',  '\'',
     '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
     '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
@@ -1476,26 +1607,26 @@ char_is_escape(unsigned char value)
     return (value == GN_CHAR_ESCAPE);
 }
 
-static unsigned char
+static gunichar
 char_def_alphabet_ext_decode(unsigned char value)
 {
     switch (value)
     {
-    case 0x0a: return 0x0c; break; /* form feed */
-    case 0x14: return '^';  break;
-    case 0x28: return '{';  break;
-    case 0x29: return '}';  break;
-    case 0x2f: return '\\'; break;
-    case 0x3c: return '[';  break;
-    case 0x3d: return '~';  break;
-    case 0x3e: return ']';  break;
-    case 0x40: return '|';  break;
-    case 0x65: return 0xa4; break; /* euro */
-    default: return '?';    break; /* invalid character */
+    case 0x0a: return 0x0c; /* form feed */
+    case 0x14: return '^';
+    case 0x28: return '{';
+    case 0x29: return '}';
+    case 0x2f: return '\\';
+    case 0x3c: return '[';
+    case 0x3d: return '~';
+    case 0x3e: return ']';
+    case 0x40: return '|';
+    case 0x65: return 0x20ac; /* euro */
+    default: return '?'; /* invalid character */
     }
 }
 
-static unsigned char
+static gunichar
 char_def_alphabet_decode(unsigned char value)
 {
     if (value < GN_CHAR_ALPHABET_SIZE)
@@ -1508,26 +1639,82 @@ char_def_alphabet_decode(unsigned char value)
     }
 }
 
-void
-gsm_sms_char_ascii_decode(unsigned char* dest, const unsigned char* src, int len)
+gchar *
+gsm_sms_chars_to_utf8(const unsigned char* src, int len)
 {
-    int i, j;
+    gint outlen, i, j;
+    gunichar c;
+    gchar *outbuf;
+
+    /* Scan the input string to see how long the output string will be */
+    for (outlen = 0, j = 0; j < len;  j++)
+    {
+       if (char_is_escape(src[j])) {
+           j++;
+           if (j == len)
+               c = '?';        /* escape with nothing following it - error */
+           else
+               c = char_def_alphabet_ext_decode(src[j]);
+       }
+       else
+           c = char_def_alphabet_decode(src[j]);
+        outlen += g_unichar_to_utf8(c,NULL);
+    }
 
-    for (i = 0, j = 0; j < len; i++, j++)
+    /* Now allocate a buffer for the output string and fill it in */
+    outbuf = ep_alloc(outlen + 1);
+    for (i = 0, j = 0; j < len;  j++)
     {
-       if (char_is_escape(src[j]))
-           dest[i] = char_def_alphabet_ext_decode(src[++j]);
+       if (char_is_escape(src[j])) {
+           j++;
+           if (j == len)
+               c = '?';        /* escape with nothing following it - error */
+           else
+               c = char_def_alphabet_ext_decode(src[j]);
+       }
        else
-           dest[i] = char_def_alphabet_decode(src[j]);
+           c = char_def_alphabet_decode(src[j]);
+        i += g_unichar_to_utf8(c,&(outbuf[i]));
     }
-    dest[i] = 0;
-    return;
+    outbuf[i] = '\0';
+    return outbuf;
 }
 
 /*
  * END FROM GNOKII
  */
 
+/* 9.2.3.24.1 */
+static void
+dis_iei_csm8(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
+{
+    guint8     oct;
+
+    EXACT_DATA_CHECK(length, 3);
+    oct = tvb_get_guint8(tvb, offset);
+       g_sm_id = oct;  
+       proto_tree_add_uint (tree,
+                                                       hf_gsm_sms_ud_multiple_messages_msg_id,
+                                                       tvb, offset, 1, g_sm_id);
+       offset++;
+
+       oct = tvb_get_guint8(tvb, offset);
+       g_frags = oct;
+       proto_tree_add_uint (tree,
+                                                       hf_gsm_sms_ud_multiple_messages_msg_parts,
+                                                       tvb , offset , 1, g_frags);
+       offset++;
+       oct = tvb_get_guint8(tvb, offset);
+       g_frag = oct;
+       proto_tree_add_uint (tree,
+                                                       hf_gsm_sms_ud_multiple_messages_msg_part,
+                                                       tvb, offset, 1, g_frag);
+
+}
+
+/* TODO 9.2.3.24.2 Special SMS Message Indication */
+
+/* 9.2.3.24.3 */
 static void
 dis_iei_apa_8bit(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
 {
@@ -1538,7 +1725,7 @@ dis_iei_apa_8bit(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
     EXACT_DATA_CHECK(length, 2);
 
     oct = tvb_get_guint8(tvb, offset);
-
+       g_port_dst = oct;
     if (oct < 240)
     {
        str = "Reserved";
@@ -1556,7 +1743,7 @@ dis_iei_apa_8bit(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
 
     offset++;
     oct = tvb_get_guint8(tvb, offset);
-
+       g_port_src = oct;
     if (oct < 240)
     {
        str = "Reserved";
@@ -1573,6 +1760,7 @@ dis_iei_apa_8bit(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
        str);
 }
 
+/* 9.2.3.24.4 */
 static void
 dis_iei_apa_16bit(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
 {
@@ -1583,7 +1771,7 @@ dis_iei_apa_16bit(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length
     EXACT_DATA_CHECK(length, 4);
 
     value = tvb_get_ntohs(tvb, offset);
-
+       g_port_dst = value;
     if (value < 16000)
     {
        str = "As allocated by IANA (http://www.IANA.com/)";
@@ -1605,7 +1793,7 @@ dis_iei_apa_16bit(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length
 
     offset += 2;
     value = tvb_get_ntohs(tvb, offset);
-
+       g_port_src = value;
     if (value < 16000)
     {
        str = "As allocated by IANA (http://www.IANA.com/)";
@@ -1624,142 +1812,725 @@ dis_iei_apa_16bit(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length
        "Originator port: %d, %s",
        value,
        str);
+
+       g_is_wsp = 1;
 }
 
+/* 9.2.3.24.5 */
 static void
-dis_field_ud_iei(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
+dis_iei_scp(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
 {
-    void (*iei_fcn)(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length);
     guint8     oct;
-    proto_item *item;
-    proto_tree *subtree = NULL;
-    const gchar        *str = NULL;
-    guint8     iei_len;
 
-
-    while (length > 2)
-    {
-       iei_fcn = NULL;
+    EXACT_DATA_CHECK(length, 1);
 
        oct = tvb_get_guint8(tvb, offset);
 
-       switch (oct)
+       if (oct & 0x01)
        {
-       case 0x00: str = "Concatenated short messages, 8-bit reference number (SMS Control)"; break;
-       case 0x01: str = "Special SMS Message Indication (SMS Control)"; break;
-       case 0x02: str = "Reserved N/A"; break;
-       case 0x03: str = "Value not used to avoid misinterpretation as <LF> character N/A"; break;
-       case 0x04: str = "Application port addressing scheme, 8 bit address (SMS Control)"; iei_fcn = dis_iei_apa_8bit; break;
-       case 0x05: str = "Application port addressing scheme, 16 bit address (SMS Control)"; iei_fcn = dis_iei_apa_16bit; break;
-       case 0x06: str = "SMSC Control Parameters (SMS Control)"; break;
-       case 0x07: str = "UDH Source Indicator (SMS Control)"; break;
-       case 0x08: str = "Concatenated short message, 16-bit reference number (SMS Control)"; break;
-       case 0x09: str = "Wireless Control Message Protocol (SMS Control)"; break;
-       case 0x0A: str = "Text Formatting (EMS Control)"; break;
-       case 0x0B: str = "Predefined Sound (EMS Content)"; break;
-       case 0x0C: str = "User Defined Sound (iMelody max 128 bytes) (EMS Content)"; break;
-       case 0x0D: str = "Predefined Animation (EMS Content)"; break;
-       case 0x0E: str = "Large Animation (16*16 times 4 = 32*4 =128 bytes) (EMS Content)"; break;
-       case 0x0F: str = "Small Animation (8*8 times 4 = 8*4 =32 bytes) (EMS Content)"; break;
-       case 0x10: str = "Large Picture (32*32 = 128 bytes) (EMS Content)"; break;
-       case 0x11: str = "Small Picture (16*16 = 32 bytes) (EMS Content)"; break;
-       case 0x12: str = "Variable Picture (EMS Content)"; break;
-       case 0x13: str = "User prompt indicator (EMS Control)"; break;
-       case 0x14: str = "Extended Object (EMS Content)"; break;
-       case 0x15: str = "Reused Extended Object (EMS Control)"; break;
-       case 0x16: str = "Compression Control (EMS Control)"; break;
-       case 0x17: str = "Object Distribution Indicator (EMS Control)"; break;
-       case 0x18: str = "Standard WVG object (EMS Content)"; break;
-       case 0x19: str = "Character Size WVG object (EMS Content)"; break;
-       case 0x1A: str = "Extended Object Data Request Command (EMS Control)"; break;
-       case 0x20: str = "RFC 822 E-Mail Header (SMS Control)"; break;
-       case 0x21: str = "Hyperlink format element (SMS Control)"; break;
-       case 0x22: str = "Reply Address Element (SMS Control)"; break;
-       default:
-           if ((oct >= 0x1b) &&
-               (oct <= 0x1f))
-           {
-               str = "Reserved for future EMS features (see subclause 3.10) N/A"; break;
-           }
-           else if ((oct >= 0x23) &&
-               (oct <= 0x6f))
-           {
-               str = "Reserved for future use N/A"; break;
-           }
-           else if ((oct >= 0x70) &&
-               (oct <= 0x7f))
-           {
-               str = "(U)SIM Toolkit Security Headers (SMS Control)"; break;
-           }
-           else if ((oct >= 0x80) &&
-               (oct <= 0x9f))
-           {
-               str = "SME to SME specific use (SMS Control)"; break;
-           }
-           else if ((oct >= 0xa0) &&
-               (oct <= 0xbf))
-           {
-               str = "Reserved for future use N/A"; break;
-           }
-           else if ((oct >= 0xc0) &&
-               (oct <= 0xdf))
-           {
-               str = "SC specific use (SMS Control)"; break;
-           }
-           else
-           {
-               str = "Reserved for future use N/A"; break;
-           }
+               proto_tree_add_text(tree,
+               tvb, offset, 1,
+               "Status Report for short message transaction completed");
+       }
+       else
+       {
+               proto_tree_add_text(tree,
+               tvb, offset, 1,
+               "No Status Report for short message transaction completed");
        }
 
-       iei_len = tvb_get_guint8(tvb, offset + 1);
+       if (oct & 0x02)
+       {
+               proto_tree_add_text(tree,
+               tvb, offset, 1,
+               "Status Report for permanent error when SC is not making any more transfer attempts");
+       }
+       else
+       {
+               proto_tree_add_text(tree,
+               tvb, offset, 1,
+               "No Status Report for permanent error when SC is not making any more transfer attempts");
+       }
 
-       item =
-           proto_tree_add_text(tree,
-               tvb, offset, iei_len + 2,
-               "IE: %s",
-               str);
+       if (oct & 0x04)
+       {
+               proto_tree_add_text(tree,
+               tvb, offset, 1,
+               "Status Report for temporary error when SC is not making any more transfer attempts");
+       }
+       else
+       {
+               proto_tree_add_text(tree,
+               tvb, offset, 1,
+               "No Status Report for temporary error when SC is not making any more transfer attempts");
+       }
 
-       subtree = proto_item_add_subtree(item, ett_udh_ieis[oct]);
+       if (oct & 0x08)
+       {
 
-       proto_tree_add_text(subtree,
-           tvb, offset, 1,
-           "Information Element Identifier: %d",
-           oct);
+               proto_tree_add_text(tree,
+               tvb, offset, 1,
+               "Status Report for temporary error when SC is still trying to transfer SM");
+       }
+       else
+       {
+               proto_tree_add_text(tree,
+               tvb, offset, 1,
+               "No Status Report for temporary error when SC is still trying to transfer SM");
+       }
 
-       offset++;
+       if (oct & 0x40)
+       {
 
-       proto_tree_add_text(subtree,
-           tvb, offset, 1,
-           "Length: %d",
-           iei_len);
+               proto_tree_add_text(tree,
+               tvb, offset, 1,
+               "A Status Report generated by this Short Message, due to a permanent error or last temporary error, cancels the SRR of the rest of the Short Messages in a concatenated message");
+       }
+       else
+       {
+               proto_tree_add_text(tree,
+               tvb, offset, 1,
+               "No activation");
+       }
 
-       offset++;
+       if (oct & 0x80)
+       {
 
-       if (iei_len > 0)
+               proto_tree_add_text(tree,
+               tvb, offset, 1,
+               "Include original UDH into the Status Report");
+       }
+       else
        {
-           if (iei_fcn == NULL)
-           {
-               proto_tree_add_text(subtree,
-                   tvb, offset, iei_len,
-                   "IE Data");
-           }
-           else
-           {
-               iei_fcn(tvb, subtree, offset, iei_len);
-           }
+               proto_tree_add_text(tree,
+               tvb, offset, 1,
+               "Do not include original UDH into the Status Report");
        }
 
-       length -= 2 + iei_len;
-       offset += iei_len;
-    }
 }
 
-/* 9.2.3.24 */
-#define NUM_FILL_BITS_MASKS 6
+/* 9.2.3.24.6 */
 static void
-dis_field_ud(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint32 length, gboolean udhi, guint8 udl,
-    gboolean seven_bit, gboolean eight_bit, gboolean ucs2, gboolean compressed)
+dis_iei_udh_si(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
+{
+    guint8     oct;
+
+    EXACT_DATA_CHECK(length, 1);
+
+       oct = tvb_get_guint8(tvb, offset);
+
+       switch (oct)
+       {
+               case 1:
+                       proto_tree_add_text(tree,
+                       tvb, offset, 1,
+                       "The following part of the UDH is created by the original sender (valid in case of Status Report)");
+               break;
+               case 2:
+                       proto_tree_add_text(tree,
+                       tvb, offset, 1,
+                       "The following part of the UDH is created by the original receiver (valid in case of Status Report)");
+               break;
+               case 3:
+                       proto_tree_add_text(tree,
+                       tvb, offset, 1,
+                       "The following part of the UDH is created by the SMSC (can occur in any message or report)");
+               break;
+               default:
+                       proto_tree_add_text(tree,
+                       tvb, offset, 1,
+                       "The following part of the UDH is created by %d" , oct);
+               break;
+       }       
+}
+/* 9.2.3.24.8 */
+static void
+dis_iei_csm16(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
+{
+    guint8     oct;
+       guint16 oct_ref;
+
+    EXACT_DATA_CHECK(length, 4);
+    oct_ref = tvb_get_ntohs(tvb, offset);
+       g_sm_id = oct_ref;
+       proto_tree_add_uint (tree,
+                                                       hf_gsm_sms_ud_multiple_messages_msg_id,
+                                                       tvb, offset, 2, g_sm_id);
+       offset+=2;
+       oct = tvb_get_guint8(tvb, offset);
+       g_frags = oct;
+       proto_tree_add_uint (tree,
+                                                       hf_gsm_sms_ud_multiple_messages_msg_parts,
+                                                       tvb , offset , 1, g_frags);
+
+       offset++;
+       oct = tvb_get_guint8(tvb, offset);
+       g_frag = oct;
+       proto_tree_add_uint (tree,
+                                                       hf_gsm_sms_ud_multiple_messages_msg_part,
+                                                       tvb, offset, 1, g_frag);
+}
+
+/* 9.2.3.24.10.1.1 */
+static void
+dis_iei_tf(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
+{
+       const gchar *str = NULL;
+    guint8     oct;
+       proto_item      *item;
+       proto_item      *item_colour;
+    proto_tree *subtree = NULL; 
+       proto_tree      *subtree_colour = NULL;
+       
+
+    EXACT_DATA_CHECK(length, 4);
+    oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, 1,
+       "Start position of the text formatting: %d",
+       oct);
+       offset++;
+
+       oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, 1,
+       "Text formatting length: %d",
+       oct);
+       offset++;
+
+       oct = tvb_get_guint8(tvb, offset);
+       
+       item =
+           proto_tree_add_text(tree,
+               tvb, offset, 1,
+               "formatting mode");
+
+       subtree = proto_item_add_subtree(item, ett_udh_tfm);
+       switch(oct & 0x03)
+       {
+               case 0x00:
+                       str = "Left";
+               break;
+               case 0x01:
+                       str = "Center";
+               break;
+               case 0x02:
+                       str = "Right";
+               break;
+               case 0x03:
+                       str = "Language dependent";
+               break;
+       }
+
+       proto_tree_add_text(subtree,
+       tvb, offset, 1,
+       "Alignment : %d %s",
+        oct & 0x03 , str);
+
+       switch((oct >> 2) & 0x03)
+       {
+               case 0x00:
+                       str = "Normal";
+               break;
+               case 0x01:
+                       str = "Large";
+               break;
+               case 0x02:
+                       str = "Small";
+               break;
+               case 0x03:
+                       str = "reserved";
+               break;
+       }
+
+       proto_tree_add_text(subtree,
+       tvb, offset, 1,
+       "Font Size : %d %s",
+        (oct >> 2) & 0x03 , str);
+       
+       if(oct & 0x10)
+               str = "on";
+       else
+               str = "off";
+       proto_tree_add_text(subtree,
+       tvb, offset, 1,
+       "Style bold : %d %s",
+        oct & 0x10 , str);
+       
+       if(oct & 0x20)
+               str = "on";
+       else
+               str = "off";
+       proto_tree_add_text(subtree,
+       tvb, offset, 1,
+       "Style Italic : %d %s",
+        oct & 0x20 , str);
+
+       if(oct & 0x40)
+               str = "on";
+       else
+               str = "off";
+       proto_tree_add_text(subtree,
+       tvb, offset, 1,
+       "Style Underlined : %d %s",
+        oct & 0x40 , str);
+
+       if(oct & 0x80)
+               str = "on";
+       else
+               str = "off";
+       proto_tree_add_text(subtree,
+       tvb, offset, 1,
+       "Style Strikethrough : %d %s",
+        oct & 0x80 , str);
+
+       offset++;
+       oct = tvb_get_guint8(tvb, offset);
+       item_colour =
+           proto_tree_add_text(tree,
+               tvb, offset, 1,
+               "Text Colour");
+
+       subtree_colour = proto_item_add_subtree(item_colour, ett_udh_tfc);
+       switch(oct & 0x0f)
+       {
+               case 0x00:
+                       str = "Dark Grey";
+               break;
+               case 0x01:
+                       str = "Dark Red";
+               break;
+                       str = "Dark Yellow";
+               break;
+                       str = "Dark Green";
+               break;
+                       str = "Dark Cyan";
+               break;
+                       str = "Dark Blue";
+               break;
+                       str = "Dark Magenta";
+               break;
+                       str = "Grey";
+               break;
+                       str = "White";
+               break;
+                       str = "Bright Red";
+               break;
+                       str = "Bright Yellow";
+               break;
+                       str = "Bright Green";
+               break;
+                       str = "Bright Cyan";
+               break;
+                       str = "Bright Blue";
+               break;
+                       str = "Bright Magenta";
+               break;
+       }
+
+       proto_tree_add_text(subtree_colour,
+       tvb, offset, 1,
+       "Foreground Colour : %d %s",
+        oct & 0x0f , str);
+       
+       switch((oct >> 4) & 0x0f)
+       {
+               case 0x00:
+                       str = "Dark Grey";
+               break;
+               case 0x01:
+                       str = "Dark Red";
+               break;
+                       str = "Dark Yellow";
+               break;
+                       str = "Dark Green";
+               break;
+                       str = "Dark Cyan";
+               break;
+                       str = "Dark Blue";
+               break;
+                       str = "Dark Magenta";
+               break;
+                       str = "Grey";
+               break;
+                       str = "White";
+               break;
+                       str = "Bright Red";
+               break;
+                       str = "Bright Yellow";
+               break;
+                       str = "Bright Green";
+               break;
+                       str = "Bright Cyan";
+               break;
+                       str = "Bright Blue";
+               break;
+                       str = "Bright Magenta";
+               break;
+       }
+
+       proto_tree_add_text(subtree_colour,
+       tvb, offset, 1,
+       "Background Colour : %d %s",
+        (oct >> 4) & 0x0f , str);
+
+}
+
+
+/* 9.2.3.24.10.1.2 */
+static void
+dis_iei_ps(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
+{
+    guint8     oct;
+
+    EXACT_DATA_CHECK(length, 2);
+    oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, 1,
+       "position: %d",
+       oct);
+       offset++;
+
+       oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, 1,
+       "sound number: %d",
+       oct);
+}
+
+/* 9.2.3.24.10.1.3 */
+static void
+dis_iei_uds(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
+{
+    guint8     oct;
+
+    SHORT_DATA_CHECK(length, 2);
+    oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, 1,
+       "position: %d",
+       oct);
+       offset++;
+
+       oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, length - 1,
+       "User Defined Sound ");
+}
+
+
+/* 9.2.3.24.10.1.4 */
+static void
+dis_iei_pa(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
+{
+    guint8     oct;
+
+    EXACT_DATA_CHECK(length, 2);
+    oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, 1,
+       "position: %d",
+       oct);
+       offset++;
+
+       oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, 1,
+       "animation number: %d",
+       oct);
+}
+
+
+/* 9.2.3.24.10.1.5 */
+static void
+dis_iei_la(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
+{
+    guint8     oct;
+
+    SHORT_DATA_CHECK(length, 2);
+    oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, 1,
+       "position: %d",
+       oct);
+       offset++;
+
+       oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, length - 1,
+       "Large Animation ");
+}
+
+/* 9.2.3.24.10.1.6 */
+static void
+dis_iei_sa(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
+{
+    guint8     oct;
+
+    SHORT_DATA_CHECK(length, 2);
+    oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, 1,
+       "position: %d",
+       oct);
+       offset++;
+
+       oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, length - 1,
+       "Small Animation ");
+}
+
+
+/* 9.2.3.24.10.1.7 */
+static void
+dis_iei_lp(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
+{
+    guint8     oct;
+
+    SHORT_DATA_CHECK(length, 2);
+    oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, 1,
+       "position: %d",
+       oct);
+       offset++;
+
+       oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, length - 1,
+       "Large Picture ");
+}
+
+/* 9.2.3.24.10.1.8 */
+static void
+dis_iei_sp(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
+{
+    guint8     oct;
+
+    SHORT_DATA_CHECK(length, 2);
+    oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, 1,
+       "position: %d",
+       oct);
+       offset++;
+
+       oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, length - 1,
+       "Small Picture ");
+}
+
+
+/* 9.2.3.24.10.1.9 */
+static void
+dis_iei_vp(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
+{
+    guint8     oct;
+
+    SHORT_DATA_CHECK(length, 4);
+    oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, 1,
+       "position: %d",
+       oct);
+       offset++;
+
+       oct = tvb_get_guint8(tvb, offset);
+       proto_tree_add_text(tree,
+       tvb, offset, 1,
+       "Horizontal dimension: %d",
+       oct);
+       offset++;
+
+       oct = tvb_get_guint8(tvb, offset);
+       proto_tree_add_text(tree,
+       tvb, offset, 1,
+       "Vertical dimension: %d",
+       oct);
+       offset++;
+
+
+       oct = tvb_get_guint8(tvb, offset);
+       proto_tree_add_text(tree,
+       tvb, offset, length - 3,
+       "Variable Picture ");
+}
+
+/* 9.2.3.24.10.1.10 */
+static void
+dis_iei_upi(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
+{
+    guint8     oct;
+
+    EXACT_DATA_CHECK(length, 1);
+    oct = tvb_get_guint8(tvb, offset);
+       
+       proto_tree_add_text(tree,
+       tvb, offset, 1,
+       "Number of corresponding objects: %d",
+       oct);
+       offset++;
+}
+
+
+/* */
+
+
+static void
+dis_field_ud_iei(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length)
+{
+    void (*iei_fcn)(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint8 length);
+    guint8     oct;
+    proto_item *item;
+    proto_tree *subtree = NULL;
+    const gchar        *str = NULL;
+    guint8     iei_len;
+
+
+    while (length >= 2)
+    {
+       iei_fcn = NULL;
+
+       oct = tvb_get_guint8(tvb, offset);
+
+       switch (oct)
+       {
+       case 0x00: str = "Concatenated short messages, 8-bit reference number (SMS Control)"; iei_fcn = dis_iei_csm8; break;
+       case 0x01: str = "Special SMS Message Indication (SMS Control)"; break;
+       case 0x02: str = "Reserved N/A"; break;
+       case 0x03: str = "Value not used to avoid misinterpretation as <LF> character N/A"; break;
+       case 0x04: str = "Application port addressing scheme, 8 bit address (SMS Control)"; iei_fcn = dis_iei_apa_8bit; break;
+       case 0x05: str = "Application port addressing scheme, 16 bit address (SMS Control)"; iei_fcn = dis_iei_apa_16bit; break;
+       case 0x06: str = "SMSC Control Parameters (SMS Control)"; iei_fcn = dis_iei_scp; break;
+       case 0x07: str = "UDH Source Indicator (SMS Control)"; iei_fcn  = dis_iei_udh_si; break;
+       case 0x08: str = "Concatenated short message, 16-bit reference number (SMS Control)"; iei_fcn = dis_iei_csm16; break;
+       case 0x09: str = "Wireless Control Message Protocol (SMS Control)"; break;
+       case 0x0A: str = "Text Formatting (EMS Control)"; iei_fcn = dis_iei_tf;
+       case 0x0B: str = "Predefined Sound (EMS Content)"; iei_fcn = dis_iei_ps;break;
+       case 0x0C: str = "User Defined Sound (iMelody max 128 bytes) (EMS Content)"; iei_fcn = dis_iei_uds;break;
+       case 0x0D: str = "Predefined Animation (EMS Content)"; iei_fcn = dis_iei_pa;break;
+       case 0x0E: str = "Large Animation (16*16 times 4 = 32*4 =128 bytes) (EMS Content)"; iei_fcn = dis_iei_la;break;
+       case 0x0F: str = "Small Animation (8*8 times 4 = 8*4 =32 bytes) (EMS Content)"; iei_fcn = dis_iei_sa;break;
+       case 0x10: str = "Large Picture (32*32 = 128 bytes) (EMS Content)"; iei_fcn = dis_iei_lp;break;
+       case 0x11: str = "Small Picture (16*16 = 32 bytes) (EMS Content)"; iei_fcn = dis_iei_sp;break;
+       case 0x12: str = "Variable Picture (EMS Content)"; iei_fcn = dis_iei_vp;break;
+       case 0x13: str = "User prompt indicator (EMS Control)"; iei_fcn = dis_iei_upi;break;
+       case 0x14: str = "Extended Object (EMS Content)"; break;
+       case 0x15: str = "Reused Extended Object (EMS Control)"; break;
+       case 0x16: str = "Compression Control (EMS Control)"; break;
+       case 0x17: str = "Object Distribution Indicator (EMS Control)"; break;
+       case 0x18: str = "Standard WVG object (EMS Content)"; break;
+       case 0x19: str = "Character Size WVG object (EMS Content)"; break;
+       case 0x1A: str = "Extended Object Data Request Command (EMS Control)"; break;
+       case 0x20: str = "RFC 822 E-Mail Header (SMS Control)"; break;
+       case 0x21: str = "Hyperlink format element (SMS Control)"; break;
+       case 0x22: str = "Reply Address Element (SMS Control)"; break;
+       default:
+           if ((oct >= 0x1b) &&
+               (oct <= 0x1f))
+           {
+               str = "Reserved for future EMS features (see subclause 3.10) N/A"; break;
+           }
+           else if ((oct >= 0x23) &&
+               (oct <= 0x6f))
+           {
+               str = "Reserved for future use N/A"; break;
+           }
+           else if ((oct >= 0x70) &&
+               (oct <= 0x7f))
+           {
+               str = "(U)SIM Toolkit Security Headers (SMS Control)"; break;
+           }
+           else if ((oct >= 0x80) &&
+               (oct <= 0x9f))
+           {
+               str = "SME to SME specific use (SMS Control)"; break;
+           }
+           else if ((oct >= 0xa0) &&
+               (oct <= 0xbf))
+           {
+               str = "Reserved for future use N/A"; break;
+           }
+           else if ((oct >= 0xc0) &&
+               (oct <= 0xdf))
+           {
+               str = "SC specific use (SMS Control)"; break;
+           }
+           else
+           {
+               str = "Reserved for future use N/A"; break;
+           }
+       }
+
+       iei_len = tvb_get_guint8(tvb, offset + 1);
+
+       item =
+           proto_tree_add_text(tree,
+               tvb, offset, iei_len + 2,
+               "IE: %s",
+               str);
+
+       subtree = proto_item_add_subtree(item, ett_udh_ieis[oct]);
+
+       proto_tree_add_text(subtree,
+           tvb, offset, 1,
+           "Information Element Identifier: %d",
+           oct);
+
+       offset++;
+
+       proto_tree_add_text(subtree,
+           tvb, offset, 1,
+           "Length: %d",
+           iei_len);
+
+       offset++;
+
+       if (iei_len > 0)
+       {
+           if (iei_fcn == NULL)
+           {
+               proto_tree_add_text(subtree,
+                   tvb, offset, iei_len,
+                   "IE Data");
+           }
+           else
+           {
+               iei_fcn(tvb, subtree, offset, iei_len);
+           }
+       }
+
+       length -= 2 + iei_len;
+       offset += iei_len;
+    }
+}
+
+/* 9.2.3.24 */
+#define NUM_FILL_BITS_MASKS 6
+#define SMS_MAX_MESSAGE_SIZE 160
+char    messagebuf[SMS_MAX_MESSAGE_SIZE+1];
+static void
+dis_field_ud(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint32 length, gboolean udhi, guint8 udl,
+    gboolean seven_bit, gboolean eight_bit, gboolean ucs2, gboolean compressed)
 {
     static guint8      fill_bits_mask[NUM_FILL_BITS_MASKS] =
        { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc };
@@ -1767,18 +2538,30 @@ dis_field_ud(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint32 length, gb
     proto_item *udh_item;
     proto_tree *subtree = NULL;
     proto_tree *udh_subtree = NULL;
+       tvbuff_t *sm_tvb = NULL;
+       fragment_data *fd_sm = NULL;
     guint8     oct;
     guint      fill_bits;
-    guint32    out_len;
+    guint32    out_len , total_sms_len , len_sms , length_ucs2 , i;
     char       *ustr;
-
+    proto_item *ucs2_item;
+    gchar *utf8_text = NULL;
+       gchar save_byte = 0 , save_byte2 = 0;
+    GIConv cd;
+    GError *l_conv_error = NULL;
+
+       gboolean    reassembled = FALSE;
+       guint32     reassembled_in = 0;
+       gboolean is_fragmented = FALSE;
+       gboolean save_fragmented = FALSE, try_gsm_sms_ud_reassemble = FALSE;
+       guint32 num_labels , save_offset;
     fill_bits = 0;
 
     item =
        proto_tree_add_text(tree, tvb,
            offset, length,
            "TP-User-Data");
-
+       save_offset = offset;
     subtree = proto_item_add_subtree(item, ett_ud);
 
     oct = tvb_get_guint8(tvb, offset);
@@ -1828,6 +2611,47 @@ dis_field_ud(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint32 length, gb
                }
     }
 
+       if (g_frags > 1)
+               is_fragmented = TRUE;
+
+       if ( is_fragmented ) 
+       {
+               try_gsm_sms_ud_reassemble = TRUE;
+               save_fragmented = g_pinfo->fragmented;
+               g_pinfo->fragmented = TRUE;
+               fd_sm = fragment_add_seq_check (tvb, offset, g_pinfo,
+                               g_sm_id, /* guint32 ID for fragments belonging together */
+                               g_sm_fragment_table, /* list of message fragments */
+                               g_sm_reassembled_table, /* list of reassembled messages */
+                               g_frag-1, /* guint32 fragment sequence number */
+                               length, /* guint32 fragment length */
+                               (g_frag != g_frags)); /* More fragments? */
+               if (fd_sm) 
+               {
+                       reassembled = TRUE;
+                       reassembled_in = fd_sm->reassembled_in;
+               }
+                               
+               sm_tvb = process_reassembled_data(tvb, offset, g_pinfo,
+                       "Reassembled Short Message", fd_sm, &sm_frag_items,
+                       NULL, tree);
+               if (reassembled) 
+               { 
+                       /* Reassembled */
+                       col_append_str (g_pinfo->cinfo, COL_INFO,
+                                               " (Short Message Reassembled)");
+               } 
+               else 
+               {
+                       /* Not last packet of reassembled Short Message */
+                       if (check_col (g_pinfo->cinfo, COL_INFO))
+                               col_append_fstr (g_pinfo->cinfo, COL_INFO,
+                                               " (Short Message fragment %u of %u)", g_frag, g_frags);
+               }
+       } /* Else: not fragmented */
+       if (! sm_tvb) /* One single Short Message, or not reassembled */
+               sm_tvb = tvb_new_subset_remaining (tvb, offset);
+       
     if (compressed)
     {
                proto_tree_add_text(subtree, tvb,
@@ -1836,55 +2660,128 @@ dis_field_ud(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint32 length, gb
     }
     else
     {
-               if (seven_bit)
+               if ((reassembled && g_pinfo->fd->num == reassembled_in) || g_frag==0 || ((g_frag != 0 && msg_udh_frag)))
                {
-                   out_len =
-                       gsm_sms_char_7bit_unpack(fill_bits, length, sizeof(bigbuf),
-                   tvb_get_ptr(tvb, offset, length), bigbuf);
-                   bigbuf[out_len] = '\0';
-                   gsm_sms_char_ascii_decode(bigbuf, bigbuf, out_len);
-                       bigbuf[udl] = '\0';
-
-                       proto_tree_add_text(subtree, tvb, offset, length, "%s", bigbuf);
-               }
-               else if (eight_bit)
+                       if (seven_bit)
                        {
-                       proto_tree_add_text(subtree, tvb, offset, length, "%s",
-               tvb_format_text(tvb, offset, length));
-               }
-               else if (ucs2)
+                               if(msg_udh_frag || g_frag == 0 )
+                               {
+                                       out_len =
+                                       gsm_sms_char_7bit_unpack(fill_bits, length , SMS_MAX_MESSAGE_SIZE,
+                                       tvb_get_ptr(tvb , offset , length) , messagebuf);
+                                       messagebuf[out_len] = '\0';
+                                       proto_tree_add_text(subtree, tvb , offset , length , "%s",
+                                           gsm_sms_chars_to_utf8(messagebuf, out_len));
+                               }
+                               else
+                               {
+                                       out_len = 0;
+                                       
+                                       total_sms_len = sm_tvb->length;
+                                       for(i = 0 ; i<g_frags; i++)
+                                       {
+                                               /* maximum len msg in 7 bit with csm8 header*/
+                                               if(total_sms_len > MAX_SMS_FRAG_LEN)
+                                               {
+                                                       total_sms_len -= MAX_SMS_FRAG_LEN;
+                                                       len_sms = MAX_SMS_FRAG_LEN;
+                                               }
+                                               else
+                                                       len_sms = total_sms_len;        
+                                               out_len =
+                                               gsm_sms_char_7bit_unpack(fill_bits, len_sms , SMS_MAX_MESSAGE_SIZE,
+                                               tvb_get_ptr(sm_tvb , i * MAX_SMS_FRAG_LEN  , len_sms) , messagebuf);
+                                               
+                                               messagebuf[out_len] = '\0';
+                                               proto_tree_add_text(subtree, sm_tvb , i * MAX_SMS_FRAG_LEN , len_sms , "%s",
+                                                   gsm_sms_chars_to_utf8(messagebuf, out_len));
+                                       }
+                               }
+                       }
+                       else if (eight_bit)
+                       {
+                               /*proto_tree_add_text(subtree, tvb , offset , length, "%s",
+                               tvb_format_text(tvb, offset, length));                          */
+                               if (! dissector_try_port(gsm_sms_dissector_tbl, g_port_src, sm_tvb, g_pinfo, subtree)) 
+                               {
+                                       if (! dissector_try_port(gsm_sms_dissector_tbl, g_port_dst,sm_tvb, g_pinfo, subtree)) 
+                                       {
+                                                       if (subtree) 
+                                                       { /* Only display if needed */
+                                                               proto_tree_add_text (subtree, sm_tvb, 0, -1,
+                                                                               "Short Message body");
+                                                       }
+                                       }
+                               }
+                       }
+                       else if (ucs2)
                        {
-                       /* tvb_get_ephemeral_faked_unicode takes the lengt in number of guint16's */
-                       ustr = tvb_get_ephemeral_faked_unicode(tvb, offset, (length>>1), FALSE);
-                       proto_tree_add_text(subtree, tvb, offset, length, "%s", ustr);
+                               if ((cd = g_iconv_open("UTF-8","UCS-2BE")) != (GIConv)-1)
+                               {
+                                       if(msg_udh_frag || g_frag == 0 )
+                                       {
+                                               utf8_text = g_convert_with_iconv(sm_tvb->real_data, sm_tvb->reported_length , cd , NULL , NULL , &l_conv_error);
+                                               if(!l_conv_error){
+                                                       ucs2_item = proto_tree_add_text(subtree, tvb, offset, length, "%s", utf8_text);
+                                               }else{
+                                                       ucs2_item = proto_tree_add_text(subtree, tvb, offset, length, "%s", "Failed on UCS2 contact wireshark developers");
+                                               }
+                                               PROTO_ITEM_SET_GENERATED(ucs2_item);
+                                       }
+                                       else
+                                       {
+                                               utf8_text = g_convert_with_iconv(sm_tvb->real_data, sm_tvb->reported_length , cd , NULL , NULL , &l_conv_error);
+                                               if(!l_conv_error)
+                                               {
+                                                       len_sms = (int)strlen(utf8_text);
+                                                       num_labels = len_sms / MAX_SMS_FRAG_LEN;
+                                                       num_labels += len_sms % MAX_SMS_FRAG_LEN ? 1 : 0;
+                                                       for(i = 0; i < num_labels;i++)
+                                                       {
+                                                               if(i * MAX_SMS_FRAG_LEN < len_sms)
+                                                               {
+                                                                       /* set '\0' to byte number 134 text_node MAX size*/
+                                                                       save_byte =  utf8_text[i * MAX_SMS_FRAG_LEN];
+                                                                       save_byte2 =  utf8_text[i * MAX_SMS_FRAG_LEN + 1];
+                                                                       if(i > 0)
+                                                                       {
+                                                                               utf8_text[i * MAX_SMS_FRAG_LEN] = '\0';
+                                                                               utf8_text[i * MAX_SMS_FRAG_LEN + 1] = '\0';
+                                                                       }
+
+                                                                       length_ucs2 = MAX_SMS_FRAG_LEN;
+                                                               }
+                                                               else
+                                                                       length_ucs2 = len_sms % MAX_SMS_FRAG_LEN;
+
+                                                               ucs2_item = proto_tree_add_text(subtree, sm_tvb , i * MAX_SMS_FRAG_LEN , length_ucs2 , "%s", &utf8_text[i * MAX_SMS_FRAG_LEN]);
+                                                               /* return the save byte to utf8 buffer*/
+                                                               if(i * MAX_SMS_FRAG_LEN < len_sms)
+                                                               {
+                                                                       utf8_text[i * MAX_SMS_FRAG_LEN] = save_byte;
+                                                                       utf8_text[i * MAX_SMS_FRAG_LEN + 1] = save_byte2;
+                                                               }
+                                                       }
+                                               }else{
+                                                       ucs2_item = proto_tree_add_text(subtree, tvb, offset, length, "%s", "Failed on UCS2 contact wireshark developers");
+                                               }
+                                       }
+
+                                       g_free(utf8_text);
+                                       g_iconv_close(cd);
+                               }
+                               else
+                               {
+                                       /* tvb_get_ephemeral_faked_unicode takes the lengt in number of guint16's */
+                                       ustr = tvb_get_ephemeral_faked_unicode(tvb, offset, (length>>1), FALSE);
+                                       proto_tree_add_text(subtree, tvb, offset, length, "%s", ustr);
+                               }
+                       }
                }
     }
-}
 
-/* 9.2.3.25 */
-#define DIS_FIELD_RD(m_tree, m_bitmask, m_offset) \
-{ \
-    other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
-    proto_tree_add_text(m_tree, tvb, \
-       m_offset, 1, \
-       "%s :  TP-Reject-Duplicates: Instruct SC to %s duplicates", \
-       bigbuf, \
-       (oct & m_bitmask) ? \
-       "reject" : \
-       "accept"); \
-}
-
-/* 9.2.3.26 */
-#define DIS_FIELD_SRQ(m_tree, m_bitmask, m_offset) \
-{ \
-    other_decode_bitfield_value(bigbuf, oct, m_bitmask, 8); \
-    proto_tree_add_text(m_tree, tvb, \
-       m_offset, 1, \
-       "%s :  TP-Status-Report-Qualifier: The SMS-STATUS-REPORT is the result of %s", \
-       bigbuf, \
-       (oct & m_bitmask) ? \
-       "an SMS-COMMAND e.g. an Enquiry" : \
-       "a SMS-SUBMIT"); \
+       if (try_gsm_sms_ud_reassemble) /* Clean up defragmentation */
+               g_pinfo->fragmented = save_fragmented;
 }
 
 /* 9.2.3.27 */
@@ -1959,16 +2856,13 @@ dis_msg_deliver(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
     length = tvb_length_remaining(tvb, offset);
 
     oct = tvb_get_guint8(tvb, offset);
+    udhi = oct & 0x40;
 
-    DIS_FIELD_RP(tree, 0x80, offset);
-
-    DIS_FIELD_UDHI(tree, 0x40, offset, udhi);
-
-    DIS_FIELD_SRI(tree, 0x20, offset);
-
-    DIS_FIELD_MMS(tree, 0x04, offset);
-
-    DIS_FIELD_MTI(tree, 0x03, offset);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_rp, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_udhi, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_sri, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_mms, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_mti_down, tvb, offset, 1, FALSE);
 
     offset++;
 
@@ -2012,10 +2906,10 @@ dis_msg_deliver_report(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
     guint8     oct;
     guint8     pi;
     guint8     udl;
-    gboolean   seven_bit;
-    gboolean   eight_bit;
-    gboolean   ucs2;
-    gboolean   compressed;
+    gboolean   seven_bit = FALSE;
+    gboolean   eight_bit = FALSE;
+    gboolean   ucs2 = FALSE;
+    gboolean   compressed = FALSE;
     gboolean   udhi;
 
 
@@ -2024,11 +2918,11 @@ dis_msg_deliver_report(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
     length = tvb_length_remaining(tvb, offset);
 
     oct = tvb_get_guint8(tvb, offset);
+    udhi = oct & 0x40;
 
-    DIS_FIELD_UDHI(tree, 0x40, offset, udhi);
-
-       DIS_FIELD_MMS(tree, 0x04, offset); /* Bit 2                     */
-    DIS_FIELD_MTI(tree, 0x03, offset); /* Bit 0 and 1  */
+    proto_tree_add_item(tree, hf_gsm_sms_tp_udhi, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_mms, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_mti_up, tvb, offset, 1, FALSE);
 
     if (length < 2)
     {
@@ -2132,7 +3026,6 @@ dis_msg_submit(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
     guint8     oct;
     guint8     vp_form;
     guint8     udl;
-    const gchar        *str = NULL;
     gboolean   seven_bit;
     gboolean   eight_bit;
     gboolean   ucs2;
@@ -2144,23 +3037,20 @@ dis_msg_submit(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
     length = tvb_length_remaining(tvb, offset);
 
     oct = tvb_get_guint8(tvb, offset);
+    udhi = oct & 0x40;
+    vp_form = ((oct & 0x18) >> 3);
 
-    DIS_FIELD_RP(tree, 0x80, offset);
-
-    DIS_FIELD_UDHI(tree, 0x40, offset, udhi);
-
-    DIS_FIELD_SRR(tree, 0x20, offset);
-
-    DIS_FIELD_VPF(tree, 0x18, offset, &vp_form);
-
-    DIS_FIELD_RD(tree, 0x04, offset);
-
-    DIS_FIELD_MTI(tree, 0x03, offset);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_rp, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_udhi, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_srr, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_vpf, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_rd, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_mti_up, tvb, offset, 1, FALSE);
 
     offset++;
     oct = tvb_get_guint8(tvb, offset);
 
-    DIS_FIELD_MR(tree, offset);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_mr, tvb, offset, 1, FALSE);
 
     offset++;
 
@@ -2204,10 +3094,10 @@ dis_msg_submit_report(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
     guint8     oct;
     guint8     pi;
     guint8     udl;
-    gboolean   seven_bit;
-    gboolean   eight_bit;
-    gboolean   ucs2;
-    gboolean   compressed;
+    gboolean   seven_bit = FALSE;
+    gboolean   eight_bit = FALSE;
+    gboolean   ucs2 = FALSE;
+    gboolean   compressed = FALSE;
     gboolean   udhi;
 
 
@@ -2216,10 +3106,10 @@ dis_msg_submit_report(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
     length = tvb_length_remaining(tvb, offset);
 
     oct = tvb_get_guint8(tvb, offset);
-
-    DIS_FIELD_UDHI(tree, 0x40, offset, udhi);
-
-    DIS_FIELD_MTI(tree, 0x03, offset);
+    udhi = oct & 0x40;
+    
+    proto_tree_add_item(tree, hf_gsm_sms_tp_udhi, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_mti_down, tvb, offset, 1, FALSE);
 
     /*
      * there does not seem to be a way to determine that this
@@ -2314,11 +3204,11 @@ dis_msg_status_report(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
     guint8     oct;
     guint8     pi;
     guint8     udl;
-    gboolean   seven_bit;
-    gboolean   eight_bit;
-    gboolean   ucs2;
-    gboolean   compressed;
-    gboolean   udhi;
+    gboolean   seven_bit = FALSE;
+    gboolean   eight_bit = FALSE;
+    gboolean   ucs2 = FALSE;
+    gboolean   compressed = FALSE;
+    gboolean   udhi; 
 
 
     udl = 0;
@@ -2326,19 +3216,17 @@ dis_msg_status_report(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
     length = tvb_length_remaining(tvb, offset);
 
     oct = tvb_get_guint8(tvb, offset);
+    udhi = oct & 0x40;
 
-    DIS_FIELD_UDHI(tree, 0x40, offset, udhi);
-
-    DIS_FIELD_SRQ(tree, 0x20, offset);
-
-    DIS_FIELD_MMS(tree, 0x04, offset);
-
-    DIS_FIELD_MTI(tree, 0x03, offset);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_udhi, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_srq, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_mms, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_mti_down, tvb, offset, 1, FALSE);
 
     offset++;
     oct = tvb_get_guint8(tvb, offset);
 
-    DIS_FIELD_MR(tree, offset);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_mr, tvb, offset, 1, FALSE);
 
     offset++;
 
@@ -2444,17 +3332,16 @@ dis_msg_command(tvbuff_t *tvb, proto_tree *tree, guint32 offset)
     length = tvb_length_remaining(tvb, offset);
 
     oct = tvb_get_guint8(tvb, offset);
+    udhi = oct & 0x40;
 
-    DIS_FIELD_UDHI(tree, 0x40, offset, udhi);
-
-    DIS_FIELD_SRR(tree, 0x20, offset);
-
-    DIS_FIELD_MTI(tree, 0x03, offset);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_udhi, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_srr, tvb, offset, 1, FALSE);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_mti_up, tvb, offset, 1, FALSE);
 
     offset++;
     oct = tvb_get_guint8(tvb, offset);
 
-    DIS_FIELD_MR(tree, offset);
+    proto_tree_add_item(tree, hf_gsm_sms_tp_mr, tvb, offset, 1, FALSE);
 
     offset++;
     oct = tvb_get_guint8(tvb, offset);
@@ -2518,14 +3405,17 @@ dissect_gsm_sms(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     gint       idx;
     const gchar        *str = NULL;
     gint       ett_msg_idx;
-
+       
 
     g_pinfo = pinfo;
+       g_is_wsp = 0;
+       g_sm_id = 0;
+       g_frags = 0;
+       g_frag = 0;     
+       g_port_src = 0;
+       g_port_dst = 0;
 
-    if (check_col(pinfo->cinfo, COL_PROTOCOL))
-    {
-       col_set_str(pinfo->cinfo, COL_PROTOCOL, gsm_sms_proto_name_short);
-    }
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, gsm_sms_proto_name_short);
 
     /* In the interest of speed, if "tree" is NULL, don't do any work not
      * necessary to generate protocol tree items.
@@ -2597,23 +3487,197 @@ dissect_gsm_sms(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 }
 
 
-/* Register the protocol with Ethereal */
+/* Register the protocol with Wireshark */
 void
 proto_register_gsm_sms(void)
 {
     guint              i;
     guint              last_offset;
+       module_t *gsm_sms_module; /* Preferences for GSM SMS UD */
 
-#if 0
     /* Setup list of header fields */
     static hf_register_info hf[] =
     {
+           { &hf_gsm_sms_coding_group_bits2,
+             { "Coding Group Bits", "gsm_sms.coding_group_bits2",
+               FT_UINT8, BASE_DEC, VALS(gsm_sms_coding_group_bits_vals), 0xc0,
+               NULL, HFILL }
+               },
+           { &hf_gsm_sms_coding_group_bits4,
+             { "Coding Group Bits", "gsm_sms.coding_group_bits4",
+               FT_UINT8, BASE_DEC, VALS(gsm_sms_coding_group_bits_vals), 0xf0,
+               NULL, HFILL }
+               },
+
+               /*
+                * Short Message fragment reassembly
+                */
+               {       &hf_gsm_sms_ud_fragments,
+                       {       "Short Message fragments", "gsm-sms-ud.fragments",
+                               FT_NONE, BASE_NONE, NULL, 0x00,
+                               "GSM Short Message fragments",
+                               HFILL
+                       }
+               },
+               {       &hf_gsm_sms_ud_fragment,
+                       {       "Short Message fragment", "gsm-sms-ud.fragment",
+                               FT_FRAMENUM, BASE_NONE, NULL, 0x00,
+                               "GSM Short Message fragment",
+                               HFILL
+                       }
+               },
+               {       &hf_gsm_sms_ud_fragment_overlap,
+                       {       "Short Message fragment overlap", "gsm-sms-ud.fragment.overlap",
+                               FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+                               "GSM Short Message fragment overlaps with other fragment(s)",
+                               HFILL
+                       }
+               },
+               {       &hf_gsm_sms_ud_fragment_overlap_conflicts,
+                       {       "Short Message fragment overlapping with conflicting data",
+                               "gsm-sms-ud.fragment.overlap.conflicts",
+                               FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+                               "GSM Short Message fragment overlaps with conflicting data",
+                               HFILL
+                       }
+               },
+               {       &hf_gsm_sms_ud_fragment_multiple_tails,
+                       {       "Short Message has multiple tail fragments",
+                               "gsm-sms-ud.fragment.multiple_tails",
+                               FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+                               "GSM Short Message fragment has multiple tail fragments",
+                               HFILL
+                       }
+               },
+               {       &hf_gsm_sms_ud_fragment_too_long_fragment,
+                       {       "Short Message fragment too long",
+                               "gsm-sms-ud.fragment.too_long_fragment",
+                               FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+                               "GSM Short Message fragment data goes beyond the packet end",
+                               HFILL
+                       }
+               },
+               {       &hf_gsm_sms_ud_fragment_error,
+                       {       "Short Message defragmentation error", "gsm-sms-ud.fragment.error",
+                               FT_FRAMENUM, BASE_NONE, NULL, 0x00,
+                               "GSM Short Message defragmentation error due to illegal fragments",
+                               HFILL
+                       }
+               },
+               {       &hf_gsm_sms_ud_reassembled_in,
+                       {       "Reassembled in",
+                               "gsm-sms-ud.reassembled.in",
+                               FT_FRAMENUM, BASE_NONE, NULL, 0x00,
+                               "GSM Short Message has been reassembled in this packet.", HFILL
+                       }
+               },
+               {   &hf_gsm_sms_ud_multiple_messages_msg_id,
+           {   "Message identifier", "gsm-sms.udh.mm.msg_id",
+               FT_UINT16, BASE_DEC, NULL, 0x00,
+               "Identification of the message",
+               HFILL
+           }
+       },
+       {   &hf_gsm_sms_ud_multiple_messages_msg_parts,
+           {   "Message parts", "gsm-sms.udh.mm.msg_parts",
+               FT_UINT8, BASE_DEC, NULL, 0x00,
+               "Total number of message parts (fragments)",
+               HFILL
+           }
+       },
+       {   &hf_gsm_sms_ud_multiple_messages_msg_part,
+           {   "Message part number", "gsm-sms.udh.mm.msg_part",
+               FT_UINT8, BASE_DEC, NULL, 0x00,
+               "Message part (fragment) sequence number",
+               HFILL
+           }
+       },
+       /* TPDU parameters */
+        { &hf_gsm_sms_tp_mti_up,
+             { "TP-MTI", "gsm_sms.tp-mti",
+               FT_UINT8, BASE_DEC, VALS(msg_type_strings_ms_to_sc), 0x03,
+               "TP-Message-Type-Indicator (in the direction MS to SC)", HFILL }
+       },      
+        { &hf_gsm_sms_tp_mti_down,
+             { "TP-MTI", "gsm_sms.tp-mti",
+               FT_UINT8, BASE_DEC, VALS(msg_type_strings_sc_to_ms), 0x03,
+               "TP-Message-Type-Indicator (in the direction SC to MS)", HFILL }
+       },      
+        { &hf_gsm_sms_tp_oa,
+             { "TP-OA Digits", "gsm_sms.tp-oa",
+               FT_STRING, BASE_NONE, NULL, 0x00,
+               "TP-Originating-Address Digits", HFILL }
+       },
+        { &hf_gsm_sms_tp_da,
+             { "TP-DA Digits", "gsm_sms.tp-da",
+               FT_STRING, BASE_NONE, NULL, 0x00,
+               "TP-Destination-Address Digits", HFILL }
+       },
+        { &hf_gsm_sms_tp_ra,
+             { "TP-RA Digits", "gsm_sms.tp-ra",
+               FT_STRING, BASE_NONE, NULL, 0x00,
+               "TP-Recipient-Address Digits", HFILL }
+       },
+        { &hf_gsm_sms_tp_pid,
+             { "TP-PID", "gsm_sms.tp-pid",
+               FT_UINT8, BASE_DEC, NULL, 0x00,
+               "TP-Protocol-Identifier", HFILL }
+       },
+        { &hf_gsm_sms_tp_dcs,
+             { "TP-DCS", "gsm_sms.tp-dcs",
+               FT_UINT8, BASE_DEC, NULL, 0x00,
+               "TP-Data-Coding-Scheme", HFILL }
+       },
+        { &hf_gsm_sms_tp_mr,
+             { "TP-MR", "gsm_sms.tp-mr",
+               FT_UINT8, BASE_DEC, NULL, 0x00,
+               "TP-Message-Reference", HFILL }
+       },
+        { &hf_gsm_sms_tp_mms,
+             { "TP-MMS", "gsm_sms.tp-mms",
+               FT_BOOLEAN, 8, TFS(&mms_bool_strings), 0x04,
+               "TP-More-Messages-to-Send", HFILL }
+       },
+        { &hf_gsm_sms_tp_sri,
+             { "TP-SRI", "gsm_sms.tp-sri",
+               FT_BOOLEAN, 8, TFS(&sri_bool_strings), 0x20,
+               "TP-Status-Report-Indication", HFILL }
+       },
+        { &hf_gsm_sms_tp_srr,
+             { "TP-SRR", "gsm_sms.tp-srr",
+               FT_BOOLEAN, 8, TFS(&srr_bool_strings), 0x20,
+               "TP-Status-Report-Request", HFILL }
+       },
+        { &hf_gsm_sms_tp_udhi,
+             { "TP-UDHI", "gsm_sms.tp-udhi",
+               FT_BOOLEAN, 8, TFS(&udhi_bool_strings), 0x40,
+               "TP-User-Data-Header-Indicator", HFILL }
+       },
+        { &hf_gsm_sms_tp_rp,
+             { "TP-RP", "gsm_sms.tp-rp",
+               FT_BOOLEAN, 8, TFS(&rp_bool_strings), 0x80,
+               "TP-Reply-Path", HFILL }
+       },      
+        { &hf_gsm_sms_tp_vpf,
+             { "TP-VPF", "gsm_sms.tp-vpf",
+               FT_UINT8, BASE_DEC, VALS(vp_type_strings), 0x18,
+               "TP-Validity-Period-Format", HFILL }
+       },      
+        { &hf_gsm_sms_tp_rd,
+             { "TP-RD", "gsm_sms.tp-rd",
+               FT_BOOLEAN, 8, TFS(&rd_bool_strings), 0x04,
+               "TP-Reject-Duplicates", HFILL }
+       },      
+        { &hf_gsm_sms_tp_srq,
+             { "TP-SRQ", "gsm_sms.tp-srq",
+               FT_BOOLEAN, 8, TFS(&srq_bool_strings), 0x20,
+               "TP-Status-Report-Qualifier", HFILL }
+       },      
     };
-#endif
 
     /* Setup protocol subtree array */
 #define        NUM_INDIVIDUAL_PARMS    12
-    static gint *ett[NUM_INDIVIDUAL_PARMS+NUM_MSGS+NUM_UDH_IEIS];
+    gint *ett[NUM_INDIVIDUAL_PARMS+NUM_MSGS+NUM_UDH_IEIS+2];
 
     ett[0] = &ett_gsm_sms;
     ett[1] = &ett_pid;
@@ -2642,16 +3706,34 @@ proto_register_gsm_sms(void)
        ett[last_offset] = &ett_udh_ieis[i];
     }
 
+    ett[last_offset++] = &ett_gsm_sms_ud_fragment;
+    ett[last_offset] = &ett_gsm_sms_ud_fragments;
+
     /* Register the protocol name and description */
 
     proto_gsm_sms =
        proto_register_protocol(gsm_sms_proto_name, gsm_sms_proto_name_short, "gsm_sms");
 
-#if 0
+
     proto_register_field_array(proto_gsm_sms, hf, array_length(hf));
-#endif
 
     proto_register_subtree_array(ett, array_length(ett));
+
+    gsm_sms_dissector_tbl = register_dissector_table("gsm-sms.udh.port",
+        "GSM SMS port IE in UDH", FT_UINT16, BASE_DEC);
+
+    gsm_sms_module = prefs_register_protocol (proto_gsm_sms, NULL);
+    prefs_register_bool_preference (gsm_sms_module,
+        "try_dissect_message_fragment",
+        "Always try subdissection of the fragment of a fragmented",
+        "Always try subdissection of 7bit, UCS2 Short Message fragment."
+        "If checked, every msg decode will shown in its fragment",
+        &msg_udh_frag);
+
+    /* register_dissector("gsm-sms", dissect_gsm_sms, proto_gsm_sms); */
+
+    /* GSM SMS UD dissector initialization routines */
+    register_init_routine (gsm_sms_defragment_init);
 }
 
 
@@ -2664,6 +3746,4 @@ proto_reg_handoff_gsm_sms(void)
 
     dissector_add("gsm_a.sms_tpdu", 0, gsm_sms_handle);
     dissector_add("gsm_map.sms_tpdu", 0, gsm_sms_handle);
-
-    data_handle = find_dissector("data");
 }