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,
32 #include <epan/packet.h>
33 #include <epan/wmem/wmem.h>
34 #include <epan/conversation.h>
35 #include <epan/dissectors/packet-tcp.h>
36 #include <epan/expert.h>
37 #include <wsutil/crc32.h>
41 /* header field byte lengths */
42 #define MPA_REQ_REP_FRAME_HEADER_LEN 20
43 #define MPA_PDLENGTH_LEN 2
44 #define MPA_ULPDU_LENGTH_LEN 2
45 #define MPA_MARKER_LEN 4
46 #define MPA_SMALLEST_FPDU_LEN 8
47 #define MPA_REQ_REP_KEY_LEN 16
48 #define MPA_REQ_REP_FLAG_LEN 1
49 #define MPA_REQ_REP_REV_LEN 1
50 #define MPA_REQ_REP_PDLENGTH_LEN 2
51 #define MPA_MARKER_RSVD_LEN 2
52 #define MPA_MARKER_FPDUPTR_LEN 2
55 /* protocol constants */
56 #define MPA_REQ_REP_FRAME G_GINT64_CONSTANT(0x4d50412049442052U)
57 #define MPA_ID_REQ_FRAME G_GINT64_CONSTANT(0x6571204672616d65U)
58 #define MPA_ID_REP_FRAME G_GINT64_CONSTANT(0x6570204672616d65U)
59 #define MPA_MARKER_INTERVAL 512
60 #define MPA_MAX_PD_LENGTH 512
61 #define MPA_ALIGNMENT 4
62 #define TCP_MAX_SEQ ((guint32) 0xffffffff)
64 /* for code readability */
65 #define MPA_REQUEST_FRAME 1
66 #define MPA_REPLY_FRAME 2
68 #define MPA_INITIATOR 0
69 #define MPA_RESPONDER 1
72 #define MPA_MARKER_FLAG 0x80
73 #define MPA_CRC_FLAG 0x40
74 #define MPA_REJECT_FLAG 0x20
75 #define MPA_RESERVED_FLAG 0x1F
79 /* initialize the protocol and registered fields */
80 static gint proto_iwarp_mpa
= -1;
82 static gint hf_mpa_req
= -1;
83 static gint hf_mpa_rep
= -1;
84 static gint hf_mpa_fpdu
= -1;
85 static gint hf_mpa_marker
= -1;
87 static gint hf_mpa_key_req
= -1;
88 static gint hf_mpa_key_rep
= -1;
89 static gint hf_mpa_flag_m
= -1;
90 static gint hf_mpa_flag_c
= -1;
91 static gint hf_mpa_flag_r
= -1;
92 static gint hf_mpa_flag_res
= -1;
93 static gint hf_mpa_rev
= -1;
94 static gint hf_mpa_pd_length
= -1;
95 static gint hf_mpa_private_data
= -1;
97 static gint hf_mpa_ulpdu_length
= -1;
98 static gint hf_mpa_pad
= -1;
99 static gint hf_mpa_crc
= -1;
100 static gint hf_mpa_crc_check
= -1;
102 static gint hf_mpa_marker_res
= -1;
103 static gint hf_mpa_marker_fpduptr
= -1;
105 /* initialize the subtree pointers */
106 static gint ett_mpa
= -1;
108 static gint ett_mpa_req
= -1;
109 static gint ett_mpa_rep
= -1;
110 static gint ett_mpa_fpdu
= -1;
111 static gint ett_mpa_marker
= -1;
113 static expert_field ei_mpa_res_field_not_set0
= EI_INIT
;
114 static expert_field ei_mpa_rev_field_not_set1
= EI_INIT
;
115 static expert_field ei_mpa_reject_bit_responder
= EI_INIT
;
116 static expert_field ei_mpa_bad_length
= EI_INIT
;
118 /* handles of our subdissectors */
119 static dissector_handle_t ddp_rdmap_handle
= NULL
;
121 static const value_string mpa_messages
[] = {
122 { MPA_REQUEST_FRAME
, "MPA Request Frame" },
123 { MPA_REPLY_FRAME
, "MPA Reply Frame" },
124 { MPA_FPDU
, "MPA FPDU" },
129 * CONNECTION STATE and MARKERS
130 * A MPA endpoint operates in two distinct phases.
131 * The Startup Phase is used to verify correct MPA setup, exchange CRC
132 * and Marker configuration, and optionally pass Private Data between
133 * endpoints prior to completing a DDP connection.
134 * The second distinct phase is Full Operation during which FPDUs are
135 * sent using all the rules that pertain (CRC, Markers, MULPDU,
136 * restrictions etc.).
137 * To keep track of a MPA connection configuration a mpa_state is declared
138 * and maintained per TCP connection, i.e. it is associated to a conversation
139 * between two endpoints.
141 * In some configurations MPA places MARKERs in a FPDU every 512th octet with
142 * respect to the TCP sequence number of the first FPDU. The struct minfo_t
143 * records the source port of a peer that has to insert Markers into its FPDUs
144 * as well as the TCP sequence number of its first FPDU. This information is
145 * necessary to locate the markers within a FPDU afterwards. Itis part of a
150 * This struct is used to record the source port 'port' and the TCP sequence
151 * number 'seq' of the first FPDU. This information is used to determine the
152 * position of the first Marker within the following FPDUs. The boolean 'valid'
153 * specifies if Markers are inserted by the endpoint running on source port
161 typedef struct minfo minfo_t
;
164 * This struct represents a MPA connection state. It specifies if Markers and
165 * CRC is used for the following FPDUs. It also contains information to
166 * distinguish between the MPA Startup and Full Operation Phase.the connection
167 * parameters negotiated between to MPA endpoints during the MPA Startup Phase
168 * as well as other information for the dissection.
170 * The two MPA endpoints are called Initiator, the sender of the MPA Request,
171 * and Responder, the sender of the MPA Reply.
173 * @full_operation: TRUE if is this state is valid and FLASE otherwise.
174 * @req_frame_num: Frame number of the MPA Request to distinguish this frame
176 * @rep_frame_num: Frame number of the MPA Reply to distinguish this frame
178 * @ini_exp_m_res: TRUE if the Initiator expects the Responder to insert
179 * Markers into his FPDUs sent to Initiator and FALSE otherwise.
180 * @res_exp_m_ini: TRUE if the Responder expects the Initiator to insert
181 * Markers into his FPDUs sent to Responder and FALSE otherwise.
182 * @minfo[2]: Array of minfo_t whichs holds necessary information to
183 * determine the start position of the first Marker within a
185 * minfo[0] is used for the Initiator endpoint
186 * minfo[1] is used for the Responder endpoint
187 * @crc: TRUE if CRC is used by both endpoints and FLASE otherwise.
188 * @revision: Stores the MPA protocol revision number.
191 gboolean full_operation
;
194 gboolean ini_exp_m_res
;
195 gboolean res_exp_m_ini
;
200 typedef struct mpa_state mpa_state_t
;
203 * Returns an initialized MPA connection state or throws an out of
211 state
= (mpa_state_t
*) wmem_alloc0(wmem_file_scope(), sizeof(mpa_state_t
));
212 state
->revision
= -1;
217 * Returns the state associated with a MPA connection or NULL otherwise.
220 get_mpa_state(conversation_t
*conversation
)
223 return (mpa_state_t
*) conversation_get_proto_data(conversation
,
231 * Returns the offset of the first Marker in a FPDU where the beginning of a
232 * FPDU has an offset of 0. It also addresses possible sequence number
234 * The endpoint is either the Initiator or the Responder.
237 get_first_marker_offset(mpa_state_t
*state
, struct tcpinfo
*tcpinfo
,
242 if (tcpinfo
->seq
> state
->minfo
[endpoint
].seq
) {
243 offset
= (tcpinfo
->seq
- state
->minfo
[endpoint
].seq
)
244 % MPA_MARKER_INTERVAL
;
247 if (tcpinfo
->seq
< state
->minfo
[endpoint
].seq
) {
248 offset
= state
->minfo
[endpoint
].seq
249 + (TCP_MAX_SEQ
- tcpinfo
->seq
) % MPA_MARKER_INTERVAL
;
252 return (MPA_MARKER_INTERVAL
- offset
) % MPA_MARKER_INTERVAL
;
256 * Returns the total length of this FPDU under the assumption that a TCP
257 * segement carries only one FPDU.
260 fpdu_total_length(struct tcpinfo
*tcpinfo
)
264 if (tcpinfo
->seq
< tcpinfo
->nxtseq
) {
265 size
= tcpinfo
->nxtseq
- tcpinfo
->seq
;
268 if (tcpinfo
->seq
>= tcpinfo
->nxtseq
) {
269 size
= tcpinfo
->nxtseq
+ (TCP_MAX_SEQ
- tcpinfo
->seq
);
276 * Returns the number of Markers of this MPA FPDU. The endpoint is either the
277 * Initiator or the Responder.
280 number_of_markers(mpa_state_t
*state
, struct tcpinfo
*tcpinfo
, guint8 endpoint
)
285 size
= fpdu_total_length(tcpinfo
);
286 offset
= get_first_marker_offset(state
, tcpinfo
, endpoint
);
289 return ((size
- offset
) / MPA_MARKER_INTERVAL
)+1;
296 * Removes any Markers from this FPDU by using memcpy or throws an out of memory
300 remove_markers(tvbuff_t
*tvb
, packet_info
*pinfo
, guint32 marker_offset
,
301 guint32 num_markers
, guint32 orig_length
)
303 guint8
*mfree_buff
= NULL
;
304 guint32 mfree_buff_length
, tot_copy
, cur_copy
;
305 guint32 source_offset
;
306 tvbuff_t
*mfree_tvb
= NULL
;
308 DISSECTOR_ASSERT(num_markers
> 0);
309 DISSECTOR_ASSERT(orig_length
> MPA_MARKER_LEN
* num_markers
);
310 DISSECTOR_ASSERT(tvb_length(tvb
) == orig_length
);
312 /* allocate memory for the marker-free buffer */
313 mfree_buff_length
= orig_length
- (MPA_MARKER_LEN
* num_markers
);
314 mfree_buff
= (guint8
*)wmem_alloc(pinfo
->pool
, mfree_buff_length
);
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 add_new_data_source(pinfo
, mfree_tvb
, "FPDU without Markers");
332 /* returns TRUE if this TCP segment carries a MPA REQUEST and FLASE otherwise */
334 is_mpa_req(tvbuff_t
*tvb
, packet_info
*pinfo
)
336 conversation_t
*conversation
= NULL
;
337 mpa_state_t
*state
= NULL
;
340 if (tvb_get_ntoh64(tvb
, 0) != MPA_REQ_REP_FRAME
341 || tvb_get_ntoh64(tvb
, 8) != MPA_ID_REQ_FRAME
)
344 conversation
= find_or_create_conversation(pinfo
);
346 if (!get_mpa_state(conversation
)) {
348 /* associate a MPA connection state to this conversation if
349 * there is no MPA state already associated to this connection
351 state
= init_mpa_state();
353 /* anaylize MPA connection parameter and record them */
354 mcrres
= tvb_get_guint8(tvb
, 16);
355 state
->ini_exp_m_res
= mcrres
& MPA_MARKER_FLAG
;
356 state
->crc
= mcrres
& MPA_CRC_FLAG
;
357 state
->revision
= tvb_get_guint8(tvb
, 17);
358 state
->req_frame_num
= pinfo
->fd
->num
;
359 state
->minfo
[MPA_INITIATOR
].port
= pinfo
->srcport
;
360 state
->minfo
[MPA_RESPONDER
].port
= pinfo
->destport
;
362 conversation_add_proto_data(conversation
, proto_iwarp_mpa
, state
);
364 /* update expert info */
365 if (mcrres
& MPA_RESERVED_FLAG
)
366 expert_add_info(pinfo
, NULL
, &ei_mpa_res_field_not_set0
);
368 if (state
->revision
!= 1)
369 expert_add_info(pinfo
, NULL
, &ei_mpa_rev_field_not_set1
);
374 /* returns TRUE if this TCP segment carries a MPA REPLY and FALSE otherwise */
376 is_mpa_rep(tvbuff_t
*tvb
, packet_info
*pinfo
)
378 conversation_t
*conversation
= NULL
;
379 mpa_state_t
*state
= NULL
;
382 if (tvb_get_ntoh64(tvb
, 0) != MPA_REQ_REP_FRAME
383 || tvb_get_ntoh64(tvb
, 8) != MPA_ID_REP_FRAME
) {
387 conversation
= find_conversation(pinfo
->fd
->num
, &pinfo
->src
,
388 &pinfo
->dst
, pinfo
->ptype
, pinfo
->srcport
,
395 state
= get_mpa_state(conversation
);
400 if (!state
->full_operation
) {
401 /* update state of this conversation */
402 mcrres
= tvb_get_guint8(tvb
, 16);
403 state
->res_exp_m_ini
= mcrres
& MPA_MARKER_FLAG
;
404 state
->crc
= state
->crc
| (mcrres
& MPA_CRC_FLAG
);
405 state
->rep_frame_num
= pinfo
->fd
->num
;
407 /* enter Full Operation Phase only if the Reject bit is not set */
408 if (!(mcrres
& MPA_REJECT_FLAG
))
409 state
->full_operation
= TRUE
;
411 expert_add_info(pinfo
, NULL
, &ei_mpa_reject_bit_responder
);
416 /* returns TRUE if this TCP segment carries a MPA FPDU and FALSE otherwise */
418 is_mpa_fpdu(packet_info
*pinfo
)
420 conversation_t
*conversation
= NULL
;
421 mpa_state_t
*state
= NULL
;
423 conversation
= find_conversation(pinfo
->fd
->num
, &pinfo
->src
,
424 &pinfo
->dst
, pinfo
->ptype
, pinfo
->srcport
,
431 state
= get_mpa_state(conversation
);
436 /* make sure all MPA connection parameters have been set */
437 if (!state
->full_operation
) {
441 if (pinfo
->fd
->num
== state
->req_frame_num
442 || pinfo
->fd
->num
== state
->rep_frame_num
) {
449 /* update packet list pane in the GUI */
451 mpa_packetlist(packet_info
*pinfo
, gint message_type
)
453 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "MPA");
455 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
456 "%d > %d %s", pinfo
->srcport
, pinfo
->destport
,
457 val_to_str(message_type
, mpa_messages
,
461 /* dissects MPA REQUEST or MPA REPLY */
463 dissect_mpa_req_rep(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
466 proto_tree
*mpa_tree
= NULL
;
467 proto_tree
*mpa_header_tree
= NULL
;
469 proto_item
*mpa_item
= NULL
;
470 proto_item
*mpa_header_item
= NULL
;
475 mpa_packetlist(pinfo
, message_type
);
478 mpa_item
= proto_tree_add_item(tree
, proto_iwarp_mpa
, tvb
, 0,
480 mpa_tree
= proto_item_add_subtree(mpa_item
, ett_mpa
);
482 if (message_type
== MPA_REQUEST_FRAME
) {
483 mpa_header_item
= proto_tree_add_item(mpa_tree
,
484 hf_mpa_req
, tvb
, offset
, -1, ENC_NA
);
485 mpa_header_tree
= proto_item_add_subtree(
486 mpa_header_item
, ett_mpa
);
487 proto_tree_add_item(mpa_header_tree
, hf_mpa_key_req
,
488 tvb
, offset
, MPA_REQ_REP_KEY_LEN
, ENC_NA
);
491 if (message_type
== MPA_REPLY_FRAME
) {
492 mpa_header_item
= proto_tree_add_item(mpa_tree
,
493 hf_mpa_rep
, tvb
, offset
, -1, ENC_NA
);
494 mpa_header_tree
= proto_item_add_subtree(
495 mpa_header_item
, ett_mpa
);
496 proto_tree_add_item(mpa_header_tree
, hf_mpa_key_rep
,
497 tvb
, offset
, MPA_REQ_REP_KEY_LEN
, ENC_NA
);
499 offset
+= MPA_REQ_REP_KEY_LEN
;
501 proto_tree_add_item(mpa_header_tree
, hf_mpa_flag_m
, tvb
,
502 offset
, MPA_REQ_REP_FLAG_LEN
, ENC_BIG_ENDIAN
);
503 proto_tree_add_item(mpa_header_tree
, hf_mpa_flag_c
, tvb
,
504 offset
, MPA_REQ_REP_FLAG_LEN
, ENC_BIG_ENDIAN
);
505 proto_tree_add_item(mpa_header_tree
, hf_mpa_flag_r
, tvb
,
506 offset
, MPA_REQ_REP_FLAG_LEN
, ENC_BIG_ENDIAN
);
507 proto_tree_add_item(mpa_header_tree
, hf_mpa_flag_res
, tvb
,
508 offset
, MPA_REQ_REP_FLAG_LEN
, ENC_BIG_ENDIAN
);
509 offset
+= MPA_REQ_REP_FLAG_LEN
;
511 proto_tree_add_item(mpa_header_tree
, hf_mpa_rev
, tvb
,
512 offset
, MPA_REQ_REP_REV_LEN
, ENC_BIG_ENDIAN
);
513 offset
+= MPA_REQ_REP_REV_LEN
;
515 /* check whether the Private Data Length conforms to RFC 5044 */
516 pd_length
= tvb_get_ntohs(tvb
, offset
);
517 if (pd_length
> MPA_MAX_PD_LENGTH
) {
518 proto_tree_add_expert_format(tree
, pinfo
, &ei_mpa_bad_length
, tvb
, offset
, 2,
519 "[PD length field indicates more 512 bytes of Private Data]");
523 proto_tree_add_uint_format_value(mpa_header_tree
,
524 hf_mpa_pd_length
, tvb
, offset
,
525 MPA_REQ_REP_PDLENGTH_LEN
, pd_length
, "%u bytes",
527 offset
+= MPA_REQ_REP_PDLENGTH_LEN
;
530 proto_tree_add_item(mpa_header_tree
,
531 hf_mpa_private_data
, tvb
, offset
,
538 /* returns byte length of the padding */
540 fpdu_pad_length(guint16 ulpdu_length
)
543 * The padding guarantees alignment of 4. Since Markers are 4 bytes long
544 * we do need to take them into consideration for computation of pad
545 * length. The padding length depends only on ULPDU (payload) length and
546 * the length of the header field for the ULPDU length.
548 guint32 length
= ulpdu_length
+ MPA_ULPDU_LENGTH_LEN
;
551 * The extra % MPA_ALIGNMENT at the end covers for the case
552 * length % MPA_ALIGNMENT == 0.
554 return (MPA_ALIGNMENT
- (length
% MPA_ALIGNMENT
)) % MPA_ALIGNMENT
;
557 /* returns offset for PAD */
559 pad_offset(struct tcpinfo
*tcpinfo
, guint32 fpdu_total_len
,
562 if ((tcpinfo
->nxtseq
- MPA_CRC_LEN
- MPA_MARKER_LEN
) % MPA_MARKER_INTERVAL
564 /* covers the case where a Marker resides between the padding
567 return fpdu_total_len
- MPA_CRC_LEN
- MPA_MARKER_LEN
- pad_len
;
569 return fpdu_total_len
- MPA_CRC_LEN
- pad_len
;
573 /* dissects CRC within a FPDU */
575 dissect_fpdu_crc(tvbuff_t
*tvb
, proto_tree
*tree
, mpa_state_t
*state
,
576 guint32 offset
, guint32 length
)
579 guint32 sent_crc
= 0;
583 crc
= ~crc32c_calculate(tvb_get_ptr(tvb
, 0, length
), length
,
586 sent_crc
= tvb_get_ntohl(tvb
, offset
); /* crc start offset */
588 if (crc
== sent_crc
) {
589 proto_tree_add_uint_format_value(tree
,
590 hf_mpa_crc_check
, tvb
, offset
, MPA_CRC_LEN
,
591 sent_crc
, "0x%08x (Good CRC32)",
594 proto_tree_add_uint_format_value(tree
,
595 hf_mpa_crc_check
, tvb
, offset
, MPA_CRC_LEN
,
597 "0x%08x (Bad CRC32, should be 0x%08x)",
601 proto_tree_add_item(tree
, hf_mpa_crc
, tvb
, offset
, MPA_CRC_LEN
,
606 /* dissects Markers within FPDU */
608 dissect_fpdu_markers(tvbuff_t
*tvb
, proto_tree
*tree
, mpa_state_t
*state
,
609 struct tcpinfo
*tcpinfo
, guint8 endpoint
)
611 proto_tree
*mpa_marker_tree
;
612 proto_item
*mpa_marker_item
;
616 mpa_marker_item
= proto_tree_add_item(tree
, hf_mpa_marker
, tvb
,
618 mpa_marker_tree
= proto_item_add_subtree(mpa_marker_item
, ett_mpa
);
620 offset
= get_first_marker_offset(state
, tcpinfo
, endpoint
);
622 for (i
=0; i
<number_of_markers(state
, tcpinfo
, endpoint
); i
++) {
623 proto_tree_add_item(mpa_marker_tree
, hf_mpa_marker_res
, tvb
,
624 offset
, MPA_MARKER_RSVD_LEN
, ENC_BIG_ENDIAN
);
625 fpduptr
= (guint16
) tvb_get_ntohs(tvb
, offset
+MPA_MARKER_RSVD_LEN
);
626 proto_tree_add_uint_format_value(mpa_marker_tree
,
627 hf_mpa_marker_fpduptr
, tvb
,
628 offset
+MPA_MARKER_RSVD_LEN
, MPA_MARKER_FPDUPTR_LEN
,
629 fpduptr
, "%u bytes", fpduptr
);
630 offset
+= MPA_MARKER_INTERVAL
;
634 /* returns the expected value of the 16 bits long MPA FPDU ULPDU LENGTH field */
636 expected_ulpdu_length(mpa_state_t
*state
, struct tcpinfo
*tcpinfo
,
639 guint32 length
, pad_length
, markers_length
;
641 length
= fpdu_total_length(tcpinfo
);
643 if (length
<= MPA_CRC_LEN
)
645 length
-= MPA_CRC_LEN
;
647 pad_length
= (MPA_ALIGNMENT
- (length
% MPA_ALIGNMENT
)) % MPA_ALIGNMENT
;
649 if (length
<= pad_length
)
651 length
-= pad_length
;
653 if (state
->minfo
[endpoint
].valid
) {
655 number_of_markers(state
, tcpinfo
, endpoint
) * MPA_MARKER_LEN
;
657 if (length
<= markers_length
)
659 length
-= markers_length
;
662 if (length
<= MPA_ULPDU_LENGTH_LEN
)
664 length
-= MPA_ULPDU_LENGTH_LEN
;
666 return (guint16
) length
;
669 /* dissects MPA FPDU */
671 dissect_mpa_fpdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
672 mpa_state_t
*state
, struct tcpinfo
*tcpinfo
, guint8 endpoint
)
674 proto_item
*mpa_item
= NULL
;
675 proto_item
*mpa_header_item
= NULL
;
677 proto_tree
*mpa_tree
= NULL
;
678 proto_tree
*mpa_header_tree
= NULL
;
681 guint16 ulpdu_length
, exp_ulpdu_length
;
682 guint32 offset
, total_length
;
683 guint32 num_of_m
= 0;
686 * Initialize starting offset for this FPDU. Deals with the case that this
687 * FPDU may start with a Marker instead of the ULPDU_LENTH header field.
689 if (state
->minfo
[endpoint
].valid
690 && get_first_marker_offset(state
, tcpinfo
, endpoint
) == 0) {
691 offset
= MPA_MARKER_LEN
;
696 /* get ULPDU length of this FPDU */
697 ulpdu_length
= (guint16
) tvb_get_ntohs(tvb
, offset
);
699 mpa_packetlist(pinfo
, MPA_FPDU
);
701 if (state
->minfo
[endpoint
].valid
) {
702 num_of_m
= number_of_markers(state
, tcpinfo
, endpoint
);
709 * Stop FPDU dissection if the read ULPDU_LENGTH field does NOT contain
711 * Reasons for getting a wrong ULPDU_LENGTH can be lost packets (because
712 * libpcap was not able to capture every packet) or lost alignment (the
713 * MPA FPDU header does not start right after TCP header).
714 * We consider the above to be an error since we make the assumption
715 * that exactly one MPA FPDU is contained in one TCP segement and starts
716 * always either with a Marker or the ULPDU_LENGTH header field.
718 exp_ulpdu_length
= expected_ulpdu_length(state
, tcpinfo
, endpoint
);
719 if (!exp_ulpdu_length
|| exp_ulpdu_length
!= ulpdu_length
) {
720 proto_tree_add_expert_format(tree
, pinfo
, &ei_mpa_bad_length
, tvb
, offset
,
721 MPA_ULPDU_LENGTH_LEN
,
722 "[ULPDU length field does not contain the expected length]");
726 mpa_item
= proto_tree_add_item(tree
, proto_iwarp_mpa
, tvb
, 0,
728 mpa_tree
= proto_item_add_subtree(mpa_item
, ett_mpa
);
730 mpa_header_item
= proto_tree_add_item(mpa_tree
, hf_mpa_fpdu
,
731 tvb
, offset
, -1, ENC_NA
);
732 mpa_header_tree
= proto_item_add_subtree(mpa_header_item
,
735 /* ULPDU Length header field */
736 proto_tree_add_uint_format_value(mpa_header_tree
,
737 hf_mpa_ulpdu_length
, tvb
, offset
,
738 MPA_ULPDU_LENGTH_LEN
, ulpdu_length
, "%u bytes",
741 pad_length
= fpdu_pad_length(ulpdu_length
);
743 /* Markers are present in this FPDU */
744 if (state
->minfo
[endpoint
].valid
&& num_of_m
> 0) {
746 total_length
= fpdu_total_length(tcpinfo
);
748 if (pad_length
> 0) {
749 proto_tree_add_item(mpa_header_tree
, hf_mpa_pad
,
750 tvb
, pad_offset(tcpinfo
,
756 dissect_fpdu_crc(tvb
, mpa_header_tree
, state
,
757 total_length
-MPA_CRC_LEN
, num_of_m
* MPA_MARKER_LEN
+
758 ulpdu_length
+ pad_length
+ MPA_ULPDU_LENGTH_LEN
);
760 dissect_fpdu_markers(tvb
, mpa_tree
, state
, tcpinfo
, endpoint
);
762 } else { /* Markers are not present or not enabled */
764 offset
+= MPA_ULPDU_LENGTH_LEN
+ ulpdu_length
;
766 if (pad_length
> 0) {
767 proto_tree_add_item(mpa_header_tree
, hf_mpa_pad
, tvb
, offset
,
769 offset
+= pad_length
;
772 dissect_fpdu_crc(tvb
, mpa_header_tree
, state
, offset
,
773 ulpdu_length
+pad_length
+MPA_ULPDU_LENGTH_LEN
);
780 * Main dissection routine.
783 dissect_iwarp_mpa(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
785 tvbuff_t
*next_tvb
= NULL
;
786 conversation_t
*conversation
= NULL
;
787 mpa_state_t
*state
= NULL
;
788 struct tcpinfo
*tcpinfo
= (struct tcpinfo
*)data
;
790 guint16 ulpdu_length
= 0;
793 if (tvb_length(tvb
) >= MPA_SMALLEST_FPDU_LEN
&& is_mpa_fpdu(pinfo
)) {
795 conversation
= find_conversation(pinfo
->fd
->num
, &pinfo
->src
,
796 &pinfo
->dst
, pinfo
->ptype
, pinfo
->srcport
, pinfo
->destport
, 0);
798 state
= get_mpa_state(conversation
);
800 if (pinfo
->srcport
== state
->minfo
[MPA_INITIATOR
].port
) {
801 endpoint
= MPA_INITIATOR
;
802 } else if (pinfo
->srcport
== state
->minfo
[MPA_RESPONDER
].port
) {
803 endpoint
= MPA_RESPONDER
;
805 REPORT_DISSECTOR_BUG("endpoint cannot be determined");
808 /* Markers are used by either the Initiator or the Responder or both. */
809 if ((state
->ini_exp_m_res
|| state
->res_exp_m_ini
) && endpoint
<= MPA_RESPONDER
) {
811 /* find the TCP sequence number of the first FPDU */
812 if (!state
->minfo
[endpoint
].valid
) {
813 state
->minfo
[endpoint
].seq
= tcpinfo
->seq
;
814 state
->minfo
[endpoint
].valid
= TRUE
;
819 ulpdu_length
= dissect_mpa_fpdu(tvb
, pinfo
, tree
, state
, tcpinfo
,
822 /* an ulpdu_length of 0 should never happen */
826 /* removes Markers if any and prepares new tvbuff for next dissector */
827 if (endpoint
<= MPA_RESPONDER
&& state
->minfo
[endpoint
].valid
828 && number_of_markers(state
, tcpinfo
, endpoint
) > 0) {
829 next_tvb
= tvb_new_subset(remove_markers(tvb
, pinfo
,
830 get_first_marker_offset(state
, tcpinfo
, endpoint
),
831 number_of_markers(state
, tcpinfo
, endpoint
),
832 fpdu_total_length(tcpinfo
)), MPA_ULPDU_LENGTH_LEN
,
833 ulpdu_length
, ulpdu_length
);
835 next_tvb
= tvb_new_subset(tvb
, MPA_ULPDU_LENGTH_LEN
, ulpdu_length
,
840 /* call subdissector */
841 if (ddp_rdmap_handle
) {
842 call_dissector(ddp_rdmap_handle
, next_tvb
, pinfo
, tree
);
844 REPORT_DISSECTOR_BUG("ddp_handle was null");
850 /* MPA REQUEST or MPA REPLY */
851 if (tvb_length(tvb
) >= MPA_REQ_REP_FRAME_HEADER_LEN
) {
852 if (is_mpa_req(tvb
, pinfo
))
853 return dissect_mpa_req_rep(tvb
, pinfo
, tree
, MPA_REQUEST_FRAME
);
854 else if (is_mpa_rep(tvb
, pinfo
))
855 return dissect_mpa_req_rep(tvb
, pinfo
, tree
, MPA_REPLY_FRAME
);
860 /* registers this protocol with Wireshark */
861 void proto_register_mpa(void)
863 /* setup list of header fields */
864 static hf_register_info hf
[] = {
866 "Request frame header", "iwarp_mpa.req",
867 FT_NONE
, BASE_NONE
, NULL
, 0x0,
870 "Reply frame header", "iwarp_mpa.rep",
871 FT_NONE
, BASE_NONE
, NULL
, 0x0,
874 "FPDU", "iwarp_mpa.fpdu",
875 FT_NONE
, BASE_NONE
, NULL
, 0x0,
878 "Markers", "iwarp_mpa.markers",
879 FT_NONE
, BASE_NONE
, NULL
, 0x0,
882 "ID Req frame", "iwarp_mpa.key.req",
883 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
886 "ID Rep frame", "iwarp_mpa.key.rep",
887 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
890 "Marker flag", "iwarp_mpa.marker_flag",
891 FT_BOOLEAN
, 8, NULL
, MPA_MARKER_FLAG
,
894 "CRC flag", "iwarp_mpa.crc_flag",
895 FT_BOOLEAN
, 8, NULL
, MPA_CRC_FLAG
,
898 "Connection rejected flag",
899 "iwarp_mpa.rej_flag", FT_BOOLEAN
, 8, NULL
, MPA_REJECT_FLAG
,
901 { &hf_mpa_flag_res
, {
902 "Reserved", "iwarp_mpa.res",
903 FT_UINT8
, BASE_HEX
, NULL
, MPA_RESERVED_FLAG
,
906 "Revision", "iwarp_mpa.rev",
907 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
909 { &hf_mpa_pd_length
, {
910 "Private data length", "iwarp_mpa.pdlength",
911 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
913 { &hf_mpa_private_data
, {
914 "Private data", "iwarp_mpa.privatedata",
915 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
917 { &hf_mpa_ulpdu_length
, {
918 "ULPDU length", "iwarp_mpa.ulpdulength",
919 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
922 "Padding", "iwarp_mpa.pad",
923 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
926 "CRC", "iwarp_mpa.crc",
927 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
929 { &hf_mpa_crc_check
, {
930 "CRC check", "iwarp_mpa.crc_check",
931 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
933 { &hf_mpa_marker_res
, {
934 "Reserved", "iwarp_mpa.marker_res",
935 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
936 "Marker: Reserved", HFILL
} },
937 { &hf_mpa_marker_fpduptr
, {
938 "FPDU back pointer", "iwarp_mpa.marker_fpduptr",
939 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
940 "Marker: FPDU Pointer", HFILL
} }
943 /* setup protocol subtree array */
944 static gint
*ett
[] = {
952 static ei_register_info ei
[] = {
953 { &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
}},
954 { &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
}},
955 { &ei_mpa_reject_bit_responder
, { "iwarp_mpa.reject_bit_responder", PI_RESPONSE_CODE
, PI_NOTE
, "Reject bit set by Responder", EXPFILL
}},
956 { &ei_mpa_bad_length
, { "iwarp_mpa.bad_length", PI_MALFORMED
, PI_ERROR
, "Bad length", EXPFILL
}},
959 expert_module_t
* expert_iwarp_mpa
;
961 /* register the protocol name and description */
962 proto_iwarp_mpa
= proto_register_protocol(
963 "iWARP Marker Protocol data unit Aligned framing",
964 "IWARP_MPA", "iwarp_mpa");
966 /* required function calls to register the header fields and subtrees */
967 proto_register_field_array(proto_iwarp_mpa
, hf
, array_length(hf
));
968 proto_register_subtree_array(ett
, array_length(ett
));
969 expert_iwarp_mpa
= expert_register_protocol(proto_iwarp_mpa
);
970 expert_register_field_array(expert_iwarp_mpa
, ei
, array_length(ei
));
974 proto_reg_handoff_mpa(void)
977 * MPA does not use any specific TCP port so, when not on a specific
978 * port, try this dissector whenever there is TCP traffic.
980 heur_dissector_add("tcp", dissect_iwarp_mpa
, proto_iwarp_mpa
);
981 ddp_rdmap_handle
= find_dissector("iwarp_ddp_rdmap");