Set the svn:eol-style property on all text files to "native", so that
[obnox/wireshark/wip.git] / packet-smpp.c
index f1f6a98b691f2a7882ccfef931e04b624f1ffdb8..5d92afc530cf34b8c977563bb2c16a8bdaaf1c4b 100644 (file)
@@ -1,38 +1,17 @@
 /* packet-smpp.c
  * Routines for Short Message Peer to Peer dissection
- * Copyright 2001, Tom Uijldert <tom.uijldert@cmg.nl>
+ * Copyright 2001, Tom Uijldert.
  *
- * UDH and WSP dissection of SMS message, Short Message reassembly,
- * "Decode Short Message with Port Number UDH as CL-WSP" preference,
- * "Always try subdissection of 1st fragment" preference,
  * Data Coding Scheme decoding for GSM (SMS and CBS),
  * provided by Olivier Biot.
  *
- * $Id: packet-smpp.c,v 1.21 2003/12/12 23:47:42 obiot Exp $
+ * Dissection of multiple SMPP PDUs within one packet
+ * provided by Chris Wilson.
  *
- * Note on SMS Message reassembly
- * ------------------------------
- *   The current Short Message reassembly is possible thanks to the
- *   message identifier (8 or 16 bit identifier). It is able to reassemble
- *   short messages that are sent over either the same SMPP connection or
- *   distinct SMPP connections. Normally the reassembly code is able to deal
- *   with duplicate message identifiers since the fragment_add_seq_check()
- *   call is used.
+ * $Id$
  *
- *   The SMPP preference "always try subdissection of 1st fragment" allows
- *   a subdissector to be called for the first Short Message fragment,
- *   even if reassembly is not possible. This way partial dissection
- *   is still possible. This preference is switched off by default.
- *
- * Note on Short Message decoding as CL-WSP
- * ----------------------------------------
- *    The SMPP preference "port_number_udh_means_wsp" is switched off
- *    by default. If it is enabled, then any Short Message with a Port Number
- *    UDH will be decoded as CL-WSP if:
- *    -  The Short Message is not segmented
- *    -  The entire segmented Short Message is reassembled
- *    -  It is the 1st segment of an unreassembled Short Message (if the
- *       "always try subdissection of 1st fragment" preference is enabled)
+ * Refer to the AUTHORS file or the AUTHORS section in the man page
+ * for contacting the author(s) of this file.
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 #include <epan/packet.h>
 
 #include "prefs.h"
-#include "reassemble.h"
+#include "packet-tcp.h"
+
+/* General-purpose debug logger.
+ * Requires double parentheses because of variable arguments of printf().
+ *
+ * Enable debug logging for SMPP by defining AM_CFLAGS
+ * so that it contains "-DDEBUG_smpp"
+ */
+#ifdef DEBUG_smpp
+#define DebugLog(x) \
+       printf("%s:%u: ", __FILE__, __LINE__); \
+       printf x; \
+       fflush(stdout)
+#else
+#define DebugLog(x) ;
+#endif
 
 /* Forward declarations                */
-static void dissect_smpp(tvbuff_t *, packet_info *, proto_tree *t);
+static void dissect_smpp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+static guint get_smpp_pdu_len(tvbuff_t *tvb, int offset);
+static void dissect_smpp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
 
 /*
  * Initialize the protocol and registered fields
@@ -207,81 +203,15 @@ static int hf_smpp_dcs_wap_charset = -1;
 static int hf_smpp_dcs_wap_class = -1;
 static int hf_smpp_dcs_cbs_class = -1;
 
-/*
- * User Data Header section
- */
-static int hf_smpp_udh_length  = -1;
-static int hf_smpp_udh_iei             = -1;
-static int hf_smpp_udh_multiple_messages                       = -1;
-static int hf_smpp_udh_multiple_messages_msg_id                = -1;
-static int hf_smpp_udh_multiple_messages_msg_parts     = -1;
-static int hf_smpp_udh_multiple_messages_msg_part      = -1;
-static int hf_smpp_udh_ports           = -1;
-static int hf_smpp_udh_ports_src       = -1;
-static int hf_smpp_udh_ports_dst       = -1;
-
-/*
- * Short Message fragment handling
- */
-static int hf_sm_fragments                                     = -1;
-static int hf_sm_fragment                                      = -1;
-static int hf_sm_fragment_overlap                      = -1;
-static int hf_sm_fragment_overlap_conflicts    = -1;
-static int hf_sm_fragment_multiple_tails       = -1;
-static int hf_sm_fragment_too_long_fragment    = -1;
-static int hf_sm_fragment_error                                = -1;
-
 /* Initialize the subtree pointers */
 static gint ett_smpp           = -1;
 static gint ett_dlist          = -1;
 static gint ett_dlist_resp     = -1;
 static gint ett_opt_param      = -1;
-static gint ett_dcs                    = -1;
-static gint ett_udh                                            = -1;
-static gint ett_udh_multiple_messages  = -1;
-static gint ett_udh_ports                              = -1;
-static gint ett_sm_fragment            = -1;
-static gint ett_sm_fragments   = -1;
-
-/* Subdissector declarations */
-static dissector_table_t smpp_dissector_table;
-
-/* Short Message reassembly */
-static GHashTable *sm_fragment_table = NULL;
-static GHashTable *sm_reassembled_table = NULL;
-
-static const fragment_items sm_frag_items = {
-       /* Fragment subtrees */
-       &ett_sm_fragment,
-       &ett_sm_fragments,
-       /* Fragment fields */
-       &hf_sm_fragments,
-       &hf_sm_fragment,
-       &hf_sm_fragment_overlap,
-       &hf_sm_fragment_overlap_conflicts,
-       &hf_sm_fragment_multiple_tails,
-       &hf_sm_fragment_too_long_fragment,
-       &hf_sm_fragment_error,
-       /* Reassembled in field */
-       NULL,
-       /* Tag */
-       "Short Message fragments"
-};
+static gint ett_dcs            = -1;
 
-/* Dissect all SM data as WSP if the UDH contains a Port Number IE */
-static gboolean port_number_udh_means_wsp = FALSE;
-/* Always try dissecting the 1st fragment of a SM,
- * even if it is not reassembled */
-static gboolean try_dissect_1st_frag = FALSE;
-
-static dissector_handle_t wsp_handle;
-
-static void
-sm_defragment_init (void)
-{
-       fragment_table_init (&sm_fragment_table);
-       reassembled_table_init(&sm_reassembled_table);
-}
+/* Reassemble SMPP TCP segments */
+static gboolean reassemble_over_tcp = FALSE;
 
 /*
  * Value-arrays for field-contents
@@ -796,41 +726,7 @@ static const value_string vals_dcs_wap_charset[] = {
        { 0x00, NULL }
 };
 
-
-/* 3GPP TS 23.040 V6.1.0 (2003-06) */
-static const value_string vals_udh_iei[] = {
-       { 0x00, "SMS - Concatenated short messages, 8-bit reference number" },
-       { 0x01, "SMS - Special SMS Message Indication" },
-       { 0x02, "Reserved" },
-       { 0x03, "Value not used to avoid misinterpretation as <LF> character" },
-       { 0x04, "SMS - Application port addressing scheme, 8 bit address" },
-       { 0x05, "SMS - Application port addressing scheme, 16 bit address" },
-       { 0x06, "SMS - SMSC Control Parameters" },
-       { 0x07, "SMS - UDH Source Indicator" },
-       { 0x08, "SMS - Concatenated short message, 16-bit reference number" },
-       { 0x09, "SMS - Wireless Control Message Protocol" },
-       { 0x0A, "EMS - Text Formatting" },
-       { 0x0B, "EMS - Predefined Sound" },
-       { 0x0C, "EMS - User Defined Sound (iMelody max 128 bytes)" },
-       { 0x0D, "EMS - Predefined Animation" },
-       { 0x0E, "EMS - Large Animation (16*16 times 4 = 32*4 =128 bytes)" },
-       { 0x0F, "EMS - Small Animation (8*8 times 4 = 8*4 =32 bytes)" },
-       { 0x10, "EMS - Large Picture (32*32 = 128 bytes)" },
-       { 0x11, "EMS - Small Picture (16*16 = 32 bytes)" },
-       { 0x12, "EMS - Variable Picture" },
-       { 0x13, "EMS - User prompt indicator" },
-       { 0x14, "EMS - Extended Object" },
-       { 0x15, "EMS - Reused Extended Object" },
-       { 0x16, "EMS - Compression Control" },
-       { 0x17, "EMS - Object Distribution Indicator" },
-       { 0x18, "EMS - Standard WVG object" },
-       { 0x19, "EMS - Character Size WVG object" },
-       { 0x1A, "EMS - Extended Object Data Request Command" },
-       { 0x20, "SMS - RFC 822 E-Mail Header" },
-       { 0x21, "SMS - Hyperlink format element" },
-       { 0x22, "SMS - Reply Address Element" },
-       { 0x00, NULL }
-};     
+static dissector_handle_t gsm_sms_handle;
 
 /*!
  * SMPP equivalent of mktime() (3). Convert date to standard 'time_t' format
@@ -893,24 +789,43 @@ smpp_handle_string(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
     len = tvb_strsize(tvb, *offset);
     if (len > 1) {
       proto_tree_add_string(tree, field, tvb, *offset, len,
-          tvb_get_ptr(tvb, *offset, len));
+          (const char *) tvb_get_ptr(tvb, *offset, len));
+    }
+    (*offset) += len;
+}
+
+/* NOTE - caller must free the returned string! */
+static char *
+smpp_handle_string_return(proto_tree *tree, tvbuff_t *tvb, int field, int *offset)
+{
+    gint        len;
+    char       *str;
+
+    len = tvb_strsize(tvb, *offset);
+    if (len > 1) {
+       str = (char *)tvb_get_stringz(tvb, *offset, &len);
+       proto_tree_add_string(tree, field, tvb, *offset, len, str);
+    } else {
+       str = g_malloc(1 * sizeof(char));
+       str[0] = '\0';
     }
     (*offset) += len;
+    return str;
 }
 
 static void
 smpp_handle_string_z(proto_tree *tree, tvbuff_t *tvb, int field, int *offset,
                const char *null_string)
 {
-    guint       len;
+    gint        len;
 
     len = tvb_strsize(tvb, *offset);
     if (len > 1) {
-      proto_tree_add_string(tree, field, tvb, *offset, len,
-          tvb_get_ptr(tvb, *offset, len));
+       proto_tree_add_string(tree, field, tvb, *offset, len,
+               (const char *)tvb_get_ptr(tvb, *offset, len));
     } else {
-               proto_tree_add_string(tree, field, tvb, *offset, len, null_string);
-       }
+       proto_tree_add_string(tree, field, tvb, *offset, len, null_string);
+    }
     (*offset) += len;
 }
 
@@ -952,7 +867,7 @@ smpp_handle_time(proto_tree *tree, tvbuff_t *tvb,
     gint        len;
     nstime_t    tmptime;
 
-    strval = tvb_get_stringz(tvb, *offset, &len);
+    strval = (char *) tvb_get_stringz(tvb, *offset, &len);
     if (*strval)
     {
        if (smpp_mktime(strval, &tmptime.secs, &tmptime.nsecs))
@@ -1419,218 +1334,25 @@ outbind(proto_tree *tree, tvbuff_t *tvb)
     smpp_handle_string(tree, tvb, hf_smpp_password, &offset);
 }
 
-/* Parse Short Message, only if UDH present
- * (otherwise this function is not called).
- * Call WSP dissector if port matches WSP traffic.
- */
 static void
-parse_sm_message(proto_tree *sm_tree, tvbuff_t *tvb, packet_info *pinfo)
-{
-       tvbuff_t *sm_tvb = NULL;
-       proto_item *subtree, *tree;
-       guint8 udh_len, udh, len;
-       guint8 sm_len = tvb_reported_length (tvb);
-       guint8 sm_data_len;
-       guint32 i = 0;
-       /* Multiple Messages UDH */
-       fragment_data *fd_sm = NULL;
-       guint16 sm_id = 0, frags = 0, frag = 0;
-       gboolean save_fragmented = FALSE, try_sm_reassemble = FALSE;
-       /* Port Number UDH */
-       guint16 p_src = 0, p_dst = 0;
-       gboolean ports_available = FALSE;
-
-       udh_len = tvb_get_guint8(tvb, i++);
-       tree = proto_tree_add_uint(sm_tree, hf_smpp_udh_length, tvb, 0, 1, udh_len);
-       tree = proto_item_add_subtree(tree, ett_udh);
-       sm_data_len = sm_len - (1 + udh_len);
-       while (i < udh_len) {
-               udh = tvb_get_guint8(tvb, i++);
-               len = tvb_get_guint8(tvb, i++);
-               subtree = proto_tree_add_uint(tree, hf_smpp_udh_iei,
-                               tvb, i-2, 2+len, udh);
-               switch (udh) {
-                       case 0x00: /* Multiple messages - 8-bit message ID */
-                               if (len == 3) {
-                                       sm_id = tvb_get_guint8(tvb, i++);
-                                       frags = tvb_get_guint8(tvb, i++);
-                                       frag  = tvb_get_guint8(tvb, i++);
-                                       proto_item_append_text(subtree,
-                                                       ": message %u, part %u of %u", sm_id, frag, frags);
-                                       subtree = proto_item_add_subtree(subtree,
-                                                       ett_udh_multiple_messages);
-                                       proto_tree_add_uint (subtree,
-                                                       hf_smpp_udh_multiple_messages_msg_id,
-                                                       tvb, i-3, 1, sm_id);
-                                       proto_tree_add_uint (subtree,
-                                                       hf_smpp_udh_multiple_messages_msg_parts,
-                                                       tvb, i-2, 1, frags);
-                                       proto_tree_add_uint (subtree,
-                                                       hf_smpp_udh_multiple_messages_msg_part,
-                                                       tvb, i-1, 1, frag);
-                               } else {
-                                       proto_item_append_text(subtree, " - Invalid format!");
-                                       i += len;
-                               }
-                               break;
-
-                       case 0x08: /* Multiple messages - 16-bit message ID */
-                               if (len == 4) {
-                                       sm_id = tvb_get_ntohs(tvb, i); i += 2;
-                                       frags = tvb_get_guint8(tvb, i++);
-                                       frag  = tvb_get_guint8(tvb, i++);
-                                       proto_item_append_text(subtree,
-                                                       ": message %u, part %u of %u", sm_id, frag, frags);
-                                       subtree = proto_item_add_subtree(subtree,
-                                                       ett_udh_multiple_messages);
-                                       proto_tree_add_uint (subtree,
-                                                       hf_smpp_udh_multiple_messages_msg_id,
-                                                       tvb, i-4, 2, sm_id);
-                                       proto_tree_add_uint (subtree,
-                                                       hf_smpp_udh_multiple_messages_msg_parts,
-                                                       tvb, i-2, 1, frags);
-                                       proto_tree_add_uint (subtree,
-                                                       hf_smpp_udh_multiple_messages_msg_part,
-                                                       tvb, i-1, 1, frag);
-                               } else {
-                                       proto_item_append_text(subtree, " - Invalid format!");
-                                       i += len;
-                               }
-                               break;
-
-                       case 0x04: /* Port Number UDH - 8-bit address */
-                               if (len == 2) { /* Port fields */
-                                       p_dst = tvb_get_guint8(tvb, i++);
-                                       p_src = tvb_get_guint8(tvb, i++);
-                                       proto_item_append_text(subtree,
-                                                       ": source port %u, destination port %u",
-                                                       p_src, p_dst);
-                                       subtree = proto_item_add_subtree(subtree, ett_udh_ports);
-                                       proto_tree_add_uint (subtree, hf_smpp_udh_ports_dst,
-                                                       tvb, i-2, 1, p_dst);
-                                       proto_tree_add_uint (subtree, hf_smpp_udh_ports_src,
-                                                       tvb, i-1, 1, p_src);
-                                       ports_available = TRUE;
-                               } else {
-                                       proto_item_append_text(subtree, " - Invalid format!");
-                                       i += len;
-                               }
-                               break;
-
-                       case 0x05: /* Port Number UDH - 16-bit address */
-                               if (len == 4) { /* Port fields */
-                                       p_dst = tvb_get_ntohs(tvb, i); i += 2;
-                                       p_src = tvb_get_ntohs(tvb, i); i += 2;
-                                       proto_item_append_text(subtree,
-                                                       ": source port %u, destination port %u",
-                                                       p_src, p_dst);
-                                       subtree = proto_item_add_subtree(subtree, ett_udh_ports);
-                                       proto_tree_add_uint (subtree, hf_smpp_udh_ports_dst,
-                                                       tvb, i-4, 2, p_dst);
-                                       proto_tree_add_uint (subtree, hf_smpp_udh_ports_src,
-                                                       tvb, i-2, 2, p_src);
-                                       ports_available = TRUE;
-                               } else {
-                                       proto_item_append_text(subtree, " - Invalid format!");
-                                       i += len;
-                               }
-                               break;
-
-                       default:
-                               i += len;
-                               break;
-               }
-       }
-       if (tvb_reported_length_remaining(tvb, i) <= 0)
-               return; /* No more data */
-
-       /* Try reassembling the packets */
-       if ( frags && tvb_bytes_exist (tvb, i, sm_data_len) ) {
-               try_sm_reassemble = TRUE;
-               save_fragmented = pinfo->fragmented;
-               pinfo->fragmented = TRUE;
-               fd_sm = fragment_add_seq_check (tvb, i, pinfo,
-                               sm_id, /* guint32 ID for fragments belonging together */
-                               sm_fragment_table, /* list of message fragments */
-                               sm_reassembled_table, /* list of reassembled messages */
-                               frag-1, /* guint32 fragment sequence number */
-                               sm_data_len, /* guint32 fragment length */
-                               (frag != frags)); /* More fragments? */
-               if (fd_sm) { /* Reassembled */
-                       sm_tvb = tvb_new_real_data (fd_sm->data, fd_sm->len, fd_sm->len);
-                       tvb_set_child_real_data_tvbuff (tvb, sm_tvb);
-                       add_new_data_source (pinfo, sm_tvb, "Reassembled Short Message");
-                       pinfo->fragmented = FALSE;
-                       /* Show all fragments */
-                       show_fragment_seq_tree (fd_sm, &sm_frag_items,
-                                       sm_tree, pinfo, sm_tvb);
-                       if (check_col (pinfo->cinfo, COL_INFO))
-                               col_append_str (pinfo->cinfo, COL_INFO,
-                                               " (Short Message Reassembled)");
-               } else {
-                       /* Not last packet of reassembled Short Message */
-                       if (check_col (pinfo->cinfo, COL_INFO))
-                               col_append_fstr (pinfo->cinfo, COL_INFO,
-                                               " (Short Message fragment %u of %u)", frag, frags);
-               }
-       }
-
-       if (! sm_tvb) /* One single Short Message, or not reassembled */
-               sm_tvb = tvb_new_subset (tvb, i, -1, -1);
-       /* Try calling a subdissector */
-       if (sm_tvb) {
-               if (fd_sm || frag==0 || (frag==1 && try_dissect_1st_frag)) {
-                       /* Try calling a subdissector only if:
-                        *  - the Short Message is reassembled,
-                        *  - the Short Message consists of only one "fragment",
-                        *  - the preference "Always Try Dissection for 1st SM fragment"
-                        *    is switched on, and this is the SM's 1st fragment. */
-                       if ( ports_available ) {
-                               if ( port_number_udh_means_wsp ) {
-                                       call_dissector (wsp_handle, sm_tvb, pinfo, sm_tree);
-                               } else {
-                                       if (! dissector_try_port(smpp_dissector_table, p_src,
-                                                               sm_tvb, pinfo, sm_tree)) {
-                                               if (! dissector_try_port(smpp_dissector_table, p_dst,
-                                                                       sm_tvb, pinfo, sm_tree)) {
-                                                       if (sm_tree) { /* Only display if needed */
-                                                               proto_tree_add_text (sm_tree, sm_tvb, 0, -1,
-                                                                               "Short Message body");
-                                                       }
-                                               }
-                                       }
-                               }
-                       } else { /* No ports IE */
-                               proto_tree_add_text (sm_tree, sm_tvb, 0, -1,
-                                               "Short Message body");
-                       }
-               } else { /* Not 1st fragment and not reassembled */
-                       proto_tree_add_text (sm_tree, sm_tvb, 0, -1,
-                                       "Unreassembled Short Message fragment %u of %u",
-                                       frag, frags);
-               }
-       }
-
-       if (try_sm_reassemble) /* Clean up defragmentation */
-               pinfo->fragmented = save_fragmented;
-       return;
-}
-
-static void
-submit_sm(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo)
+submit_sm(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo,
+               proto_tree *top_tree)
 {
     tvbuff_t   *tvb_msg;
     int                 offset = 0;
     guint8      flag, udhi;
     guint8      length;
+       char *src_str = NULL;
+       char *dst_str = NULL;
+       address save_src, save_dst;
 
     smpp_handle_string_z(tree, tvb, hf_smpp_service_type, &offset, "(Default)");
     smpp_handle_int1(tree, tvb, hf_smpp_source_addr_ton, &offset);
     smpp_handle_int1(tree, tvb, hf_smpp_source_addr_npi, &offset);
-    smpp_handle_string(tree, tvb, hf_smpp_source_addr, &offset);
+    src_str = smpp_handle_string_return(tree, tvb, hf_smpp_source_addr, &offset);
     smpp_handle_int1(tree, tvb, hf_smpp_dest_addr_ton, &offset);
     smpp_handle_int1(tree, tvb, hf_smpp_dest_addr_npi, &offset);
-    smpp_handle_string(tree, tvb, hf_smpp_destination_addr, &offset);
+    dst_str = smpp_handle_string_return(tree, tvb, hf_smpp_destination_addr, &offset);
     flag = tvb_get_guint8(tvb, offset);
     udhi = flag & 0x40;
     proto_tree_add_item(tree, hf_smpp_esm_submit_msg_mode,
@@ -1672,16 +1394,29 @@ submit_sm(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo)
                            tvb, offset, length, FALSE);
        if (udhi) /* UDHI indicator present */
        {
+           DebugLog(("UDHI present - set addresses\n"));
+           /* Save original addresses */
+           COPY_ADDRESS(&save_src, &(pinfo->src));
+           COPY_ADDRESS(&save_dst, &(pinfo->dst));
+           /* Set SMPP source and destination address */
+           SET_ADDRESS(&(pinfo->src), AT_STRINGZ, 1+strlen(src_str), src_str);
+           SET_ADDRESS(&(pinfo->dst), AT_STRINGZ, 1+strlen(dst_str), dst_str);
            tvb_msg = tvb_new_subset (tvb, offset,
-                                     MIN(length, tvb_reported_length(tvb) - offset), length);
-           parse_sm_message(tree, tvb_msg, pinfo);
+                   MIN(length, tvb_reported_length(tvb) - offset), length);
+           call_dissector (gsm_sms_handle, tvb_msg, pinfo, top_tree);
+           /* Restore original addresses */
+           COPY_ADDRESS(&(pinfo->src), &save_src);
+           COPY_ADDRESS(&(pinfo->dst), &save_dst);
+           /* Get rid of SMPP text string addresses */
+           g_free(src_str);
+           g_free(dst_str);
        }
        offset += length;
     }
     smpp_handle_tlv(tree, tvb, &offset);
 }
 
-#define deliver_sm(a, b, c) submit_sm(a, b, c)
+#define deliver_sm(a, b, c, d) submit_sm(a, b, c, d)
 
 static void
 replace_sm(proto_tree *tree, tvbuff_t *tvb)
@@ -1753,41 +1488,41 @@ submit_multi(proto_tree *tree, tvbuff_t *tvb)
 
     flag = tvb_get_guint8(tvb, offset);
     proto_tree_add_item(tree, hf_smpp_esm_submit_msg_mode,
-                       tvb, offset, 1, flag);
+           tvb, offset, 1, flag);
     proto_tree_add_item(tree, hf_smpp_esm_submit_msg_type,
-                       tvb, offset, 1, flag);
+           tvb, offset, 1, flag);
     proto_tree_add_item(tree, hf_smpp_esm_submit_features,
-                       tvb, offset, 1, flag);
+           tvb, offset, 1, flag);
     offset++;
     smpp_handle_int1(tree, tvb, hf_smpp_protocol_id, &offset);
     smpp_handle_int1(tree, tvb, hf_smpp_priority_flag, &offset);
-       if (tvb_get_guint8(tvb,offset)) {
-    smpp_handle_time(tree, tvb, hf_smpp_schedule_delivery_time,
-                               hf_smpp_schedule_delivery_time_r, &offset);
-       } else { /* Time = NULL means Immediate delivery */
-               proto_tree_add_text(tree, tvb, offset++, 1,
-                               "Scheduled delivery time: Immediate delivery");
-       }
-       if (tvb_get_guint8(tvb,offset)) {
-    smpp_handle_time(tree, tvb, hf_smpp_validity_period,
-                               hf_smpp_validity_period_r, &offset);
-       } else { /* Time = NULL means SMSC default validity */
-               proto_tree_add_text(tree, tvb, offset++, 1,
-                               "Validity period: SMSC default validity period");
-       }
+    if (tvb_get_guint8(tvb,offset)) {
+       smpp_handle_time(tree, tvb, hf_smpp_schedule_delivery_time,
+               hf_smpp_schedule_delivery_time_r, &offset);
+    } else { /* Time = NULL means Immediate delivery */
+       proto_tree_add_text(tree, tvb, offset++, 1,
+               "Scheduled delivery time: Immediate delivery");
+    }
+    if (tvb_get_guint8(tvb,offset)) {
+       smpp_handle_time(tree, tvb, hf_smpp_validity_period,
+               hf_smpp_validity_period_r, &offset);
+    } else { /* Time = NULL means SMSC default validity */
+       proto_tree_add_text(tree, tvb, offset++, 1,
+               "Validity period: SMSC default validity period");
+    }
     flag = tvb_get_guint8(tvb, offset);
     proto_tree_add_item(tree, hf_smpp_regdel_receipt, tvb, offset, 1, flag);
     proto_tree_add_item(tree, hf_smpp_regdel_acks, tvb, offset, 1, flag);
     proto_tree_add_item(tree, hf_smpp_regdel_notif, tvb, offset, 1, flag);
     offset++;
     smpp_handle_int1(tree, tvb, hf_smpp_replace_if_present_flag, &offset);
-       smpp_handle_dcs(tree, tvb, &offset);
+    smpp_handle_dcs(tree, tvb, &offset);
     smpp_handle_int1(tree, tvb, hf_smpp_sm_default_msg_id, &offset);
     length = tvb_get_guint8(tvb, offset);
     proto_tree_add_uint(tree, hf_smpp_sm_length, tvb, offset++, 1, length);
     if (length)
        proto_tree_add_item(tree, hf_smpp_short_message,
-                           tvb, offset, length, FALSE);
+               tvb, offset, length, FALSE);
     offset += length;
     smpp_handle_tlv(tree, tvb, &offset);
 }
@@ -1924,193 +1659,309 @@ dissect_smpp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     return TRUE;
 }
 
-/* Code to actually dissect the packets */
+static guint
+get_smpp_pdu_len(tvbuff_t *tvb, int offset)
+{
+    return tvb_get_ntohl(tvb, offset);
+}
+
+/*
+ * This global SMPP variable is used to determine whether the PDU to dissect
+ * is the first SMPP PDU in the packet (or reassembled buffer), requiring
+ * different column update code than subsequent SMPP PDUs within this packet
+ * (or reassembled buffer).
+ *
+ * FIXME - This approach is NOT dissection multi-thread safe!
+ */
+static gboolean first = TRUE;
+
 static void
 dissect_smpp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+    first = TRUE;
+    if (pinfo->ptype == PT_TCP)        {       /* are we running on top of TCP */
+       tcp_dissect_pdus(tvb, pinfo, tree,
+               reassemble_over_tcp,    /* Do we try to reassemble      */
+               16,                     /* Length of fixed header       */
+               get_smpp_pdu_len,       /* Function returning PDU len   */
+               dissect_smpp_pdu);      /* PDU dissector                */
+    } else {                           /* no? probably X.25            */
+       guint32 offset = 0;
+       while (tvb_reported_length_remaining(tvb, offset) > 0) {
+           guint16 pdu_len = tvb_get_ntohl(tvb, offset);
+           gint pdu_real_len = tvb_length_remaining(tvb, offset);
+           tvbuff_t *pdu_tvb;
+
+           if (pdu_real_len <= 0)
+               return;
+           if (pdu_real_len > pdu_len)
+               pdu_real_len = pdu_len;
+           pdu_tvb = tvb_new_subset(tvb, offset, pdu_real_len, pdu_len);
+           dissect_smpp_pdu(pdu_tvb, pinfo, tree);
+           offset += pdu_len;
+           first = FALSE;
+       }
+    }
+}
+
+
+/* Dissect a single SMPP PDU contained within "tvb". */
+static void
+dissect_smpp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
     int                 offset = 0;            /* Offset within tvbuff */
     guint       command_length;        /* length of PDU        */
     guint       command_id;            /* SMPP command         */
     guint       command_status;        /* Status code          */
     guint       sequence_number;       /* ...of command        */
-
+    gchar      *command_str;
+    gchar      *command_status_str = NULL;
     /* Set up structures needed to add the protocol subtree and manage it */
-    proto_item *ti;
-    proto_tree *smpp_tree;
-    tvbuff_t   *tmp_tvb;
+    proto_item *ti = NULL;
+    proto_tree *smpp_tree = NULL;
 
     /*
-     * Safety: don't even try it when the mandatory header isn't present.
+     * Safety: don't even try to dissect the PDU
+     * when the mandatory header isn't present.
      */
     if (tvb_reported_length(tvb) < 4 * 4)
        return;
     command_length = tvb_get_ntohl(tvb, offset);
     offset += 4;
     command_id = tvb_get_ntohl(tvb, offset);
+    command_str = val_to_str(command_id, vals_command_id,
+           "(Unknown SMPP Operation 0x%08X)");
     offset += 4;
     command_status = tvb_get_ntohl(tvb, offset);
-    offset +=4;
+    if (command_id & 0x80000000) {
+       command_status_str = val_to_str(command_status, vals_command_status,
+               "(Reserved Error 0x%08X)");
+    }
+    offset += 4;
     sequence_number = tvb_get_ntohl(tvb, offset);
     offset += 4;
-    /* Make entries in Protocol column and Info column on summary display */
-    if (check_col(pinfo->cinfo, COL_PROTOCOL))
-       col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMPP");
 
-    if (check_col(pinfo->cinfo, COL_INFO))
-    {
-       col_clear(pinfo->cinfo, COL_INFO);
-       col_add_fstr(pinfo->cinfo, COL_INFO, "SMPP %s",
-                val_to_str(command_id,vals_command_id,"unknown operation"));
-       if (command_id & 0x80000000)
-           col_append_fstr(pinfo->cinfo, COL_INFO, ": \"%s\"",
-                           val_to_str(command_status, vals_command_status,
-                                      "reserved error"));
-       if (command_length > tvb_reported_length(tvb))
-           col_append_str(pinfo->cinfo, COL_INFO, " [short packet]");
-       if (command_length < tvb_reported_length(tvb))
-           col_append_str(pinfo->cinfo, COL_INFO, " [trailing data]");
+    /*
+     * Update the protocol column.
+     */
+    if (first == TRUE) {
+       if (check_col(pinfo->cinfo, COL_PROTOCOL))
+           col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMPP");
     }
 
-    /* In the interest of speed, if "tree" is NULL, don't do any work not
-     * necessary to generate protocol tree items.
-        *
-        * Exception: sm_submit (command_id == 0x00000004) - for SMS reassembly
+    /*
+     * Create display subtree for the protocol
      */
-    if (tree || (command_id == 4)) {
-
-       /* create display subtree for the protocol      */
-       ti = proto_tree_add_item(tree, proto_smpp, tvb, 0,
-                                command_length, FALSE);
-       smpp_tree = proto_item_add_subtree(ti, ett_smpp);
-
-       /* add an item to the subtree                   */
-       proto_tree_add_uint(smpp_tree, hf_smpp_command_length, tvb,
-                           0, 4, command_length);
-       proto_tree_add_uint(smpp_tree, hf_smpp_command_id, tvb,
-                           4, 4, command_id);
-       proto_item_append_text (ti, ", %s",
-                       match_strval (command_id, vals_command_id));
-       /* Status is only meaningful with responses     */
-       if (command_id & 0x80000000) {
-           proto_tree_add_uint(smpp_tree, hf_smpp_command_status, tvb,
-                               8, 4, command_status);
-               proto_item_append_text (ti, ": \"%s\"",
-                               match_strval (command_status, vals_command_status));
-       }
-       proto_tree_add_uint(smpp_tree, hf_smpp_sequence_number, tvb,
-                           12, 4, sequence_number);
-       proto_item_append_text (ti, ", Seq: %u, Len: %u",
-                       sequence_number, command_length);
+    if (tree) {
+       ti = proto_tree_add_item (tree, proto_smpp, tvb, 0, tvb->length, FALSE);
+       smpp_tree = proto_item_add_subtree (ti, ett_smpp);
+    }
+
+    /*
+     * Cycle over the encapsulated PDUs
+     */
+    {
+       tvbuff_t *pdu_tvb;
+
        /*
-        * End of header. Don't dissect variable part if it is shortened.
+        * Make entries in the Info column on the summary display
         */
-       if (command_length > tvb_reported_length(tvb))
-           return;
-       tmp_tvb = tvb_new_subset(tvb, offset, -1, command_length - offset);
-       if (command_id & 0x80000000)
-       {
-           switch (command_id & 0x7FFFFFFF) {
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+           if (first == TRUE) {
+               /*
+                * First PDU - We already computed the fixed header
+                */
+               col_clear(pinfo->cinfo, COL_INFO);
+               col_add_fstr(pinfo->cinfo, COL_INFO, "SMPP %s", command_str);
+               first = FALSE;
+           } else {
                /*
-                * All of these only have a fixed header
+                * Subsequent PDUs
                 */
-               case 0:                         /* Generic nack */
-               case 6:                         /* Unbind resp  */
-               case 7:                         /* Replace SM resp      */
-               case 8:                         /* Cancel SM resp       */
-               case 21:                        /* Enquire link resp    */
-                   break;
-               case 1:
-                   if (!command_status)
-                       bind_receiver_resp(smpp_tree, tmp_tvb);
-                   break;
-               case 2:
-                   if (!command_status)
-                       bind_transmitter_resp(smpp_tree, tmp_tvb);
-                   break;
-               case 3:
-                   if (!command_status)
-                       query_sm_resp(smpp_tree, tmp_tvb);
-                   break;
-               case 4:
-                   if (!command_status)
-                       submit_sm_resp(smpp_tree, tmp_tvb);
-                   break;
-               case 5:
-                   if (!command_status)
-                       deliver_sm_resp(smpp_tree, tmp_tvb);
-                   break;
-               case 9:
-                   if (!command_status)
-                       bind_transceiver_resp(smpp_tree, tmp_tvb);
-                   break;
-               case 33:
-                   if (!command_status)
-                       submit_multi_resp(smpp_tree, tmp_tvb);
-                   break;
-               case 259:
-                   if (!command_status)
-                       data_sm_resp(smpp_tree, tmp_tvb);
-                   break;
-               default:
-                   break;
+               col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", command_str);
+           }
+           /*
+            * Display command status of responses in Info column
+            */
+           if (command_id & 0x80000000) {
+               col_append_fstr(pinfo->cinfo, COL_INFO, ": \"%s\"",
+                       command_status_str);
            }
        }
-       else
+
+       /*
+        * Create a tvb for the current PDU.
+        * Physical length: at most command_length
+        * Reported length: command_length
+        */
+       if (tvb_length_remaining(tvb, offset - 16 + command_length) > 0) {
+           pdu_tvb = tvb_new_subset(tvb, offset - 16,
+                   command_length,     /* Physical length */
+                   command_length);    /* Length reported by the protocol */
+       } else {
+           pdu_tvb = tvb_new_subset(tvb, offset - 16,
+                   tvb_length_remaining(tvb, offset - 16),/* Physical length */
+                   command_length);    /* Length reported by the protocol */
+       }
+
+       /*
+        * Dissect the PDU
+        *
+        * If "tree" is NULL, Ethereal is only interested in creation
+        * of conversations, reassembly and subdissection but not in
+        * the detailed protocol tree.
+        * In the interest of speed, skip the generation of protocol tree
+        * items when "tree" is NULL.
+        *
+        * The only PDU which requires subdissection currently is the
+        * sm_submit PDU (command ID = 0x00000004).
+        */
+       if (tree || (command_id == 4))
        {
-           switch (command_id) {
-               case  1:
-                   bind_receiver(smpp_tree, tmp_tvb);
-                   break;
-               case  2:
-                   bind_transmitter(smpp_tree, tmp_tvb);
-                   break;
-               case  3:
-                   query_sm(smpp_tree, tmp_tvb);
-                   break;
-               case  4:
-                   submit_sm(smpp_tree, tmp_tvb, pinfo);
-                   break;
-               case  5:
-                   deliver_sm(smpp_tree, tmp_tvb, pinfo);
-                   break;
-               case  6:                        /* Unbind       */
-               case 21:                        /* Enquire link */
-                   break;
-               case  7:
-                   replace_sm(smpp_tree, tmp_tvb);
-                   break;
-               case  8:
-                   cancel_sm(smpp_tree, tmp_tvb);
-                   break;
-               case  9:
-                   bind_transceiver(smpp_tree, tmp_tvb);
-                   break;
-               case  11:
-                   outbind(smpp_tree, tmp_tvb);
-                   break;
-               case  33:
-                   submit_multi(smpp_tree, tmp_tvb);
-                   break;
-               case  258:
-                   alert_notification(smpp_tree, tmp_tvb);
-                   break;
-               case  259:
-                   data_sm(smpp_tree, tmp_tvb);
-                   break;
-               default:
-                   break;
+           /*
+            * Create display subtree for the PDU
+            */
+           if (tree) {
+               proto_tree_add_uint(smpp_tree, hf_smpp_command_length,
+                       pdu_tvb, 0, 4, command_length);
+               proto_tree_add_uint(smpp_tree, hf_smpp_command_id,
+                       pdu_tvb, 4, 4, command_id);
+               proto_item_append_text(ti, ", Command: %s", command_str);
+
+               /*
+                * Status is only meaningful with responses
+                */
+               if (command_id & 0x80000000) {
+                   proto_tree_add_uint(smpp_tree, hf_smpp_command_status,
+                           pdu_tvb, 8, 4, command_status);
+                   proto_item_append_text (ti, ", Status: \"%s\"",
+                           command_status_str);
+               }
+               proto_tree_add_uint(smpp_tree, hf_smpp_sequence_number,
+                       pdu_tvb, 12, 4, sequence_number);
+               proto_item_append_text(ti, ", Seq: %u, Len: %u",
+                       sequence_number, command_length);
            }
-       }
+
+           /*
+            * End of fixed header.
+            * Don't dissect variable part if it is shortened.
+            *
+            * FIXME - We then do not report a Short Frame or Malformed Packet
+            */
+           if (command_length <= tvb_reported_length(pdu_tvb))
+           {
+               tvbuff_t *tmp_tvb = tvb_new_subset(pdu_tvb, 16,
+                       -1, command_length - 16);
+               if (command_id & 0x80000000)
+               {
+                   switch (command_id & 0x7FFFFFFF) {
+                       /*
+                        * All of these only have a fixed header
+                        */
+                       case   0:       /* Generic nack         */
+                       case   6:       /* Unbind resp          */
+                       case   7:       /* Replace SM resp      */
+                       case   8:       /* Cancel SM resp       */
+                       case  21:       /* Enquire link resp    */
+                           break;
+                       case   1:
+                           if (!command_status)
+                               bind_receiver_resp(smpp_tree, tmp_tvb);
+                           break;
+                       case   2:
+                           if (!command_status)
+                               bind_transmitter_resp(smpp_tree, tmp_tvb);
+                           break;
+                       case   3:
+                           if (!command_status)
+                               query_sm_resp(smpp_tree, tmp_tvb);
+                           break;
+                       case   4:
+                           if (!command_status)
+                               submit_sm_resp(smpp_tree, tmp_tvb);
+                           break;
+                       case   5:
+                           if (!command_status)
+                               deliver_sm_resp(smpp_tree, tmp_tvb);
+                           break;
+                       case   9:
+                           if (!command_status)
+                               bind_transceiver_resp(smpp_tree, tmp_tvb);
+                           break;
+                       case  33:
+                           if (!command_status)
+                               submit_multi_resp(smpp_tree, tmp_tvb);
+                           break;
+                       case 259:
+                           if (!command_status)
+                               data_sm_resp(smpp_tree, tmp_tvb);
+                           break;
+                       default:
+                           break;
+                   } /* switch (command_id & 0x7FFFFFFF) */
+               }
+               else
+               {
+                   switch (command_id) {
+                       case   1:
+                           bind_receiver(smpp_tree, tmp_tvb);
+                           break;
+                       case   2:
+                           bind_transmitter(smpp_tree, tmp_tvb);
+                           break;
+                       case   3:
+                           query_sm(smpp_tree, tmp_tvb);
+                           break;
+                       case   4:
+                           submit_sm(smpp_tree, tmp_tvb, pinfo, tree);
+                           break;
+                       case   5:
+                           deliver_sm(smpp_tree, tmp_tvb, pinfo, tree);
+                           break;
+                       case   6:       /* Unbind               */
+                       case  21:       /* Enquire link         */
+                           break;
+                       case   7:
+                           replace_sm(smpp_tree, tmp_tvb);
+                           break;
+                       case   8:
+                           cancel_sm(smpp_tree, tmp_tvb);
+                           break;
+                       case   9:
+                           bind_transceiver(smpp_tree, tmp_tvb);
+                           break;
+                       case  11:
+                           outbind(smpp_tree, tmp_tvb);
+                           break;
+                       case  33:
+                           submit_multi(smpp_tree, tmp_tvb);
+                           break;
+                       case  258:
+                           alert_notification(smpp_tree, tmp_tvb);
+                           break;
+                       case  259:
+                           data_sm(smpp_tree, tmp_tvb);
+                           break;
+                       default:
+                           break;
+                   } /* switch (command_id) */
+               } /* if (command_id & 0x80000000) */
+           } /* if (command_length <= tvb_reported_length(pdu_tvb)) */
+           offset += command_length;
+       } /* if (tree || (command_id == 4)) */
+       first = FALSE;
     }
-    /* If this protocol has a sub-dissector call it here.      */
+
     return;
 }
 
+
 /* Register the protocol with Ethereal */
 void
 proto_register_smpp(void)
 {
-       module_t *smpp_module; /* Preferences for SMPP */
+    module_t *smpp_module; /* Preferences for SMPP */
 
     /* Setup list of header fields     */
     static hf_register_info hf[] = {
@@ -2781,6 +2632,9 @@ proto_register_smpp(void)
                HFILL
            }
        },
+       /*
+        * Data Coding Scheme
+        */
        {       &hf_smpp_dcs,
                { "SMPP Data Coding Scheme", "smpp.dcs",
                FT_UINT8, BASE_HEX, VALS(vals_data_coding), 0x00,
@@ -2853,136 +2707,16 @@ proto_register_smpp(void)
                        "as specified by the WAP Forum (WAP over GSM USSD).", HFILL
                }
        },
-       {   &hf_smpp_udh_iei,
-               {       "IE Id", "smpp.udh.iei",
-               FT_UINT8, BASE_HEX, VALS(vals_udh_iei), 0x00,
-               "Name of the User Data Header Information Element.",
-               HFILL
-               }
-       },
-       {   &hf_smpp_udh_length,
-           {   "UDH Length", "smpp.udh.len",
-               FT_UINT8, BASE_DEC, NULL, 0x00,
-               "Length of the User Data Header (bytes)",
-               HFILL
-           }
-       },
-       {   &hf_smpp_udh_multiple_messages,
-           {   "Multiple messages UDH", "smpp.udh.mm",
-               FT_NONE, BASE_NONE, NULL, 0x00,
-               "Multiple messages User Data Header",
-               HFILL
-           }
-       },
-       {   &hf_smpp_udh_multiple_messages_msg_id,
-           {   "Message identifier", "smpp.udh.mm.msg_id",
-               FT_UINT16, BASE_DEC, NULL, 0x00,
-               "Identification of the message",
-               HFILL
-           }
-       },
-       {   &hf_smpp_udh_multiple_messages_msg_parts,
-           {   "Message parts", "smpp.udh.mm.msg_parts",
-               FT_UINT8, BASE_DEC, NULL, 0x00,
-               "Total number of message parts (fragments)",
-               HFILL
-           }
-       },
-       {   &hf_smpp_udh_multiple_messages_msg_part,
-           {   "Message part number", "smpp.udh.mm.msg_part",
-               FT_UINT8, BASE_DEC, NULL, 0x00,
-               "Message part (fragment) sequence number",
-               HFILL
-           }
-       },
-       {   &hf_smpp_udh_ports,
-           {   "Port number UDH", "smpp.udh.ports",
-               FT_NONE, BASE_NONE, NULL, 0x00,
-               "Port number User Data Header",
-               HFILL
-           }
-       },
-       {   &hf_smpp_udh_ports_src,
-           {   "Source port", "smpp.udh.ports.src",
-               FT_UINT8, BASE_DEC, NULL, 0x00,
-               "Source port",
-               HFILL
-           }
-       },
-       {   &hf_smpp_udh_ports_dst,
-           {   "Destination port", "smpp.udh.ports.dst",
-               FT_UINT8, BASE_DEC, NULL, 0x00,
-               "Destination port",
-               HFILL
-           }
-       },
-       /* Short Message fragment reassembly */
-       {       &hf_sm_fragments,
-               {       "Short Message fragments", "smpp.fragments",
-                       FT_NONE, BASE_NONE, NULL, 0x00,
-                       "SMPP Short Message fragments",
-                       HFILL
-               }
-       },
-       {       &hf_sm_fragment,
-               {       "Short Message fragment", "smpp.fragment",
-                       FT_FRAMENUM, BASE_NONE, NULL, 0x00,
-                       "SMPP Short Message fragment",
-                       HFILL
-               }
-       },
-       {       &hf_sm_fragment_overlap,
-               {       "Short Message fragment overlap", "smpp.fragment.overlap",
-                       FT_BOOLEAN, BASE_NONE, NULL, 0x00,
-                       "SMPP Short Message fragment overlaps with other fragment(s)",
-                       HFILL
-               }
-       },
-       {       &hf_sm_fragment_overlap_conflicts,
-               {       "Short Message fragment overlapping with conflicting data",
-                       "smpp.fragment.overlap.conflicts",
-                       FT_BOOLEAN, BASE_NONE, NULL, 0x00,
-                       "SMPP Short Message fragment overlaps with conflicting data",
-                       HFILL
-               }
-       },
-       {       &hf_sm_fragment_multiple_tails,
-               {       "Short Message has multiple tail fragments",
-                       "smpp.fragment.multiple_tails",
-                       FT_BOOLEAN, BASE_NONE, NULL, 0x00,
-                       "SMPP Short Message fragment has multiple tail fragments",
-                       HFILL
-               }
-       },
-       {       &hf_sm_fragment_too_long_fragment,
-               {       "Short Message fragment too long",
-                       "smpp.fragment.too_long_fragment",
-                       FT_BOOLEAN, BASE_NONE, NULL, 0x00,
-                       "SMPP Short Message fragment data goes beyond the packet end",
-                       HFILL
-               }
-       },
-       {       &hf_sm_fragment_error,
-               {       "Short Message defragmentation error", "smpp.fragment.error",
-                       FT_FRAMENUM, BASE_NONE, NULL, 0x00,
-                       "SMPP Short Message defragmentation error due to illegal fragments",
-                       HFILL
-               }
-       },
     };
     /* Setup protocol subtree array */
     static gint *ett[] = {
-           &ett_smpp,
-           &ett_dlist,
-           &ett_dlist_resp,
-           &ett_opt_param,
-               &ett_dcs,
-               &ett_udh,
-           &ett_udh_multiple_messages,
-           &ett_udh_ports,
-               &ett_sm_fragment,
-               &ett_sm_fragments,
+       &ett_smpp,
+       &ett_dlist,
+       &ett_dlist_resp,
+       &ett_opt_param,
+       &ett_dcs,
     };
+    DebugLog(("Registering SMPP dissector\n"));
     /* Register the protocol name and description */
     proto_smpp = proto_register_protocol("Short Message Peer to Peer",
                                         "SMPP", "smpp");
@@ -2991,28 +2725,13 @@ proto_register_smpp(void)
     proto_register_field_array(proto_smpp, hf, array_length(hf));
     proto_register_subtree_array(ett, array_length(ett));
 
-    /* Subdissector code */
-    smpp_dissector_table = register_dissector_table("smpp.udh.port",
-                       "SMPP UDH port", FT_UINT16, BASE_DEC);
-
-       /* Preferences for SMPP */
-       smpp_module = prefs_register_protocol (proto_smpp, NULL);
-       prefs_register_bool_preference (smpp_module, "port_number_udh_means_wsp",
-                       "Port Number IE in UDH always triggers CL-WSP dissection",
-                       "Always decode a Short Message as Connectionless WSP "
-                       "if a Port Number Information Element is present "
-                       "in the User Data Header.",
-                       &port_number_udh_means_wsp);
-       prefs_register_bool_preference (smpp_module, "try_dissect_1st_fragment",
-                       "Always try subdissection of 1st Short Message fragment",
-                       "Always try subdissection of the 1st fragment of a fragmented "
-                       "Short Message. If reassembly is possible, the Short Message "
-                       "may be dissected twice (once as a short frame, once in its "
-                       "entirety).",
-                       &try_dissect_1st_frag);
-
-       /* SMPP dissector initialization routines */
-       register_init_routine (sm_defragment_init);
+    /* Preferences */
+    smpp_module = prefs_register_protocol (proto_smpp, NULL);
+    prefs_register_bool_preference (smpp_module,
+           "reassemble_smpp_over_tcp",
+           "Reassemble SMPP over TCP",
+           "Reassemble TCP segments that convey SMPP traffic.",
+           &reassemble_over_tcp);
 }
 
 /*
@@ -3040,6 +2759,7 @@ proto_reg_handoff_smpp(void)
     heur_dissector_add("x.25", dissect_smpp_heur, proto_smpp);
 
        /* Required for call_dissector() */
-       wsp_handle = find_dissector ("wsp-cl");
-       assert (wsp_handle);
+       DebugLog(("Finding gsm-sms-ud subdissector\n"));
+       gsm_sms_handle = find_dissector("gsm-sms-ud");
+       g_assert (gsm_sms_handle);
 }