2 * Routines for iSCSI RDMA Extensions dissection
3 * Copyright 2014, Mellanox Technologies Ltd.
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
17 #include <epan/packet.h>
18 #include <epan/prefs.h>
19 #include <epan/conversation.h>
20 #include <epan/addr_resolv.h>
22 #include "packet-infiniband.h"
28 #define ISER_ISCSI_CTRL 0x10
29 #define ISER_HELLO 0x20
30 #define ISER_HELLORPLY 0x30
32 #define ISER_OPCODE_MASK 0xf0
33 #define ISER_SPECIFIC_MASK 0x0f
35 #define ISER_HDR_SZ (1 + 3 + 4 + 8 + 4 + 8)
36 #define ISCSI_HDR_SZ 48
38 #define ISER_ISCSI_HDR_SZ (ISER_HDR_SZ + ISCSI_HDR_SZ)
40 #define SID_ULP_MASK 0x00000000FF000000
41 #define SID_PROTO_MASK 0x0000000000FF0000
42 #define SID_PORT_MASK 0x000000000000FFFF
45 #define SID_PROTO_TCP 0x06
46 #define TCP_PORT_ISER_RANGE "3260"
48 #define SID_MASK (SID_ULP_MASK | SID_PROTO_MASK)
49 #define SID_ULP_TCP ((SID_ULP << 3 * 8) | (SID_PROTO_TCP << 2 * 8))
51 void proto_reg_handoff_iser(void);
52 void proto_register_iser(void);
54 static dissector_handle_t iser_handle
;
56 static int proto_iser
;
57 static dissector_handle_t iscsi_handler
;
62 static int hf_iser_flags
;
63 static int hf_iser_opcode_f
;
64 static int hf_iser_RSV_f
;
65 static int hf_iser_WSV_f
;
66 static int hf_iser_REJ_f
;
67 static int hf_iser_write_stag
;
68 static int hf_iser_write_va
;
69 static int hf_iser_read_stag
;
70 static int hf_iser_read_va
;
71 static int hf_iser_ird
;
72 static int hf_iser_ord
;
74 /* Initialize the subtree pointers */
76 static int ett_iser_flags
;
78 /* global preferences */
79 static range_t
*gPORT_RANGE
;
81 static const value_string iser_flags_opcode
[] = {
82 { ISER_ISCSI_CTRL
>> 4, "iSCSI Control-Type PDU"},
83 { ISER_HELLO
>> 4, "Hello Message"},
84 { ISER_HELLORPLY
>> 4, "HelloReply Message"},
88 static int * const flags_fields
[] = {
94 static int * const hello_flags_fields
[] = {
98 static int * const hellorply_flags_fields
[] = {
104 static int dissect_packet(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
107 /* Set up structures needed to add the protocol subtree and manage it */
109 proto_tree
*iser_tree
;
111 uint8_t flags
, vers
, opcode
;
113 if (tvb_reported_length(tvb
) < ISER_ISCSI_HDR_SZ
)
116 flags
= tvb_get_uint8(tvb
, 0);
117 opcode
= flags
& ISER_OPCODE_MASK
;
119 /* Check if the opcode is valid */
121 case ISER_ISCSI_CTRL
:
122 switch (flags
& ISER_SPECIFIC_MASK
) {
126 case ISER_RSV
|ISER_WSV
:
136 vers
= tvb_get_uint8(tvb
, 1);
137 if ((vers
& 0xf) != 10)
139 if (((vers
>> 4) & 0x0f) != 10)
147 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "iSER");
148 /* Clear out stuff in the info column */
149 col_clear(pinfo
->cinfo
, COL_INFO
);
151 /* Set info only for hello, since for iscsi, the iscsi dissector will */
154 col_set_str(pinfo
->cinfo
, COL_INFO
, "iSER Hello");
158 col_set_str(pinfo
->cinfo
, COL_INFO
, "iSER HelloRply");
163 /* create display subtree for the protocol */
164 ti
= proto_tree_add_item(tree
, proto_iser
, tvb
, 0, ISER_HDR_SZ
, ENC_NA
);
166 iser_tree
= proto_item_add_subtree(ti
, ett_iser
);
169 case ISER_ISCSI_CTRL
:
170 proto_tree_add_bitmask(iser_tree
, tvb
, offset
, hf_iser_flags
,
171 ett_iser_flags
, flags_fields
, ENC_LITTLE_ENDIAN
);
173 proto_tree_add_item(iser_tree
, hf_iser_write_stag
, tvb
,
174 offset
, 4, ENC_BIG_ENDIAN
);
176 proto_tree_add_item(iser_tree
, hf_iser_write_va
, tvb
,
177 offset
, 8, ENC_BIG_ENDIAN
);
179 proto_tree_add_item(iser_tree
, hf_iser_read_stag
, tvb
,
180 offset
, 4, ENC_BIG_ENDIAN
);
182 proto_tree_add_item(iser_tree
, hf_iser_read_va
, tvb
,
183 offset
, 8, ENC_BIG_ENDIAN
);
187 proto_tree_add_bitmask(iser_tree
, tvb
, offset
, hf_iser_flags
,
188 ett_iser_flags
, hello_flags_fields
, ENC_LITTLE_ENDIAN
);
190 proto_tree_add_item(iser_tree
, hf_iser_ird
, tvb
,
191 offset
, 2, ENC_BIG_ENDIAN
);
195 proto_tree_add_bitmask(iser_tree
, tvb
, offset
, hf_iser_flags
,
196 ett_iser_flags
, hellorply_flags_fields
, ENC_LITTLE_ENDIAN
);
198 proto_tree_add_item(iser_tree
, hf_iser_ord
, tvb
,
199 offset
, 2, ENC_BIG_ENDIAN
);
204 if (opcode
== ISER_ISCSI_CTRL
) {
205 next_tvb
= tvb_new_subset_remaining(tvb
, ISER_HDR_SZ
);
206 call_dissector(iscsi_handler
, next_tvb
, pinfo
, tree
);
213 dissect_iser(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
216 conversation_t
*conv
;
217 conversation_infiniband_data
*convo_data
= NULL
;
219 if (tvb_reported_length(tvb
) < ISER_ISCSI_HDR_SZ
)
222 /* first try to find a conversation between the two current hosts. in most cases this
223 will not work since we do not have the source QP. this WILL succeed when we're still
224 in the process of CM negotiations */
225 conv
= find_conversation(pinfo
->num
, &pinfo
->src
, &pinfo
->dst
,
226 CONVERSATION_IBQP
, pinfo
->srcport
, pinfo
->destport
, 0);
229 /* if not, try to find an established RC channel. recall Infiniband conversations are
230 registered with one side of the channel. since the packet is only guaranteed to
231 contain the qpn of the destination, we'll use this */
232 conv
= find_conversation(pinfo
->num
, &pinfo
->dst
, &pinfo
->dst
,
233 CONVERSATION_IBQP
, pinfo
->destport
, pinfo
->destport
, NO_ADDR_B
|NO_PORT_B
);
236 return false; /* nothing to do with no conversation context */
239 convo_data
= (conversation_infiniband_data
*)conversation_get_proto_data(conv
, proto_ib
);
244 if ((convo_data
->service_id
& SID_MASK
) != SID_ULP_TCP
)
245 return false; /* the service id doesn't match that of TCP ULP - nothing for us to do here */
247 if (!(value_is_in_range(gPORT_RANGE
, (uint32_t)(convo_data
->service_id
& SID_PORT_MASK
))))
248 return false; /* the port doesn't match that of iSER - nothing for us to do here */
250 dissect_packet(tvb
, pinfo
, tree
, data
);
255 proto_register_iser(void)
257 module_t
*iser_module
;
258 static hf_register_info hf
[] = {
260 { "Flags", "iser.flags",
261 FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
264 { "Opcode", "iser.flags.opcode",
265 FT_UINT8
, BASE_HEX
, VALS(iser_flags_opcode
),
266 ISER_OPCODE_MASK
, NULL
, HFILL
}
269 { "RSV", "iser.flags.rsv",
270 FT_BOOLEAN
, 8, NULL
, ISER_RSV
, "Read STag Valid", HFILL
}
273 { "WSV", "iser.flags.wsv",
274 FT_BOOLEAN
, 8, NULL
, ISER_WSV
, "Write STag Valid", HFILL
}
277 { "REJ", "iser.flags.rej",
278 FT_BOOLEAN
, 8, NULL
, ISER_REJ
, "Target reject connection", HFILL
}
280 { &hf_iser_write_stag
,
281 { "Write STag", "iser.write_stag",
282 FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
285 { "Write Base Offset", "iser.write_base_offset",
286 FT_UINT64
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
288 { &hf_iser_read_stag
,
289 { "Read STag", "iser.read_stag",
290 FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
293 { "Read Base Offset", "iser.read_base_offset",
294 FT_UINT64
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
297 { "iSER-IRD", "iser.ird",
298 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
301 { "iSER-ORD", "iser.ord",
302 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
306 static int *ett
[] = {
311 proto_iser
= proto_register_protocol (
312 "iSCSI Extensions for RDMA", /* name */
313 "iSER", /* short name */
317 proto_register_field_array(proto_iser
, hf
, array_length(hf
));
318 proto_register_subtree_array(ett
, array_length(ett
));
320 /* Register preferences */
321 iser_module
= prefs_register_protocol(proto_iser
, proto_reg_handoff_iser
);
323 prefs_register_static_text_preference(iser_module
, "use_decode_as",
324 "Heuristic matching preferences removed. Use Infiniband protocol preferences or Decode As.",
325 "Simple heuristics can still be enable (may generate false positives) through Infiniband protocol preferences."
326 "To force iSER dissection use Decode As");
328 prefs_register_obsolete_preference(iser_module
, "manual_en");
330 prefs_register_obsolete_preference(iser_module
, "addr_a");
331 prefs_register_obsolete_preference(iser_module
, "addr_a_type");
332 prefs_register_obsolete_preference(iser_module
, "addr_a_id");
333 prefs_register_obsolete_preference(iser_module
, "addr_a_qp");
335 prefs_register_obsolete_preference(iser_module
, "addr_b");
336 prefs_register_obsolete_preference(iser_module
, "addr_b_type");
337 prefs_register_obsolete_preference(iser_module
, "addr_b_id");
338 prefs_register_obsolete_preference(iser_module
, "addr_b_qp");
340 range_convert_str(wmem_epan_scope(), &gPORT_RANGE
, TCP_PORT_ISER_RANGE
, MAX_TCP_PORT
);
341 prefs_register_range_preference(iser_module
,
343 "Target Ports Range",
344 "Range of iSER target ports"
345 "(default " TCP_PORT_ISER_RANGE
")",
346 &gPORT_RANGE
, MAX_TCP_PORT
);
348 iser_handle
= register_dissector("iser", dissect_packet
, proto_iser
);
352 proto_reg_handoff_iser(void)
354 heur_dissector_add("infiniband.payload", dissect_iser
, "iSER Infiniband", "iser_infiniband", proto_iser
, HEURISTIC_ENABLE
);
355 heur_dissector_add("infiniband.mad.cm.private", dissect_iser
, "iSER in PrivateData of CM packets", "iser_ib_private", proto_iser
, HEURISTIC_ENABLE
);
357 dissector_add_for_decode_as("infiniband", iser_handle
);
359 iscsi_handler
= find_dissector_add_dependency("iscsi", proto_iser
);
360 proto_ib
= proto_get_id_by_filter_name( "infiniband" );
364 * Editor modelines - https://www.wireshark.org/tools/modelines.html
369 * indent-tabs-mode: nil
372 * vi: set shiftwidth=4 tabstop=8 expandtab:
373 * :indentSize=4:tabSize=8:noTabs=true: