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>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
17 #include <epan/packet.h>
18 #include <epan/unit_strings.h>
19 #include <epan/expert.h>
20 #include <epan/crc32-tvb.h>
21 #include <wsutil/crc32.h>
22 #include "packet-tcp.h"
24 void proto_register_mpa(void);
25 void proto_reg_handoff_mpa(void);
29 /* header field byte lengths */
30 #define MPA_REQ_REP_FRAME_HEADER_LEN 20
31 #define MPA_PDLENGTH_LEN 2
32 #define MPA_ULPDU_LENGTH_LEN 2
33 #define MPA_MARKER_LEN 4
34 #define MPA_SMALLEST_FPDU_LEN 8
35 #define MPA_REQ_REP_KEY_LEN 16
36 #define MPA_REQ_REP_FLAG_LEN 1
37 #define MPA_REQ_REP_REV_LEN 1
38 #define MPA_REQ_REP_PDLENGTH_LEN 2
39 #define MPA_MARKER_RSVD_LEN 2
40 #define MPA_MARKER_FPDUPTR_LEN 2
43 /* protocol constants */
44 #define MPA_REQ_REP_FRAME UINT64_C(0x4d50412049442052)
45 #define MPA_ID_REQ_FRAME UINT64_C(0x6571204672616d65)
46 #define MPA_ID_REP_FRAME UINT64_C(0x6570204672616d65)
47 #define MPA_MARKER_INTERVAL 512
48 #define MPA_MAX_PD_LENGTH 512
49 #define MPA_ALIGNMENT 4
50 #define TCP_MAX_SEQ ((uint32_t) 0xffffffff)
52 /* for code readability */
53 #define MPA_REQUEST_FRAME 1
54 #define MPA_REPLY_FRAME 2
56 #define MPA_INITIATOR 0
57 #define MPA_RESPONDER 1
60 #define MPA_MARKER_FLAG 0x80
61 #define MPA_CRC_FLAG 0x40
62 #define MPA_REJECT_FLAG 0x20
63 #define MPA_RESERVED_FLAG 0x1F
67 /* initialize the protocol and registered fields */
68 static int proto_iwarp_mpa
;
70 static int hf_mpa_req
;
71 static int hf_mpa_rep
;
72 static int hf_mpa_fpdu
;
73 static int hf_mpa_marker
;
75 static int hf_mpa_key_req
;
76 static int hf_mpa_key_rep
;
77 static int hf_mpa_flag_m
;
78 static int hf_mpa_flag_c
;
79 static int hf_mpa_flag_r
;
80 static int hf_mpa_flag_res
;
81 static int hf_mpa_rev
;
82 static int hf_mpa_pd_length
;
83 static int hf_mpa_private_data
;
85 static int hf_mpa_ulpdu_length
;
86 static int hf_mpa_pad
;
87 static int hf_mpa_crc
;
88 static int hf_mpa_crc_check
;
90 static int hf_mpa_marker_res
;
91 static int hf_mpa_marker_fpduptr
;
93 /* initialize the subtree pointers */
96 static int ett_mpa_req
;
97 static int ett_mpa_rep
;
98 static int ett_mpa_fpdu
;
99 static int ett_mpa_marker
;
101 static expert_field ei_mpa_res_field_not_set0
;
102 static expert_field ei_mpa_rev_field_not_set1
;
103 static expert_field ei_mpa_reject_bit_responder
;
104 static expert_field ei_mpa_bad_length
;
106 /* handles of our subdissectors */
107 static dissector_handle_t ddp_rdmap_handle
;
109 static const value_string mpa_messages
[] = {
110 { MPA_REQUEST_FRAME
, "MPA Request Frame" },
111 { MPA_REPLY_FRAME
, "MPA Reply Frame" },
112 { MPA_FPDU
, "MPA FPDU" },
117 * CONNECTION STATE and MARKERS
118 * A MPA endpoint operates in two distinct phases.
119 * The Startup Phase is used to verify correct MPA setup, exchange CRC
120 * and Marker configuration, and optionally pass Private Data between
121 * endpoints prior to completing a DDP connection.
122 * The second distinct phase is Full Operation during which FPDUs are
123 * sent using all the rules that pertain (CRC, Markers, MULPDU,
124 * restrictions etc.).
125 * To keep track of a MPA connection configuration a mpa_state is declared
126 * and maintained per TCP connection, i.e. it is associated to a conversation
127 * between two endpoints.
129 * In some configurations MPA places MARKERs in a FPDU every 512th octet with
130 * respect to the TCP sequence number of the first FPDU. The struct minfo_t
131 * records the source port of a peer that has to insert Markers into its FPDUs
132 * as well as the TCP sequence number of its first FPDU. This information is
133 * necessary to locate the markers within a FPDU afterwards. Itis part of a
138 * This struct is used to record the source port 'port' and the TCP sequence
139 * number 'seq' of the first FPDU. This information is used to determine the
140 * position of the first Marker within the following FPDUs. The boolean 'valid'
141 * specifies if Markers are inserted by the endpoint running on source port
149 typedef struct minfo minfo_t
;
152 * This struct represents a MPA connection state. It specifies if Markers and
153 * CRC is used for the following FPDUs. It also contains information to
154 * distinguish between the MPA Startup and Full Operation Phase.the connection
155 * parameters negotiated between to MPA endpoints during the MPA Startup Phase
156 * as well as other information for the dissection.
158 * The two MPA endpoints are called Initiator, the sender of the MPA Request,
159 * and Responder, the sender of the MPA Reply.
161 * @full_operation: true if is this state is valid and FLASE otherwise.
162 * @req_frame_num: Frame number of the MPA Request to distinguish this frame
164 * @rep_frame_num: Frame number of the MPA Reply to distinguish this frame
166 * @ini_exp_m_res: true if the Initiator expects the Responder to insert
167 * Markers into his FPDUs sent to Initiator and false otherwise.
168 * @res_exp_m_ini: true if the Responder expects the Initiator to insert
169 * Markers into his FPDUs sent to Responder and false otherwise.
170 * @minfo[2]: Array of minfo_t whichs holds necessary information to
171 * determine the start position of the first Marker within a
173 * minfo[0] is used for the Initiator endpoint
174 * minfo[1] is used for the Responder endpoint
175 * @crc: true if CRC is used by both endpoints and FLASE otherwise.
176 * @revision: Stores the MPA protocol revision number.
180 unsigned req_frame_num
;
181 unsigned rep_frame_num
;
188 typedef struct mpa_state mpa_state_t
;
191 * Returns an initialized MPA connection state or throws an out of
199 state
= wmem_new0(wmem_file_scope(), mpa_state_t
);
200 state
->revision
= -1;
205 * Returns the state associated with a MPA connection or NULL otherwise.
208 get_mpa_state(conversation_t
*conversation
)
211 return (mpa_state_t
*) conversation_get_proto_data(conversation
,
219 * Returns the offset of the first Marker in a FPDU where the beginning of a
220 * FPDU has an offset of 0. It also addresses possible sequence number
222 * The endpoint is either the Initiator or the Responder.
225 get_first_marker_offset(mpa_state_t
*state
, struct tcpinfo
*tcpinfo
,
230 if (tcpinfo
->seq
> state
->minfo
[endpoint
].seq
) {
231 offset
= (tcpinfo
->seq
- state
->minfo
[endpoint
].seq
)
232 % MPA_MARKER_INTERVAL
;
235 if (tcpinfo
->seq
< state
->minfo
[endpoint
].seq
) {
236 offset
= state
->minfo
[endpoint
].seq
237 + (TCP_MAX_SEQ
- tcpinfo
->seq
) % MPA_MARKER_INTERVAL
;
240 return (MPA_MARKER_INTERVAL
- offset
) % MPA_MARKER_INTERVAL
;
244 * Returns the total length of this FPDU under the assumption that a TCP
245 * segment carries only one FPDU.
248 fpdu_total_length(struct tcpinfo
*tcpinfo
)
252 if (tcpinfo
->seq
< tcpinfo
->nxtseq
) {
253 size
= tcpinfo
->nxtseq
- tcpinfo
->seq
;
256 if (tcpinfo
->seq
>= tcpinfo
->nxtseq
) {
257 size
= tcpinfo
->nxtseq
+ (TCP_MAX_SEQ
- tcpinfo
->seq
);
264 * Returns the number of Markers of this MPA FPDU. The endpoint is either the
265 * Initiator or the Responder.
268 number_of_markers(mpa_state_t
*state
, struct tcpinfo
*tcpinfo
, uint8_t endpoint
)
273 size
= fpdu_total_length(tcpinfo
);
274 offset
= get_first_marker_offset(state
, tcpinfo
, endpoint
);
277 return ((size
- offset
) / MPA_MARKER_INTERVAL
)+1;
284 * Removes any Markers from this FPDU by using memcpy or throws an out of memory
288 remove_markers(tvbuff_t
*tvb
, packet_info
*pinfo
, uint32_t marker_offset
,
289 uint32_t num_markers
, uint32_t orig_length
)
291 uint8_t *mfree_buff
= NULL
;
292 uint32_t mfree_buff_length
, tot_copy
, cur_copy
;
293 uint32_t source_offset
;
294 tvbuff_t
*mfree_tvb
= NULL
;
296 DISSECTOR_ASSERT(num_markers
> 0);
297 DISSECTOR_ASSERT(orig_length
> MPA_MARKER_LEN
* num_markers
);
298 DISSECTOR_ASSERT(tvb_captured_length(tvb
) == orig_length
);
300 /* allocate memory for the marker-free buffer */
301 mfree_buff_length
= orig_length
- (MPA_MARKER_LEN
* num_markers
);
302 mfree_buff
= (uint8_t *)wmem_alloc(pinfo
->pool
, mfree_buff_length
);
306 cur_copy
= marker_offset
;
307 while (tot_copy
< mfree_buff_length
) {
308 tvb_memcpy(tvb
, mfree_buff
+tot_copy
, source_offset
, cur_copy
);
309 tot_copy
+= cur_copy
;
310 source_offset
+= cur_copy
+ MPA_MARKER_LEN
;
311 cur_copy
= MIN(MPA_MARKER_INTERVAL
, (mfree_buff_length
- tot_copy
));
313 mfree_tvb
= tvb_new_child_real_data(tvb
, mfree_buff
, mfree_buff_length
,
315 add_new_data_source(pinfo
, mfree_tvb
, "FPDU without Markers");
320 /* returns true if this TCP segment carries a MPA REQUEST and FLASE otherwise */
322 is_mpa_req(tvbuff_t
*tvb
, packet_info
*pinfo
)
324 conversation_t
*conversation
= NULL
;
325 mpa_state_t
*state
= NULL
;
328 if (tvb_get_ntoh64(tvb
, 0) != MPA_REQ_REP_FRAME
329 || tvb_get_ntoh64(tvb
, 8) != MPA_ID_REQ_FRAME
)
332 conversation
= find_or_create_conversation(pinfo
);
334 if (!get_mpa_state(conversation
)) {
336 /* associate a MPA connection state to this conversation if
337 * there is no MPA state already associated to this connection
339 state
= init_mpa_state();
341 /* analyze MPA connection parameter and record them */
342 mcrres
= tvb_get_uint8(tvb
, 16);
343 state
->ini_exp_m_res
= mcrres
& MPA_MARKER_FLAG
;
344 state
->crc
= mcrres
& MPA_CRC_FLAG
;
345 state
->revision
= tvb_get_uint8(tvb
, 17);
346 state
->req_frame_num
= pinfo
->num
;
347 state
->minfo
[MPA_INITIATOR
].port
= pinfo
->srcport
;
348 state
->minfo
[MPA_RESPONDER
].port
= pinfo
->destport
;
350 conversation_add_proto_data(conversation
, proto_iwarp_mpa
, state
);
352 /* update expert info */
353 if (mcrres
& MPA_RESERVED_FLAG
)
354 expert_add_info(pinfo
, NULL
, &ei_mpa_res_field_not_set0
);
356 if (state
->revision
!= 1)
357 expert_add_info(pinfo
, NULL
, &ei_mpa_rev_field_not_set1
);
362 /* returns true if this TCP segment carries a MPA REPLY and false otherwise */
364 is_mpa_rep(tvbuff_t
*tvb
, packet_info
*pinfo
)
366 conversation_t
*conversation
= NULL
;
367 mpa_state_t
*state
= NULL
;
370 if (tvb_get_ntoh64(tvb
, 0) != MPA_REQ_REP_FRAME
371 || tvb_get_ntoh64(tvb
, 8) != MPA_ID_REP_FRAME
) {
375 conversation
= find_conversation_pinfo(pinfo
, 0);
381 state
= get_mpa_state(conversation
);
386 if (!state
->full_operation
) {
387 /* update state of this conversation */
388 mcrres
= tvb_get_uint8(tvb
, 16);
389 state
->res_exp_m_ini
= mcrres
& MPA_MARKER_FLAG
;
390 state
->crc
= state
->crc
| (mcrres
& MPA_CRC_FLAG
);
391 state
->rep_frame_num
= pinfo
->num
;
393 /* enter Full Operation Phase only if the Reject bit is not set */
394 if (!(mcrres
& MPA_REJECT_FLAG
))
395 state
->full_operation
= true;
397 expert_add_info(pinfo
, NULL
, &ei_mpa_reject_bit_responder
);
402 /* returns true if this TCP segment carries a MPA FPDU and false otherwise */
404 is_mpa_fpdu(packet_info
*pinfo
)
406 conversation_t
*conversation
= NULL
;
407 mpa_state_t
*state
= NULL
;
409 conversation
= find_conversation_pinfo(pinfo
, 0);
415 state
= get_mpa_state(conversation
);
420 /* make sure all MPA connection parameters have been set */
421 if (!state
->full_operation
) {
425 if (pinfo
->num
== state
->req_frame_num
426 || pinfo
->num
== state
->rep_frame_num
) {
433 /* update packet list pane in the GUI */
435 mpa_packetlist(packet_info
*pinfo
, int message_type
)
437 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "MPA");
439 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
440 "%d > %d %s", pinfo
->srcport
, pinfo
->destport
,
441 val_to_str(message_type
, mpa_messages
,
445 /* dissects MPA REQUEST or MPA REPLY */
447 dissect_mpa_req_rep(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
450 proto_tree
*mpa_tree
= NULL
;
451 proto_tree
*mpa_header_tree
= NULL
;
453 proto_item
*mpa_item
= NULL
;
454 proto_item
*mpa_header_item
= NULL
;
459 mpa_packetlist(pinfo
, message_type
);
462 mpa_item
= proto_tree_add_item(tree
, proto_iwarp_mpa
, tvb
, 0,
464 mpa_tree
= proto_item_add_subtree(mpa_item
, ett_mpa
);
466 if (message_type
== MPA_REQUEST_FRAME
) {
467 mpa_header_item
= proto_tree_add_item(mpa_tree
,
468 hf_mpa_req
, tvb
, offset
, -1, ENC_NA
);
469 mpa_header_tree
= proto_item_add_subtree(
470 mpa_header_item
, ett_mpa
);
471 proto_tree_add_item(mpa_header_tree
, hf_mpa_key_req
,
472 tvb
, offset
, MPA_REQ_REP_KEY_LEN
, ENC_NA
);
475 if (message_type
== MPA_REPLY_FRAME
) {
476 mpa_header_item
= proto_tree_add_item(mpa_tree
,
477 hf_mpa_rep
, tvb
, offset
, -1, ENC_NA
);
478 mpa_header_tree
= proto_item_add_subtree(
479 mpa_header_item
, ett_mpa
);
480 proto_tree_add_item(mpa_header_tree
, hf_mpa_key_rep
,
481 tvb
, offset
, MPA_REQ_REP_KEY_LEN
, ENC_NA
);
483 offset
+= MPA_REQ_REP_KEY_LEN
;
485 proto_tree_add_item(mpa_header_tree
, hf_mpa_flag_m
, tvb
,
486 offset
, MPA_REQ_REP_FLAG_LEN
, ENC_BIG_ENDIAN
);
487 proto_tree_add_item(mpa_header_tree
, hf_mpa_flag_c
, tvb
,
488 offset
, MPA_REQ_REP_FLAG_LEN
, ENC_BIG_ENDIAN
);
489 proto_tree_add_item(mpa_header_tree
, hf_mpa_flag_r
, tvb
,
490 offset
, MPA_REQ_REP_FLAG_LEN
, ENC_BIG_ENDIAN
);
491 proto_tree_add_item(mpa_header_tree
, hf_mpa_flag_res
, tvb
,
492 offset
, MPA_REQ_REP_FLAG_LEN
, ENC_BIG_ENDIAN
);
493 offset
+= MPA_REQ_REP_FLAG_LEN
;
495 proto_tree_add_item(mpa_header_tree
, hf_mpa_rev
, tvb
,
496 offset
, MPA_REQ_REP_REV_LEN
, ENC_BIG_ENDIAN
);
497 offset
+= MPA_REQ_REP_REV_LEN
;
499 /* check whether the Private Data Length conforms to RFC 5044 */
500 pd_length
= tvb_get_ntohs(tvb
, offset
);
501 if (pd_length
> MPA_MAX_PD_LENGTH
) {
502 proto_tree_add_expert_format(tree
, pinfo
, &ei_mpa_bad_length
, tvb
, offset
, 2,
503 "[PD length field indicates more 512 bytes of Private Data]");
507 proto_tree_add_uint(mpa_header_tree
,
508 hf_mpa_pd_length
, tvb
, offset
,
509 MPA_REQ_REP_PDLENGTH_LEN
, pd_length
);
510 offset
+= MPA_REQ_REP_PDLENGTH_LEN
;
513 proto_tree_add_item(mpa_header_tree
,
514 hf_mpa_private_data
, tvb
, offset
,
521 /* returns byte length of the padding */
523 fpdu_pad_length(uint16_t ulpdu_length
)
526 * The padding guarantees alignment of 4. Since Markers are 4 bytes long
527 * we do need to take them into consideration for computation of pad
528 * length. The padding length depends only on ULPDU (payload) length and
529 * the length of the header field for the ULPDU length.
531 uint32_t length
= ulpdu_length
+ MPA_ULPDU_LENGTH_LEN
;
534 * The extra % MPA_ALIGNMENT at the end covers for the case
535 * length % MPA_ALIGNMENT == 0.
537 return (MPA_ALIGNMENT
- (length
% MPA_ALIGNMENT
)) % MPA_ALIGNMENT
;
540 /* returns offset for PAD */
542 pad_offset(struct tcpinfo
*tcpinfo
, uint32_t fpdu_total_len
,
545 if ((tcpinfo
->nxtseq
- MPA_CRC_LEN
- MPA_MARKER_LEN
) % MPA_MARKER_INTERVAL
547 /* covers the case where a Marker resides between the padding
550 return fpdu_total_len
- MPA_CRC_LEN
- MPA_MARKER_LEN
- pad_len
;
552 return fpdu_total_len
- MPA_CRC_LEN
- pad_len
;
556 /* dissects CRC within a FPDU */
558 dissect_fpdu_crc(tvbuff_t
*tvb
, proto_tree
*tree
, mpa_state_t
*state
,
559 uint32_t offset
, uint32_t length
)
562 uint32_t sent_crc
= 0;
566 crc
= ~crc32c_tvb_offset_calculate(tvb
, 0, length
, CRC32C_PRELOAD
);
568 sent_crc
= tvb_get_ntohl(tvb
, offset
); /* crc start offset */
570 if (crc
== sent_crc
) {
571 proto_tree_add_uint_format_value(tree
,
572 hf_mpa_crc_check
, tvb
, offset
, MPA_CRC_LEN
,
573 sent_crc
, "0x%08x (Good CRC32)",
576 proto_tree_add_uint_format_value(tree
,
577 hf_mpa_crc_check
, tvb
, offset
, MPA_CRC_LEN
,
579 "0x%08x (Bad CRC32, should be 0x%08x)",
583 proto_tree_add_item(tree
, hf_mpa_crc
, tvb
, offset
, MPA_CRC_LEN
,
588 /* dissects Markers within FPDU */
590 dissect_fpdu_markers(tvbuff_t
*tvb
, proto_tree
*tree
, mpa_state_t
*state
,
591 struct tcpinfo
*tcpinfo
, uint8_t endpoint
)
593 proto_tree
*mpa_marker_tree
;
594 proto_item
*mpa_marker_item
;
597 mpa_marker_item
= proto_tree_add_item(tree
, hf_mpa_marker
, tvb
,
599 mpa_marker_tree
= proto_item_add_subtree(mpa_marker_item
, ett_mpa
);
601 offset
= get_first_marker_offset(state
, tcpinfo
, endpoint
);
603 for (i
=0; i
<number_of_markers(state
, tcpinfo
, endpoint
); i
++) {
604 proto_tree_add_item(mpa_marker_tree
, hf_mpa_marker_res
, tvb
,
605 offset
, MPA_MARKER_RSVD_LEN
, ENC_BIG_ENDIAN
);
606 proto_tree_add_item(mpa_marker_tree
,
607 hf_mpa_marker_fpduptr
, tvb
,
608 offset
+MPA_MARKER_RSVD_LEN
, MPA_MARKER_FPDUPTR_LEN
, ENC_BIG_ENDIAN
);
609 offset
+= MPA_MARKER_INTERVAL
;
613 /* returns the expected value of the 16 bits long MPA FPDU ULPDU LENGTH field */
615 expected_ulpdu_length(mpa_state_t
*state
, struct tcpinfo
*tcpinfo
,
618 uint32_t length
, pad_length
, markers_length
;
620 length
= fpdu_total_length(tcpinfo
);
622 if (length
<= MPA_CRC_LEN
)
624 length
-= MPA_CRC_LEN
;
626 pad_length
= (MPA_ALIGNMENT
- (length
% MPA_ALIGNMENT
)) % MPA_ALIGNMENT
;
628 if (length
<= pad_length
)
630 length
-= pad_length
;
632 if (state
->minfo
[endpoint
].valid
) {
634 number_of_markers(state
, tcpinfo
, endpoint
) * MPA_MARKER_LEN
;
636 if (length
<= markers_length
)
638 length
-= markers_length
;
641 if (length
<= MPA_ULPDU_LENGTH_LEN
)
643 length
-= MPA_ULPDU_LENGTH_LEN
;
645 return (uint16_t) length
;
648 /* dissects MPA FPDU */
650 dissect_mpa_fpdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
651 mpa_state_t
*state
, struct tcpinfo
*tcpinfo
, uint8_t endpoint
)
653 proto_item
*mpa_item
= NULL
;
654 proto_item
*mpa_header_item
= NULL
;
656 proto_tree
*mpa_tree
= NULL
;
657 proto_tree
*mpa_header_tree
= NULL
;
660 uint16_t ulpdu_length
, exp_ulpdu_length
;
661 uint32_t offset
, total_length
;
662 uint32_t num_of_m
= 0;
665 * Initialize starting offset for this FPDU. Deals with the case that this
666 * FPDU may start with a Marker instead of the ULPDU_LENTH header field.
668 if (state
->minfo
[endpoint
].valid
669 && get_first_marker_offset(state
, tcpinfo
, endpoint
) == 0) {
670 offset
= MPA_MARKER_LEN
;
675 /* get ULPDU length of this FPDU */
676 ulpdu_length
= (uint16_t) tvb_get_ntohs(tvb
, offset
);
678 if (state
->minfo
[endpoint
].valid
) {
679 num_of_m
= number_of_markers(state
, tcpinfo
, endpoint
);
684 * Stop FPDU dissection if the read ULPDU_LENGTH field does NOT contain
686 * Reasons for getting a wrong ULPDU_LENGTH can be lost packets (because
687 * libpcap was not able to capture every packet) or lost alignment (the
688 * MPA FPDU header does not start right after TCP header).
689 * We consider the above to be an error since we make the assumption
690 * that exactly one MPA FPDU is contained in one TCP segment and starts
691 * always either with a Marker or the ULPDU_LENGTH header field.
693 pad_length
= fpdu_pad_length(ulpdu_length
);
695 exp_ulpdu_length
= expected_ulpdu_length(state
, tcpinfo
, endpoint
);
696 if (!exp_ulpdu_length
|| exp_ulpdu_length
!= (ulpdu_length
+ pad_length
)) {
701 mpa_packetlist(pinfo
, MPA_FPDU
);
703 mpa_item
= proto_tree_add_item(tree
, proto_iwarp_mpa
, tvb
, 0,
705 mpa_tree
= proto_item_add_subtree(mpa_item
, ett_mpa
);
707 mpa_header_item
= proto_tree_add_item(mpa_tree
, hf_mpa_fpdu
,
708 tvb
, offset
, -1, ENC_NA
);
709 mpa_header_tree
= proto_item_add_subtree(mpa_header_item
,
712 /* ULPDU Length header field */
713 proto_tree_add_uint(mpa_header_tree
,
714 hf_mpa_ulpdu_length
, tvb
, offset
,
715 MPA_ULPDU_LENGTH_LEN
, ulpdu_length
);
717 /* Markers are present in this FPDU */
720 total_length
= fpdu_total_length(tcpinfo
);
722 if (pad_length
> 0) {
723 proto_tree_add_item(mpa_header_tree
, hf_mpa_pad
,
724 tvb
, pad_offset(tcpinfo
,
730 dissect_fpdu_crc(tvb
, mpa_header_tree
, state
,
731 total_length
-MPA_CRC_LEN
, num_of_m
* MPA_MARKER_LEN
+
732 ulpdu_length
+ pad_length
+ MPA_ULPDU_LENGTH_LEN
);
734 dissect_fpdu_markers(tvb
, mpa_tree
, state
, tcpinfo
, endpoint
);
736 } else { /* Markers are not present or not enabled */
738 offset
+= MPA_ULPDU_LENGTH_LEN
+ ulpdu_length
;
740 if (pad_length
> 0) {
741 proto_tree_add_item(mpa_header_tree
, hf_mpa_pad
, tvb
, offset
,
743 offset
+= pad_length
;
746 dissect_fpdu_crc(tvb
, mpa_header_tree
, state
, offset
,
747 ulpdu_length
+pad_length
+MPA_ULPDU_LENGTH_LEN
);
752 /* Extracted from dissect_warp_mpa, Obtain the TCP seq of the first FPDU */
754 get_state_of_first_fpdu(tvbuff_t
*tvb
, packet_info
*pinfo
, struct tcpinfo
*tcpinfo
, uint8_t *endpoint
)
756 conversation_t
*conversation
= NULL
;
757 mpa_state_t
*state
= NULL
;
759 if (tvb_captured_length(tvb
) >= MPA_SMALLEST_FPDU_LEN
&& is_mpa_fpdu(pinfo
)) {
760 conversation
= find_conversation_pinfo(pinfo
, 0);
761 state
= get_mpa_state(conversation
);
763 if (pinfo
->srcport
== state
->minfo
[MPA_INITIATOR
].port
) {
764 *endpoint
= MPA_INITIATOR
;
765 } else if (pinfo
->srcport
== state
->minfo
[MPA_RESPONDER
].port
) {
766 *endpoint
= MPA_RESPONDER
;
768 REPORT_DISSECTOR_BUG("endpoint cannot be determined");
771 /* Markers are used by either the Initiator or the Responder or both. */
772 if ((state
->ini_exp_m_res
|| state
->res_exp_m_ini
) && *endpoint
<= MPA_RESPONDER
) {
774 /* find the TCP sequence number of the first FPDU */
775 if (!state
->minfo
[*endpoint
].valid
) {
776 state
->minfo
[*endpoint
].seq
= tcpinfo
->seq
;
777 state
->minfo
[*endpoint
].valid
= true;
787 * Main dissection routine.
790 dissect_iwarp_mpa(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
792 tvbuff_t
*next_tvb
= NULL
;
793 mpa_state_t
*state
= NULL
;
794 struct tcpinfo
*tcpinfo
;
795 uint8_t endpoint
= 3;
796 uint16_t ulpdu_length
= 0;
800 tcpinfo
= (struct tcpinfo
*)data
;
803 state
= get_state_of_first_fpdu(tvb
, pinfo
, tcpinfo
, &endpoint
);
806 ulpdu_length
= dissect_mpa_fpdu(tvb
, pinfo
, tree
, state
, tcpinfo
,
809 /* an ulpdu_length of 0 should never happen */
813 /* removes Markers if any and prepares new tvbuff for next dissector */
814 if (endpoint
<= MPA_RESPONDER
&& state
->minfo
[endpoint
].valid
815 && number_of_markers(state
, tcpinfo
, endpoint
) > 0) {
816 next_tvb
= tvb_new_subset_length(remove_markers(tvb
, pinfo
,
817 get_first_marker_offset(state
, tcpinfo
, endpoint
),
818 number_of_markers(state
, tcpinfo
, endpoint
),
819 fpdu_total_length(tcpinfo
)), MPA_ULPDU_LENGTH_LEN
,
822 next_tvb
= tvb_new_subset_length(tvb
, MPA_ULPDU_LENGTH_LEN
, ulpdu_length
);
826 /* call subdissector */
827 if (ddp_rdmap_handle
) {
828 call_dissector(ddp_rdmap_handle
, next_tvb
, pinfo
, tree
);
830 REPORT_DISSECTOR_BUG("ddp_handle was null");
836 /* MPA REQUEST or MPA REPLY */
837 if (tvb_captured_length(tvb
) >= MPA_REQ_REP_FRAME_HEADER_LEN
) {
838 if (is_mpa_req(tvb
, pinfo
))
839 return dissect_mpa_req_rep(tvb
, pinfo
, tree
, MPA_REQUEST_FRAME
);
840 else if (is_mpa_rep(tvb
, pinfo
))
841 return dissect_mpa_req_rep(tvb
, pinfo
, tree
, MPA_REPLY_FRAME
);
847 iwrap_mpa_pdu_length(packet_info
*pinfo _U_
, tvbuff_t
*tvb
,
848 int offset
, void *data _U_
)
851 int remaining
= tvb_captured_length_remaining(tvb
, offset
);
852 unsigned pdu_length
= 0;
854 mpa_state_t
*state
= NULL
;
855 uint8_t endpoint
= 3;
856 uint32_t num_of_m
= 0;
857 struct tcpinfo
*tcpinfo
;
858 int current_offset
= offset
;
860 tag
= tvb_get_ntoh64(tvb
, offset
);
861 if (tag
!= MPA_REQ_REP_FRAME
) {
863 uint16_t ULPDU_Length
;
866 tcpinfo
= (struct tcpinfo
*)data
;
868 state
= get_state_of_first_fpdu(tvb
, pinfo
, tcpinfo
, &endpoint
);
870 if (state
-> minfo
[endpoint
] . valid
&& get_first_marker_offset(state
, tcpinfo
, endpoint
) == 0) {
871 current_offset
+= MPA_MARKER_LEN
;
874 if (state
-> minfo
[endpoint
] . valid
) {
875 num_of_m
= number_of_markers(state
, tcpinfo
, endpoint
);
880 pdu_length
+= num_of_m
* MPA_MARKER_LEN
;
882 ULPDU_Length
= tvb_get_ntohs(tvb
, current_offset
);
883 pad_length
= fpdu_pad_length(ULPDU_Length
);
885 pdu_length
+= MPA_ULPDU_LENGTH_LEN
;
886 pdu_length
+= ULPDU_Length
;
887 pdu_length
+= pad_length
;
888 pdu_length
+= MPA_CRC_LEN
;
894 * MPA Request and Reply Frame Format...
897 if (remaining
< MPA_REQ_REP_FRAME_HEADER_LEN
) {
904 offset
+= MPA_REQ_REP_FRAME_HEADER_LEN
;
905 offset
-= MPA_REQ_REP_PDLENGTH_LEN
;
907 PD_Length
= tvb_get_ntohs(tvb
, offset
);
909 pdu_length
+= MPA_REQ_REP_FRAME_HEADER_LEN
;
910 pdu_length
+= PD_Length
;
916 dissect_iwarp_mpa_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
921 len
= iwrap_mpa_pdu_length(pinfo
, tvb
, 0, data
);
922 ok
= dissect_iwarp_mpa(tvb
, pinfo
, tree
, data
);
931 dissect_iwarp_mpa_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
933 struct tcpinfo
*tcpinfo
= NULL
;
934 bool is_mpa_pdu
= false;
938 tcpinfo
= (struct tcpinfo
*)data
;
940 /* MPA REQUEST or MPA REPLY */
941 if (tvb_captured_length(tvb
) >= MPA_REQ_REP_FRAME_HEADER_LEN
) {
942 if (is_mpa_req(tvb
, pinfo
)) {
944 } else if (is_mpa_rep(tvb
, pinfo
)) {
948 if (tvb_captured_length(tvb
) >= MPA_SMALLEST_FPDU_LEN
&& is_mpa_fpdu(pinfo
)) {
956 /* Set the port type for this packet to be iWarp MPA */
957 pinfo
->ptype
= PT_IWARP_MPA
;
959 tcp_dissect_pdus(tvb
, pinfo
, tree
,
960 true, /* proto_desegment*/
961 MPA_SMALLEST_FPDU_LEN
,
962 iwrap_mpa_pdu_length
,
963 dissect_iwarp_mpa_pdu
,
968 /* registers this protocol with Wireshark */
969 void proto_register_mpa(void)
971 /* setup list of header fields */
972 static hf_register_info hf
[] = {
974 "Request frame header", "iwarp_mpa.req",
975 FT_NONE
, BASE_NONE
, NULL
, 0x0,
978 "Reply frame header", "iwarp_mpa.rep",
979 FT_NONE
, BASE_NONE
, NULL
, 0x0,
982 "FPDU", "iwarp_mpa.fpdu",
983 FT_NONE
, BASE_NONE
, NULL
, 0x0,
986 "Markers", "iwarp_mpa.markers",
987 FT_NONE
, BASE_NONE
, NULL
, 0x0,
990 "ID Req frame", "iwarp_mpa.key.req",
991 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
994 "ID Rep frame", "iwarp_mpa.key.rep",
995 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
998 "Marker flag", "iwarp_mpa.marker_flag",
999 FT_BOOLEAN
, 8, NULL
, MPA_MARKER_FLAG
,
1002 "CRC flag", "iwarp_mpa.crc_flag",
1003 FT_BOOLEAN
, 8, NULL
, MPA_CRC_FLAG
,
1006 "Connection rejected flag",
1007 "iwarp_mpa.rej_flag", FT_BOOLEAN
, 8, NULL
, MPA_REJECT_FLAG
,
1009 { &hf_mpa_flag_res
, {
1010 "Reserved", "iwarp_mpa.res",
1011 FT_UINT8
, BASE_HEX
, NULL
, MPA_RESERVED_FLAG
,
1014 "Revision", "iwarp_mpa.rev",
1015 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1017 { &hf_mpa_pd_length
, {
1018 "Private data length", "iwarp_mpa.pdlength",
1019 FT_UINT16
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_byte_bytes
), 0x0,
1021 { &hf_mpa_private_data
, {
1022 "Private data", "iwarp_mpa.privatedata",
1023 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1025 { &hf_mpa_ulpdu_length
, {
1026 "ULPDU length", "iwarp_mpa.ulpdulength",
1027 FT_UINT16
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_byte_bytes
), 0x0,
1030 "Padding", "iwarp_mpa.pad",
1031 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1034 "CRC", "iwarp_mpa.crc",
1035 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
1037 { &hf_mpa_crc_check
, {
1038 "CRC check", "iwarp_mpa.crc_check",
1039 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
1041 { &hf_mpa_marker_res
, {
1042 "Reserved", "iwarp_mpa.marker_res",
1043 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
1044 "Marker: Reserved", HFILL
} },
1045 { &hf_mpa_marker_fpduptr
, {
1046 "FPDU back pointer", "iwarp_mpa.marker_fpduptr",
1047 FT_UINT16
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_byte_bytes
), 0x0,
1048 "Marker: FPDU Pointer", HFILL
} }
1051 /* setup protocol subtree array */
1052 static int *ett
[] = {
1060 static ei_register_info ei
[] = {
1061 { &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
}},
1062 { &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
}},
1063 { &ei_mpa_reject_bit_responder
, { "iwarp_mpa.reject_bit_responder", PI_RESPONSE_CODE
, PI_NOTE
, "Reject bit set by Responder", EXPFILL
}},
1064 { &ei_mpa_bad_length
, { "iwarp_mpa.bad_length", PI_MALFORMED
, PI_ERROR
, "Bad length", EXPFILL
}},
1067 expert_module_t
* expert_iwarp_mpa
;
1069 /* register the protocol name and description */
1070 proto_iwarp_mpa
= proto_register_protocol("iWARP Marker Protocol data unit Aligned framing", "IWARP_MPA", "iwarp_mpa");
1072 /* required function calls to register the header fields and subtrees */
1073 proto_register_field_array(proto_iwarp_mpa
, hf
, array_length(hf
));
1074 proto_register_subtree_array(ett
, array_length(ett
));
1075 expert_iwarp_mpa
= expert_register_protocol(proto_iwarp_mpa
);
1076 expert_register_field_array(expert_iwarp_mpa
, ei
, array_length(ei
));
1080 proto_reg_handoff_mpa(void)
1083 * MPA does not use any specific TCP port so, when not on a specific
1084 * port, try this dissector whenever there is TCP traffic.
1086 heur_dissector_add("tcp", dissect_iwarp_mpa_heur
, "IWARP_MPA over TCP", "iwarp_mpa_tcp", proto_iwarp_mpa
, HEURISTIC_ENABLE
);
1087 ddp_rdmap_handle
= find_dissector_add_dependency("iwarp_ddp_rdmap", proto_iwarp_mpa
);
1091 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1096 * indent-tabs-mode: t
1099 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1100 * :indentSize=8:tabSize=8:noTabs=false: