2 * Routines for Marker Protocol data unit Aligned framing (MPA) dissection
3 * According to IETF RFC 5044
4 * Copyright 2008, Yves Geissbuehler <yves.geissbuehler@gmx.net>
5 * Copyright 2008, Philip Frey <frey.philip@gmail.com>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
34 #include <epan/packet.h>
35 #include <epan/emem.h>
36 #include <epan/conversation.h>
37 #include <epan/dissectors/packet-tcp.h>
38 #include <epan/expert.h>
39 #include <epan/crc32.h>
43 /* header field byte lengths */
44 #define MPA_REQ_REP_FRAME_HEADER_LEN 20
45 #define MPA_PDLENGTH_LEN 2
46 #define MPA_ULPDU_LENGTH_LEN 2
47 #define MPA_MARKER_LEN 4
48 #define MPA_SMALLEST_FPDU_LEN 8
49 #define MPA_REQ_REP_KEY_LEN 16
50 #define MPA_REQ_REP_FLAG_LEN 1
51 #define MPA_REQ_REP_REV_LEN 1
52 #define MPA_REQ_REP_PDLENGTH_LEN 2
53 #define MPA_MARKER_RSVD_LEN 2
54 #define MPA_MARKER_FPDUPTR_LEN 2
57 /* protocol constants */
58 #define MPA_REQ_REP_FRAME G_GINT64_CONSTANT(0x4d50412049442052U)
59 #define MPA_ID_REQ_FRAME G_GINT64_CONSTANT(0x6571204672616d65U)
60 #define MPA_ID_REP_FRAME G_GINT64_CONSTANT(0x6570204672616d65U)
61 #define MPA_MARKER_INTERVAL 512
62 #define MPA_MAX_PD_LENGTH 512
63 #define MPA_ALIGNMENT 4
64 #define TCP_MAX_SEQ ((guint32) 0xffffffff)
66 /* for code readability */
67 #define MPA_REQUEST_FRAME 1
68 #define MPA_REPLY_FRAME 2
70 #define MPA_INITIATOR 0
71 #define MPA_RESPONDER 1
74 #define MPA_MARKER_FLAG 0x80
75 #define MPA_CRC_FLAG 0x40
76 #define MPA_REJECT_FLAG 0x20
77 #define MPA_RESERVED_FLAG 0x1F
81 /* initialize the protocol and registered fields */
82 static gint proto_iwarp_mpa = -1;
84 static gint hf_mpa_req = -1;
85 static gint hf_mpa_rep = -1;
86 static gint hf_mpa_fpdu = -1;
87 static gint hf_mpa_marker = -1;
89 static gint hf_mpa_key_req = -1;
90 static gint hf_mpa_key_rep = -1;
91 static gint hf_mpa_flag_m = -1;
92 static gint hf_mpa_flag_c = -1;
93 static gint hf_mpa_flag_r = -1;
94 static gint hf_mpa_flag_res = -1;
95 static gint hf_mpa_rev = -1;
96 static gint hf_mpa_pd_length = -1;
97 static gint hf_mpa_private_data = -1;
99 static gint hf_mpa_ulpdu_length = -1;
100 static gint hf_mpa_pad = -1;
101 static gint hf_mpa_crc = -1;
102 static gint hf_mpa_crc_check = -1;
104 static gint hf_mpa_marker_res = -1;
105 static gint hf_mpa_marker_fpduptr = -1;
107 /* initialize the subtree pointers */
108 static gint ett_mpa = -1;
110 static gint ett_mpa_req = -1;
111 static gint ett_mpa_rep = -1;
112 static gint ett_mpa_fpdu = -1;
113 static gint ett_mpa_marker = -1;
115 /* handles of our subdissectors */
116 static dissector_handle_t ddp_rdmap_handle = NULL;
118 static const value_string mpa_messages[] = {
119 { MPA_REQUEST_FRAME, "MPA Request Frame" },
120 { MPA_REPLY_FRAME, "MPA Reply Frame" },
121 { MPA_FPDU, "MPA FPDU" },
126 * CONNECTION STATE and MARKERS
127 * A MPA endpoint operates in two distinct phases.
128 * The Startup Phase is used to verify correct MPA setup, exchange CRC
129 * and Marker configuration, and optionally pass Private Data between
130 * endpoints prior to completing a DDP connection.
131 * The second distinct phase is Full Operation during which FPDUs are
132 * sent using all the rules that pertain (CRC, Markers, MULPDU,
133 * restrictions etc.).
134 * To keep track of a MPA connection configuration a mpa_state is declared
135 * and maintained per TCP connection, i.e. it is associated to a conversation
136 * between two endpoints.
138 * In some configurations MPA places MARKERs in a FPDU every 512th octet with
139 * respect to the TCP sequence number of the first FPDU. The struct minfo_t
140 * records the source port of a peer that has to insert Markers into its FPDUs
141 * as well as the TCP sequence number of its first FPDU. This information is
142 * necessary to locate the markers within a FPDU afterwards. Itis part of a
147 * This struct is used to record the source port 'port' and the TCP sequence
148 * number 'seq' of the first FPDU. This information is used to determine the
149 * position of the first Marker within the following FPDUs. The boolean 'valid'
150 * specifies if Markers are inserted by the endpoint running on source port
158 typedef struct minfo minfo_t;
161 * This struct represents a MPA connection state. It specifies if Markers and
162 * CRC is used for the following FPDUs. It also contains information to
163 * distinguish between the MPA Startup and Full Operation Phase.the connection
164 * parameters negotiated between to MPA endpoints during the MPA Startup Phase
165 * as well as other information for the dissection.
167 * The two MPA endpoints are called Initiator, the sender of the MPA Request,
168 * and Responder, the sender of the MPA Reply.
170 * @full_operation: TRUE if is this state is valid and FLASE otherwise.
171 * @req_frame_num: Frame number of the MPA Request to distinguish this frame
173 * @rep_frame_num: Frame number of the MPA Reply to distinguish this frame
175 * @ini_exp_m_res: TRUE if the Initiator expects the Responder to insert
176 * Markers into his FPDUs sent to Initiator and FALSE otherwise.
177 * @res_exp_m_ini: TRUE if the Responder expects the Initiator to insert
178 * Markers into his FPDUs sent to Responder and FALSE otherwise.
179 * @minfo[2]: Array of minfo_t whichs holds necessary information to
180 * determine the start position of the first Marker within a
182 * minfo[0] is used for the Initiator endpoint
183 * minfo[1] is used for the Responder endpoint
184 * @crc: TRUE if CRC is used by both endpoints and FLASE otherwise.
185 * @revision: Stores the MPA protocol revision number.
188 gboolean full_operation;
191 gboolean ini_exp_m_res;
192 gboolean res_exp_m_ini;
197 typedef struct mpa_state mpa_state_t;
200 * Returns an initialized MPA connection state or throws an out of
208 state = (mpa_state_t *) se_alloc0(sizeof(mpa_state_t));
209 state->revision = -1;
214 * Returns the state associated with a MPA connection or NULL otherwise.
217 get_mpa_state(conversation_t *conversation)
220 return (mpa_state_t*) conversation_get_proto_data(conversation,
228 * Returns the offset of the first Marker in a FPDU where the beginning of a
229 * FPDU has an offset of 0. It also addresses possible sequence number
231 * The endpoint is either the Initiator or the Responder.
234 get_first_marker_offset(mpa_state_t *state, struct tcpinfo *tcpinfo,
239 if (tcpinfo->seq > state->minfo[endpoint].seq) {
240 offset = (tcpinfo->seq - state->minfo[endpoint].seq)
241 % MPA_MARKER_INTERVAL;
244 if (tcpinfo->seq < state->minfo[endpoint].seq) {
245 offset = state->minfo[endpoint].seq
246 + (TCP_MAX_SEQ - tcpinfo->seq) % MPA_MARKER_INTERVAL;
249 return (MPA_MARKER_INTERVAL - offset) % MPA_MARKER_INTERVAL;
253 * Returns the total length of this FPDU under the assumption that a TCP
254 * segement carries only one FPDU.
257 fpdu_total_length(struct tcpinfo *tcpinfo)
261 if (tcpinfo->seq < tcpinfo->nxtseq) {
262 size = tcpinfo->nxtseq - tcpinfo->seq;
265 if (tcpinfo->seq >= tcpinfo->nxtseq) {
266 size = tcpinfo->nxtseq + (TCP_MAX_SEQ - tcpinfo->seq);
273 * Returns the number of Markers of this MPA FPDU. The endpoint is either the
274 * Initiator or the Responder.
277 number_of_markers(mpa_state_t *state, struct tcpinfo *tcpinfo, guint8 endpoint)
282 size = fpdu_total_length(tcpinfo);
283 offset = get_first_marker_offset(state, tcpinfo, endpoint);
286 return ((size - offset) / MPA_MARKER_INTERVAL)+1;
293 * Removes any Markers from this FPDU by using memcpy or throws an out of memory
297 remove_markers(tvbuff_t *tvb, packet_info *pinfo, guint32 marker_offset,
298 guint32 num_markers, guint32 orig_length)
300 guint8 *mfree_buff = NULL;
301 guint32 mfree_buff_length, tot_copy, cur_copy;
302 guint32 source_offset;
303 tvbuff_t *mfree_tvb = NULL;
305 DISSECTOR_ASSERT(num_markers > 0);
306 DISSECTOR_ASSERT(orig_length > MPA_MARKER_LEN * num_markers);
307 DISSECTOR_ASSERT(tvb_length(tvb) == orig_length);
309 /* allocate memory for the marker-free buffer */
310 mfree_buff_length = orig_length - (MPA_MARKER_LEN * num_markers);
311 mfree_buff = g_malloc(mfree_buff_length);
314 THROW(OutOfMemoryError);
318 cur_copy = marker_offset;
319 while (tot_copy < mfree_buff_length) {
320 tvb_memcpy(tvb, mfree_buff+tot_copy, source_offset, cur_copy);
321 tot_copy += cur_copy;
322 source_offset += cur_copy + MPA_MARKER_LEN;
323 cur_copy = MIN(MPA_MARKER_INTERVAL, (mfree_buff_length - tot_copy));
325 mfree_tvb = tvb_new_child_real_data(tvb, mfree_buff, mfree_buff_length,
327 tvb_set_free_cb(mfree_tvb, g_free);
328 add_new_data_source(pinfo, mfree_tvb, "FPDU without Markers");
333 /* returns TRUE if this TCP segment carries a MPA REQUEST and FLASE otherwise */
335 is_mpa_req(tvbuff_t *tvb, packet_info *pinfo)
337 conversation_t *conversation = NULL;
338 mpa_state_t *state = NULL;
341 if (tvb_get_ntoh64(tvb, 0) != MPA_REQ_REP_FRAME
342 || tvb_get_ntoh64(tvb, 8) != MPA_ID_REQ_FRAME)
345 conversation = find_or_create_conversation(pinfo);
347 if (!get_mpa_state(conversation)) {
349 /* associate a MPA connection state to this conversation if
350 * there is no MPA state already associated to this connection
352 state = init_mpa_state();
354 /* anaylize MPA connection parameter and record them */
355 mcrres = tvb_get_guint8(tvb, 16);
356 state->ini_exp_m_res = mcrres & MPA_MARKER_FLAG;
357 state->crc = mcrres & MPA_CRC_FLAG;
358 state->revision = tvb_get_guint8(tvb, 17);
359 state->req_frame_num = pinfo->fd->num;
360 state->minfo[MPA_INITIATOR].port = pinfo->srcport;
361 state->minfo[MPA_RESPONDER].port = pinfo->destport;
363 conversation_add_proto_data(conversation, proto_iwarp_mpa, state);
365 /* update expert info */
366 if (mcrres & MPA_RESERVED_FLAG)
367 expert_add_info_format(pinfo, NULL, PI_REQUEST_CODE, PI_WARN,
368 "Res field is NOT set to zero as required by RFC 5044");
370 if (state->revision != 1)
371 expert_add_info_format(pinfo, NULL, PI_REQUEST_CODE, PI_WARN,
372 "Rev field is NOT set to one as required by RFC 5044");
377 /* returns TRUE if this TCP segment carries a MPA REPLY and FALSE otherwise */
379 is_mpa_rep(tvbuff_t *tvb, packet_info *pinfo)
381 conversation_t *conversation = NULL;
382 mpa_state_t *state = NULL;
385 if (tvb_get_ntoh64(tvb, 0) != MPA_REQ_REP_FRAME
386 || tvb_get_ntoh64(tvb, 8) != MPA_ID_REP_FRAME) {
390 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
391 &pinfo->dst, pinfo->ptype, pinfo->srcport,
398 state = get_mpa_state(conversation);
403 if (!state->full_operation) {
404 /* update state of this conversation */
405 mcrres = tvb_get_guint8(tvb, 16);
406 state->res_exp_m_ini = mcrres & MPA_MARKER_FLAG;
407 state->crc = state->crc | (mcrres & MPA_CRC_FLAG);
408 state->rep_frame_num = pinfo->fd->num;
410 /* enter Full Operation Phase only if the Reject bit is not set */
411 if (!(mcrres & MPA_REJECT_FLAG))
412 state->full_operation = TRUE;
414 expert_add_info_format(pinfo, NULL, PI_RESPONSE_CODE, PI_NOTE,
415 "Reject bit set by Responder");
420 /* returns TRUE if this TCP segment carries a MPA FPDU and FALSE otherwise */
422 is_mpa_fpdu(packet_info *pinfo)
424 conversation_t *conversation = NULL;
425 mpa_state_t *state = NULL;
427 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
428 &pinfo->dst, pinfo->ptype, pinfo->srcport,
435 state = get_mpa_state(conversation);
440 /* make sure all MPA connection parameters have been set */
441 if (!state->full_operation) {
445 if (pinfo->fd->num == state->req_frame_num
446 || pinfo->fd->num == state->rep_frame_num) {
453 /* update packet list pane in the GUI */
455 mpa_packetlist(packet_info *pinfo, gint message_type)
457 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MPA");
459 if (check_col(pinfo->cinfo, COL_INFO)) {
460 col_add_fstr(pinfo->cinfo, COL_INFO,
461 "%d > %d %s", pinfo->srcport, pinfo->destport,
462 val_to_str(message_type, mpa_messages,
467 /* dissects MPA REQUEST or MPA REPLY */
469 dissect_mpa_req_rep(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
472 proto_tree *mpa_tree = NULL;
473 proto_tree *mpa_header_tree = NULL;
475 proto_item *mpa_item = NULL;
476 proto_item *mpa_header_item = NULL;
478 proto_item* bad_pd_length_pi = NULL;
483 mpa_packetlist(pinfo, message_type);
486 mpa_item = proto_tree_add_item(tree, proto_iwarp_mpa, tvb, 0,
488 mpa_tree = proto_item_add_subtree(mpa_item, ett_mpa);
490 if (message_type == MPA_REQUEST_FRAME) {
491 mpa_header_item = proto_tree_add_item(mpa_tree,
492 hf_mpa_req, tvb, offset, -1, FALSE);
493 mpa_header_tree = proto_item_add_subtree(
494 mpa_header_item, ett_mpa);
495 proto_tree_add_item(mpa_header_tree, hf_mpa_key_req,
496 tvb, offset, MPA_REQ_REP_KEY_LEN, FALSE);
499 if (message_type == MPA_REPLY_FRAME) {
500 mpa_header_item = proto_tree_add_item(mpa_tree,
501 hf_mpa_rep, tvb, offset, -1, FALSE);
502 mpa_header_tree = proto_item_add_subtree(
503 mpa_header_item, ett_mpa);
504 proto_tree_add_item(mpa_header_tree, hf_mpa_key_rep,
505 tvb, offset, MPA_REQ_REP_KEY_LEN, FALSE);
507 offset += MPA_REQ_REP_KEY_LEN;
509 proto_tree_add_item(mpa_header_tree, hf_mpa_flag_m, tvb,
510 offset, MPA_REQ_REP_FLAG_LEN, FALSE);
511 proto_tree_add_item(mpa_header_tree, hf_mpa_flag_c, tvb,
512 offset, MPA_REQ_REP_FLAG_LEN, FALSE);
513 proto_tree_add_item(mpa_header_tree, hf_mpa_flag_r, tvb,
514 offset, MPA_REQ_REP_FLAG_LEN, FALSE);
515 proto_tree_add_item(mpa_header_tree, hf_mpa_flag_res, tvb,
516 offset, MPA_REQ_REP_FLAG_LEN, FALSE);
517 offset += MPA_REQ_REP_FLAG_LEN;
519 proto_tree_add_item(mpa_header_tree, hf_mpa_rev, tvb,
520 offset, MPA_REQ_REP_REV_LEN, FALSE);
521 offset += MPA_REQ_REP_REV_LEN;
523 /* check whether the Private Data Length conforms to RFC 5044 */
524 pd_length = tvb_get_ntohs(tvb, offset);
525 if (pd_length > MPA_MAX_PD_LENGTH) {
526 bad_pd_length_pi = proto_tree_add_text(tree, tvb, offset, 2,
527 "[PD length field indicates more 512 bytes of Private Data]");
528 proto_item_set_expert_flags(bad_pd_length_pi,
529 PI_MALFORMED, PI_ERROR);
533 proto_tree_add_uint_format_value(mpa_header_tree,
534 hf_mpa_pd_length, tvb, offset,
535 MPA_REQ_REP_PDLENGTH_LEN, pd_length, "%u bytes",
537 offset += MPA_REQ_REP_PDLENGTH_LEN;
540 proto_tree_add_item(mpa_header_tree,
541 hf_mpa_private_data, tvb, offset,
548 /* returns byte length of the padding */
550 fpdu_pad_length(guint16 ulpdu_length)
553 * The padding guarantees alignment of 4. Since Markers are 4 bytes long
554 * we do need to take them into consideration for computation of pad
555 * length. The padding length depends only on ULPDU (payload) length and
556 * the length of the header field for the ULPDU length.
558 guint32 length = ulpdu_length + MPA_ULPDU_LENGTH_LEN;
561 * The extra % MPA_ALIGNMENT at the end covers for the case
562 * length % MPA_ALIGNMENT == 0.
564 return (MPA_ALIGNMENT - (length % MPA_ALIGNMENT)) % MPA_ALIGNMENT;
567 /* returns offset for PAD */
569 pad_offset(struct tcpinfo *tcpinfo, guint32 fpdu_total_len,
572 if ((tcpinfo->nxtseq - MPA_CRC_LEN - MPA_MARKER_LEN) % MPA_MARKER_INTERVAL
574 /* covers the case where a Marker resides between the padding
577 return fpdu_total_len - MPA_CRC_LEN - MPA_MARKER_LEN - pad_len;
579 return fpdu_total_len - MPA_CRC_LEN - pad_len;
583 /* dissects CRC within a FPDU */
585 dissect_fpdu_crc(tvbuff_t *tvb, proto_tree *tree, mpa_state_t *state,
586 guint32 offset, guint32 length)
589 guint32 sent_crc = 0;
593 crc = ~crc32c_calculate(tvb_get_ptr(tvb, 0, length), length,
596 sent_crc = tvb_get_ntohl(tvb, offset); /* crc start offset */
598 if (crc == sent_crc) {
599 proto_tree_add_uint_format_value(tree,
600 hf_mpa_crc_check, tvb, offset, MPA_CRC_LEN,
601 sent_crc, "0x%08x (Good CRC32)",
604 proto_tree_add_uint_format_value(tree,
605 hf_mpa_crc_check, tvb, offset, MPA_CRC_LEN,
607 "0x%08x (Bad CRC32, should be 0x%08x)",
611 proto_tree_add_item(tree, hf_mpa_crc, tvb, offset, MPA_CRC_LEN,
616 /* dissects Markers within FPDU */
618 dissect_fpdu_markers(tvbuff_t *tvb, proto_tree *tree, mpa_state_t *state,
619 struct tcpinfo *tcpinfo, guint8 endpoint)
621 proto_tree *mpa_marker_tree;
622 proto_item *mpa_marker_item;
626 mpa_marker_item = proto_tree_add_item(tree, hf_mpa_marker, tvb,
628 mpa_marker_tree = proto_item_add_subtree(mpa_marker_item, ett_mpa);
630 offset = get_first_marker_offset(state, tcpinfo, endpoint);
632 for (i=0; i<number_of_markers(state, tcpinfo, endpoint); i++) {
633 proto_tree_add_item(mpa_marker_tree, hf_mpa_marker_res, tvb,
634 offset, MPA_MARKER_RSVD_LEN, FALSE);
635 fpduptr = (guint16) tvb_get_ntohs(tvb, offset+MPA_MARKER_RSVD_LEN);
636 proto_tree_add_uint_format_value(mpa_marker_tree,
637 hf_mpa_marker_fpduptr, tvb,
638 offset+MPA_MARKER_RSVD_LEN, MPA_MARKER_FPDUPTR_LEN,
639 fpduptr, "%u bytes", fpduptr);
640 offset += MPA_MARKER_INTERVAL;
644 /* returns the expected value of the 16 bits long MPA FPDU ULPDU LENGTH field */
646 expected_ulpdu_length(mpa_state_t *state, struct tcpinfo *tcpinfo,
649 guint32 length, pad_length, markers_length;
651 length = fpdu_total_length(tcpinfo);
653 if (length <= MPA_CRC_LEN)
655 length -= MPA_CRC_LEN;
657 pad_length = (MPA_ALIGNMENT - (length % MPA_ALIGNMENT)) % MPA_ALIGNMENT;
659 if (length <= pad_length)
661 length -= pad_length;
663 if (state->minfo[endpoint].valid) {
665 number_of_markers(state, tcpinfo, endpoint) * MPA_MARKER_LEN;
667 if (length <= markers_length)
669 length -= markers_length;
672 if (length <= MPA_ULPDU_LENGTH_LEN)
674 length -= MPA_ULPDU_LENGTH_LEN;
676 return (guint16) length;
679 /* dissects MPA FPDU */
681 dissect_mpa_fpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
682 mpa_state_t *state, struct tcpinfo *tcpinfo, guint8 endpoint)
684 proto_item *mpa_item = NULL;
685 proto_item *mpa_header_item = NULL;
687 proto_tree *mpa_tree = NULL;
688 proto_tree *mpa_header_tree = NULL;
690 proto_item* bad_ulpdu_length_pi = NULL;
693 guint16 ulpdu_length, exp_ulpdu_length;
694 guint32 offset, total_length;
695 guint32 num_of_m = 0;
698 * Initialize starting offset for this FPDU. Deals with the case that this
699 * FPDU may start with a Marker instead of the ULPDU_LENTH header field.
701 if (state->minfo[endpoint].valid
702 && get_first_marker_offset(state, tcpinfo, endpoint) == 0) {
703 offset = MPA_MARKER_LEN;
708 /* get ULPDU length of this FPDU */
709 ulpdu_length = (guint16) tvb_get_ntohs(tvb, offset);
711 mpa_packetlist(pinfo, MPA_FPDU);
713 if (state->minfo[endpoint].valid) {
714 num_of_m = number_of_markers(state, tcpinfo, endpoint);
721 * Stop FPDU dissection if the read ULPDU_LENGTH field does NOT contain
723 * Reasons for getting a wrong ULPDU_LENGTH can be lost packets (because
724 * libpcap was not able to capture every packet) or lost alignment (the
725 * MPA FPDU header does not start right after TCP header).
726 * We consider the above to be an error since we make the assumption
727 * that exactly one MPA FPDU is contained in one TCP segement and starts
728 * always either with a Marker or the ULPDU_LENGTH header field.
730 exp_ulpdu_length = expected_ulpdu_length(state, tcpinfo, endpoint);
731 if (!exp_ulpdu_length || exp_ulpdu_length != ulpdu_length) {
732 bad_ulpdu_length_pi = proto_tree_add_text(tree, tvb, offset,
733 MPA_ULPDU_LENGTH_LEN,
734 "[ULPDU length field does not contain the expected length]");
735 proto_item_set_expert_flags(bad_ulpdu_length_pi,
736 PI_MALFORMED, PI_ERROR);
740 mpa_item = proto_tree_add_item(tree, proto_iwarp_mpa, tvb, 0,
742 mpa_tree = proto_item_add_subtree(mpa_item, ett_mpa);
744 mpa_header_item = proto_tree_add_item(mpa_tree, hf_mpa_fpdu,
745 tvb, offset, -1, FALSE);
746 mpa_header_tree = proto_item_add_subtree(mpa_header_item,
749 /* ULPDU Length header field */
750 proto_tree_add_uint_format_value(mpa_header_tree,
751 hf_mpa_ulpdu_length, tvb, offset,
752 MPA_ULPDU_LENGTH_LEN, ulpdu_length, "%u bytes",
755 pad_length = fpdu_pad_length(ulpdu_length);
757 /* Markers are present in this FPDU */
758 if (state->minfo[endpoint].valid && num_of_m > 0) {
760 total_length = fpdu_total_length(tcpinfo);
762 if (pad_length > 0) {
763 proto_tree_add_item(mpa_header_tree, hf_mpa_pad,
764 tvb, pad_offset(tcpinfo,
770 dissect_fpdu_crc(tvb, mpa_header_tree, state,
771 total_length-MPA_CRC_LEN, num_of_m * MPA_MARKER_LEN +
772 ulpdu_length + pad_length + MPA_ULPDU_LENGTH_LEN);
774 dissect_fpdu_markers(tvb, mpa_tree, state, tcpinfo, endpoint);
776 } else { /* Markers are not present or not enabled */
778 offset += MPA_ULPDU_LENGTH_LEN + ulpdu_length;
780 if (pad_length > 0) {
781 proto_tree_add_item(mpa_header_tree, hf_mpa_pad, tvb, offset,
783 offset += pad_length;
786 dissect_fpdu_crc(tvb, mpa_header_tree, state, offset,
787 ulpdu_length+pad_length+MPA_ULPDU_LENGTH_LEN);
794 * Main dissection routine.
797 dissect_iwarp_mpa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
799 tvbuff_t *next_tvb = NULL;
800 conversation_t *conversation = NULL;
801 mpa_state_t *state = NULL;
802 struct tcpinfo *tcpinfo = NULL;
804 guint16 ulpdu_length = 0;
807 if (tvb_length(tvb) >= MPA_SMALLEST_FPDU_LEN && is_mpa_fpdu(pinfo)) {
809 tcpinfo = pinfo->private_data;
811 conversation = find_conversation(pinfo->fd->num, &pinfo->src,
812 &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
814 state = get_mpa_state(conversation);
816 if (pinfo->srcport == state->minfo[MPA_INITIATOR].port) {
817 endpoint = MPA_INITIATOR;
818 } else if (pinfo->srcport == state->minfo[MPA_RESPONDER].port) {
819 endpoint = MPA_RESPONDER;
821 REPORT_DISSECTOR_BUG("endpoint cannot be determined");
824 /* Markers are used by either the Initiator or the Responder or both. */
825 if ((state->ini_exp_m_res || state->res_exp_m_ini) && endpoint <= MPA_RESPONDER) {
827 /* find the TCP sequence number of the first FPDU */
828 if (!state->minfo[endpoint].valid) {
829 state->minfo[endpoint].seq = tcpinfo->seq;
830 state->minfo[endpoint].valid = TRUE;
835 ulpdu_length = dissect_mpa_fpdu(tvb, pinfo, tree, state, tcpinfo,
838 /* an ulpdu_length of 0 should never happen */
842 /* removes Markers if any and prepares new tvbuff for next dissector */
843 if (endpoint <= MPA_RESPONDER && state->minfo[endpoint].valid
844 && number_of_markers(state, tcpinfo, endpoint) > 0) {
845 next_tvb = tvb_new_subset(remove_markers(tvb, pinfo,
846 get_first_marker_offset(state, tcpinfo, endpoint),
847 number_of_markers(state, tcpinfo, endpoint),
848 fpdu_total_length(tcpinfo)), MPA_ULPDU_LENGTH_LEN,
849 ulpdu_length, ulpdu_length);
851 next_tvb = tvb_new_subset(tvb, MPA_ULPDU_LENGTH_LEN, ulpdu_length,
856 /* call subdissector */
857 if (ddp_rdmap_handle) {
858 call_dissector(ddp_rdmap_handle, next_tvb, pinfo, tree);
860 REPORT_DISSECTOR_BUG("ddp_handle was null");
866 /* MPA REQUEST or MPA REPLY */
867 if (tvb_length(tvb) >= MPA_REQ_REP_FRAME_HEADER_LEN) {
868 if (is_mpa_req(tvb, pinfo))
869 return dissect_mpa_req_rep(tvb, pinfo, tree, MPA_REQUEST_FRAME);
870 else if (is_mpa_rep(tvb, pinfo))
871 return dissect_mpa_req_rep(tvb, pinfo, tree, MPA_REPLY_FRAME);
876 /* registers this protocol with Wireshark */
877 void proto_register_mpa(void)
879 /* setup list of header fields */
880 static hf_register_info hf[] = {
882 "Request frame header", "iwarp_mpa.req",
883 FT_NONE, BASE_NONE, NULL, 0x0,
886 "Reply frame header", "iwarp_mpa.rep",
887 FT_NONE, BASE_NONE, NULL, 0x0,
890 "FPDU", "iwarp_mpa.fpdu",
891 FT_NONE, BASE_NONE, NULL, 0x0,
894 "Markers", "iwarp_mpa.markers",
895 FT_NONE, BASE_NONE, NULL, 0x0,
898 "ID Req frame", "iwarp_mpa.key.req",
899 FT_BYTES, BASE_NONE, NULL, 0x0,
902 "ID Rep frame", "iwarp_mpa.key.rep",
903 FT_BYTES, BASE_NONE, NULL, 0x0,
906 "Marker flag", "iwarp_mpa.marker_flag",
907 FT_BOOLEAN, 8, NULL, MPA_MARKER_FLAG,
910 "CRC flag", "iwarp_mpa.crc_flag",
911 FT_BOOLEAN, 8, NULL, MPA_CRC_FLAG,
914 "Connection rejected flag",
915 "iwarp_mpa.rej_flag", FT_BOOLEAN, 8, NULL, MPA_REJECT_FLAG,
917 { &hf_mpa_flag_res, {
918 "Reserved", "iwarp_mpa.res",
919 FT_UINT8, BASE_HEX, NULL, MPA_RESERVED_FLAG,
922 "Revision", "iwarp_mpa.rev",
923 FT_UINT8, BASE_DEC, NULL, 0x0,
925 { &hf_mpa_pd_length, {
926 "Private data length", "iwarp_mpa.pdlength",
927 FT_UINT16, BASE_DEC, NULL, 0x0,
929 { &hf_mpa_private_data, {
930 "Private data", "iwarp_mpa.privatedata",
931 FT_BYTES, BASE_NONE, NULL, 0x0,
933 { &hf_mpa_ulpdu_length, {
934 "ULPDU length", "iwarp_mpa.ulpdulength",
935 FT_UINT16, BASE_DEC, NULL, 0x0,
938 "Padding", "iwarp_mpa.pad",
939 FT_BYTES, BASE_NONE, NULL, 0x0,
942 "CRC", "iwarp_mpa.crc",
943 FT_UINT32, BASE_HEX, NULL, 0x0,
945 { &hf_mpa_crc_check, {
946 "CRC check", "iwarp_mpa.crc_check",
947 FT_UINT32, BASE_HEX, NULL, 0x0,
949 { &hf_mpa_marker_res, {
950 "Reserved", "iwarp_mpa.marker_res",
951 FT_UINT16, BASE_HEX, NULL, 0x0,
952 "Marker: Reserved", HFILL } },
953 { &hf_mpa_marker_fpduptr, {
954 "FPDU back pointer", "iwarp_mpa.marker_fpduptr",
955 FT_UINT16, BASE_DEC, NULL, 0x0,
956 "Marker: FPDU Pointer", HFILL } }
959 /* setup protocol subtree array */
960 static gint *ett[] = {
968 /* register the protocol name and description */
969 proto_iwarp_mpa = proto_register_protocol(
970 "iWARP Marker Protocol data unit Aligned framing",
971 "IWARP_MPA", "iwarp_mpa");
973 /* required function calls to register the header fields and subtrees */
974 proto_register_field_array(proto_iwarp_mpa, hf, array_length(hf));
975 proto_register_subtree_array(ett, array_length(ett));
980 proto_reg_handoff_mpa(void)
983 * MPA does not use any specific TCP port so, when not on a specific
984 * port, try this dissector whenever there is TCP traffic.
986 heur_dissector_add("tcp", dissect_iwarp_mpa, proto_iwarp_mpa);
987 ddp_rdmap_handle = find_dissector("iwarp_ddp_rdmap");