* 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 */
#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
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;
{
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;
}
/*
* 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)
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;
}
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;
*/
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;
/* 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;
}
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;
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;
}
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;
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;
{
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 */
proto_item *mpa_item = NULL;
proto_item *mpa_header_item = NULL;
- proto_item* bad_pd_length_pi = NULL;
-
guint16 pd_length;
guint32 offset = 0;
/* 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) {
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 */
{
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,
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;
}
}
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;
/* 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.
* 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);
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);
dissect_fpdu_crc(tvb, mpa_header_tree, state, offset,
ulpdu_length+pad_length+MPA_ULPDU_LENGTH_LEN);
}
- }
return ulpdu_length;
}
* 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);
/* 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);
}
}
/* 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))
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)
{
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",
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",
"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 } }
};
&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",
/* 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
* 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:
+ */