fix no marker pdu fragmentation epan/dissectors/packet-iwarp-mpa.c
[metze/wireshark/wip.git] / epan / dissectors / packet-iwarp-mpa.c
index aae4c593193d027eecd893480e3c8c2cbd08db3c..fe183b7c76d6239d3066f2400c4e4bb9250cb6c0 100644 (file)
@@ -4,39 +4,24 @@
  * Copyright 2008, Yves Geissbuehler <yves.geissbuehler@gmx.net>
  * Copyright 2008, Philip Frey <frey.philip@gmail.com>
  *
- * $Id$
- *
  * Wireshark - Network traffic analyzer
  * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
- * USA.
+ * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
 /* INCLUDES */
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #include <epan/packet.h>
-#include <epan/emem.h>
-#include <epan/conversation.h>
-#include <epan/dissectors/packet-tcp.h>
 #include <epan/expert.h>
+#include <epan/crc32-tvb.h>
 #include <wsutil/crc32.h>
+#include "packet-tcp.h"
+
+void proto_register_mpa(void);
+void proto_reg_handoff_mpa(void);
 
 /* DEFINES */
 
@@ -55,9 +40,9 @@
 #define MPA_CRC_LEN 4
 
 /* protocol constants */
-#define MPA_REQ_REP_FRAME G_GINT64_CONSTANT(0x4d50412049442052U)
-#define MPA_ID_REQ_FRAME G_GINT64_CONSTANT(0x6571204672616d65U)
-#define MPA_ID_REP_FRAME G_GINT64_CONSTANT(0x6570204672616d65U)
+#define MPA_REQ_REP_FRAME G_GUINT64_CONSTANT(0x4d50412049442052)
+#define MPA_ID_REQ_FRAME G_GUINT64_CONSTANT(0x6571204672616d65)
+#define MPA_ID_REP_FRAME G_GUINT64_CONSTANT(0x6570204672616d65)
 #define MPA_MARKER_INTERVAL 512
 #define MPA_MAX_PD_LENGTH 512
 #define MPA_ALIGNMENT 4
@@ -112,6 +97,11 @@ static gint ett_mpa_rep = -1;
 static gint ett_mpa_fpdu = -1;
 static gint ett_mpa_marker = -1;
 
+static expert_field ei_mpa_res_field_not_set0 = EI_INIT;
+static expert_field ei_mpa_rev_field_not_set1 = EI_INIT;
+static expert_field ei_mpa_reject_bit_responder = EI_INIT;
+static expert_field ei_mpa_bad_length = EI_INIT;
+
 /* handles of our subdissectors */
 static dissector_handle_t ddp_rdmap_handle = NULL;
 
@@ -205,7 +195,7 @@ init_mpa_state(void)
 {
        mpa_state_t *state;
 
-       state = (mpa_state_t *) se_alloc0(sizeof(mpa_state_t));
+       state = (mpa_state_t *) wmem_alloc0(wmem_file_scope(), sizeof(mpa_state_t));
        state->revision = -1;
        return state;
 }
@@ -251,7 +241,7 @@ get_first_marker_offset(mpa_state_t *state, struct tcpinfo *tcpinfo,
 
 /*
  * Returns the total length of this FPDU under the assumption that a TCP
- * segement carries only one FPDU.
+ * segment carries only one FPDU.
  */
 static guint32
 fpdu_total_length(struct tcpinfo *tcpinfo)
@@ -304,11 +294,11 @@ remove_markers(tvbuff_t *tvb, packet_info *pinfo, guint32 marker_offset,
 
        DISSECTOR_ASSERT(num_markers > 0);
        DISSECTOR_ASSERT(orig_length > MPA_MARKER_LEN * num_markers);
-       DISSECTOR_ASSERT(tvb_length(tvb) == orig_length);
+       DISSECTOR_ASSERT(tvb_captured_length(tvb) == orig_length);
 
        /* allocate memory for the marker-free buffer */
        mfree_buff_length = orig_length - (MPA_MARKER_LEN * num_markers);
-       mfree_buff = g_malloc(mfree_buff_length);
+       mfree_buff = (guint8 *)wmem_alloc(pinfo->pool, mfree_buff_length);
 
        tot_copy = 0;
        source_offset = 0;
@@ -321,7 +311,6 @@ remove_markers(tvbuff_t *tvb, packet_info *pinfo, guint32 marker_offset,
        }
        mfree_tvb = tvb_new_child_real_data(tvb, mfree_buff, mfree_buff_length,
                                            mfree_buff_length);
-       tvb_set_free_cb(mfree_tvb, g_free);
        add_new_data_source(pinfo, mfree_tvb, "FPDU without Markers");
 
        return mfree_tvb;
@@ -348,12 +337,12 @@ is_mpa_req(tvbuff_t *tvb, packet_info *pinfo)
                 */
                state = init_mpa_state();
 
-               /* anaylize MPA connection parameter and record them */
+               /* analyze MPA connection parameter and record them */
                mcrres = tvb_get_guint8(tvb, 16);
                state->ini_exp_m_res = mcrres & MPA_MARKER_FLAG;
                state->crc = mcrres & MPA_CRC_FLAG;
                state->revision = tvb_get_guint8(tvb, 17);
-               state->req_frame_num = pinfo->fd->num;
+               state->req_frame_num = pinfo->num;
                state->minfo[MPA_INITIATOR].port = pinfo->srcport;
                state->minfo[MPA_RESPONDER].port = pinfo->destport;
 
@@ -361,12 +350,10 @@ is_mpa_req(tvbuff_t *tvb, packet_info *pinfo)
 
                /* update expert info */
                if (mcrres & MPA_RESERVED_FLAG)
-                       expert_add_info_format(pinfo, NULL, PI_REQUEST_CODE, PI_WARN,
-                                       "Res field is NOT set to zero as required by RFC 5044");
+                       expert_add_info(pinfo, NULL, &ei_mpa_res_field_not_set0);
 
                if (state->revision != 1)
-                       expert_add_info_format(pinfo, NULL, PI_REQUEST_CODE, PI_WARN,
-                                       "Rev field is NOT set to one as required by RFC 5044");
+                       expert_add_info(pinfo, NULL, &ei_mpa_rev_field_not_set1);
        }
        return TRUE;
 }
@@ -384,9 +371,7 @@ is_mpa_rep(tvbuff_t *tvb, packet_info *pinfo)
                return FALSE;
        }
 
-       conversation = find_conversation(pinfo->fd->num, &pinfo->src,
-                       &pinfo->dst, pinfo->ptype, pinfo->srcport,
-                       pinfo->destport, 0);
+       conversation = find_conversation_pinfo(pinfo, 0);
 
        if (!conversation) {
                return FALSE;
@@ -402,14 +387,13 @@ is_mpa_rep(tvbuff_t *tvb, packet_info *pinfo)
                mcrres = tvb_get_guint8(tvb, 16);
                state->res_exp_m_ini = mcrres & MPA_MARKER_FLAG;
                state->crc = state->crc | (mcrres & MPA_CRC_FLAG);
-               state->rep_frame_num = pinfo->fd->num;
+               state->rep_frame_num = pinfo->num;
 
                 /* enter Full Operation Phase only if the Reject bit is not set */
                if (!(mcrres & MPA_REJECT_FLAG))
                        state->full_operation = TRUE;
                else
-                       expert_add_info_format(pinfo, NULL, PI_RESPONSE_CODE, PI_NOTE,
-                               "Reject bit set by Responder");
+                       expert_add_info(pinfo, NULL, &ei_mpa_reject_bit_responder);
        }
        return TRUE;
 }
@@ -421,9 +405,7 @@ is_mpa_fpdu(packet_info *pinfo)
        conversation_t *conversation = NULL;
        mpa_state_t *state = NULL;
 
-       conversation = find_conversation(pinfo->fd->num, &pinfo->src,
-                       &pinfo->dst, pinfo->ptype, pinfo->srcport,
-                       pinfo->destport, 0);
+       conversation = find_conversation_pinfo(pinfo, 0);
 
        if (!conversation) {
                return FALSE;
@@ -439,8 +421,8 @@ is_mpa_fpdu(packet_info *pinfo)
                return FALSE;
        }
 
-       if (pinfo->fd->num == state->req_frame_num
-                       || pinfo->fd->num == state->rep_frame_num) {
+       if (pinfo->num == state->req_frame_num
+                       || pinfo->num == state->rep_frame_num) {
                return FALSE;
        } else {
                return TRUE;
@@ -453,12 +435,10 @@ mpa_packetlist(packet_info *pinfo, gint message_type)
 {
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "MPA");
 
-       if (check_col(pinfo->cinfo, COL_INFO)) {
-               col_add_fstr(pinfo->cinfo, COL_INFO,
+       col_add_fstr(pinfo->cinfo, COL_INFO,
                                "%d > %d %s", pinfo->srcport, pinfo->destport,
                                val_to_str(message_type, mpa_messages,
                                                "Unknown %d"));
-       }
 }
 
 /* dissects MPA REQUEST or MPA REPLY */
@@ -472,8 +452,6 @@ dissect_mpa_req_rep(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        proto_item *mpa_item = NULL;
        proto_item *mpa_header_item = NULL;
 
-       proto_item* bad_pd_length_pi = NULL;
-
        guint16 pd_length;
        guint32 offset = 0;
 
@@ -520,17 +498,14 @@ dissect_mpa_req_rep(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                /* check whether the Private Data Length conforms to RFC 5044 */
                pd_length = tvb_get_ntohs(tvb, offset);
                if (pd_length > MPA_MAX_PD_LENGTH) {
-                       bad_pd_length_pi = proto_tree_add_text(tree, tvb, offset, 2,
+                       proto_tree_add_expert_format(tree, pinfo, &ei_mpa_bad_length, tvb, offset, 2,
                                "[PD length field indicates more 512 bytes of Private Data]");
-                       proto_item_set_expert_flags(bad_pd_length_pi,
-                               PI_MALFORMED, PI_ERROR);
                        return FALSE;
                }
 
-               proto_tree_add_uint_format_value(mpa_header_tree,
+               proto_tree_add_uint(mpa_header_tree,
                                hf_mpa_pd_length, tvb, offset,
-                               MPA_REQ_REP_PDLENGTH_LEN, pd_length, "%u bytes",
-                               pd_length);
+                               MPA_REQ_REP_PDLENGTH_LEN, pd_length);
                offset += MPA_REQ_REP_PDLENGTH_LEN;
 
                if (pd_length) {
@@ -587,8 +562,7 @@ dissect_fpdu_crc(tvbuff_t *tvb, proto_tree *tree, mpa_state_t *state,
 
        if (state->crc) {
 
-               crc = ~crc32c_calculate(tvb_get_ptr(tvb, 0, length), length,
-                               CRC32C_PRELOAD);
+               crc = ~crc32c_tvb_offset_calculate(tvb, 0, length, CRC32C_PRELOAD);
 
                sent_crc = tvb_get_ntohl(tvb, offset); /* crc start offset */
 
@@ -617,7 +591,6 @@ dissect_fpdu_markers(tvbuff_t *tvb, proto_tree *tree, mpa_state_t *state,
 {
        proto_tree *mpa_marker_tree;
        proto_item *mpa_marker_item;
-       guint16 fpduptr;
        guint32 offset, i;
 
        mpa_marker_item = proto_tree_add_item(tree, hf_mpa_marker, tvb,
@@ -629,11 +602,9 @@ dissect_fpdu_markers(tvbuff_t *tvb, proto_tree *tree, mpa_state_t *state,
        for (i=0; i<number_of_markers(state, tcpinfo, endpoint); i++) {
                proto_tree_add_item(mpa_marker_tree, hf_mpa_marker_res, tvb,
                                offset, MPA_MARKER_RSVD_LEN, ENC_BIG_ENDIAN);
-               fpduptr = (guint16) tvb_get_ntohs(tvb, offset+MPA_MARKER_RSVD_LEN);
-               proto_tree_add_uint_format_value(mpa_marker_tree,
+               proto_tree_add_item(mpa_marker_tree,
                                hf_mpa_marker_fpduptr, tvb,
-                               offset+MPA_MARKER_RSVD_LEN,     MPA_MARKER_FPDUPTR_LEN,
-                               fpduptr, "%u bytes", fpduptr);
+                               offset+MPA_MARKER_RSVD_LEN,     MPA_MARKER_FPDUPTR_LEN, ENC_BIG_ENDIAN);
                offset += MPA_MARKER_INTERVAL;
        }
 }
@@ -684,8 +655,6 @@ dissect_mpa_fpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        proto_tree *mpa_tree = NULL;
        proto_tree *mpa_header_tree = NULL;
 
-       proto_item* bad_ulpdu_length_pi = NULL;
-
        guint8 pad_length;
        guint16 ulpdu_length, exp_ulpdu_length;
        guint32 offset, total_length;
@@ -705,15 +674,11 @@ dissect_mpa_fpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
        /* get ULPDU length of this FPDU */
        ulpdu_length = (guint16) tvb_get_ntohs(tvb, offset);
 
-       mpa_packetlist(pinfo, MPA_FPDU);
-
        if (state->minfo[endpoint].valid) {
                num_of_m = number_of_markers(state, tcpinfo, endpoint);
        }
 
 
-       if (tree) {
-
                /*
                 * Stop FPDU dissection if the read ULPDU_LENGTH field does NOT contain
                 * what is expected.
@@ -721,19 +686,19 @@ dissect_mpa_fpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                 * libpcap was not able to capture every packet) or lost alignment (the
                 * MPA FPDU header does not start right after TCP header).
                 * We consider the above to be an error since we make the assumption
-                * that exactly one MPA FPDU is contained in one TCP segement and starts
+                * that exactly one MPA FPDU is contained in one TCP segment and starts
                 * always either with a Marker or the ULPDU_LENGTH header field.
                 */
-               exp_ulpdu_length = expected_ulpdu_length(state, tcpinfo, endpoint);
-               if (!exp_ulpdu_length || exp_ulpdu_length != ulpdu_length) {
-                       bad_ulpdu_length_pi = proto_tree_add_text(tree, tvb, offset,
-                               MPA_ULPDU_LENGTH_LEN,
-                               "[ULPDU length field does not contain the expected length]");
-                       proto_item_set_expert_flags(bad_ulpdu_length_pi,
-                               PI_MALFORMED, PI_ERROR);
-                       return 0;
+               pad_length = fpdu_pad_length(ulpdu_length);
+               if (num_of_m > 0) {
+                       exp_ulpdu_length = expected_ulpdu_length(state, tcpinfo, endpoint);
+                       if (!exp_ulpdu_length || exp_ulpdu_length != (ulpdu_length + pad_length)) {
+                               return 0;
+                       }
                }
 
+               mpa_packetlist(pinfo, MPA_FPDU);
+
                mpa_item = proto_tree_add_item(tree, proto_iwarp_mpa, tvb, 0,
                                -1, ENC_NA);
                mpa_tree = proto_item_add_subtree(mpa_item, ett_mpa);
@@ -744,15 +709,12 @@ dissect_mpa_fpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                ett_mpa);
 
                /* ULPDU Length header field */
-               proto_tree_add_uint_format_value(mpa_header_tree,
+               proto_tree_add_uint(mpa_header_tree,
                                hf_mpa_ulpdu_length, tvb, offset,
-                               MPA_ULPDU_LENGTH_LEN, ulpdu_length, "%u bytes",
-                               ulpdu_length);
-
-               pad_length = fpdu_pad_length(ulpdu_length);
+                               MPA_ULPDU_LENGTH_LEN, ulpdu_length);
 
                /* Markers are present in this FPDU */
-               if (state->minfo[endpoint].valid && num_of_m > 0) {
+               if (num_of_m > 0) {
 
                        total_length = fpdu_total_length(tcpinfo);
 
@@ -783,7 +745,6 @@ dissect_mpa_fpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                        dissect_fpdu_crc(tvb, mpa_header_tree, state, offset,
                                        ulpdu_length+pad_length+MPA_ULPDU_LENGTH_LEN);
                }
-       }
        return ulpdu_length;
 }
 
@@ -791,22 +752,23 @@ dissect_mpa_fpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
  * Main dissection routine.
  */
 static gboolean
-dissect_iwarp_mpa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_iwarp_mpa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
 {
        tvbuff_t *next_tvb = NULL;
        conversation_t *conversation = NULL;
        mpa_state_t *state = NULL;
-       struct tcpinfo *tcpinfo = NULL;
+       struct tcpinfo *tcpinfo;
        guint8 endpoint = 3;
        guint16 ulpdu_length = 0;
 
-       /* FPDU */
-       if (tvb_length(tvb) >= MPA_SMALLEST_FPDU_LEN && is_mpa_fpdu(pinfo)) {
+       if (data == NULL)
+               return FALSE;
+       tcpinfo = (struct tcpinfo *)data;
 
-               tcpinfo = pinfo->private_data;
+       /* FPDU */
+       if (tvb_captured_length(tvb) >= MPA_SMALLEST_FPDU_LEN && is_mpa_fpdu(pinfo)) {
 
-               conversation = find_conversation(pinfo->fd->num, &pinfo->src,
-                               &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
+               conversation = find_conversation_pinfo(pinfo, 0);
 
                state = get_mpa_state(conversation);
 
@@ -839,14 +801,13 @@ dissect_iwarp_mpa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                /* removes Markers if any and prepares new tvbuff for next dissector */
                if (endpoint <= MPA_RESPONDER && state->minfo[endpoint].valid
                                && number_of_markers(state, tcpinfo, endpoint) > 0) {
-                       next_tvb = tvb_new_subset(remove_markers(tvb, pinfo,
+                       next_tvb = tvb_new_subset_length(remove_markers(tvb, pinfo,
                                        get_first_marker_offset(state, tcpinfo, endpoint),
                                        number_of_markers(state, tcpinfo, endpoint),
                                        fpdu_total_length(tcpinfo)), MPA_ULPDU_LENGTH_LEN,
-                                       ulpdu_length, ulpdu_length);
-               } else {
-                       next_tvb = tvb_new_subset(tvb, MPA_ULPDU_LENGTH_LEN, ulpdu_length,
                                        ulpdu_length);
+               } else {
+                       next_tvb = tvb_new_subset_length(tvb, MPA_ULPDU_LENGTH_LEN, ulpdu_length);
                }
 
 
@@ -861,7 +822,7 @@ dissect_iwarp_mpa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        }
 
        /* MPA REQUEST or MPA REPLY */
-       if (tvb_length(tvb) >= MPA_REQ_REP_FRAME_HEADER_LEN) {
+       if (tvb_captured_length(tvb) >= MPA_REQ_REP_FRAME_HEADER_LEN) {
                if (is_mpa_req(tvb, pinfo))
                        return dissect_mpa_req_rep(tvb, pinfo, tree, MPA_REQUEST_FRAME);
                else if (is_mpa_rep(tvb, pinfo))
@@ -870,6 +831,104 @@ dissect_iwarp_mpa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        return FALSE;
 }
 
+static guint
+iwrap_mpa_pdu_length(packet_info *pinfo _U_, tvbuff_t *tvb,
+                    int offset, void *data _U_)
+{
+       guint64 tag;
+       gint remaining = tvb_captured_length_remaining(tvb, offset);
+       guint pdu_length = 0;
+       guint16 PD_Length;
+
+       tag = tvb_get_ntoh64(tvb, offset);
+       if (tag != MPA_REQ_REP_FRAME) {
+               /* FPDU */
+               guint16 ULPDU_Length;
+               guint8 pad_length;
+
+               ULPDU_Length = tvb_get_ntohs(tvb, offset);
+               pad_length = fpdu_pad_length(ULPDU_Length);
+
+               pdu_length += MPA_ULPDU_LENGTH_LEN;
+               pdu_length += ULPDU_Length;
+               pdu_length += pad_length;
+               pdu_length += MPA_CRC_LEN;
+
+               return pdu_length;
+       }
+
+       /*
+        * MPA Request and Reply Frame Format...
+        */
+
+       if (remaining < MPA_REQ_REP_FRAME_HEADER_LEN) {
+               /*
+                * We need more data.
+                */
+               return 0;
+       }
+
+       offset += MPA_REQ_REP_FRAME_HEADER_LEN;
+       offset -= MPA_REQ_REP_PDLENGTH_LEN;
+
+       PD_Length = tvb_get_ntohs(tvb, offset);
+
+       pdu_length += MPA_REQ_REP_FRAME_HEADER_LEN;
+       pdu_length += PD_Length;
+
+       return pdu_length;
+}
+
+static int
+dissect_iwarp_mpa_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+       gboolean ok;
+       guint len;
+
+       len = iwrap_mpa_pdu_length(pinfo, tvb, 0, data);
+       ok = dissect_iwarp_mpa(tvb, pinfo, tree, data);
+       if (!ok) {
+               return -1;
+       }
+
+       return len;
+}
+
+static gboolean
+dissect_iwarp_mpa_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+       struct tcpinfo *tcpinfo = NULL;
+       gboolean is_mpa_pdu = FALSE;
+
+       if (data == NULL)
+               return FALSE;
+       tcpinfo = (struct tcpinfo *)data;
+
+       /* MPA REQUEST or MPA REPLY */
+       if (tvb_captured_length(tvb) >= MPA_REQ_REP_FRAME_HEADER_LEN) {
+               if (is_mpa_req(tvb, pinfo)) {
+                       is_mpa_pdu = TRUE;
+               } else if (is_mpa_rep(tvb, pinfo)) {
+                       is_mpa_pdu = TRUE;
+               }
+       }
+       if (tvb_captured_length(tvb) >= MPA_SMALLEST_FPDU_LEN && is_mpa_fpdu(pinfo)) {
+               is_mpa_pdu = TRUE;
+       }
+
+       if (!is_mpa_pdu) {
+               return FALSE;
+       }
+
+       tcp_dissect_pdus(tvb, pinfo, tree,
+                        TRUE, /* proto_desegment*/
+                        MPA_SMALLEST_FPDU_LEN,
+                        iwrap_mpa_pdu_length,
+                        dissect_iwarp_mpa_pdu,
+                        tcpinfo);
+       return TRUE;
+}
+
 /* registers this protocol with Wireshark */
 void proto_register_mpa(void)
 {
@@ -921,7 +980,7 @@ void proto_register_mpa(void)
                                        NULL, HFILL } },
                        { &hf_mpa_pd_length, {
                                        "Private data length", "iwarp_mpa.pdlength",
-                                       FT_UINT16, BASE_DEC, NULL, 0x0,
+                                       FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0x0,
                                        NULL, HFILL } },
                        { &hf_mpa_private_data, {
                                        "Private data", "iwarp_mpa.privatedata",
@@ -929,7 +988,7 @@ void proto_register_mpa(void)
                                        NULL, HFILL } },
                        { &hf_mpa_ulpdu_length, {
                                        "ULPDU length", "iwarp_mpa.ulpdulength",
-                                       FT_UINT16, BASE_DEC, NULL, 0x0,
+                                       FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0x0,
                                        NULL, HFILL } },
                        { &hf_mpa_pad, {
                                        "Padding", "iwarp_mpa.pad",
@@ -949,7 +1008,7 @@ void proto_register_mpa(void)
                                        "Marker: Reserved", HFILL } },
                        { &hf_mpa_marker_fpduptr, {
                                        "FPDU back pointer", "iwarp_mpa.marker_fpduptr",
-                                       FT_UINT16, BASE_DEC, NULL, 0x0,
+                                       FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0x0,
                                        "Marker: FPDU Pointer", HFILL } }
        };
 
@@ -962,6 +1021,15 @@ void proto_register_mpa(void)
                        &ett_mpa_marker
        };
 
+       static ei_register_info ei[] = {
+               { &ei_mpa_res_field_not_set0, { "iwarp_mpa.res.not_set0", PI_REQUEST_CODE, PI_WARN, "Res field is NOT set to zero as required by RFC 5044", EXPFILL }},
+               { &ei_mpa_rev_field_not_set1, { "iwarp_mpa.rev.not_set1", PI_REQUEST_CODE, PI_WARN, "Rev field is NOT set to one as required by RFC 5044", EXPFILL }},
+               { &ei_mpa_reject_bit_responder, { "iwarp_mpa.reject_bit_responder", PI_RESPONSE_CODE, PI_NOTE, "Reject bit set by Responder", EXPFILL }},
+               { &ei_mpa_bad_length, { "iwarp_mpa.bad_length", PI_MALFORMED, PI_ERROR, "Bad length", EXPFILL }},
+       };
+
+       expert_module_t* expert_iwarp_mpa;
+
        /* register the protocol name and description */
        proto_iwarp_mpa = proto_register_protocol(
                "iWARP Marker Protocol data unit Aligned framing",
@@ -970,7 +1038,8 @@ void proto_register_mpa(void)
        /* required function calls to register the header fields and subtrees */
        proto_register_field_array(proto_iwarp_mpa, hf, array_length(hf));
        proto_register_subtree_array(ett, array_length(ett));
-
+       expert_iwarp_mpa = expert_register_protocol(proto_iwarp_mpa);
+       expert_register_field_array(expert_iwarp_mpa, ei, array_length(ei));
 }
 
 void
@@ -980,6 +1049,19 @@ proto_reg_handoff_mpa(void)
         * MPA does not use any specific TCP port so, when not on a specific
         * port, try this dissector whenever there is TCP traffic.
         */
-       heur_dissector_add("tcp", dissect_iwarp_mpa, proto_iwarp_mpa);
-       ddp_rdmap_handle = find_dissector("iwarp_ddp_rdmap");
+       heur_dissector_add("tcp", dissect_iwarp_mpa_heur, "IWARP_MPA over TCP", "iwarp_mpa_tcp", proto_iwarp_mpa, HEURISTIC_ENABLE);
+       ddp_rdmap_handle = find_dissector_add_dependency("iwarp_ddp_rdmap", proto_iwarp_mpa);
 }
+
+/*
+ * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */