Use ENC_NA as encoding for proto_tree_add_item() calls which directly reference an...
[obnox/wireshark/wip.git] / epan / dissectors / packet-rpc.c
index d146ce2263d25fcf7ec7199bb5f434672827c10a..3895923263375f5b37935ecaf2a8bb66559a0a75 100644 (file)
@@ -4,8 +4,8 @@
  *
  * $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
  *
  * Copied from packet-smb.c
 #endif
 
 #include <glib.h>
-#include <stdio.h>
 #include <string.h>
 #include <ctype.h>
 #include <epan/packet.h>
 #include <epan/conversation.h>
+#include <epan/emem.h>
 #include "packet-rpc.h"
 #include "packet-frame.h"
 #include "packet-tcp.h"
@@ -43,8 +43,8 @@
 #include <epan/dissectors/rpc_defrag.h>
 #include "packet-nfs.h"
 #include <epan/tap.h>
-#include <epan/emem.h>
 #include <epan/strutil.h>
+#include <epan/garrayfix.h>
 
 /*
  * See:
@@ -70,7 +70,7 @@ static gboolean rpc_desegment = TRUE;
 static gboolean rpc_defragment = TRUE;
 
 /* try to dissect RPC packets for programs that are not known
- * (proprietary ones) by ethereal.
+ * (proprietary ones) by wireshark.
  */
 static gboolean rpc_dissect_unknown_programs = FALSE;
 
@@ -79,8 +79,6 @@ static gboolean rpc_dissect_unknown_programs = FALSE;
  */
 static gboolean rpc_find_fragment_start = FALSE;
 
-static struct true_false_string yesno = { "Yes", "No" };
-
 static int rpc_tap = -1;
 
 static const value_string rpc_msg_type[] = {
@@ -102,6 +100,15 @@ const value_string rpc_auth_flavor[] = {
        { AUTH_DES, "AUTH_DES" },
        { RPCSEC_GSS, "RPCSEC_GSS" },
        { AUTH_GSSAPI, "AUTH_GSSAPI" },
+       { RPCSEC_GSS_KRB5, "RPCSEC_GSS_KRB5" },
+       { RPCSEC_GSS_KRB5I, "RPCSEC_GSS_KRB5I" },
+       { RPCSEC_GSS_KRB5P, "RPCSEC_GSS_KRB5P" },
+       { RPCSEC_GSS_LIPKEY, "RPCSEC_GSS_LIPKEY" },
+       { RPCSEC_GSS_LIPKEY_I, "RPCSEC_GSS_LIPKEY_I" },
+       { RPCSEC_GSS_LIPKEY_P, "RPCSEC_GSS_LIPKEY_P" },
+       { RPCSEC_GSS_SPKM3, "RPCSEC_GSS_SPKM3" },
+       { RPCSEC_GSS_SPKM3I, "RPCSEC_GSS_SPKM3I" },
+       { RPCSEC_GSS_SPKM3P, "RPCSEC_GSS_SPKM3P" },
        { 0, NULL }
 };
 
@@ -122,7 +129,7 @@ static const value_string rpc_authgssapi_proc[] = {
        { 0, NULL }
 };
 
-value_string rpc_authgss_svc[] = {
+const value_string rpc_authgss_svc[] = {
        { RPCSEC_GSS_SVC_NONE, "rpcsec_gss_svc_none" },
        { RPCSEC_GSS_SVC_INTEGRITY, "rpcsec_gss_svc_integrity" },
        { RPCSEC_GSS_SVC_PRIVACY, "rpcsec_gss_svc_privacy" },
@@ -195,6 +202,7 @@ static int hf_rpc_authgss_window = -1;
 static int hf_rpc_authgss_token_length = -1;
 static int hf_rpc_authgss_data_length = -1;
 static int hf_rpc_authgss_data = -1;
+static int hf_rpc_authgss_token = -1;
 static int hf_rpc_authgss_checksum = -1;
 static int hf_rpc_authgssapi_v = -1;
 static int hf_rpc_authgssapi_msg = -1;
@@ -226,6 +234,8 @@ static int hf_rpc_fragment_overlap_conflict = -1;
 static int hf_rpc_fragment_multiple_tails = -1;
 static int hf_rpc_fragment_too_long_fragment = -1;
 static int hf_rpc_fragment_error = -1;
+static int hf_rpc_fragment_count = -1;
+static int hf_rpc_reassembled_length = -1;
 
 static gint ett_rpc = -1;
 static gint ett_rpc_unknown_program = -1;
@@ -246,7 +256,7 @@ static dissector_handle_t rpc_handle;
 static dissector_handle_t gssapi_handle;
 static dissector_handle_t data_handle;
 
-static guint max_rpc_tcp_pdu_size = 262144;
+static guint max_rpc_tcp_pdu_size = 4 * 1024 * 1024;
 
 static const fragment_items rpc_frag_items = {
        &ett_rpc_fragment,
@@ -258,7 +268,9 @@ static const fragment_items rpc_frag_items = {
        &hf_rpc_fragment_multiple_tails,
        &hf_rpc_fragment_too_long_fragment,
        &hf_rpc_fragment_error,
+       &hf_rpc_fragment_count,
        NULL,
+       &hf_rpc_reassembled_length,
        "fragments"
 };
 
@@ -345,7 +357,6 @@ rpc_proc_name(guint32 prog, guint32 vers, guint32 proc)
        rpc_proc_info_value *value;
        char *procname;
 
-       procname=ep_alloc(20);
        key.prog = prog;
        key.vers = vers;
        key.proc = proc;
@@ -355,7 +366,7 @@ rpc_proc_name(guint32 prog, guint32 vers, guint32 proc)
        else {
                /* happens only with strange program versions or
                   non-existing dissectors */
-               g_snprintf(procname, 20, "proc-%u", key.proc);
+               procname = ep_strdup_printf("proc-%u", key.proc);
        }
        return procname;
 }
@@ -414,7 +425,8 @@ rpc_init_prog(int proto, guint32 prog, int ett)
 
 /*     return the hf_field associated with a previously registered program.
 */
-int rpc_prog_hf(guint32 prog, guint32 vers)
+int
+rpc_prog_hf(guint32 prog, guint32 vers)
 {
        rpc_prog_info_key       rpc_prog_key;
        rpc_prog_info_value     *rpc_prog;
@@ -428,8 +440,9 @@ int rpc_prog_hf(guint32 prog, guint32 vers)
 
 /*     return the name associated with a previously registered program. This
        should probably eventually be expanded to use the rpc YP/NIS map
-       so that it can give names for programs not handled by ethereal */
-const char *rpc_prog_name(guint32 prog)
+       so that it can give names for programs not handled by wireshark */
+const char *
+rpc_prog_name(guint32 prog)
 {
        const char *progname = NULL;
        rpc_prog_info_key       rpc_prog_key;
@@ -450,48 +463,30 @@ const char *rpc_prog_name(guint32 prog)
 /* end of Hash array with program names */
 /*--------------------------------------*/
 
-typedef struct _rpc_call_info_key {
-       guint32 xid;
-       conversation_t *conversation;
-} rpc_call_info_key;
-
-static GHashTable *rpc_calls = NULL;
-
-static GHashTable *rpc_indir_calls = NULL;
-
-/* compare 2 keys */
-static gint
-rpc_call_equal(gconstpointer k1, gconstpointer k2)
-{
-       const rpc_call_info_key* key1 = (const rpc_call_info_key*) k1;
-       const rpc_call_info_key* key2 = (const rpc_call_info_key*) k2;
-
-       return (key1->xid == key2->xid &&
-           key1->conversation == key2->conversation);
-}
-
-
-/* calculate a hash key */
-static guint
-rpc_call_hash(gconstpointer k)
-{
-       const rpc_call_info_key* key = (const rpc_call_info_key*) k;
-
-       return key->xid + GPOINTER_TO_UINT(key->conversation);
-}
+/* One of these structures are created for each conversation that contains
+ * RPC and contains the state we need to maintain for the conversation.
+ */
+typedef struct _rpc_conv_info_t {
+        emem_tree_t *xids;
+} rpc_conv_info_t;
 
 
 unsigned int
 rpc_roundup(unsigned int a)
 {
        unsigned int mod = a % 4;
-       return a + ((mod)? 4-mod : 0);
+        unsigned int ret;
+       ret = a + ((mod)? 4-mod : 0);
+        /* Check for overflow */
+        if (ret < a)
+               THROW(ReportedBoundsError);
+       return ret;
 }
 
 
 int
 dissect_rpc_bool(tvbuff_t *tvb, proto_tree *tree,
-int hfindex, int offset)
+                int hfindex, int offset)
 {
        if (tree)
                proto_tree_add_item(tree, hfindex, tvb, offset, 4, FALSE);
@@ -501,7 +496,7 @@ int hfindex, int offset)
 
 int
 dissect_rpc_uint32(tvbuff_t *tvb, proto_tree *tree,
-int hfindex, int offset)
+                  int hfindex, int offset)
 {
        if (tree)
                proto_tree_add_item(tree, hfindex, tvb, offset, 4, FALSE);
@@ -511,7 +506,7 @@ int hfindex, int offset)
 
 int
 dissect_rpc_uint64(tvbuff_t *tvb, proto_tree *tree,
-int hfindex, int offset)
+                  int hfindex, int offset)
 {
        header_field_info       *hfinfo;
 
@@ -619,9 +614,7 @@ dissect_rpc_opaque_data(tvbuff_t *tvb, int offset,
         }
 
        if (string_data) {
-               char *tmpstr;
-               tmpstr = tvb_get_ephemeral_string(tvb, data_offset, string_length_copy);
-               string_buffer = memcpy(ep_alloc(string_length_copy+1), tmpstr, string_length_copy);
+               string_buffer = tvb_get_ephemeral_string(tvb, data_offset, string_length_copy);
        } else {
                string_buffer = tvb_memcpy(tvb, ep_alloc(string_length_copy+1), data_offset, string_length_copy);
        }
@@ -633,24 +626,21 @@ dissect_rpc_opaque_data(tvbuff_t *tvb, int offset,
                                char *formatted;
 
                                formatted = format_text(string_buffer, strlen(string_buffer));
-                               /* alloc maximum data area */
-#define STRING_BUFFER_PRINT_MAX_LEN (strlen(formatted)+12+1)
-                               string_buffer_print = (char*)ep_alloc(STRING_BUFFER_PRINT_MAX_LEN);
                                /* copy over the data and append <TRUNCATED> */
-                               g_snprintf(string_buffer_print, STRING_BUFFER_PRINT_MAX_LEN, "%s<TRUNCATED>", formatted);
+                               string_buffer_print=ep_strdup_printf("%s%s", formatted, RPC_STRING_TRUNCATED);
                        } else {
-                               string_buffer_print="<DATA><TRUNCATED>";
+                               string_buffer_print=RPC_STRING_DATA RPC_STRING_TRUNCATED;
                        }
                } else {
                        if (string_data) {
                                string_buffer_print =
                                    ep_strdup(format_text(string_buffer, strlen(string_buffer)));
                        } else {
-                               string_buffer_print="<DATA>";
+                               string_buffer_print=RPC_STRING_DATA;
                        }
                }
        } else {
-               string_buffer_print="<EMPTY>";
+               string_buffer_print=RPC_STRING_EMPTY;
        }
 
        if (tree) {
@@ -896,7 +886,7 @@ dissect_rpc_authgss_cred(tvbuff_t* tvb, proto_tree* tree, int offset)
 
 static int
 dissect_rpc_authdes_desblock(tvbuff_t *tvb, proto_tree *tree,
-int hfindex, int offset)
+                            int hfindex, int offset)
 {
        guint32 value_low;
        guint32 value_high;
@@ -1035,7 +1025,7 @@ dissect_rpc_cred(tvbuff_t* tvb, proto_tree* tree, int offset)
  */
 static int
 dissect_rpc_authgss_token(tvbuff_t* tvb, proto_tree* tree, int offset,
-    packet_info *pinfo)
+    packet_info *pinfo, int hfindex)
 {
        guint32 opaque_length, rounded_length;
        gint len_consumed, length, reported_length;
@@ -1047,26 +1037,27 @@ dissect_rpc_authgss_token(tvbuff_t* tvb, proto_tree* tree, int offset,
        opaque_length = tvb_get_ntohl(tvb, offset+0);
        rounded_length = rpc_roundup(opaque_length);
        if (tree) {
-               gitem = proto_tree_add_text(tree, tvb, offset,
-                                           4+rounded_length, "GSS Token");
+               gitem = proto_tree_add_item(tree, hfindex, tvb, offset, 4+rounded_length, FALSE);
                gtree = proto_item_add_subtree(gitem, ett_rpc_gss_token);
                proto_tree_add_uint(gtree, hf_rpc_authgss_token_length,
                                    tvb, offset+0, 4, opaque_length);
        }
        offset += 4;
-       length = tvb_length_remaining(tvb, offset);
-       reported_length = tvb_reported_length_remaining(tvb, offset);
-       DISSECTOR_ASSERT(length >= 0);
-       DISSECTOR_ASSERT(reported_length >= 0);
-       if (length > reported_length)
-               length = reported_length;
-       if ((guint32)length > opaque_length)
-               length = opaque_length;
-       if ((guint32)reported_length > opaque_length)
-               reported_length = opaque_length;
-       new_tvb = tvb_new_subset(tvb, offset, length, reported_length);
-       len_consumed = call_dissector(gssapi_handle, new_tvb, pinfo, gtree);
-       offset += len_consumed;
+       if (opaque_length != 0) {
+               length = tvb_length_remaining(tvb, offset);
+               reported_length = tvb_reported_length_remaining(tvb, offset);
+               DISSECTOR_ASSERT(length >= 0);
+               DISSECTOR_ASSERT(reported_length >= 0);
+               if (length > reported_length)
+                       length = reported_length;
+               if ((guint32)length > opaque_length)
+                       length = opaque_length;
+               if ((guint32)reported_length > opaque_length)
+                       reported_length = opaque_length;
+               new_tvb = tvb_new_subset(tvb, offset, length, reported_length);
+               len_consumed = call_dissector(gssapi_handle, new_tvb, pinfo, gtree);
+               offset += len_consumed;
+       }
        offset = rpc_roundup(offset);
        return offset;
 }
@@ -1128,7 +1119,7 @@ dissect_rpc_verf(tvbuff_t* tvb, proto_tree* tree, int offset, int msg_type,
                        }
                        break;
                case RPCSEC_GSS:
-                       dissect_rpc_authgss_token(tvb, vtree, offset+4, pinfo);
+                       dissect_rpc_authgss_token(tvb, vtree, offset+4, pinfo, hf_rpc_authgss_token);
                        break;
                default:
                        proto_tree_add_uint(vtree, hf_rpc_auth_length, tvb,
@@ -1148,7 +1139,7 @@ static int
 dissect_rpc_authgss_initarg(tvbuff_t* tvb, proto_tree* tree, int offset,
     packet_info *pinfo)
 {
-       return dissect_rpc_authgss_token(tvb, tree, offset, pinfo);
+       return dissect_rpc_authgss_token(tvb, tree, offset, pinfo, hf_rpc_authgss_token);
 }
 
 static int
@@ -1178,7 +1169,7 @@ dissect_rpc_authgss_initres(tvbuff_t* tvb, proto_tree* tree, int offset,
                                    offset+0, 4, window);
        offset += 4;
 
-       offset = dissect_rpc_authgss_token(tvb, tree, offset, pinfo);
+       offset = dissect_rpc_authgss_token(tvb, tree, offset, pinfo, hf_rpc_authgss_token);
 
        return offset;
 }
@@ -1203,7 +1194,7 @@ dissect_rpc_authgssapi_initarg(tvbuff_t* tvb, proto_tree* tree, int offset,
        }
        offset += 4;
 
-       offset = dissect_rpc_authgss_token(tvb, mtree, offset, pinfo);
+       offset = dissect_rpc_authgss_token(tvb, mtree, offset, pinfo, hf_rpc_authgss_token);
 
        return offset;
 }
@@ -1247,7 +1238,7 @@ dissect_rpc_authgssapi_initres(tvbuff_t* tvb, proto_tree* tree, int offset,
        }
        offset += 4;
 
-       offset = dissect_rpc_authgss_token(tvb, mtree, offset, pinfo);
+       offset = dissect_rpc_authgss_token(tvb, mtree, offset, pinfo, hf_rpc_authgss_token);
 
        offset = dissect_rpc_data(tvb, mtree, hf_rpc_authgssapi_isn, offset);
 
@@ -1268,6 +1259,7 @@ call_dissect_function(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 {
        const char *saved_proto;
 
+       tvb_ensure_length_remaining(tvb, offset);
        if (dissect_function != NULL) {
                /* set the current protocol name */
                saved_proto = pinfo->current_proto;
@@ -1317,8 +1309,8 @@ dissect_rpc_authgss_integ_data(tvbuff_t *tvb, packet_info *pinfo,
                                      dissect_function, progname);
        }
        offset += rounded_length - 4;
-       offset = dissect_rpc_data(tvb, tree, hf_rpc_authgss_checksum,
-                       offset);
+       offset = dissect_rpc_authgss_token(tvb, tree, offset, pinfo, hf_rpc_authgss_checksum);
+
        return offset;
 }
 
@@ -1333,10 +1325,12 @@ dissect_rpc_authgss_priv_data(tvbuff_t *tvb, proto_tree *tree, int offset)
 
 /*
  * Dissect the arguments to an indirect call; used by the portmapper/RPCBIND
- * dissector.
+ * dissector for the CALLIT procedure.
  *
- * Record this call in a hash table, similar to the hash table for
- * direct calls, so we can find it when dissecting an indirect call reply.
+ * Record these in the same table as the direct calls
+ * so we can find it when dissecting an indirect call reply.
+ * (There should not be collissions between xid between direct and
+ *  indirect calls.)
  */
 int
 dissect_rpc_indir_call(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
@@ -1347,9 +1341,9 @@ dissect_rpc_indir_call(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        rpc_proc_info_key key;
        rpc_proc_info_value *value;
        rpc_call_info_value *rpc_call;
-       rpc_call_info_key rpc_call_key;
-       rpc_call_info_key *new_rpc_call_key;
        dissect_function_t *dissect_function = NULL;
+       rpc_conv_info_t *rpc_conv_info=NULL;
+       guint32 xid;
 
        key.prog = prog;
        key.vers = vers;
@@ -1409,30 +1403,37 @@ dissect_rpc_indir_call(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                    0, NO_ADDR2|NO_PORT2);
                        }
                }
+               /*
+                * Do we already have a state structure for this conv
+                */
+               rpc_conv_info = conversation_get_proto_data(conversation, proto_rpc);
+               if (!rpc_conv_info) {
+                       /* No.  Attach that information to the conversation, and add
+                        * it to the list of information structures.
+                        */
+                       rpc_conv_info = se_alloc(sizeof(rpc_conv_info_t));
+                       rpc_conv_info->xids=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "rpc_xids");
+
+                       conversation_add_proto_data(conversation, proto_rpc, rpc_conv_info);
+               }
 
                /* Make the dissector for this conversation the non-heuristic
                   RPC dissector. */
                conversation_set_dissector(conversation,
                    (pinfo->ptype == PT_TCP) ? rpc_tcp_handle : rpc_handle);
 
-               /* Prepare the key data.
-
-                  Dissectors for RPC procedure calls and replies shouldn't
+               /* Dissectors for RPC procedure calls and replies shouldn't
                   create new tvbuffs, and we don't create one ourselves,
                   so we should have been handed the tvbuff for this RPC call;
                   as such, the XID is at offset 0 in this tvbuff. */
-               rpc_call_key.xid = tvb_get_ntohl(tvb, 0);
-               rpc_call_key.conversation = conversation;
-
                /* look up the request */
-               rpc_call = g_hash_table_lookup(rpc_indir_calls, &rpc_call_key);
+               xid = tvb_get_ntohl(tvb, offset + 0);
+               rpc_call = se_tree_lookup32(rpc_conv_info->xids, xid);
                if (rpc_call == NULL) {
                        /* We didn't find it; create a new entry.
                           Prepare the value data.
                           Not all of it is needed for handling indirect
                           calls, so we set a bunch of items to 0. */
-                       new_rpc_call_key = se_alloc(sizeof(rpc_call_info_key));
-                       *new_rpc_call_key = rpc_call_key;
                        rpc_call = se_alloc(sizeof(rpc_call_info_value));
                        rpc_call->req_num = 0;
                        rpc_call->rep_num = 0;
@@ -1450,8 +1451,7 @@ dissect_rpc_indir_call(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                        rpc_call->gss_svc = 0;
                        rpc_call->proc_info = value;
                        /* store it */
-                       g_hash_table_insert(rpc_indir_calls, new_rpc_call_key,
-                           rpc_call);
+                       se_tree_insert32(rpc_conv_info->xids, xid, (void *)rpc_call);
                }
        }
        else {
@@ -1488,13 +1488,14 @@ dissect_rpc_indir_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 {
        conversation_t* conversation;
        static address null_address = { AT_NONE, 0, NULL };
-       rpc_call_info_key rpc_call_key;
        rpc_call_info_value *rpc_call;
        char *procname=NULL;
        dissect_function_t *dissect_function = NULL;
+       rpc_conv_info_t *rpc_conv_info=NULL;
+       guint32 xid;
 
-       /* Look for the matching call in the hash table of indirect
-          calls.  A reply must match a call that we've seen, and the
+       /* Look for the matching call in the xid table.
+          A reply must match a call that we've seen, and the
           reply must be sent to the same address that the call came
           from, and must come from the port to which the call was sent.
 
@@ -1534,11 +1535,22 @@ dissect_rpc_indir_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                    offset);
                return offset;
        }
+       /*
+        * Do we already have a state structure for this conv
+        */
+       rpc_conv_info = conversation_get_proto_data(conversation, proto_rpc);
+       if (!rpc_conv_info) {
+               /* No.  Attach that information to the conversation, and add
+                * it to the list of information structures.
+                */
+               rpc_conv_info = se_alloc(sizeof(rpc_conv_info_t));
+               rpc_conv_info->xids=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "rpc_xids");
+               conversation_add_proto_data(conversation, proto_rpc, rpc_conv_info);
+       }
 
        /* The XIDs of the call and reply must match. */
-       rpc_call_key.xid = tvb_get_ntohl(tvb, 0);
-       rpc_call_key.conversation = conversation;
-       rpc_call = g_hash_table_lookup(rpc_indir_calls, &rpc_call_key);
+       xid = tvb_get_ntohl(tvb, 0);
+       rpc_call = se_tree_lookup32(rpc_conv_info->xids, xid);
        if (rpc_call == NULL) {
                /* The XID doesn't match a call from that
                   conversation, so it's probably not an RPC reply.
@@ -1554,16 +1566,14 @@ dissect_rpc_indir_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                        procname = (char *)rpc_call->proc_info->name;
                }
                else {
-                       procname=ep_alloc(20);
-                       g_snprintf(procname, 20, "proc-%u", rpc_call->proc);
+                       procname=ep_strdup_printf("proc-%u", rpc_call->proc);
                }
        }
        else {
 #if 0
                dissect_function = NULL;
 #endif
-               procname=ep_alloc(20);
-               g_snprintf(procname, 20, "proc-%u", rpc_call->proc);
+               procname=ep_strdup_printf("proc-%u", rpc_call->proc);
        }
 
        if ( tree )
@@ -1616,10 +1626,8 @@ dissect_rpc_continuation(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        proto_item *rpc_item;
        proto_tree *rpc_tree;
 
-       if (check_col(pinfo->cinfo, COL_PROTOCOL))
-               col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPC");
-       if (check_col(pinfo->cinfo, COL_INFO))
-               col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
+       col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPC");
+       col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
 
        if (tree) {
                rpc_item = proto_tree_add_item(tree, proto_rpc, tvb, 0, -1,
@@ -1635,19 +1643,15 @@ dissect_rpc_continuation(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
  *  and version values.
  */
 
-static void  make_fake_rpc_prog_if_needed (rpc_prog_info_key *prpc_prog_key,
-                                                                                                                guint prog_ver)
+static void
+make_fake_rpc_prog_if_needed (rpc_prog_info_key *prpc_prog_key, guint prog_ver)
 {
-
-rpc_prog_info_value *rpc_prog = NULL;
-
-
        /* sanity check: no one uses versions > 10 */
        if(prog_ver>10){
                return;
        }
 
-       if( (rpc_prog = g_hash_table_lookup(rpc_progs, prpc_prog_key)) == NULL) {
+       if(g_hash_table_lookup(rpc_progs, prpc_prog_key) == NULL) {
                /* ok this is not a known rpc program so we
                 * will have to fake it.
                 */
@@ -1658,12 +1662,9 @@ rpc_prog_info_value *rpc_prog = NULL;
                        { 0,NULL,NULL,NULL }
                };
 
-               NAME=g_malloc(36);
-               Name=g_malloc(32);
-               name=g_malloc(32);
-               g_snprintf(NAME, 36, "Unknown RPC Program:%d",prpc_prog_key->prog);
-               g_snprintf(Name, 32, "RPC:%d",prpc_prog_key->prog);
-               g_snprintf(name, 32, "rpc%d",prpc_prog_key->prog);
+               NAME = g_strdup_printf("Unknown RPC Program:%d",prpc_prog_key->prog);
+               Name = g_strdup_printf("RPC:%d",prpc_prog_key->prog);
+               name = g_strdup_printf("rpc%d",prpc_prog_key->prog);
                proto_rpc_unknown_program = proto_register_protocol(NAME, Name, name);
 
                rpc_init_prog(proto_rpc_unknown_program, prpc_prog_key->prog, ett_rpc_unknown_program);
@@ -1679,7 +1680,6 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
     guint32 rpc_rm, gboolean first_pdu)
 {
        guint32 msg_type;
-       rpc_call_info_key rpc_call_key;
        rpc_call_info_value *rpc_call = NULL;
        rpc_prog_info_value *rpc_prog = NULL;
        rpc_prog_info_key rpc_prog_key;
@@ -1717,7 +1717,6 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        proto_tree *ptree = NULL;
        int offset = (is_tcp && tvb == frag_tvb) ? 4 : 0;
 
-       rpc_call_info_key       *new_rpc_call_key;
        rpc_proc_info_key       key;
        rpc_proc_info_value     *value = NULL;
        conversation_t* conversation;
@@ -1725,7 +1724,9 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        nstime_t ns;
 
        dissect_function_t *dissect_function = NULL;
-       gboolean dissect_rpc = TRUE;
+       gboolean dissect_rpc_flag = TRUE;
+
+       rpc_conv_info_t *rpc_conv_info=NULL;
 
 
        /*
@@ -1776,7 +1777,7 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                }
                /* let the user be able to weaken the heuristics if he need
                 * to look at proprietary protocols not known
-                * to ethereal.
+                * to wireshark.
                 */
                if(rpc_dissect_unknown_programs){
                        guint32 version;
@@ -1840,11 +1841,23 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                           so we can't check for a reply to that call. */
                        return FALSE;
                }
+               /*
+                * Do we already have a state structure for this conv
+                */
+               rpc_conv_info = conversation_get_proto_data(conversation, proto_rpc);
+               if (!rpc_conv_info) {
+                       /* No.  Attach that information to the conversation, and add
+                        * it to the list of information structures.
+                        */
+                       rpc_conv_info = se_alloc(sizeof(rpc_conv_info_t));
+                       rpc_conv_info->xids=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "rpc_xids");
+
+                       conversation_add_proto_data(conversation, proto_rpc, rpc_conv_info);
+               }
 
                /* The XIDs of the call and reply must match. */
-               rpc_call_key.xid = tvb_get_ntohl(tvb, offset + 0);
-               rpc_call_key.conversation = conversation;
-               rpc_call = g_hash_table_lookup(rpc_calls, &rpc_call_key);
+               xid = tvb_get_ntohl(tvb, offset + 0);
+               rpc_call = se_tree_lookup32(rpc_conv_info->xids, xid);
                if (rpc_call == NULL) {
                        /* The XID doesn't match a call from that
                           conversation, so it's probably not an RPC reply. */
@@ -1852,12 +1865,10 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                        /* unless we're permitted to scan for embedded records
                         * and this is a connection-oriented transport, give up */
                        if ((! rpc_find_fragment_start) || (pinfo->ptype != PT_TCP)) {
-                       return FALSE;
-               }
+                               return FALSE;
+                       }
 
                        /* in parse-partials, so define a dummy conversation for this reply */
-                       new_rpc_call_key = se_alloc(sizeof(rpc_call_info_key));
-                       *new_rpc_call_key = rpc_call_key;
                        rpc_call = se_alloc(sizeof(rpc_call_info_value));
                        rpc_call->req_num = 0;
                        rpc_call->rep_num = pinfo->fd->num;
@@ -1865,7 +1876,7 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                        rpc_call->vers = 0;
                        rpc_call->proc = 0;
                        rpc_call->private_data = NULL;
-                       rpc_call->xid = rpc_call_key.xid;
+                       rpc_call->xid = xid;
                        rpc_call->flavor = FLAVOR_NOT_GSSAPI;  /* total punt */
                        rpc_call->gss_proc = 0;
                        rpc_call->gss_svc = 0;
@@ -1873,7 +1884,7 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                        rpc_call->req_time = pinfo->fd->abs_ts;
 
                        /* store it */
-                       g_hash_table_insert(rpc_calls, new_rpc_call_key, rpc_call);
+                       se_tree_insert32(rpc_conv_info->xids, xid, (void *)rpc_call);
 
                        /* and fake up a matching program */
                        rpc_prog_key.prog = rpc_call->prog;
@@ -1909,8 +1920,7 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                }
        }
 
-       if (check_col(pinfo->cinfo, COL_PROTOCOL))
-               col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPC");
+       col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPC");
 
        if (tree) {
                rpc_item = proto_tree_add_item(tree, proto_rpc, tvb, 0, -1,
@@ -1962,11 +1972,9 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                "Program: %s (%u)", progname, prog);
                }
 
-               if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
-                       /* Set the protocol name to the underlying
-                          program name. */
-                       col_set_str(pinfo->cinfo, COL_PROTOCOL, progname);
-               }
+               /* Set the protocol name to the underlying
+                  program name. */
+               col_set_str(pinfo->cinfo, COL_PROTOCOL, progname);
 
                vers = tvb_get_ntohl(tvb, offset+8);
                if (rpc_tree) {
@@ -1990,8 +1998,7 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 #if 0
                        dissect_function = NULL;
 #endif
-                       procname=ep_alloc(20);
-                       g_snprintf(procname, 20, "proc-%u", proc);
+                       procname=ep_strdup_printf("proc-%u", proc);
                }
 
                /* Check for RPCSEC_GSS and AUTH_GSSAPI */
@@ -2030,8 +2037,8 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                                flavor = FLAVOR_AUTHGSSAPI_MSG;
                                                gss_proc = proc;
                                                procname = (char *)
-                                                   match_strval(gss_proc,
-                                                   rpc_authgssapi_proc);
+                                                   val_to_str(gss_proc,
+                                                   rpc_authgssapi_proc, "Unknown (%d)");
                                        } else {
                                                flavor = FLAVOR_AUTHGSSAPI;
                                        }
@@ -2053,16 +2060,18 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                "Procedure: %s (%u)", procname, proc);
                }
 
-               if (check_col(pinfo->cinfo, COL_INFO)) {
-                       if (first_pdu)
-                               col_clear(pinfo->cinfo, COL_INFO);
-                       else
-                               col_append_fstr(pinfo->cinfo, COL_INFO, "  ; ");
+               /* Print the program version, procedure name, and message type (call or reply). */
+               if (first_pdu)
+                       col_clear(pinfo->cinfo, COL_INFO);
+               else
+                       col_append_str(pinfo->cinfo, COL_INFO, "  ; ");
+               /* Special case for NFSv4 - if the type is COMPOUND, do not print the procedure name */
+               if (vers==4 && prog==NFS_PROGRAM && !strcmp(procname, "COMPOUND"))
+                       col_append_fstr(pinfo->cinfo, COL_INFO,"V%u %s", vers,
+                                       msg_type_name);
+               else
                        col_append_fstr(pinfo->cinfo, COL_INFO,"V%u %s %s",
-                               vers,
-                               procname,
-                               msg_type_name);
-               }
+                                       vers, procname, msg_type_name);
 
                /* Keep track of the address whence the call came, and the
                   port to which the call is being sent, so that we can
@@ -2112,18 +2121,28 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                    0, NO_ADDR2|NO_PORT2);
                        }
                }
+               /*
+                * Do we already have a state structure for this conv
+                */
+               rpc_conv_info = conversation_get_proto_data(conversation, proto_rpc);
+               if (!rpc_conv_info) {
+                       /* No.  Attach that information to the conversation, and add
+                        * it to the list of information structures.
+                        */
+                       rpc_conv_info = se_alloc(sizeof(rpc_conv_info_t));
+                       rpc_conv_info->xids=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "rpc_xids");
+
+                       conversation_add_proto_data(conversation, proto_rpc, rpc_conv_info);
+               }
+
 
                /* Make the dissector for this conversation the non-heuristic
                   RPC dissector. */
                conversation_set_dissector(conversation,
                        (pinfo->ptype == PT_TCP) ? rpc_tcp_handle : rpc_handle);
 
-               /* prepare the key data */
-               rpc_call_key.xid = xid;
-               rpc_call_key.conversation = conversation;
-
                /* look up the request */
-               rpc_call = g_hash_table_lookup(rpc_calls, &rpc_call_key);
+               rpc_call = se_tree_lookup32(rpc_conv_info->xids, xid);
                if (rpc_call) {
                        /* We've seen a request with this XID, with the same
                           source and destination, before - but was it
@@ -2131,19 +2150,16 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                        if (pinfo->fd->num != rpc_call->req_num) {
                                /* No, so it's a duplicate request.
                                   Mark it as such. */
-                               if (check_col(pinfo->cinfo, COL_INFO)) {
-                                       col_prepend_fstr(pinfo->cinfo, COL_INFO,
-                                               "[RPC retransmission of #%d]", rpc_call->req_num);
-                               }
-                               proto_tree_add_item(rpc_tree,
-                                       hf_rpc_dup, tvb, 0,0, TRUE);
-                               proto_tree_add_uint(rpc_tree,
-                                       hf_rpc_call_dup, tvb, 0,0, rpc_call->req_num);
+                               col_prepend_fstr(pinfo->cinfo, COL_INFO,
+                                                "[RPC retransmission of #%d]",
+                                                rpc_call->req_num);
+                               proto_tree_add_item(rpc_tree, hf_rpc_dup, tvb,
+                                                   0, 0, ENC_NA);
+                               proto_tree_add_uint(rpc_tree, hf_rpc_call_dup,
+                                                   tvb, 0,0, rpc_call->req_num);
                        }
                        if(rpc_call->rep_num){
-                               if (check_col(pinfo->cinfo, COL_INFO)) {
-                                       col_append_fstr(pinfo->cinfo, COL_INFO," (Reply In %d)", rpc_call->rep_num);
-                               }
+                               col_append_fstr(pinfo->cinfo, COL_INFO," (Reply In %d)", rpc_call->rep_num);
                        }
                } else {
                        /* Prepare the value data.
@@ -2151,8 +2167,6 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                           frame numbers are 1-origin, so we use 0
                           to mean "we don't yet know in which frame
                           the reply for this call appears". */
-                       new_rpc_call_key = se_alloc(sizeof(rpc_call_info_key));
-                       *new_rpc_call_key = rpc_call_key;
                        rpc_call = se_alloc(sizeof(rpc_call_info_value));
                        rpc_call->req_num = pinfo->fd->num;
                        rpc_call->rep_num = 0;
@@ -2168,14 +2182,13 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                        rpc_call->req_time = pinfo->fd->abs_ts;
 
                        /* store it */
-                       g_hash_table_insert(rpc_calls, new_rpc_call_key,
-                           rpc_call);
+                       se_tree_insert32(rpc_conv_info->xids, xid, (void *)rpc_call);
                }
 
                if(rpc_call && rpc_call->rep_num){
                        proto_item *tmp_item;
 
-                       tmp_item=proto_tree_add_uint_format(rpc_tree, hf_rpc_repframe,
+                       tmp_item=proto_tree_add_uint_format(rpc_tree, hf_rpc_reqframe,
                            tvb, 0, 0, rpc_call->rep_num,
                            "The reply to this request is in frame %u",
                            rpc_call->rep_num);
@@ -2211,16 +2224,14 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                procname = (char *)rpc_call->proc_info->name;
                        }
                        else {
-                               procname=ep_alloc(20);
-                               g_snprintf(procname, 20, "proc-%u", proc);
+                               procname=ep_strdup_printf("proc-%u", proc);
                        }
                }
                else {
 #if 0
                        dissect_function = NULL;
 #endif
-                       procname=ep_alloc(20);
-                       g_snprintf(procname, 20, "proc-%u", proc);
+                       procname=ep_strdup_printf("proc-%u", proc);
                }
 
                /*
@@ -2231,7 +2242,7 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                 * AUTH_GSSAPI procname.
                 */
                if (flavor == FLAVOR_AUTHGSSAPI_MSG) {
-                       procname = (char *)match_strval(gss_proc, rpc_authgssapi_proc);
+                       procname = (char *)val_to_str_const(gss_proc, rpc_authgssapi_proc, "(null)");
                }
 
                rpc_prog_key.prog = prog;
@@ -2247,23 +2258,23 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                        ett = rpc_prog->ett;
                        progname = rpc_prog->progname;
 
-                       if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
-                               /* Set the protocol name to the underlying
-                                  program name. */
-                               col_set_str(pinfo->cinfo, COL_PROTOCOL, progname);
-                       }
+                       /* Set the protocol name to the underlying
+                          program name. */
+                       col_set_str(pinfo->cinfo, COL_PROTOCOL, progname);
                }
 
-               if (check_col(pinfo->cinfo, COL_INFO)) {
-                       if (first_pdu)
-                               col_clear(pinfo->cinfo, COL_INFO);
-                       else
-                               col_append_fstr(pinfo->cinfo, COL_INFO, "  ; ");
+               /* Print the program version, procedure name, and message type (call or reply). */
+               if (first_pdu)
+                       col_clear(pinfo->cinfo, COL_INFO);
+               else
+                       col_append_str(pinfo->cinfo, COL_INFO, "  ; ");
+               /* Special case for NFSv4 - if the type is COMPOUND, do not print the procedure name */
+               if (vers==4 && prog==NFS_PROGRAM && !strcmp(procname, "COMPOUND"))
+                       col_append_fstr(pinfo->cinfo, COL_INFO,"V%u %s",
+                                       vers, msg_type_name);
+               else
                        col_append_fstr(pinfo->cinfo, COL_INFO,"V%u %s %s",
-                               vers,
-                               procname,
-                               msg_type_name);
-               }
+                                       vers, procname, msg_type_name);
 
                if (rpc_tree) {
                        proto_item *tmp_item;
@@ -2291,7 +2302,7 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                if(rpc_call && rpc_call->req_num){
                        proto_item *tmp_item;
 
-                       tmp_item=proto_tree_add_uint_format(rpc_tree, hf_rpc_reqframe,
+                       tmp_item=proto_tree_add_uint_format(rpc_tree, hf_rpc_repframe,
                            tvb, 0, 0, rpc_call->req_num,
                            "This is a reply to a request in frame %u",
                            rpc_call->req_num);
@@ -2302,9 +2313,7 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                &ns);
                        PROTO_ITEM_SET_GENERATED(tmp_item);
 
-                       if (check_col(pinfo->cinfo, COL_INFO)) {
-                               col_append_fstr(pinfo->cinfo, COL_INFO," (Call In %d)", rpc_call->req_num);
-                       }
+                       col_append_fstr(pinfo->cinfo, COL_INFO," (Call In %d)", rpc_call->req_num);
                }
 
 
@@ -2321,12 +2330,10 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
                                /* No, so it's a duplicate reply.
                                   Mark it as such. */
-                               if (check_col(pinfo->cinfo, COL_INFO)) {
-                                       col_prepend_fstr(pinfo->cinfo, COL_INFO,
+                               col_prepend_fstr(pinfo->cinfo, COL_INFO,
                                                "[RPC duplicate of #%d]", rpc_call->rep_num);
-                               }
                                tmp_item=proto_tree_add_item(rpc_tree,
-                                       hf_rpc_dup, tvb, 0,0, TRUE);
+                                       hf_rpc_dup, tvb, 0,0, ENC_NA);
                                PROTO_ITEM_SET_GENERATED(tmp_item);
 
                                tmp_item=proto_tree_add_uint(rpc_tree,
@@ -2368,7 +2375,7 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                 * There's no protocol reply, so don't
                                 * try to dissect it.
                                 */
-                               dissect_rpc = FALSE;
+                               dissect_rpc_flag = FALSE;
                                break;
 
                        default:
@@ -2376,7 +2383,7 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                 * There's no protocol reply, so don't
                                 * try to dissect it.
                                 */
-                               dissect_rpc = FALSE;
+                               dissect_rpc_flag = FALSE;
                                break;
                        }
                        break;
@@ -2416,7 +2423,7 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                         * There's no protocol reply, so don't
                         * try to dissect it.
                         */
-                       dissect_rpc = FALSE;
+                       dissect_rpc_flag = FALSE;
                        break;
 
                default:
@@ -2425,7 +2432,7 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                         * no clue what's going on; don't try to dissect
                         * the protocol reply.
                         */
-                       dissect_rpc = FALSE;
+                       dissect_rpc_flag = FALSE;
                        break;
                }
                break; /* end of RPC reply */
@@ -2446,16 +2453,23 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                proto_item_set_end(rpc_item, tvb, offset);
        }
 
-       if (!dissect_rpc) {
+       if (!dissect_rpc_flag) {
                /*
                 * There's no RPC call or reply here; just dissect
                 * whatever's left as data.
                 */
                call_dissector(data_handle,
-                   tvb_new_subset(tvb, offset, -1, -1), pinfo, rpc_tree);
+                   tvb_new_subset_remaining(tvb, offset), pinfo, rpc_tree);
                return TRUE;
        }
 
+       /* we must queue this packet to the tap system before we actually
+          call the subdissectors since short packets (i.e. nfs read reply)
+          will cause an exception and execution would never reach the call
+          to tap_queue_packet() in that case
+       */
+       tap_queue_packet(rpc_tap, pinfo, rpc_call);
+
        /* create here the program specific sub-tree */
        if (tree && (flavor != FLAVOR_AUTHGSSAPI_MSG)) {
                pitem = proto_tree_add_item(tree, proto_id, tvb, offset, -1,
@@ -2491,18 +2505,18 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                }
        }
 
-       /* we must queue this packet to the tap system before we actually
-          call the subdissectors since short packets (i.e. nfs read reply)
-          will cause an exception and execution would never reach the call
-          to tap_queue_packet() in that case
-       */
-       tap_queue_packet(rpc_tap, pinfo, rpc_call);
-
        /* proto==0 if this is an unknown program */
        if( (proto==0) || !proto_is_protocol_enabled(proto)){
                dissect_function = NULL;
        }
 
+        /*
+         * Don't call any subdissector if we have no more date to dissect.
+         */
+        if (tvb_length_remaining(tvb, offset) == 0) {
+                return TRUE;
+        }
+
        /*
         * Handle RPCSEC_GSS and AUTH_GSSAPI specially.
         */
@@ -2588,16 +2602,12 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                 * protocol and info fields to indicate that this is
                 * an RPC auth level message, then process the args.
                 */
-               if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
-                       col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPC");
-               }
-               if (check_col(pinfo->cinfo, COL_INFO)) {
-                       col_clear(pinfo->cinfo, COL_INFO);
-                       col_append_fstr(pinfo->cinfo, COL_INFO,
-                           "%s %s XID 0x%x",
-                           match_strval(gss_proc, rpc_authgssapi_proc),
-                           msg_type_name, xid);
-               }
+               col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPC");
+               col_clear(pinfo->cinfo, COL_INFO);
+               col_append_fstr(pinfo->cinfo, COL_INFO,
+                               "%s %s XID 0x%x",
+                               val_to_str(gss_proc, rpc_authgssapi_proc, "Unknown (%d)"),
+                               msg_type_name, xid);
 
                switch (gss_proc) {
 
@@ -2644,7 +2654,7 @@ dissect_rpc_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
            */
 
           call_dissector(data_handle,
-              tvb_new_subset(tvb, offset, -1, -1), pinfo, ptree);
+              tvb_new_subset_remaining(tvb, offset), pinfo, ptree);
         }
 
        /* XXX this should really loop over all fhandles registred for the frame */
@@ -2696,6 +2706,7 @@ typedef struct _rpc_fragment_key {
        guint32 conv_id;
        guint32 seq;
        guint32 offset;
+       guint32 port;
        /* xxx */
        guint32 start_seq;
 } rpc_fragment_key;
@@ -2715,7 +2726,7 @@ rpc_fragment_equal(gconstpointer k1, gconstpointer k2)
        const rpc_fragment_key *key2 = (const rpc_fragment_key *)k2;
 
        return key1->conv_id == key2->conv_id &&
-           key1->seq == key2->seq;
+           key1->seq == key2->seq && key1->port == key2->port;
 }
 
 static void
@@ -2807,6 +2818,7 @@ call_message_dissector(tvbuff_t *tvb, tvbuff_t *rec_tvb, packet_info *pinfo,
 {
        const char *saved_proto;
        volatile gboolean rpc_succeeded;
+       void *pd_save;
 
        /*
         * Catch the ReportedBoundsError exception; if
@@ -2821,6 +2833,7 @@ call_message_dissector(tvbuff_t *tvb, tvbuff_t *rec_tvb, packet_info *pinfo,
         */
        saved_proto = pinfo->current_proto;
        rpc_succeeded = FALSE;
+       pd_save = pinfo->private_data;
        TRY {
                rpc_succeeded = (*dissector)(rec_tvb, pinfo, tree,
                    frag_tvb, ipfd_head, TRUE, rpc_rm, first_pdu);
@@ -2832,6 +2845,12 @@ call_message_dissector(tvbuff_t *tvb, tvbuff_t *rec_tvb, packet_info *pinfo,
                show_reported_bounds_error(tvb, pinfo, tree);
                pinfo->current_proto = saved_proto;
 
+               /*  Restore the private_data structure in case one of the
+                *  called dissectors modified it (and, due to the exception,
+                *  was unable to restore it).
+                */
+               pinfo->private_data = pd_save;
+
                /*
                 * We treat this as a "successful" dissection of
                 * an RPC packet, as "dissect_rpc_message()"
@@ -2996,6 +3015,7 @@ dissect_rpc_fragment(tvbuff_t *tvb, int offset, packet_info *pinfo,
        }
        old_rfk.conv_id = conversation->index;
        old_rfk.seq = seq;
+        old_rfk.port = pinfo->srcport;
        rfk = g_hash_table_lookup(rpc_reassembly_table, &old_rfk);
 
        if (rfk == NULL) {
@@ -3036,6 +3056,7 @@ dissect_rpc_fragment(tvbuff_t *tvb, int offset, packet_info *pinfo,
                        rfk = se_alloc(sizeof(rpc_fragment_key));
                        rfk->conv_id = conversation->index;
                        rfk->seq = seq;
+                       rfk->port = pinfo->srcport;
                        rfk->offset = 0;
                        rfk->start_seq = seq;
                        g_hash_table_insert(rpc_reassembly_table, rfk, rfk);
@@ -3057,6 +3078,7 @@ dissect_rpc_fragment(tvbuff_t *tvb, int offset, packet_info *pinfo,
                                new_rfk = se_alloc(sizeof(rpc_fragment_key));
                                new_rfk->conv_id = rfk->conv_id;
                                new_rfk->seq = seq + len;
+                               new_rfk->port = pinfo->srcport;
                                new_rfk->offset = rfk->offset + len - 4;
                                new_rfk->start_seq = rfk->start_seq;
                                g_hash_table_insert(rpc_reassembly_table, new_rfk,
@@ -3122,6 +3144,7 @@ dissect_rpc_fragment(tvbuff_t *tvb, int offset, packet_info *pinfo,
                        new_rfk = se_alloc(sizeof(rpc_fragment_key));
                        new_rfk->conv_id = rfk->conv_id;
                        new_rfk->seq = seq + len;
+                        new_rfk->port = pinfo->srcport;
                        new_rfk->offset = rfk->offset + len - 4;
                        new_rfk->start_seq = rfk->start_seq;
                        g_hash_table_insert(rpc_reassembly_table, new_rfk,
@@ -3184,15 +3207,9 @@ dissect_rpc_fragment(tvbuff_t *tvb, int offset, packet_info *pinfo,
                 * Create a new TVB structure for
                 * defragmented data.
                 */
-               rec_tvb = tvb_new_real_data(ipfd_head->data,
+               rec_tvb = tvb_new_child_real_data(tvb, ipfd_head->data,
                    ipfd_head->datalen, ipfd_head->datalen);
 
-               /*
-                * Add this tvb as a child to the original
-                * one.
-                */
-               tvb_set_child_real_data_tvbuff(tvb, rec_tvb);
-
                /*
                 * Add defragmented data to the data source list.
                 */
@@ -3224,63 +3241,63 @@ static int
 find_rpc_over_tcp_reply_start(tvbuff_t *tvb, int offset)
 {
 
-/*
- * Looking for partial header sequence.  From beginning of
- * stream-style header, including "record mark", full ONC-RPC
- * looks like:
- *    BE int32    record mark (rfc 1831 sec. 10)
- *    ?  int32    XID (rfc 1831 sec. 8)
- *    BE int32    msg_type (ibid sec. 8, call = 0, reply = 1)
- *
- * -------------------------------------------------------------
- * Then reply-specific fields are
- *    BE int32    reply_stat (ibid, accept = 0, deny = 1)
- *
- * Then, assuming accepted,
- *   opaque_auth
- *    BE int32    auth_flavor (ibid, none = 0)
- *    BE int32    ? auth_len (ibid, none = 0)
- *
- *    BE int32    accept_stat (ibid, success = 0, errs are 1..5 in rpc v2)
- *
- * -------------------------------------------------------------
- * Or, call-specific fields are
- *    BE int32    rpc_vers (rfc 1831 sec 8, always == 2)
- *    BE int32    prog (NFS == 000186A3)
- *    BE int32    prog_ver (NFS v2/3 == 2 or 3)
- *    BE int32    proc_id (NFS, <= 256 ???)
- *   opaque_auth
- *    ...
- */
+       /*
       * Looking for partial header sequence.  From beginning of
       * stream-style header, including "record mark", full ONC-RPC
       * looks like:
       *    BE int32    record mark (rfc 1831 sec. 10)
       *    ?  int32    XID (rfc 1831 sec. 8)
       *    BE int32    msg_type (ibid sec. 8, call = 0, reply = 1)
       *
       * -------------------------------------------------------------
       * Then reply-specific fields are
       *    BE int32    reply_stat (ibid, accept = 0, deny = 1)
       *
       * Then, assuming accepted,
       *   opaque_auth
       *    BE int32    auth_flavor (ibid, none = 0)
       *    BE int32    ? auth_len (ibid, none = 0)
       *
       *    BE int32    accept_stat (ibid, success = 0, errs are 1..5 in rpc v2)
       *
       * -------------------------------------------------------------
       * Or, call-specific fields are
       *    BE int32    rpc_vers (rfc 1831 sec 8, always == 2)
       *    BE int32    prog (NFS == 000186A3)
       *    BE int32    prog_ver (NFS v2/3 == 2 or 3)
       *    BE int32    proc_id (NFS, <= 256 ???)
       *   opaque_auth
       *    ...
       */
 
-/* Initially, we search only for something matching the template
- * of a successful reply with no auth verifier.
- * Our first qualification test is search for a string of zero bytes,
- * corresponding the four guint32 values
- *    reply_stat
- *    auth_flavor
- *    auth_len
- *    accept_stat
- *
- * If this string of zeros matches, then we go back and check the
- * preceding msg_type and record_mark fields.
- */
+       /* Initially, we search only for something matching the template
       * of a successful reply with no auth verifier.
       * Our first qualification test is search for a string of zero bytes,
       * corresponding the four guint32 values
       *    reply_stat
       *    auth_flavor
       *    auth_len
       *    accept_stat
       *
       * If this string of zeros matches, then we go back and check the
       * preceding msg_type and record_mark fields.
       */
 
-const gint     cbZeroTail = 4 * 4;     /* four guint32s of zeros */
-const gint     ibPatternStart = 3 * 4;    /* offset of zero fill from reply start */
-const guint8 * pbWholeBuf;    /* all of tvb, from offset onwards */
-const int      NoMatch = -1;
+       const gint     cbZeroTail = 4 * 4;     /* four guint32s of zeros */
+       const gint     ibPatternStart = 3 * 4;    /* offset of zero fill from reply start */
+       const guint8 * pbWholeBuf;    /* all of tvb, from offset onwards */
+       const int      NoMatch = -1;
 
-gint     ibSearchStart;       /* offset of search start, in case of false hits. */
+       gint     ibSearchStart;       /* offset of search start, in case of false hits. */
 
-const    guint8 * pbBuf;
+       const    guint8 * pbBuf;
 
-gint     cbInBuf;       /* bytes in tvb, from offset onwards */
+       gint     cbInBuf;       /* bytes in tvb, from offset onwards */
 
-guint32  ulMsgType;
-guint32  ulRecMark;
+       guint32  ulMsgType;
+       guint32  ulRecMark;
 
-int      i;
+       int      i;
 
 
        cbInBuf = tvb_reported_length_remaining(tvb, offset);
@@ -3359,9 +3376,9 @@ int      i;
 
 static int
 find_and_dissect_rpc_fragment(tvbuff_t *tvb, int offset, packet_info *pinfo,
-                                                         proto_tree *tree, rec_dissector_t dissector,
-                                                         gboolean is_heur,
-                                                         int proto, int ett, gboolean defragment)
+                             proto_tree *tree, rec_dissector_t dissector,
+                             gboolean is_heur,
+                             int proto, int ett, gboolean defragment)
 {
 
        int   offReply;
@@ -3375,16 +3392,16 @@ find_and_dissect_rpc_fragment(tvbuff_t *tvb, int offset, packet_info *pinfo,
        }
 
        len = dissect_rpc_fragment(tvb, offReply,
-                                                          pinfo, tree,
-                                                          dissector, is_heur, proto, ett,
-                                                          defragment,
-                                                          TRUE /* force first-pdu state */);
+                                  pinfo, tree,
+                                  dissector, is_heur, proto, ett,
+                                  defragment,
+                                  TRUE /* force first-pdu state */);
 
        /* misses are reported as-is */
        if (len == 0)
-               {
+       {
                return (0);
-               }
+       }
 
        /* returning a non-zero length, correct it to reflect the extra offset
         * we found necessary
@@ -3462,6 +3479,14 @@ dissect_rpc_tcp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                        break;
                }
 
+               /*  Set a fence so whatever the subdissector put in the
+                *  Info column stays there.  This is useful when the
+                *  subdissector clears the column (which it might have to do
+                *  if it runs over some other protocol too) and there are
+                *  multiple PDUs in one frame.
+                */
+               col_set_fence(pinfo->cinfo, COL_INFO);
+
                /* PDU tracking
                  If the length indicates that the PDU continues beyond
                  the end of this tvb, then tell TCP about it so that it
@@ -3511,21 +3536,11 @@ dissect_rpc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 static void
 rpc_init_protocol(void)
 {
-       if (rpc_calls != NULL) {
-               g_hash_table_destroy(rpc_calls);
-               rpc_calls = NULL;
-       }
-       if (rpc_indir_calls != NULL) {
-               g_hash_table_destroy(rpc_indir_calls);
-               rpc_indir_calls = NULL;
-       }
        if (rpc_reassembly_table != NULL) {
                g_hash_table_destroy(rpc_reassembly_table);
                rpc_reassembly_table = NULL;
        }
 
-       rpc_calls = g_hash_table_new(rpc_call_hash, rpc_call_equal);
-       rpc_indir_calls = g_hash_table_new(rpc_call_hash, rpc_call_equal);
        rpc_reassembly_table = g_hash_table_new(rpc_fragment_hash,
            rpc_fragment_equal);
 
@@ -3539,166 +3554,169 @@ proto_register_rpc(void)
        static hf_register_info hf[] = {
                { &hf_rpc_reqframe, {
                        "Request Frame", "rpc.reqframe", FT_FRAMENUM, BASE_NONE,
-                       NULL, 0, "Request Frame", HFILL }},
+                       NULL, 0, NULL, HFILL }},
                { &hf_rpc_repframe, {
                        "Reply Frame", "rpc.repframe", FT_FRAMENUM, BASE_NONE,
-                       NULL, 0, "Reply Frame", HFILL }},
+                       NULL, 0, NULL, HFILL }},
                { &hf_rpc_lastfrag, {
                        "Last Fragment", "rpc.lastfrag", FT_BOOLEAN, 32,
-                       &yesno, RPC_RM_LASTFRAG, "Last Fragment", HFILL }},
+                       TFS(&tfs_yes_no), RPC_RM_LASTFRAG, NULL, HFILL }},
                { &hf_rpc_fraglen, {
                        "Fragment Length", "rpc.fraglen", FT_UINT32, BASE_DEC,
-                       NULL, RPC_RM_FRAGLEN, "Fragment Length", HFILL }},
+                       NULL, RPC_RM_FRAGLEN, NULL, HFILL }},
                { &hf_rpc_xid, {
                        "XID", "rpc.xid", FT_UINT32, BASE_HEX,
-                       NULL, 0, "XID", HFILL }},
+                       NULL, 0, NULL, HFILL }},
                { &hf_rpc_msgtype, {
                        "Message Type", "rpc.msgtyp", FT_UINT32, BASE_DEC,
-                       VALS(rpc_msg_type), 0, "Message Type", HFILL }},
+                       VALS(rpc_msg_type), 0, NULL, HFILL }},
                { &hf_rpc_state_reply, {
                        "Reply State", "rpc.replystat", FT_UINT32, BASE_DEC,
-                       VALS(rpc_reply_state), 0, "Reply State", HFILL }},
+                       VALS(rpc_reply_state), 0, NULL, HFILL }},
                { &hf_rpc_state_accept, {
                        "Accept State", "rpc.state_accept", FT_UINT32, BASE_DEC,
-                       VALS(rpc_accept_state), 0, "Accept State", HFILL }},
+                       VALS(rpc_accept_state), 0, NULL, HFILL }},
                { &hf_rpc_state_reject, {
                        "Reject State", "rpc.state_reject", FT_UINT32, BASE_DEC,
-                       VALS(rpc_reject_state), 0, "Reject State", HFILL }},
+                       VALS(rpc_reject_state), 0, NULL, HFILL }},
                { &hf_rpc_state_auth, {
                        "Auth State", "rpc.state_auth", FT_UINT32, BASE_DEC,
-                       VALS(rpc_auth_state), 0, "Auth State", HFILL }},
+                       VALS(rpc_auth_state), 0, NULL, HFILL }},
                { &hf_rpc_version, {
                        "RPC Version", "rpc.version", FT_UINT32, BASE_DEC,
-                       NULL, 0, "RPC Version", HFILL }},
+                       NULL, 0, NULL, HFILL }},
                { &hf_rpc_version_min, {
                        "RPC Version (Minimum)", "rpc.version.min", FT_UINT32,
                        BASE_DEC, NULL, 0, "Program Version (Minimum)", HFILL }},
                { &hf_rpc_version_max, {
                        "RPC Version (Maximum)", "rpc.version.max", FT_UINT32,
-                       BASE_DEC, NULL, 0, "RPC Version (Maximum)", HFILL }},
+                       BASE_DEC, NULL, 0, NULL, HFILL }},
                { &hf_rpc_program, {
                        "Program", "rpc.program", FT_UINT32, BASE_DEC,
-                       NULL, 0, "Program", HFILL }},
+                       NULL, 0, NULL, HFILL }},
                { &hf_rpc_programversion, {
                        "Program Version", "rpc.programversion", FT_UINT32,
-                       BASE_DEC, NULL, 0, "Program Version", HFILL }},
+                       BASE_DEC, NULL, 0, NULL, HFILL }},
                { &hf_rpc_programversion_min, {
                        "Program Version (Minimum)", "rpc.programversion.min", FT_UINT32,
-                       BASE_DEC, NULL, 0, "Program Version (Minimum)", HFILL }},
+                       BASE_DEC, NULL, 0, NULL, HFILL }},
                { &hf_rpc_programversion_max, {
                        "Program Version (Maximum)", "rpc.programversion.max", FT_UINT32,
-                       BASE_DEC, NULL, 0, "Program Version (Maximum)", HFILL }},
+                       BASE_DEC, NULL, 0, NULL, HFILL }},
                { &hf_rpc_procedure, {
                        "Procedure", "rpc.procedure", FT_UINT32, BASE_DEC,
-                       NULL, 0, "Procedure", HFILL }},
+                       NULL, 0, NULL, HFILL }},
                { &hf_rpc_auth_flavor, {
                        "Flavor", "rpc.auth.flavor", FT_UINT32, BASE_DEC,
-                       VALS(rpc_auth_flavor), 0, "Flavor", HFILL }},
+                       VALS(rpc_auth_flavor), 0, NULL, HFILL }},
                { &hf_rpc_auth_length, {
                        "Length", "rpc.auth.length", FT_UINT32, BASE_DEC,
-                       NULL, 0, "Length", HFILL }},
+                       NULL, 0, NULL, HFILL }},
                { &hf_rpc_auth_stamp, {
                        "Stamp", "rpc.auth.stamp", FT_UINT32, BASE_HEX,
-                       NULL, 0, "Stamp", HFILL }},
+                       NULL, 0, NULL, HFILL }},
                { &hf_rpc_auth_uid, {
                        "UID", "rpc.auth.uid", FT_UINT32, BASE_DEC,
-                       NULL, 0, "UID", HFILL }},
+                       NULL, 0, NULL, HFILL }},
                { &hf_rpc_auth_gid, {
                        "GID", "rpc.auth.gid", FT_UINT32, BASE_DEC,
-                       NULL, 0, "GID", HFILL }},
+                       NULL, 0, NULL, HFILL }},
                { &hf_rpc_authgss_v, {
                        "GSS Version", "rpc.authgss.version", FT_UINT32,
-                       BASE_DEC, NULL, 0, "GSS Version", HFILL }},
+                       BASE_DEC, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authgss_proc, {
                        "GSS Procedure", "rpc.authgss.procedure", FT_UINT32,
-                       BASE_DEC, VALS(rpc_authgss_proc), 0, "GSS Procedure", HFILL }},
+                       BASE_DEC, VALS(rpc_authgss_proc), 0, NULL, HFILL }},
                { &hf_rpc_authgss_seq, {
                        "GSS Sequence Number", "rpc.authgss.seqnum", FT_UINT32,
-                       BASE_DEC, NULL, 0, "GSS Sequence Number", HFILL }},
+                       BASE_DEC, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authgss_svc, {
                        "GSS Service", "rpc.authgss.service", FT_UINT32,
-                       BASE_DEC, VALS(rpc_authgss_svc), 0, "GSS Service", HFILL }},
+                       BASE_DEC, VALS(rpc_authgss_svc), 0, NULL, HFILL }},
                { &hf_rpc_authgss_ctx, {
                        "GSS Context", "rpc.authgss.context", FT_BYTES,
-                       BASE_HEX, NULL, 0, "GSS Context", HFILL }},
+                       BASE_NONE, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authgss_major, {
                        "GSS Major Status", "rpc.authgss.major", FT_UINT32,
-                       BASE_DEC, NULL, 0, "GSS Major Status", HFILL }},
+                       BASE_DEC, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authgss_minor, {
                        "GSS Minor Status", "rpc.authgss.minor", FT_UINT32,
-                       BASE_DEC, NULL, 0, "GSS Minor Status", HFILL }},
+                       BASE_DEC, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authgss_window, {
                        "GSS Sequence Window", "rpc.authgss.window", FT_UINT32,
-                       BASE_DEC, NULL, 0, "GSS Sequence Window", HFILL }},
+                       BASE_DEC, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authgss_token_length, {
                        "GSS Token Length", "rpc.authgss.token_length", FT_UINT32,
-                       BASE_DEC, NULL, 0, "GSS Token Length", HFILL }},
+                       BASE_DEC, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authgss_data_length, {
                        "Length", "rpc.authgss.data.length", FT_UINT32,
-                       BASE_DEC, NULL, 0, "Length", HFILL }},
+                       BASE_DEC, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authgss_data, {
                        "GSS Data", "rpc.authgss.data", FT_BYTES,
-                       BASE_HEX, NULL, 0, "GSS Data", HFILL }},
+                       BASE_NONE, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authgss_checksum, {
                        "GSS Checksum", "rpc.authgss.checksum", FT_BYTES,
-                       BASE_HEX, NULL, 0, "GSS Checksum", HFILL }},
+                       BASE_NONE, NULL, 0, NULL, HFILL }},
+               { &hf_rpc_authgss_token, {
+                       "GSS Token", "rpc.authgss.token", FT_BYTES,
+                       BASE_NONE, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authgssapi_v, {
                        "AUTH_GSSAPI Version", "rpc.authgssapi.version",
-                       FT_UINT32, BASE_DEC, NULL, 0, "AUTH_GSSAPI Version",
+                       FT_UINT32, BASE_DEC, NULL, 0, NULL,
                        HFILL }},
                { &hf_rpc_authgssapi_msg, {
                        "AUTH_GSSAPI Message", "rpc.authgssapi.message",
-                       FT_BOOLEAN, BASE_NONE, &yesno, 0, "AUTH_GSSAPI Message",
+                       FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0, NULL,
                        HFILL }},
                { &hf_rpc_authgssapi_msgv, {
                        "Msg Version", "rpc.authgssapi.msgversion",
-                       FT_UINT32, BASE_DEC, NULL, 0, "Msg Version",
+                       FT_UINT32, BASE_DEC, NULL, 0, NULL,
                        HFILL }},
                { &hf_rpc_authgssapi_handle, {
                        "Client Handle", "rpc.authgssapi.handle",
-                       FT_BYTES, BASE_HEX, NULL, 0, "Client Handle", HFILL }},
+                       FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authgssapi_isn, {
                        "Signed ISN", "rpc.authgssapi.isn",
-                       FT_BYTES, BASE_HEX, NULL, 0, "Signed ISN", HFILL }},
+                       FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authdes_namekind, {
                        "Namekind", "rpc.authdes.namekind", FT_UINT32, BASE_DEC,
-                       VALS(rpc_authdes_namekind), 0, "Namekind", HFILL }},
+                       VALS(rpc_authdes_namekind), 0, NULL, HFILL }},
                { &hf_rpc_authdes_netname, {
                        "Netname", "rpc.authdes.netname", FT_STRING,
-                       BASE_DEC, NULL, 0, "Netname", HFILL }},
+                       BASE_NONE, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authdes_convkey, {
                        "Conversation Key (encrypted)", "rpc.authdes.convkey", FT_UINT32,
-                       BASE_HEX, NULL, 0, "Conversation Key (encrypted)", HFILL }},
+                       BASE_HEX, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authdes_window, {
                        "Window (encrypted)", "rpc.authdes.window", FT_UINT32,
                        BASE_HEX, NULL, 0, "Windows (encrypted)", HFILL }},
                { &hf_rpc_authdes_nickname, {
                        "Nickname", "rpc.authdes.nickname", FT_UINT32,
-                       BASE_HEX, NULL, 0, "Nickname", HFILL }},
+                       BASE_HEX, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authdes_timestamp, {
                        "Timestamp (encrypted)", "rpc.authdes.timestamp", FT_UINT32,
-                       BASE_HEX, NULL, 0, "Timestamp (encrypted)", HFILL }},
+                       BASE_HEX, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authdes_windowverf, {
                        "Window verifier (encrypted)", "rpc.authdes.windowverf", FT_UINT32,
-                       BASE_HEX, NULL, 0, "Window verifier (encrypted)", HFILL }},
+                       BASE_HEX, NULL, 0, NULL, HFILL }},
                { &hf_rpc_authdes_timeverf, {
                        "Timestamp verifier (encrypted)", "rpc.authdes.timeverf", FT_UINT32,
-                       BASE_HEX, NULL, 0, "Timestamp verifier (encrypted)", HFILL }},
+                       BASE_HEX, NULL, 0, NULL, HFILL }},
                { &hf_rpc_auth_machinename, {
                        "Machine Name", "rpc.auth.machinename", FT_STRING,
-                       BASE_DEC, NULL, 0, "Machine Name", HFILL }},
+                       BASE_NONE, NULL, 0, NULL, HFILL }},
                { &hf_rpc_dup, {
                        "Duplicate Call/Reply", "rpc.dup", FT_NONE, BASE_NONE,
-                       NULL, 0, "Duplicate Call/Reply", HFILL }},
+                       NULL, 0, NULL, HFILL }},
                { &hf_rpc_call_dup, {
-                       "Duplicate to the call in", "rpc.call.dup", FT_FRAMENUM, BASE_DEC,
+                       "Duplicate to the call in", "rpc.call.dup", FT_FRAMENUM, BASE_NONE,
                        NULL, 0, "This is a duplicate to the call in frame", HFILL }},
                { &hf_rpc_reply_dup, {
-                       "Duplicate to the reply in", "rpc.reply.dup", FT_FRAMENUM, BASE_DEC,
+                       "Duplicate to the reply in", "rpc.reply.dup", FT_FRAMENUM, BASE_NONE,
                        NULL, 0, "This is a duplicate to the reply in frame", HFILL }},
                { &hf_rpc_value_follows, {
                        "Value Follows", "rpc.value_follows", FT_BOOLEAN, BASE_NONE,
-                       &yesno, 0, "Value Follows", HFILL }},
+                       TFS(&tfs_yes_no), 0x0, NULL, HFILL }},
                { &hf_rpc_array_len, {
                        "num", "rpc.array.len", FT_UINT32, BASE_DEC,
                        NULL, 0, "Length of RPC array", HFILL }},
@@ -3727,13 +3745,21 @@ proto_register_rpc(void)
                { "Defragmentation error", "rpc.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
                        "Defragmentation error due to illegal fragments", HFILL }},
 
+               { &hf_rpc_fragment_count,
+               { "Fragment count", "rpc.fragment.count", FT_UINT32, BASE_DEC, NULL, 0x0,
+                       NULL, HFILL }},
+
                { &hf_rpc_fragment,
                { "RPC Fragment", "rpc.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
-                       "RPC Fragment", HFILL }},
+                       NULL, HFILL }},
 
                { &hf_rpc_fragments,
                { "RPC Fragments", "rpc.fragments", FT_NONE, BASE_NONE, NULL, 0x0,
-                       "RPC Fragments", HFILL }},
+                       NULL, HFILL }},
+
+               { &hf_rpc_reassembled_length,
+               { "Reassembled RPC length", "rpc.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x0,
+                       "The total length of the reassembled payload", HFILL }},
        };
        static gint *ett[] = {
                &ett_rpc,
@@ -3778,7 +3804,7 @@ proto_register_rpc(void)
 
        prefs_register_bool_preference(rpc_module, "dissect_unknown_programs",
                "Dissect unknown RPC program numbers",
-               "Whether the RPC dissector should attempt to dissect RPC PDUs containing programs that are not known to Ethereal. This will make the heuristics significantly weaker and elevate the risk for falsely identifying and misdissecting packets significantly.",
+               "Whether the RPC dissector should attempt to dissect RPC PDUs containing programs that are not known to Wireshark. This will make the heuristics significantly weaker and elevate the risk for falsely identifying and misdissecting packets significantly.",
                &rpc_dissect_unknown_programs);
 
        prefs_register_bool_preference(rpc_module, "find_fragment_start",
@@ -3787,9 +3813,7 @@ proto_register_rpc(void)
                &rpc_find_fragment_start);
 
        register_dissector("rpc", dissect_rpc, proto_rpc);
-       rpc_handle = find_dissector("rpc");
        register_dissector("rpc-tcp", dissect_rpc_tcp, proto_rpc);
-       rpc_tcp_handle = find_dissector("rpc-tcp");
        rpc_tap = register_tap("rpc");
 
        /*
@@ -3810,9 +3834,6 @@ proto_register_rpc(void)
 void
 proto_reg_handoff_rpc(void)
 {
-       dissector_handle_t rpc_tcp_handle;
-       dissector_handle_t rpc_udp_handle;
-
        /* tcp/udp port 111 is used by portmapper which is an onc-rpc service.
           we register onc-rpc on this port so that we can choose RPC in
           the list offered by DecodeAs, and so that traffic to or from
@@ -3821,13 +3842,27 @@ proto_reg_handoff_rpc(void)
           probably RPC traffic from some randomly-chosen port that happens
           to match some port for which we have a dissector)
        */
-       rpc_tcp_handle = create_dissector_handle(dissect_rpc_tcp, proto_rpc);
-       dissector_add("tcp.port", 111, rpc_tcp_handle);
-       rpc_udp_handle = create_dissector_handle(dissect_rpc, proto_rpc);
-       dissector_add("udp.port", 111, rpc_udp_handle);
+       rpc_tcp_handle = find_dissector("rpc-tcp");
+       dissector_add_uint("tcp.port", 111, rpc_tcp_handle);
+       rpc_handle = find_dissector("rpc");
+       dissector_add_uint("udp.port", 111, rpc_handle);
 
        heur_dissector_add("tcp", dissect_rpc_tcp_heur, proto_rpc);
        heur_dissector_add("udp", dissect_rpc_heur, proto_rpc);
        gssapi_handle = find_dissector("gssapi");
        data_handle = find_dissector("data");
 }
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * ex: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
+