Add escaping of an apostrophe in XML output.
[obnox/wireshark/wip.git] / packet-wtp.c
index 92de3b735507944fdf9df443f7e03ffc04e741d9..5b59266606fbc1fceffb5a78a2ae3bdf29a15a37 100644 (file)
@@ -2,7 +2,7 @@
  *
  * Routines to dissect WTP component of WAP traffic.
  *
- * $Id: packet-wtp.c,v 1.44 2003/04/09 18:15:53 guy Exp $
+ * $Id: packet-wtp.c,v 1.63 2004/02/28 22:56:36 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -76,7 +76,7 @@ static const true_false_string TVETOK_truth = {
     "False"
 };
 
-static const value_string vals_pdu_type[] = {
+static const value_string vals_wtp_pdu_type[] = {
     { 0, "Not Allowed" },
     { 1, "Invoke" },
     { 2, "Result" },
@@ -195,9 +195,11 @@ static int hf_wtp_fragment_overlap_conflict        = HF_EMPTY;
 static int hf_wtp_fragment_multiple_tails      = HF_EMPTY;
 static int hf_wtp_fragment_too_long_fragment   = HF_EMPTY;
 static int hf_wtp_fragment_error               = HF_EMPTY;
+static int hf_wtp_reassembled_in               = HF_EMPTY;
 
 /* Initialize the subtree pointers */
 static gint ett_wtp                            = ETT_EMPTY;
+static gint ett_wtp_sub_pdu_tree       = ETT_EMPTY;
 static gint ett_header                                 = ETT_EMPTY;
 static gint ett_tpilist                        = ETT_EMPTY;
 static gint ett_wsp_fragments                  = ETT_EMPTY;
@@ -213,6 +215,7 @@ static const fragment_items wtp_frag_items = {
     &hf_wtp_fragment_multiple_tails,
     &hf_wtp_fragment_too_long_fragment,
     &hf_wtp_fragment_error,
+    &hf_wtp_reassembled_in,
     "fragments"
 };
 
@@ -307,7 +310,7 @@ wtp_handle_tpi(proto_tree *tree, tvbuff_t *tvb)
 static void
 dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-    char       szInfo[50];
+    static GString *szInfo = NULL;
     int                offCur          = 0; /* current offset from start of WTP data */
 
     unsigned char  b0;
@@ -321,18 +324,21 @@ dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     int                abortType       = 0;
 
     /* Set up structures we'll need to add the protocol subtree and manage it */
-    proto_item         *ti;
+    proto_item         *ti = NULL;
     proto_tree         *wtp_tree = NULL;
 
     char               pdut;
     char               clsTransaction  = ' ';
-    int                        cchInfo;
     int                        numMissing = 0;         /* Number of missing packets in a negative ack */
     int                        i;
     tvbuff_t           *wsp_tvb = NULL;
-    fragment_data      *fd_head = NULL;
     guint8             psn = 0;                /* Packet sequence number*/
     guint16            TID = 0;                /* Transaction-Id       */
+    int                        dataOffset;
+    gint               dataLen;
+
+    if (szInfo == NULL)
+       szInfo = g_string_sized_new(32);
 
     b0 = tvb_get_guint8 (tvb, offCur + 0);
     /* Discover Concatenated PDUs */
@@ -343,11 +349,19 @@ dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        if (tree) {
            ti = proto_tree_add_item(tree, proto_wtp,
                                    tvb, offCur, 1, bo_little_endian);
-           wtp_tree = proto_item_add_subtree(ti, ett_wtp);
+           wtp_tree = proto_item_add_subtree(ti, ett_wtp_sub_pdu_tree);
+               proto_item_append_text(ti, ", PDU concatenation");
        }
        offCur = 1;
        i = 1;
        while (offCur < (int) tvb_reported_length(tvb)) {
+           tvbuff_t *wtp_tvb;
+           /* The length of an embedded WTP PDU is coded as either:
+            *  - a 7-bit value contained in one octet with highest bit == 0.
+            *  - a 15-bit value contained in two octets (little endian)
+            *    if the 1st octet has its highest bit == 1.
+            * This means that this is NOT encoded as an uintvar-integer!!!
+            */
            b0 = tvb_get_guint8(tvb, offCur + 0);
            if (b0 & 0x80) {
                c_fieldlen = 2;
@@ -357,26 +371,37 @@ dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                c_pdulen = b0;
            }
            if (tree) {
-               proto_tree_add_item(wtp_tree, hf_wtp_header_sub_pdu_size,
-                                   tvb, offCur, c_fieldlen, bo_big_endian);
+               proto_tree_add_uint(wtp_tree, hf_wtp_header_sub_pdu_size,
+                                   tvb, offCur, c_fieldlen, c_pdulen);
            }
            if (i > 1 && check_col(pinfo->cinfo, COL_INFO)) {
                col_append_str(pinfo->cinfo, COL_INFO, ", ");
            }
-           wsp_tvb = tvb_new_subset(tvb, offCur + c_fieldlen, -1, c_pdulen);
-           dissect_wtp_common(wsp_tvb, pinfo, wtp_tree);
+           /* Skip the length field for the WTP sub-tvb */
+           wtp_tvb = tvb_new_subset(tvb, offCur + c_fieldlen, c_pdulen, c_pdulen);
+           dissect_wtp_common(wtp_tvb, pinfo, wtp_tree);
            offCur += c_fieldlen + c_pdulen;
            i++;
        }
+       if (tree) {
+               proto_item_append_text(ti, ", PDU count: %u", i);
+       }
        return;
     }
+    /* No concatenation */
     fCon = b0 & 0x80;
     fRID = retransmission_indicator(b0);
     pdut = pdu_type(b0);
 
+#ifdef DEBUG
+       printf("WTP packet %u: tree = %p, pdu = %s (%u) length: %u\n",
+                       pinfo->fd->num, tree,
+                       match_strval(pdut, vals_wtp_pdu_type), pdut, tvb_length(tvb));
+#endif
+
     /* Develop the string to put in the Info column */
-    cchInfo = snprintf(szInfo, sizeof( szInfo ), "WTP %s",
-                   val_to_str(pdut, vals_pdu_type, "Unknown PDU type 0x%x"));
+    g_string_sprintf(szInfo, "WTP %s",
+                   val_to_str(pdut, vals_wtp_pdu_type, "Unknown PDU type 0x%x"));
 
     switch (pdut) {
        case INVOKE:
@@ -384,8 +409,7 @@ dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
            TID = tvb_get_ntohs(tvb, offCur + 1);
            psn = 0;
            clsTransaction = transaction_class(tvb_get_guint8(tvb, offCur + 3));
-           snprintf(szInfo + cchInfo, sizeof(szInfo) - cchInfo,
-                    " Class %d", clsTransaction);
+           g_string_sprintfa(szInfo, " Class %d", clsTransaction);
            cbHeader = 4;
            break;
 
@@ -394,6 +418,8 @@ dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
            fTTR = transmission_trailer(b0);
            TID = tvb_get_ntohs(tvb, offCur + 1);
            psn = tvb_get_guint8(tvb, offCur + 3);
+           if (psn != 0)
+               g_string_sprintfa(szInfo, " (%u)", psn);
            cbHeader = 4;
            break;
 
@@ -422,38 +448,7 @@ dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
            break;
     };
     if (fRID) {
-       strcat( szInfo, " R" );
-    };
-    if (fCon) {                                /* Scan variable part (TPI's),  */
-                                       /* determine length of it       */
-       unsigned char   tCon;
-       unsigned char   tByte;
-
-       do {
-           tByte = tvb_get_guint8(tvb, offCur + cbHeader + vHeader);
-           tCon = tByte & 0x80;
-           if (tByte & 0x04)   /* Long format  */
-               vHeader = vHeader + tvb_get_guint8(tvb,
-                                       offCur + cbHeader + vHeader + 1) + 2;
-           else
-               vHeader = vHeader + (tByte & 0x03) + 1;
-       } while (tCon);
-    }
-
-#ifdef DEBUG
-    fprintf( stderr, "dissect_wtp: cbHeader = %d\n", cbHeader );
-#endif
-
-    /* Only update "Info" column when no data in this PDU will
-     * be handed off to a subsequent dissector.
-     */
-    if (check_col(pinfo->cinfo, COL_INFO) &&
-       ((tvb_length_remaining(tvb, offCur + cbHeader + vHeader) <= 0) ||
-        (pdut == ACK) || (pdut==NEGATIVE_ACK) || (pdut==ABORT)) ) {
-#ifdef DEBUG
-       fprintf(stderr, "dissect_wtp: (6) About to set info_col header to %s\n", szInfo);
-#endif
-       col_append_str(pinfo->cinfo, COL_INFO, szInfo);
+       g_string_append( szInfo, " R" );
     };
     /* In the interest of speed, if "tree" is NULL, don't do any work not
        necessary to generate protocol tree items. */
@@ -461,7 +456,8 @@ dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 #ifdef DEBUG
        fprintf(stderr, "dissect_wtp: cbHeader = %d\n", cbHeader);
 #endif
-       ti = proto_tree_add_item(tree, proto_wtp, tvb, offCur, cbHeader + vHeader, bo_little_endian);
+       /* NOTE - Length will be set when we process the TPI */
+       ti = proto_tree_add_item(tree, proto_wtp, tvb, offCur, 0, bo_little_endian);
 #ifdef DEBUG
        fprintf(stderr, "dissect_wtp: (7) Returned from proto_tree_add_item\n");
 #endif
@@ -495,6 +491,12 @@ dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_flag_UP, tvb, offCur + 3, 1, bo_little_endian);
                proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_Reserved, tvb, offCur + 3, 1, bo_little_endian);
                proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_TransactionClass, tvb, offCur + 3, 1, bo_little_endian);
+               proto_item_append_text(ti,
+                               ", PDU: Invoke (%u)"
+                               ", Transaction Class: %s (%u)",
+                               INVOKE,
+                               match_strval(clsTransaction, vals_transaction_classes),
+                               clsTransaction);
                break;
 
            case RESULT:
@@ -502,6 +504,7 @@ dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian);
                proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian);
                proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian);
+               proto_item_append_text(ti, ", PDU: Result (%u)", RESULT);
                break;
 
            case ACK:
@@ -510,6 +513,7 @@ dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, bo_little_endian);
                proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, bo_big_endian);
                proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian);
+               proto_item_append_text(ti, ", PDU: ACK (%u)", ACK);
                break;
 
            case ABORT:
@@ -520,11 +524,29 @@ dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
                if (abortType == PROVIDER)
                {
+                       guint8 reason = tvb_get_guint8(tvb, offCur + 3);
                    proto_tree_add_item( wtp_tree, hf_wtp_header_Abort_reason_provider , tvb, offCur + 3 , 1, bo_little_endian);
+                       proto_item_append_text(ti,
+                                       ", PDU: Abort (%u)"
+                                       ", Type: Provider (%u)"
+                                       ", Reason: %s (%u)",
+                                       ABORT,
+                                       PROVIDER,
+                                       match_strval(reason, vals_abort_reason_provider), 
+                                       reason);
                }
                else if (abortType == USER)
                {
+                       guint8 reason = tvb_get_guint8(tvb, offCur + 3);
                    proto_tree_add_item(wtp_tree, hf_wtp_header_Abort_reason_user , tvb, offCur + 3 , 1, bo_little_endian);
+                       proto_item_append_text(ti,
+                                       ", PDU: Abort (%u)"
+                                       ", Type: User (%u)"
+                                       ", Reason: %s (%u)",
+                                       ABORT,
+                                       PROVIDER,
+                                       match_strval(reason, vals_wsp_reason_codes), 
+                                       reason);
                }
                break;
 
@@ -535,6 +557,10 @@ dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian);
 
                proto_tree_add_item(wtp_tree, hf_wtp_header_sequence_number , tvb, offCur + 3, 1, bo_little_endian);
+               proto_item_append_text(ti,
+                               ", PDU: Segmented Invoke (%u)"
+                               ", Packet Sequence Number: %u",
+                               SEGMENTED_INVOKE, psn);
                break;
 
            case SEGMENTED_RESULT:
@@ -544,6 +570,10 @@ dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, bo_big_endian);
 
                proto_tree_add_item(wtp_tree, hf_wtp_header_sequence_number , tvb, offCur + 3, 1, bo_little_endian);
+               proto_item_append_text(ti,
+                               ", PDU: Segmented Result (%u)"
+                               ", Packet Sequence Number: %u",
+                               SEGMENTED_RESULT, psn);
                break;
 
            case NEGATIVE_ACK:
@@ -557,11 +587,24 @@ dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                {
                    proto_tree_add_item(wtp_tree, hf_wtp_header_sequence_number, tvb, offCur + 4 + i, 1, bo_little_endian);
                }
+               proto_item_append_text(ti,
+                               ", PDU: Negative Ack (%u)"
+                               ", Missing Packets: %u",
+                               NEGATIVE_ACK, numMissing);
                break;
 
            default:
                break;
        };
+       if (fRID) {
+               proto_item_append_text(ti, ", Retransmission");
+       }
+    } else { /* tree is NULL */
+#ifdef DEBUG
+       fprintf(stderr, "dissect_wtp: (4) tree was %p\n", tree);
+#endif
+    }
+       /* Process the variable part */
        if (fCon) {                     /* Now, analyze variable part   */
            unsigned char        tCon;
            unsigned char        tByte;
@@ -578,71 +621,155 @@ dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                                            offCur + cbHeader + vHeader + 1);
                else
                    tpiLen = 1 + (tByte & 0x03);
+               if (tree)
+               {
                tmp_tvb = tvb_new_subset(tvb, offCur + cbHeader + vHeader,
                                        tpiLen, tpiLen);
                wtp_handle_tpi(wtp_tree, tmp_tvb);
+               }
                vHeader += tpiLen;
            } while (tCon);
        } else {
                /* There is no variable part */
        }       /* End of variable part of header */
-    } else {
+
+       /* Set the length of the WTP protocol part now we know the length of the
+        * fixed and variable WTP headers */
+       if (tree)
+       proto_item_set_len(ti, cbHeader + vHeader);
+
 #ifdef DEBUG
-       fprintf(stderr, "dissect_wtp: (4) tree was %p\n", tree);
+    fprintf( stderr, "dissect_wtp: cbHeader = %d\n", cbHeader );
 #endif
-    }
+
     /*
      * Any remaining data ought to be WSP data (if not WTP ACK, NACK
-     * or ABORT pdu), so hand off (defragmented) to the WSP dissector
-     */
-    if ((tvb_reported_length_remaining(tvb, offCur + cbHeader + vHeader) > 0) &&
-       ! ((pdut==ACK) || (pdut==NEGATIVE_ACK) || (pdut==ABORT)))
+     * or ABORT pdu), so, if we have any remaining data, and it's
+     * not an ACK, NACK, or ABORT PDU, hand it off (defragmented) to the
+     * WSP dissector.
+     * Note that the last packet of a fragmented WTP message needn't
+     * contain any data, so we allow payloadless packets to be
+     * reassembled.  (XXX - does the reassembly code handle this
+     * for packets other than the last packet?)
+     *
+        * Try calling a subdissector only if:
+        *      - The WTP payload is ressembled in this very packet,
+        *      - The WTP payload is not fragmented across packets.
+        */
+    dataOffset = offCur + cbHeader + vHeader;
+    dataLen = tvb_reported_length_remaining(tvb, dataOffset);
+    if ((dataLen >= 0) &&
+                       ! ((pdut==ACK) || (pdut==NEGATIVE_ACK) || (pdut==ABORT)))
     {
-       int     dataOffset = offCur + cbHeader + vHeader;
-       gint    dataLen = tvb_reported_length_remaining(tvb, dataOffset);
-       gboolean save_fragmented;
-
-       if (((pdut == SEGMENTED_INVOKE) || (pdut == SEGMENTED_RESULT) ||
-           (((pdut == INVOKE) || (pdut == RESULT)) && (!fTTR))) &&
-           tvb_bytes_exist(tvb, dataOffset, dataLen))
-       {                                       /* 1st part of segment  */
-           save_fragmented = pinfo->fragmented;
-           pinfo->fragmented = TRUE;
-           fd_head = fragment_add_seq(tvb, dataOffset, pinfo, TID,
-                           wtp_fragment_table, psn, dataLen, !fTTR);
-           if (fd_head != NULL)                /* Reassembled  */
-           {
-               wsp_tvb = tvb_new_real_data(fd_head->data,
-                                           fd_head->len,
-                                           fd_head->len);
-               tvb_set_child_real_data_tvbuff(tvb, wsp_tvb);
-               add_new_data_source(pinfo, wsp_tvb,
-                                       "Reassembled WTP");
-               pinfo->fragmented = FALSE;
-
-               /* show all fragments */
-               show_fragment_seq_tree(fd_head, &wtp_frag_items,
-                                       wtp_tree, pinfo, wsp_tvb);
-
-               call_dissector(wsp_handle, wsp_tvb, pinfo, tree);
-           }
-           else
-           {
-               if (check_col(pinfo->cinfo, COL_INFO))          /* Won't call WSP so display */
-                   col_append_str(pinfo->cinfo, COL_INFO, szInfo);
-           }
-           pinfo->fragmented = save_fragmented;
+               /* Try to reassemble if needed, and hand over to WSP
+                * A fragmented WTP packet is either:
+                *      - An INVOKE with fTTR (transmission trailer) not set,
+                *      - a SEGMENTED_INVOKE,
+                *      - A RESULT with fTTR (transmission trailer) not set,
+                *      - a SEGMENTED_RESULT.
+                */
+               if ( ( (pdut == SEGMENTED_INVOKE) || (pdut == SEGMENTED_RESULT)
+                               || ( ((pdut == INVOKE) || (pdut == RESULT)) && (!fTTR) )
+                       ) && tvb_bytes_exist(tvb, dataOffset, dataLen) )
+               {
+                       /* Try reassembling fragments */
+                       fragment_data *fd_wtp = NULL;
+                       guint32 reassembled_in = 0;
+                       gboolean save_fragmented = pinfo->fragmented;
+
+                       pinfo->fragmented = TRUE;
+                       fd_wtp = fragment_add_seq(tvb, dataOffset, pinfo, TID,
+                                       wtp_fragment_table, psn, dataLen, !fTTR);
+                       /* XXX - fragment_add_seq() yields NULL unless Ethereal knows
+                        * that the packet is part of a reassembled whole. This means
+                        * that fd_wtp will be NULL as long as Ethereal did not encounter
+                        * (and process) the packet containing the last fragment.
+                        * This implies that Ethereal needs two passes over the data for
+                        * correct reassembly. At the first pass, a capture containing
+                        * three fragments plus a retransmssion of the last fragment
+                        * will progressively show:
+                        *
+                        *              Packet 1: (Unreassembled fragment 1)
+                        *              Packet 2: (Unreassembled fragment 2)
+                        *              Packet 3: (Reassembled WTP)
+                        *              Packet 4: (WTP payload reassembled in packet 3)
+                        *
+                        * However at subsequent evaluation (e.g., by applying a display
+                        * filter) the packet summary will show:
+                        *
+                        *              Packet 1: (WTP payload reassembled in packet 3)
+                        *              Packet 2: (WTP payload reassembled in packet 3)
+                        *              Packet 3: (Reassembled WTP)
+                        *              Packet 4: (WTP payload reassembled in packet 3)
+                        *
+                        * This is important to know, and also affects read filters!
+                        */
+                       wsp_tvb = process_reassembled_data(tvb, dataOffset, pinfo,
+                                       "Reassembled WTP", fd_wtp, &wtp_frag_items,
+                                       NULL, wtp_tree);
+#ifdef DEBUG
+                       printf("WTP: Packet %u %s -> %d: wsp_tvb = %p, fd_wtp = %p, frame = %u\n",
+                                       pinfo->fd->num,
+                                       fd_wtp ? "Reassembled" : "Not reassembled",
+                                       fd_wtp ? fd_wtp->reassembled_in : -1,
+                                       wsp_tvb,
+                                       fd_wtp
+                                       );
+#endif
+                       if (fd_wtp) {
+                               /* Reassembled */
+                               reassembled_in = fd_wtp->reassembled_in;
+                               if (pinfo->fd->num == reassembled_in) {
+                                       /* Reassembled in this very packet:
+                                        * We can safely hand the tvb to the WSP dissector */
+                                       call_dissector(wsp_handle, wsp_tvb, pinfo, tree);
+                               } else {
+                                       /* Not reassembled in this packet */
+                                       if (check_col(pinfo->cinfo, COL_INFO)) {
+                                               col_append_fstr(pinfo->cinfo, COL_INFO,
+                                                               "%s (WTP payload reassembled in packet %u)",
+                                                               szInfo->str, fd_wtp->reassembled_in);
+                                       }
+                                       if (tree) {
+                                               proto_tree_add_text(wtp_tree, tvb, dataOffset, -1,
+                                                               "Payload");
+                                       }
+                               }
+                       } else {
+                               /* Not reassembled yet, or not reassembled at all */
+                               if (check_col(pinfo->cinfo, COL_INFO)) {
+                                       col_append_fstr(pinfo->cinfo, COL_INFO,
+                                                               "%s (Unreassembled fragment %u)",
+                                                               szInfo->str, psn);
+                               }
+                               if (tree) {
+                                       proto_tree_add_text(wtp_tree, tvb, dataOffset, -1,
+                                                       "Payload");
+                               }
+                       }
+                       /* Now reset fragmentation information in pinfo */
+                       pinfo->fragmented = save_fragmented;
+               }
+               else if ( ((pdut == INVOKE) || (pdut == RESULT)) && (fTTR) )
+               {
+                       /* Non-fragmented payload */
+                       wsp_tvb = tvb_new_subset(tvb, dataOffset, -1, -1);
+                       /* We can safely hand the tvb to the WSP dissector */
+                       call_dissector(wsp_handle, wsp_tvb, pinfo, tree);
+               }
+               else
+               {
+                       /* Nothing to hand to subdissector */
+                       if (check_col(pinfo->cinfo, COL_INFO))
+                               col_append_str(pinfo->cinfo, COL_INFO, szInfo->str);
+               }
        }
        else
        {
-           /*
-            * Normal packet, or not all the fragment data is available;
-            * call next dissector.
-            */
-           wsp_tvb = tvb_new_subset(tvb, dataOffset, -1, -1);
-           call_dissector(wsp_handle, wsp_tvb, pinfo, tree);
+               /* Nothing to hand to subdissector */
+               if (check_col(pinfo->cinfo, COL_INFO))
+                       col_append_str(pinfo->cinfo, COL_INFO, szInfo->str);
        }
-    }
 }
 
 /*
@@ -670,7 +797,7 @@ dissect_wtp_fromudp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
  * XXX - can this be called from any other dissector?
  */
 static void
-dissect_wtp_fromwap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_wtp_fromwtls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
     if (check_col(pinfo->cinfo, COL_PROTOCOL))
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "WTLS+WTP+WSP" );
@@ -690,8 +817,8 @@ proto_register_wtp(void)
        { &hf_wtp_header_sub_pdu_size,
            {   "Sub PDU size",
                "wtp.sub_pdu_size",
-               FT_BYTES, BASE_HEX, NULL, 0x0,
-               "Size of Sub-PDU", HFILL
+               FT_UINT16, BASE_DEC, NULL, 0x0,
+               "Size of Sub-PDU (bytes)", HFILL
            }
        },
        { &hf_wtp_header_flag_continue,
@@ -704,7 +831,7 @@ proto_register_wtp(void)
        { &hf_wtp_header_pdu_type,
            {   "PDU Type",
                "wtp.pdu_type",
-               FT_UINT8, BASE_HEX, VALS( vals_pdu_type ), 0x78,
+               FT_UINT8, BASE_HEX, VALS( vals_wtp_pdu_type ), 0x78,
                "PDU Type", HFILL
            }
        },
@@ -900,6 +1027,13 @@ proto_register_wtp(void)
                "Defragmentation error due to illegal fragments", HFILL
            }
        },
+       { &hf_wtp_reassembled_in,
+           {   "Reassembled in",
+               "wtp.reassembled.in",
+               FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+               "WTP fragments are reassembled in the given packet", HFILL
+           }
+       },
        { &hf_wtp_fragment,
            {   "WTP Fragment",
                "wtp.fragment",
@@ -919,6 +1053,7 @@ proto_register_wtp(void)
     /* Setup protocol subtree array */
     static gint *ett[] = {
        &ett_wtp,
+       &ett_wtp_sub_pdu_tree,
        &ett_header,
        &ett_tpilist,
        &ett_wsp_fragments,
@@ -929,8 +1064,8 @@ proto_register_wtp(void)
     proto_wtp = proto_register_protocol(
        "Wireless Transaction Protocol",   /* protocol name for use by ethereal */
        "WTP",                             /* short version of name */
-       "wap-wsp-wtp"                      /* Abbreviated protocol name, should Match IANA
-                                           < URL:http://www.isi.edu/in-notes/iana/assignments/port-numbers/ >
+       "wtp"                      /* Abbreviated protocol name, should Match IANA
+                                           < URL:http://www.iana.org/assignments/port-numbers/ >
                                            */
     );
 
@@ -938,10 +1073,10 @@ proto_register_wtp(void)
     proto_register_field_array(proto_wtp, hf, array_length(hf));
     proto_register_subtree_array(ett, array_length(ett));
 
-    register_dissector("wtp", dissect_wtp_fromwap, proto_wtp);
+    register_dissector("wtp-wtls", dissect_wtp_fromwtls, proto_wtp);
     register_dissector("wtp-udp", dissect_wtp_fromudp, proto_wtp);
     register_init_routine(wtp_defragment_init);
-};
+}
 
 void
 proto_reg_handoff_wtp(void)
@@ -956,4 +1091,5 @@ proto_reg_handoff_wtp(void)
 
     wtp_fromudp_handle = find_dissector("wtp-udp");
     dissector_add("udp.port", UDP_PORT_WTP_WSP, wtp_fromudp_handle);
+    dissector_add("gsm-sms-ud.udh.port", UDP_PORT_WTP_WSP, wtp_fromudp_handle);
 }