Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-irdma.c
blob3bf7d4c9fed1fedc2b5f2b4c8ff16494bdb5e525
1 /* packet-irdma.c
3 * Routines for IBM i RDMA dissection
4 * Copyright 2018, 2024 IBM Corporation
5 * Brian Jongekryg (bej@us.ibm.com, bej@arbin.net)
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
15 * Dissector for IBM i base RDMA frame traffic
16 * captured via TRCCNN TYPE(*RDMA) command
18 * Subdissectors for IBM i RDMA endoint traffic can be registered
19 * by calling
20 * dissector_add_uint("irdma.ep.port", port, handle);
23 #include <config.h>
25 #include <string.h>
27 #include <epan/packet.h> /* Should be first Wireshark include (other than config.h) */
28 #include <epan/conversation.h>
29 #include <epan/proto_data.h>
30 #include <epan/expert.h>
31 #include <epan/prefs.h>
32 #include <epan/addr_resolv.h>
33 #include <wsutil/utf8_entities.h>
35 #include <packet-irdma.h>
37 /* irdmaep conversation and packet analysis data */
38 typedef struct irdmaep_buffer
40 /* Size of buffer */
41 uint32_t size;
43 /* Offset of first byte available for use */
44 uint32_t offset;
46 /* Last data sequence number in buffer */
47 uint32_t seq_num;
49 /* Contents of buffer unknown */
50 bool indeterminate;
52 } irdmaep_buffer_t;
54 #define IRDMAEP_MAX_DATA_BUFID 2
55 typedef struct irdmaep_flow
57 /* Last sent DATA sequence */
58 bool data_seq_valid;
59 uint32_t data_seq;
61 /* Last sent USER_RDMA data (RECVACK) ID, offset */
62 bool recvack_valid;
63 uint32_t recvack_id;
64 uint32_t recvack_offset;
66 /* Receive buffer status */
67 /* Number of receive buffers */
68 uint32_t recv_buffer_count;
70 /* Most recent buffer used by sender */
71 uint32_t recv_mrb;
73 /* Calculated buffer size estimate */
74 uint32_t recv_min_size;
76 /* Track up to two remote receive buffers */
77 irdmaep_buffer_t recv_buffer[IRDMAEP_MAX_DATA_BUFID];
79 } irdmaep_flow_t;
81 typedef struct irdmaep_analysis
83 /* Trace status for both directions of the flow.
84 Info for sends with smaller src port is recorded in flow1,
85 larger src port in flow2. */
86 irdmaep_flow_t flow1;
87 irdmaep_flow_t flow2;
89 /* Forward or reverse flow info based on current packet ports */
90 irdmaep_flow_t *fwd_flow, *rev_flow;
92 /* Server port number from CONNREQ or CONNACK to help determine
93 which payload dissector to call. */
94 uint32_t server_port;
96 /* Keep track of RDMA endpoint stream numbers */
97 uint32_t stream;
99 /* Track whether conversation was closed, so we know to start
100 new conversation if CONNREQ/ACK seen. */
101 bool closed;
103 /* Current link sequence number */
104 uint32_t link;
106 /* Link switch timestamps */
107 nstime_t movereq_time;
109 /* Conversation timestamps */
110 nstime_t ts_first;
111 nstime_t ts_prev;
113 } irdmaep_analysis_t;
115 typedef struct irdmaep_packet_analysis
117 /* Retransmitted packet? */
118 bool retransmission;
120 /* Out-of-order sequence (should never occur) */
121 bool out_of_order;
123 /* Bytes remaining available for sending/receiving */
124 uint32_t rbuf_available;
126 /* Bytes remaining in current/active receive buffer */
127 uint32_t rbuf_cur;
129 /* Max bytes available for next send */
130 uint32_t rbuf_max;
132 /* Is rbuf_available estimated or true value */
133 bool rbuf_estimated;
135 /* Does packet sequence indicate this is stale (prior link) */
136 bool seq_stale;
138 /* First packet on new link */
139 bool linkswt;
141 /* Time to move link */
142 nstime_t movelink_time;
144 /* Delta time from previous packet */
145 nstime_t delta_time;
147 } irdmaep_packet_analysis_t;
149 /* Prototypes */
150 void proto_reg_handoff_irdma(void);
151 void proto_register_irdma(void);
153 static int dissect_irdma(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
154 static int dissect_irdmaqp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
155 static int dissect_irdmalink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
156 static int dissect_irdmaep(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data);
157 static void dissect_data_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
158 irdmaep_analysis_t *epd, proto_tree *ep_tree);
159 static void irdmaep_add_rbuf_tree(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
160 irdmaep_packet_analysis_t *eppd);
161 static void dissect_reuse_msg(tvbuff_t *tvb, packet_info *pinfo,
162 irdmaep_analysis_t *epd, proto_tree *ep_tree);
163 static void dissect_user_recv_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
164 irdmaep_analysis_t *epd, proto_tree *ep_tree);
165 static void dissect_user_send_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
166 irdmaep_analysis_t *epd, proto_tree *ep_tree);
167 static void dissect_connect_msg(tvbuff_t *tvb, packet_info *pinfo,
168 irdmaep_analysis_t *epd, proto_tree *ep_tree);
169 static void dissect_close_msg(tvbuff_t *tvb, packet_info *pinfo,
170 irdmaep_analysis_t *epd, proto_tree *ep_tree);
171 static void dissect_buffer_msg_mkeyaddr(tvbuff_t *tvb, packet_info *pinfo,
172 irdmaep_analysis_t *epd, proto_tree *ep_tree);
173 static void dissect_buffer_msg(tvbuff_t *tvb, packet_info *pinfo,
174 irdmaep_analysis_t *epd, proto_tree *ep_tree);
175 static void dissect_move_link_msg(tvbuff_t *tvb, packet_info *pinfo,
176 irdmaep_analysis_t *epd, proto_tree *ep_tree);
177 static void dissect_move_link_ack_msg(tvbuff_t *tvb, packet_info *pinfo,
178 irdmaep_analysis_t *epd, proto_tree *ep_tree);
179 static void dissect_move_link_cmp_msg(tvbuff_t *tvb, packet_info *pinfo,
180 irdmaep_analysis_t *epd, proto_tree *ep_tree);
181 static void dissect_irdmaep_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
182 irdmaep_pdata_t *data);
183 static irdmaep_analysis_t *init_irdmaep_conversation_data(packet_info *pinfo);
184 static void analyze_irdmaep_rbuffer(irdmaep_flow_t *flow,
185 irdmaep_packet_analysis_t *eppd);
186 static void *add_eppd(packet_info *pinfo);
187 static void *get_eppd(packet_info *pinfo);
188 static void *get_or_add_eppd(packet_info *pinfo);
190 /* Initialize the protocol and registered fields */
191 static int proto_irdma;
192 static int proto_irdmaqp;
193 static int proto_irdmalink;
194 static int proto_irdmaep;
196 static int hf_irdma_hwdst;
197 static int hf_irdma_hwsrc;
198 static int hf_irdma_qpindex;
199 static int hf_irdma_ip6src;
200 static int hf_irdma_ip6dst;
201 static int hf_irdma_ip4src;
202 static int hf_irdma_ip4dst;
203 static int hf_irdma_hwaddr;
204 static int hf_irdma_ip6addr;
205 static int hf_irdma_ip4addr;
207 static int hf_irdmaqp_type;
208 static int hf_irdmaqp_id;
210 static int hf_irdmalink_type;
211 static int hf_irdmalink_groups;
213 static int hf_irdmaep_type;
214 static int hf_irdmaep_len;
215 static int hf_irdmaep_grpid;
216 static int hf_irdmaep_grpid_ctr;
217 static int hf_irdmaep_grpid_time;
218 static int hf_irdmaep_grpid_hwaddr;
219 static int hf_irdmaep_srcport;
220 static int hf_irdmaep_dstport;
221 static int hf_irdmaep_port;
222 static int hf_irdmaep_stream;
223 static int hf_irdmaep_linkseq;
224 static int hf_irdmaep_sndbufsize;
225 static int hf_irdmaep_usrblksize;
226 static int hf_irdmaep_reason;
227 static int hf_irdmaep_rbuf;
228 static int hf_irdmaep_rkey;
229 static int hf_irdmaep_raddr;
230 static int hf_irdmaep_flags;
231 static int hf_irdmaep_flag_buf0_free;
232 static int hf_irdmaep_flag_buf1_free;
233 static int hf_irdmaep_rcvbufsize;
234 static int hf_irdmaep_sendseq;
235 static int hf_irdmaep_recvseq0;
236 static int hf_irdmaep_recvseq1;
237 static int hf_irdmaep_usndsent;
238 static int hf_irdmaep_usndid;
239 static int hf_irdmaep_urcvid;
240 static int hf_irdmaep_seqnum;
241 static int hf_irdmaep_bufid;
242 static int hf_irdmaep_offset;
243 static int hf_irdmaep_datalen;
244 static int hf_irdmaep_ulength;
245 static int hf_irdmaep_blength;
246 static int hf_irdmaep_recvid;
247 static int hf_irdmaep_rbufavail;
248 static int hf_irdmaep_rbufactive;
249 static int hf_irdmaep_rbufmax;
250 static int hf_irdmaep_move1;
251 static int hf_irdmaep_move2;
252 static int hf_irdmaep_ts_relative;
253 static int hf_irdmaep_ts_delta;
255 static expert_field ei_irdmaep_analysis_stale;
256 static expert_field ei_irdmaep_analysis_dup;
257 static expert_field ei_irdmaep_analysis_oos;
258 static expert_field ei_irdmaep_connection_req;
259 static expert_field ei_irdmaep_connection_ack;
260 static expert_field ei_irdmaep_connection_lswt;
262 /* Initialize the subtree pointers */
263 static int ett_irdma;
264 static int ett_irdmaqp;
265 static int ett_irdmalink;
266 static int ett_irdmaep;
267 static int ett_irdmaep_grpid;
268 static int ett_irdmaep_rbuf;
269 static int ett_irdmaep_bufflags;
270 static int ett_irdmaep_rcvbuf_analyze;
271 static int ett_irdmaep_timestamps;
273 static dissector_table_t irdmaep_dissector_table = NULL;
275 static dissector_handle_t irdmaqp_handle;
276 static dissector_handle_t irdmalink_handle;
277 static dissector_handle_t irdmaep_handle;
279 static uint32_t irdmaep_stream_count;
281 /* Data passed from iRDMA dissector to QP, Link, Endpoint dissectors */
282 typedef struct
284 uint32_t qpindex;
285 } irdma_data_t;
287 /* Miscellaneous utility functions */
288 static inline bool
289 seq16_lt(uint16_t a, uint16_t b)
291 return (int16_t) (a - b) < 0;
294 static inline bool
295 seq16_gt(uint16_t a, uint16_t b)
297 return (int16_t) (a - b) > 0;
300 static inline bool
301 is_v4mapped(ws_in6_addr *addr)
303 static uint8_t mapped[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF};
304 return memcmp(addr, mapped, 12) == 0;
307 static inline bool
308 is_v4compat(ws_in6_addr *addr)
310 static uint8_t zeroes[12] = {0};
311 return memcmp(addr, zeroes, 12) == 0
312 && memcmp(&addr->bytes[12], zeroes, 4) != 0;
315 static const value_string irdma_serv_names[] = {
316 {930, "mrdb-engine"},
317 {931, "mrdb-objrep"},
318 {932, "mrdb-objrepr"},
319 {940, "ifs-mfs"},
320 {946, "drda-ddm"},
321 {0, NULL}};
323 static inline const char *
324 irdma_serv_name_lookup(unsigned port)
326 return try_val_to_str(port, irdma_serv_names);
329 static inline void
330 irdma_col_snprint_port(char *buf, unsigned long buf_siz, uint16_t val)
332 const char *str;
334 if (gbl_resolv_flags.transport_name &&
335 (str = irdma_serv_name_lookup(val)) != NULL) {
336 snprintf(buf, buf_siz, "%s(%" PRIu16 ")", str, val);
337 } else {
338 snprintf(buf, buf_siz, "%" PRIu16, val);
342 static void
343 irdma_col_append_ports(column_info *cinfo, const int col, uint16_t src, uint16_t dst)
345 char buf_src[32], buf_dst[32];
347 irdma_col_snprint_port(buf_src, 32, src);
348 irdma_col_snprint_port(buf_dst, 32, dst);
349 col_append_lstr(cinfo, col, buf_src, " " UTF8_RIGHTWARDS_ARROW " ", buf_dst, COL_ADD_LSTR_TERMINATOR);
352 static void
353 irdma_custom_format_port(char *str, uint32_t port)
355 irdma_col_snprint_port(str, ITEM_LABEL_LENGTH, port);
358 static void
359 irdma_custom_format_rbufsize(char *str, uint32_t bufsize)
361 bufsize &= 0xFFF;
362 uint32_t kb_bufsize = bufsize * 4;
363 snprintf(str, ITEM_LABEL_LENGTH, "%" PRIu32 " (%" PRIu32 " KB)", bufsize, kb_bufsize);
366 static void
367 irdma_init(void)
369 irdmaep_stream_count = 0;
372 /*********************************************************************/
373 /*********************************************************************/
374 /* RDMA pseudo-header data and functions */
375 /*********************************************************************/
376 /*********************************************************************/
378 /* IBM i RDMA pseudo-header from TRCCNN offsets */
379 #define IRDMA_HDR_DST 0
380 #define IRDMA_HDR_SRC 6
381 #define IRDMA_HDR_QPINDEX 12
382 #define IRDMA_HDR_SRCIP 14
383 #define IRDMA_HDR_SRCIP4 26
384 #define IRDMA_HDR_DSTIP 30
385 #define IRDMA_HDR_DSTIP4 42
386 #define IRDMA_HDR_LENGTH 46
388 /* Payload types for IBM i RDMA frames */
389 #define IRDMA_PROTO_ENDPOINT 0 /* 0b */
390 #define IRDMA_PROTO_QP 4 /* 100b */
391 #define IRDMA_PROTO_LINK 5 /* 101b */
393 /* Dissect IBM i RDMA pseudo-header */
394 static int
395 dissect_irdma(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
397 /* Set up structures needed to add the protocol subtree and manage it */
398 proto_item *ti;
399 proto_item *irdma_item;
400 proto_tree *irdma_tree;
401 /* Other misc. local variables. */
402 ws_in6_addr ipsrc;
403 bool ipv4 = false;
404 char *src_str, *dst_str;
405 irdma_data_t irdma_data = {0};
406 dissector_handle_t subdissector_handle = NULL;
408 /*** HEURISTICS ***/
410 /* First, if at all possible, do some heuristics to check if the packet
411 * cannot possibly belong to your protocol. This is especially important
412 * for protocols directly on top of TCP or UDP where port collisions are
413 * common place (e.g., even though your protocol uses a well known port,
414 * someone else may set up, for example, a web server on that port which,
415 * if someone analyzed that web server's traffic in Wireshark, would result
416 * in Wireshark handing an HTTP packet to your dissector).
418 * For example:
421 /* Check that the packet is long enough for it to belong to us. */
422 if (tvb_reported_length(tvb) < IRDMA_HDR_LENGTH)
423 return 0;
425 /* Check that the packet has a recognizable frame type. This probably
426 won't eliminate many bad packets. */
427 uint8_t ftype = tvb_get_bits8(tvb, IRDMA_HDR_LENGTH * 8, 3);
428 if (ftype > 5)
429 return 0;
431 /*** COLUMN DATA ***/
433 /* There are two normal columns to fill in: the 'Protocol' column which
434 * is narrow and generally just contains the constant string 'irdma',
435 * and the 'Info' column which can be much wider and contain misc. summary
436 * information (for example, the port number for TCP packets).
438 * If you are setting the column to a constant string, use "col_set_str()",
439 * as it's more efficient than the other "col_set_XXX()" calls.
441 * If
442 * - you may be appending to the column later OR
443 * - you have constructed the string locally OR
444 * - the string was returned from a call to val_to_str()
445 * then use "col_add_str()" instead, as that takes a copy of the string.
447 * The function "col_add_fstr()" can be used instead of "col_add_str()"; it
448 * takes "printf()"-like arguments. Don't use "col_add_fstr()" with a format
449 * string of "%s" - just use "col_add_str()" or "col_set_str()", as it's
450 * more efficient than "col_add_fstr()".
452 * For full details see section 1.4 of README.dissector.
455 /* Set the Protocol column to the constant string of irdma */
456 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RDMA");
458 /* Use first 3 bits beyond header to determine what type of frame this is
459 (QP management, Link Management, Endpoint) */
460 if (ftype == IRDMA_PROTO_QP)
462 col_set_str(pinfo->cinfo, COL_INFO, "QP Management");
463 subdissector_handle = irdmaqp_handle;
465 else
466 if (ftype == IRDMA_PROTO_LINK)
468 col_set_str(pinfo->cinfo, COL_INFO, "Link Management");
469 subdissector_handle = irdmalink_handle;
471 else
473 col_set_str(pinfo->cinfo, COL_INFO, "RDMA Endpoint");
474 subdissector_handle = irdmaep_handle;
477 /*** PROTOCOL TREE ***/
479 /* Now we will create a sub-tree for our protocol and start adding fields
480 * to display under that sub-tree. Most of the time the only functions you
481 * will need are proto_tree_add_item() and proto_item_add_subtree().
483 * NOTE: The offset and length values in the call to proto_tree_add_item()
484 * define what data bytes to highlight in the hex display window when the
485 * line in the protocol tree display corresponding to that item is selected.
487 * Supplying a length of -1 tells Wireshark to highlight all data from the
488 * offset to the end of the packet.
491 /* create display subtree for the protocol */
492 irdma_item = proto_tree_add_item(tree, proto_irdma, tvb, 0, IRDMA_HDR_LENGTH, ENC_NA);
493 irdma_tree = proto_item_add_subtree(irdma_item, ett_irdma);
495 set_address_tvb(&pinfo->dl_dst, AT_ETHER, 6, tvb, IRDMA_HDR_DST);
496 set_address_tvb(&pinfo->dl_src, AT_ETHER, 6, tvb, IRDMA_HDR_SRC);
498 proto_tree_add_item(irdma_tree, hf_irdma_hwdst, tvb, IRDMA_HDR_DST, 6, ENC_NA);
499 ti = proto_tree_add_item(irdma_tree, hf_irdma_hwaddr, tvb, IRDMA_HDR_DST, 6, ENC_NA);
500 PROTO_ITEM_SET_HIDDEN(ti);
502 proto_tree_add_item(irdma_tree, hf_irdma_hwsrc, tvb, IRDMA_HDR_SRC, 6, ENC_NA);
503 ti = proto_tree_add_item(irdma_tree, hf_irdma_hwaddr, tvb, IRDMA_HDR_SRC, 6, ENC_NA);
504 PROTO_ITEM_SET_HIDDEN(ti);
506 proto_tree_add_item_ret_uint(irdma_tree, hf_irdma_qpindex, tvb,
507 IRDMA_HDR_QPINDEX, 2, ENC_BIG_ENDIAN,
508 &irdma_data.qpindex);
510 /* Get source IP address and determine if we've got an IPv4 or IPv6 address */
511 tvb_get_ipv6(tvb, IRDMA_HDR_SRCIP, &ipsrc);
512 ipv4 = is_v4mapped(&ipsrc) || is_v4compat(&ipsrc);
514 if (ipv4)
516 set_address_tvb(&pinfo->net_dst, AT_IPv4, 4, tvb, IRDMA_HDR_DSTIP4);
517 copy_address_shallow(&pinfo->dst, &pinfo->net_dst);
519 set_address_tvb(&pinfo->net_src, AT_IPv4, 4, tvb, IRDMA_HDR_SRCIP4);
520 copy_address_shallow(&pinfo->src, &pinfo->net_src);
522 src_str = tvb_address_with_resolution_to_str(wmem_packet_scope(), tvb, AT_IPv4, IRDMA_HDR_SRCIP4);
523 dst_str = tvb_address_with_resolution_to_str(wmem_packet_scope(), tvb, AT_IPv4, IRDMA_HDR_DSTIP4);
525 proto_tree_add_item(irdma_tree, hf_irdma_ip4src, tvb, IRDMA_HDR_SRCIP4, 4, ENC_BIG_ENDIAN);
526 ti = proto_tree_add_item(irdma_tree, hf_irdma_ip4addr, tvb, IRDMA_HDR_SRCIP4, 4, ENC_BIG_ENDIAN);
527 PROTO_ITEM_SET_HIDDEN(ti);
529 proto_tree_add_item(irdma_tree, hf_irdma_ip4dst, tvb, IRDMA_HDR_DSTIP4, 4, ENC_BIG_ENDIAN);
530 ti = proto_tree_add_item(irdma_tree, hf_irdma_ip4addr, tvb, IRDMA_HDR_DSTIP4, 4, ENC_BIG_ENDIAN);
531 PROTO_ITEM_SET_HIDDEN(ti);
533 else
535 set_address_tvb(&pinfo->net_dst, AT_IPv6, 16, tvb, IRDMA_HDR_DSTIP);
536 copy_address_shallow(&pinfo->dst, &pinfo->net_dst);
538 set_address_tvb(&pinfo->net_src, AT_IPv6, 16, tvb, IRDMA_HDR_SRCIP);
539 copy_address_shallow(&pinfo->src, &pinfo->net_src);
541 src_str = tvb_address_with_resolution_to_str(wmem_packet_scope(), tvb, AT_IPv6, IRDMA_HDR_SRCIP);
542 dst_str = tvb_address_with_resolution_to_str(wmem_packet_scope(), tvb, AT_IPv6, IRDMA_HDR_DSTIP);
544 proto_tree_add_item(irdma_tree, hf_irdma_ip6src, tvb, IRDMA_HDR_SRCIP, 16, ENC_NA);
545 ti = proto_tree_add_item(irdma_tree, hf_irdma_ip6addr, tvb, IRDMA_HDR_SRCIP, 16, ENC_NA);
546 PROTO_ITEM_SET_HIDDEN(ti);
548 proto_tree_add_item(irdma_tree, hf_irdma_ip6dst, tvb, IRDMA_HDR_DSTIP, 16, ENC_NA);
549 ti = proto_tree_add_item(irdma_tree, hf_irdma_ip6addr, tvb, IRDMA_HDR_DSTIP, 16, ENC_NA);
550 PROTO_ITEM_SET_HIDDEN(ti);
553 proto_item_append_text(irdma_item, ", Src: %s", src_str);
554 proto_item_append_text(irdma_item, ", Dst: %s", dst_str);
556 call_dissector_with_data(subdissector_handle,
557 tvb_new_subset_remaining(tvb, IRDMA_HDR_LENGTH),
558 pinfo, tree, &irdma_data);
560 /* Return the amount of data this dissector was able to dissect (which may
561 * or may not be the total captured packet as we return here). */
562 return tvb_captured_length(tvb);
565 /*********************************************************************/
566 /*********************************************************************/
567 /* RDMA QP data and functions */
568 /*********************************************************************/
569 /*********************************************************************/
570 /* IBM i RDMA QP message types */
571 #define IRDMA_QP_ECHOREQ 0x8000
572 #define IRDMA_QP_ECHORSP 0x8001
574 /* IBM i RDMA QP message offsets */
575 #define IRDMA_QP_TYPE 0 /* 16-bit message type */
576 #define IRDMA_QP_ECHO_ID 2 /* 16-bit Echo req/rsp ID */
578 static const value_string irdmaqp_type_str[] = {
579 {IRDMA_QP_ECHOREQ, "Echo request"},
580 {IRDMA_QP_ECHORSP, "Echo response"},
581 {0, NULL}};
583 /* Dissect RDMA QP packets */
584 static int
585 dissect_irdmaqp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
587 proto_item *ti;
588 proto_tree *qp_tree;
590 irdma_data_t *irdma_data = (irdma_data_t *) data;
592 if (tvb_reported_length(tvb) < 2)
593 return 0;
595 /* Set the Protocol column */
596 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RDMA-QP");
598 uint16_t msg_type = tvb_get_ntohs(tvb, IRDMA_QP_TYPE);
599 const char *msg_type_str = val_to_str(msg_type, irdmaqp_type_str,
600 "Unknown message (0x%04X)");
602 col_add_fstr(pinfo->cinfo, COL_INFO,
603 "%-16s qp=%2" PRIu32, msg_type_str, irdma_data->qpindex);
605 /* Create display subtree for the QP message */
606 ti = proto_tree_add_item(tree, proto_irdmaqp, tvb, 0, -1, ENC_NA);
607 qp_tree = proto_item_add_subtree(ti, ett_irdmaqp);
609 proto_tree_add_item(qp_tree, hf_irdmaqp_type, tvb, IRDMA_QP_TYPE, 2,
610 ENC_BIG_ENDIAN);
612 switch (msg_type)
614 case IRDMA_QP_ECHOREQ:
615 case IRDMA_QP_ECHORSP:
617 uint32_t echo_id;
618 proto_tree_add_item_ret_uint(qp_tree, hf_irdmaqp_id, tvb,
619 IRDMA_QP_ECHO_ID, 2,
620 ENC_BIG_ENDIAN, &echo_id);
621 col_append_fstr(pinfo->cinfo, COL_INFO, ", id=%" PRIu32, echo_id);
622 break;
626 return tvb_captured_length(tvb);
629 /*********************************************************************/
630 /*********************************************************************/
631 /* RDMA Link data and functions */
632 /*********************************************************************/
633 /*********************************************************************/
634 /* IBM i RDMA Link message types */
635 #define IRDMA_LINK_STATUS 0xA000
637 /* IBM i RDMA Link message offsets */
638 #define IRDMA_LINK_TYPE 0 /* 16-bit message type */
639 #define IRDMA_LINK_STATUS_GROUPS 2 /* 16-bit count of active groups */
641 static const value_string irdmalink_type_str[] = {
642 {IRDMA_LINK_STATUS, "Link Status"},
643 {0, NULL}};
645 /* Dissect RDMA Link packets */
646 static int
647 dissect_irdmalink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
649 proto_item *ti;
650 proto_tree *link_tree;
652 if (tvb_reported_length(tvb) < 2)
653 return 0;
655 /* Set the Protocol column */
656 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RDMA-Link");
658 uint16_t msg_type = tvb_get_ntohs(tvb, IRDMA_LINK_TYPE);
659 const char *msg_type_str = val_to_str(msg_type, irdmalink_type_str,
660 "Unknown message (0x%04X)");
662 col_add_str(pinfo->cinfo, COL_INFO, msg_type_str);
664 /* Create display subtree for the Link message */
665 ti = proto_tree_add_item(tree, proto_irdmalink, tvb, 0, -1, ENC_NA);
666 link_tree = proto_item_add_subtree(ti, ett_irdmalink);
668 proto_tree_add_item(link_tree, hf_irdmalink_type, tvb, IRDMA_LINK_TYPE, 2,
669 ENC_BIG_ENDIAN);
671 switch (msg_type)
673 case IRDMA_LINK_STATUS:
675 uint32_t groups;
676 proto_tree_add_item_ret_uint(link_tree, hf_irdmalink_groups, tvb,
677 IRDMA_LINK_STATUS_GROUPS, 2,
678 ENC_BIG_ENDIAN, &groups);
679 col_append_fstr(pinfo->cinfo, COL_INFO, ", groups=%" PRIu32, groups);
680 break;
684 return tvb_captured_length(tvb);
687 /*********************************************************************/
688 /*********************************************************************/
689 /* RDMA Endpoint data and functions */
690 /*********************************************************************/
691 /*********************************************************************/
692 /* IBM i RDMA Endpoint preferences */
693 static bool irdmaep_calculate_ts = true;
694 static bool irdmaep_no_subdissector_on_error = true;
696 /* IBM i RDMA Endpoint message types */
697 #define IRDMA_EP_CONNREQ 0x01
698 #define IRDMA_EP_CONNACK 0x02
699 #define IRDMA_EP_CONNBUF 0x03
700 #define IRDMA_EP_RNEGREQ 0x04
701 #define IRDMA_EP_RNEGACK 0x05
702 #define IRDMA_EP_CLOSE 0x06
703 #define IRDMA_EP_RESET 0x09
704 #define IRDMA_EP_MOVEREQ 0x11
705 #define IRDMA_EP_MOVEACK 0x12
706 #define IRDMA_EP_MOVECMP 0x13
707 #define IRDMA_EP_DATA 0x21
708 #define IRDMA_EP_REUSEBUF 0x22
709 #define IRDMA_EP_RECVREQ 0x23
710 #define IRDMA_EP_RECVACK 0x24
711 #define IRDMA_EP_RECVNAK 0x25
713 /* IBM i RDMA Endpoint message offsets */
714 #define IRDMA_EP_TYPE 0 /* ( 1) Message type */
715 #define IRDMA_EP_LEN 1 /* ( 1) Message length */
716 #define IRDMA_EP_GRPID 2 /* (12) Group ID */
717 #define IRDMA_EP_GRPID_CTR 2 /* ( 1) Uniqueness counter */
718 #define IRDMA_EP_GRPID_TIME 3 /* ( 5) Bits 4-43 of TOD */
719 #define IRDMA_EP_GRPID_MAC 8 /* ( 6) MAC address */
720 #define IRDMA_EP_SPORT 14 /* ( 2) Source port */
721 #define IRDMA_EP_DPORT 16 /* ( 2) Destination port */
722 #define IRDMA_EP_LINKSEQ 18 /* ( 2) Link sequence number */
723 #define IRDMA_EP_MIN_LENGTH 20
725 #define IRDMA_EP_CONNECT_BUFSIZE 20 /* ( 2) Send buffer size (* 4KB) */
726 #define IRDMA_EP_CONNECT_USRBLKSIZE 22 /* ( 2) USER_RDMA receive block size (* 4KB) */
727 #define IRDMA_EP_CONNECT_MIN_LENGTH 24
729 #define IRDMA_EP_CLOSE_REASON 20 /* ( 4) Close reason */
730 #define IRDMA_EP_CLOSE_MIN_LENGTH 24
732 #define IRDMA_EP_BUFFER_RKEY 20 /* ( 4) x2 Receive buffer MKeys */
733 #define IRDMA_EP_BUFFER_RADDR 28 /* ( 8) x2 Receive buffer addresses */
734 #define IRDMA_EP_BUFFER_FLAGS 44 /* ( 4 bits) Flags */
735 #define IRDMA_EP_BUFFER_RBUFSIZE 44 /* (12 bits) Size of each receive buffer (* 4KB) */
736 #define IRDMA_EP_MOVELINK_SENDSEQ 46 /* ( 2) Last sent sequence number */
737 #define IRDMA_EP_MOVELINK_RBUFSEQ 48 /* ( 2) x2 Last received sequence number */
738 #define IRDMA_EP_MOVELINK_USNDSENT 52 /* ( 4) Number of bytes sent from current USER_RDMA */
739 #define IRDMA_EP_MOVELINK_USNDID 56 /* ( 2) Current USER_RDMA recv ID being sent */
740 #define IRDMA_EP_MOVELINKACK_URCVID 58 /* ( 2) Last USER_RDMA recv ID complete */
742 #define IRDMA_EP_MOVELINKCMP_URCVID 20 /* ( 2) Last USER_RDMA recv ID complete */
744 #define IRDMA_EP_DATA_SEQNUM 20 /* ( 2) Sequence number */
745 #define IRDMA_EP_DATA_BUFID 22 /* ( 2) Buffer index */
746 #define IRDMA_EP_DATA_OFFSET 24 /* ( 4) Buffer offset */
747 #define IRDMA_EP_DATA_DATALEN 28 /* ( 4) Data length */
748 #define IRDMA_EP_DATA_MSG_LEN 32
750 #define IRDMA_EP_REUSE_SEQNUM 20 /* ( 2) Sequence number */
751 #define IRDMA_EP_REUSE_BUFID 22 /* ( 2) Buffer index */
753 #define IRDMA_EP_USERRECV_ULENGTH 20 /* ( 4) Total user receive length */
754 #define IRDMA_EP_USERRECV_OFFSET 24 /* ( 4) Offset within full buffer */
755 #define IRDMA_EP_USERRECV_RLENGTH 28 /* ( 4) Buffer length */
756 #define IRDMA_EP_USERRECV_RECVID 32 /* ( 2) Receive identifier */
757 #define IRDMA_EP_USERRECV_RKEY 34 /* ( 4) Buffer MKey */
758 #define IRDMA_EP_USERRECV_RADDR 38 /* ( 8) Buffer address */
759 #define IRDMA_EP_USERRECV_MSG_LEN 46
761 #define IRDMA_EP_USERSEND_ULENGTH 20 /* ( 4) Total user send length */
762 #define IRDMA_EP_USERSEND_OFFSET 24 /* ( 4) Offset within full buffer */
763 #define IRDMA_EP_USERSEND_SLENGTH 28 /* ( 4) Length sent */
764 #define IRDMA_EP_USERSEND_RECVID 32 /* ( 2) Receive identifier */
765 #define IRDMA_EP_USERSEND_MSG_LEN 34
767 static const value_string irdmaep_type_str[] = {
768 {IRDMA_EP_CONNREQ, "CONNREQ"},
769 {IRDMA_EP_CONNACK, "CONNACK"},
770 {IRDMA_EP_CONNBUF, "CONNBUF"},
771 {IRDMA_EP_RNEGREQ, "RNEGREQ"},
772 {IRDMA_EP_RNEGACK, "RNEGACK"},
773 {IRDMA_EP_CLOSE, "CLOSE"},
774 {IRDMA_EP_RESET, "RESET"},
775 {IRDMA_EP_MOVEREQ, "MOVEREQ"},
776 {IRDMA_EP_MOVEACK, "MOVEACK"},
777 {IRDMA_EP_MOVECMP, "MOVECMP"},
778 {IRDMA_EP_DATA, "DATA"},
779 {IRDMA_EP_REUSEBUF, "REUSEBUF"},
780 {IRDMA_EP_RECVREQ, "RECVREQ"},
781 {IRDMA_EP_RECVACK, "RECVACK"},
782 {IRDMA_EP_RECVNAK, "RECVNAK"},
783 {0, NULL}};
785 static const value_string vals_free_inuse[] = {
786 {0, "In-use"},
787 {1, "Free"},
788 {0, NULL}};
790 /* Dissect RDMA Endpoint packets */
791 static int
792 dissect_irdmaep(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
794 proto_item *ti, *ti_seq, *ti_type;
795 proto_tree *ep_tree, *ts_tree;
796 proto_tree *grpid_tree;
797 address group_addr;
798 conversation_t *conv = NULL;
799 irdmaep_analysis_t *epd = NULL;
800 irdmaep_packet_analysis_t *eppd = NULL;
801 uint32_t linkseq;
802 nstime_t ts;
804 if (tvb_reported_length(tvb) < IRDMA_EP_MIN_LENGTH)
805 return 0;
807 /* Set the Protocol column */
808 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RDMA-EP");
810 col_clear(pinfo->cinfo, COL_INFO);
812 pinfo->srcport = tvb_get_ntohs(tvb, IRDMA_EP_SPORT);
813 pinfo->destport = tvb_get_ntohs(tvb, IRDMA_EP_DPORT);
814 pinfo->ptype = PT_TCP; /* Not really TCP, but nothing else better */
815 irdma_col_append_ports(pinfo->cinfo, COL_INFO,
816 pinfo->srcport, pinfo->destport);
818 set_address(&group_addr, AT_STRINGZ, 25,
819 tvb_bytes_to_str(wmem_packet_scope(), tvb, IRDMA_EP_GRPID, 12));
821 uint8_t msg_type = tvb_get_uint8(tvb, IRDMA_EP_TYPE);
822 uint8_t msg_length = tvb_get_uint8(tvb, IRDMA_EP_LEN);
823 const char *msg_type_str = val_to_str(msg_type, irdmaep_type_str,
824 "UNKNOWN (0x%02X)");
825 col_append_fstr(pinfo->cinfo, COL_INFO, " [%s]", msg_type_str);
827 /* Find or create conversation for this packet */
828 conv = find_conversation(pinfo->num, &group_addr, &group_addr,
829 CONVERSATION_NONE, pinfo->srcport, pinfo->destport, 0);
831 /* If first time through the packets and conversation exists but message
832 is a CONNREQ, check if we really should be starting a new conversation
833 instead */
834 if (!PINFO_FD_VISITED(pinfo)
835 && conv
836 && msg_type == IRDMA_EP_CONNREQ)
838 epd = (irdmaep_analysis_t *) conversation_get_proto_data(conv, proto_irdmaep);
839 if (epd && epd->closed)
840 conv = NULL;
843 /* If this is a new conversation, allocate conversation data */
844 if (!conv)
846 conv = conversation_new(pinfo->num, &group_addr, &group_addr,
847 CONVERSATION_NONE, pinfo->srcport, pinfo->destport, 0);
848 epd = init_irdmaep_conversation_data(pinfo);
849 conversation_add_proto_data(conv, proto_irdmaep, epd);
851 else
852 epd = (irdmaep_analysis_t *) conversation_get_proto_data(conv, proto_irdmaep);
854 DISSECTOR_ASSERT(epd != NULL);
856 if (pinfo->num > conv->last_frame)
857 conv->last_frame = pinfo->num;
859 epd->fwd_flow = &epd->flow1;
860 epd->rev_flow = &epd->flow2;
861 if (pinfo->srcport < pinfo->destport)
863 epd->fwd_flow = &epd->flow2;
864 epd->rev_flow = &epd->flow1;
867 /* Create display subtree for the Endpoint message */
868 ti = proto_tree_add_item(tree, proto_irdmaep, tvb, 0, msg_length, ENC_NA);
869 ep_tree = proto_item_add_subtree(ti, ett_irdmaep);
871 ti_type = proto_tree_add_item(ep_tree, hf_irdmaep_type, tvb,
872 IRDMA_EP_TYPE, 1, ENC_NA);
873 proto_tree_add_item(ep_tree, hf_irdmaep_len, tvb,
874 IRDMA_EP_LEN, 1, ENC_NA);
876 ti = proto_tree_add_item(ep_tree, hf_irdmaep_grpid, tvb,
877 IRDMA_EP_GRPID, 12, ENC_NA);
878 grpid_tree = proto_item_add_subtree(ti, ett_irdmaep_grpid);
880 proto_tree_add_item(grpid_tree, hf_irdmaep_grpid_ctr, tvb,
881 IRDMA_EP_GRPID_CTR, 1, ENC_NA);
882 proto_tree_add_item(grpid_tree, hf_irdmaep_grpid_time, tvb,
883 IRDMA_EP_GRPID_TIME, 5, ENC_BIG_ENDIAN);
884 proto_tree_add_item(grpid_tree, hf_irdmaep_grpid_hwaddr, tvb,
885 IRDMA_EP_GRPID_MAC, 6, ENC_NA);
888 proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_srcport, tvb,
889 IRDMA_EP_SPORT, 2, ENC_BIG_ENDIAN,
890 &pinfo->srcport);
891 ti = proto_tree_add_item(ep_tree, hf_irdmaep_port, tvb,
892 IRDMA_EP_SPORT, 2, ENC_BIG_ENDIAN);
893 PROTO_ITEM_SET_HIDDEN(ti);
895 proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_dstport, tvb,
896 IRDMA_EP_DPORT, 2, ENC_BIG_ENDIAN,
897 &pinfo->destport);
898 ti = proto_tree_add_item(ep_tree, hf_irdmaep_port, tvb,
899 IRDMA_EP_DPORT, 2, ENC_BIG_ENDIAN);
900 PROTO_ITEM_SET_HIDDEN(ti);
901 ti = proto_tree_add_uint(ep_tree, hf_irdmaep_stream, tvb, 0, 0,
902 epd->stream);
903 PROTO_ITEM_SET_GENERATED(ti);
904 ti_seq = proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_linkseq, tvb,
905 IRDMA_EP_LINKSEQ, 2, ENC_BIG_ENDIAN,
906 &linkseq);
908 /* Record conversation info that should only be done on first pass
909 (when packets are seen in order) */
910 if (!PINFO_FD_VISITED(pinfo))
912 if (irdmaep_calculate_ts)
914 if (!eppd)
915 eppd = (irdmaep_packet_analysis_t *) get_or_add_eppd(pinfo);
916 nstime_delta(&eppd->delta_time, &pinfo->abs_ts, &epd->ts_prev);
918 nstime_copy(&epd->ts_prev, &pinfo->abs_ts);
921 /* If this is a CLOSE or RESET request, remember so that if we see a
922 later CONNREQ with the same ports, we'll create a new conversation. */
923 if (msg_type == IRDMA_EP_CLOSE
924 || msg_type == IRDMA_EP_RESET)
925 epd->closed = 1;
927 /* If link seq not yet known, save current link seq */
928 if (epd->link == 0xFFFFFFFF)
929 epd->link = linkseq;
931 /* Update current link seq if it has increased */
932 if (seq16_gt(linkseq, epd->link))
934 epd->link = linkseq;
935 if (!eppd)
936 eppd = (irdmaep_packet_analysis_t *) get_or_add_eppd(pinfo);
937 eppd->linkswt = 1;
940 /* If packet is from prior link, set stale flag */
941 if (seq16_lt(linkseq, epd->link))
943 if (!eppd)
944 eppd = (irdmaep_packet_analysis_t *) get_or_add_eppd(pinfo);
945 eppd->seq_stale = 1;
948 else
949 eppd = (irdmaep_packet_analysis_t *) get_eppd(pinfo);
951 if (eppd)
953 if (eppd->linkswt)
954 expert_add_info(pinfo, ti_seq, &ei_irdmaep_connection_lswt);
956 if (eppd->seq_stale)
957 expert_add_info(pinfo, ti_seq, &ei_irdmaep_analysis_stale);
960 switch (msg_type)
962 case IRDMA_EP_DATA:
963 dissect_data_msg(tvb, pinfo, tree, epd, ep_tree);
964 break;
966 case IRDMA_EP_REUSEBUF:
967 dissect_reuse_msg(tvb, pinfo, epd, ep_tree);
968 break;
970 case IRDMA_EP_RECVREQ:
971 dissect_user_recv_msg(tvb, pinfo, tree, epd, ep_tree);
972 break;
974 case IRDMA_EP_RECVACK:
975 case IRDMA_EP_RECVNAK:
976 dissect_user_send_msg(tvb, pinfo, tree, epd, ep_tree);
977 break;
979 case IRDMA_EP_CONNREQ:
980 expert_add_info_format(pinfo, ti_type, &ei_irdmaep_connection_req,
981 "Connection request (CONNREQ): server port %u",
982 pinfo->destport);
983 dissect_connect_msg(tvb, pinfo, epd, ep_tree);
984 break;
986 case IRDMA_EP_CONNACK:
987 expert_add_info_format(pinfo, ti_type, &ei_irdmaep_connection_ack,
988 "Connection acknowledgement (CONNACK): server port %u",
989 pinfo->srcport);
990 dissect_connect_msg(tvb, pinfo, epd, ep_tree);
991 break;
993 case IRDMA_EP_RNEGREQ:
994 dissect_connect_msg(tvb, pinfo, epd, ep_tree);
995 break;
997 case IRDMA_EP_CLOSE:
998 dissect_close_msg(tvb, pinfo, epd, ep_tree);
999 break;
1001 case IRDMA_EP_CONNBUF:
1002 case IRDMA_EP_RNEGACK:
1003 dissect_buffer_msg(tvb, pinfo, epd, ep_tree);
1004 break;
1006 case IRDMA_EP_MOVEREQ:
1007 if (!PINFO_FD_VISITED(pinfo))
1009 /* Save time of MOVEREQ so we can report link switch delay */
1010 epd->movereq_time = pinfo->abs_ts;
1013 dissect_move_link_msg(tvb, pinfo, epd, ep_tree);
1014 break;
1016 case IRDMA_EP_MOVEACK:
1017 dissect_move_link_ack_msg(tvb, pinfo, epd, ep_tree);
1018 break;
1020 case IRDMA_EP_MOVECMP:
1021 dissect_move_link_cmp_msg(tvb, pinfo, epd, ep_tree);
1022 break;
1025 ts_tree = proto_tree_add_subtree(ep_tree, tvb, 0, 0, ett_irdmaep_timestamps,
1026 &ti, "Timestamps");
1027 PROTO_ITEM_SET_GENERATED(ti);
1028 nstime_delta(&ts, &pinfo->abs_ts, &epd->ts_first);
1029 ti = proto_tree_add_time(ts_tree, hf_irdmaep_ts_relative, tvb, 0, 0, &ts);
1030 PROTO_ITEM_SET_GENERATED(ti);
1031 if (eppd && !nstime_is_unset(&eppd->delta_time))
1033 ti = proto_tree_add_time(ts_tree, hf_irdmaep_ts_delta, tvb, 0, 0,
1034 &eppd->delta_time);
1035 PROTO_ITEM_SET_GENERATED(ti);
1038 return tvb_captured_length(tvb);
1041 static void
1042 dissect_data_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1043 irdmaep_analysis_t *epd, proto_tree *ep_tree)
1045 proto_item *ti_seq;
1046 irdmaep_packet_analysis_t *eppd = NULL;
1047 irdmaep_pdata_t pdata = {IRDMAEP_DATA_TYPE};
1048 uint32_t bufid, seqnum, offset, datalen;
1050 ti_seq = proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_seqnum, tvb,
1051 IRDMA_EP_DATA_SEQNUM, 2, ENC_BIG_ENDIAN,
1052 &seqnum);
1053 proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_bufid, tvb,
1054 IRDMA_EP_DATA_BUFID, 2, ENC_BIG_ENDIAN,
1055 &bufid);
1056 proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_offset, tvb,
1057 IRDMA_EP_DATA_OFFSET, 4, ENC_BIG_ENDIAN,
1058 &offset);
1059 proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_datalen, tvb,
1060 IRDMA_EP_DATA_DATALEN, 4, ENC_BIG_ENDIAN,
1061 &datalen);
1063 /* Update flow analysis only on first (in-order) pass */
1064 if (!PINFO_FD_VISITED(pinfo)
1065 && bufid < IRDMAEP_MAX_DATA_BUFID)
1067 /* Only validate sequence number if we know previous seq# */
1068 if (epd->fwd_flow->data_seq_valid)
1070 uint16_t expected = epd->fwd_flow->data_seq + 1;
1071 if (seqnum != expected)
1073 /* Unexpected sequence number -- update packet data */
1074 eppd = (irdmaep_packet_analysis_t *) get_or_add_eppd(pinfo);
1075 if (seq16_lt(seqnum, expected))
1076 eppd->retransmission = 1;
1077 else
1078 eppd->out_of_order = 1; /* Should never occur! */
1082 epd->fwd_flow->data_seq_valid = 1;
1083 epd->fwd_flow->data_seq = seqnum;
1085 /* Update remote receive buffer status */
1086 /* First, if this gives info on receive buffer we didn't yet know about,
1087 bump buffer count but set those buffers to indeterminate state */
1088 for (; epd->fwd_flow->recv_buffer_count <= bufid; ++epd->fwd_flow->recv_buffer_count)
1089 epd->fwd_flow->recv_buffer[epd->fwd_flow->recv_buffer_count].indeterminate = 1;
1091 epd->fwd_flow->recv_mrb = bufid;
1092 epd->fwd_flow->recv_buffer[bufid].seq_num = seqnum;
1093 epd->fwd_flow->recv_buffer[bufid].offset = (offset + datalen + 0xF) & ~0xF;
1094 epd->fwd_flow->recv_buffer[bufid].indeterminate = 0;
1096 /* Adjust discovered size of buffer (in case initial buffer info msg
1097 wasn't captured for this flow) */
1098 if (epd->fwd_flow->recv_buffer[bufid].offset > epd->fwd_flow->recv_min_size)
1099 epd->fwd_flow->recv_min_size = (epd->fwd_flow->recv_buffer[bufid].offset + 0xFFF) & ~0xFFF;
1101 if (!eppd)
1102 eppd = (irdmaep_packet_analysis_t *) get_or_add_eppd(pinfo);
1103 analyze_irdmaep_rbuffer(epd->fwd_flow, eppd);
1105 else
1106 eppd = (irdmaep_packet_analysis_t *) get_eppd(pinfo);
1108 if (eppd)
1110 if (eppd->retransmission)
1112 col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, "[Retransmission] ");
1113 expert_add_info(pinfo, ti_seq, &ei_irdmaep_analysis_dup);
1116 if (eppd->out_of_order)
1118 col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, "[Out-of-order] ");
1119 expert_add_info(pinfo, ti_seq, &ei_irdmaep_analysis_oos);
1122 irdmaep_add_rbuf_tree(tvb, pinfo, ep_tree, eppd);
1125 dissect_irdmaep_data(tvb_new_subset_remaining(tvb, IRDMA_EP_DATA_MSG_LEN),
1126 pinfo, tree, &pdata);
1129 static void
1130 irdmaep_add_rbuf_tree(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1131 irdmaep_packet_analysis_t *eppd)
1133 proto_item *ti;
1134 proto_tree *rcvbuf_tree;
1136 ti = proto_tree_add_uint(tree, hf_irdmaep_rbufavail, tvb, 0, 0,
1137 eppd->rbuf_available);
1138 if (eppd->rbuf_estimated)
1139 proto_item_append_text(ti, " (min)");
1140 PROTO_ITEM_SET_GENERATED(ti);
1142 rcvbuf_tree = proto_item_add_subtree(ti, ett_irdmaep_rcvbuf_analyze);
1144 ti = proto_tree_add_uint(rcvbuf_tree, hf_irdmaep_rbufactive, tvb, 0, 0,
1145 eppd->rbuf_cur);
1146 if (eppd->rbuf_estimated)
1147 proto_item_append_text(ti, " (min)");
1148 PROTO_ITEM_SET_GENERATED(ti);
1150 ti = proto_tree_add_uint(rcvbuf_tree, hf_irdmaep_rbufmax, tvb, 0, 0,
1151 eppd->rbuf_max);
1152 if (eppd->rbuf_estimated)
1153 proto_item_append_text(ti, " (min)");
1154 PROTO_ITEM_SET_GENERATED(ti);
1157 static void
1158 dissect_reuse_msg(tvbuff_t *tvb, packet_info *pinfo,
1159 irdmaep_analysis_t *epd, proto_tree *ep_tree)
1161 irdmaep_packet_analysis_t *eppd = NULL;
1162 uint32_t bufid, seqnum;
1164 proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_seqnum, tvb,
1165 IRDMA_EP_REUSE_SEQNUM, 2, ENC_BIG_ENDIAN,
1166 &seqnum);
1167 proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_bufid, tvb,
1168 IRDMA_EP_REUSE_BUFID, 2, ENC_BIG_ENDIAN,
1169 &bufid);
1171 /* Update receive buffer analysis only on first (in-order) pass */
1172 if (!PINFO_FD_VISITED(pinfo)
1173 && bufid < IRDMAEP_MAX_DATA_BUFID)
1175 /* Reuse msg reflects local receive buffer status, so update lcl_rbuf */
1177 /* First, if this gives info on receive buffer we didn't yet know about,
1178 bump buffer count but set those buffers to indeterminate state */
1179 for (; epd->rev_flow->recv_buffer_count <= bufid; ++epd->rev_flow->recv_buffer_count)
1180 epd->rev_flow->recv_buffer[epd->rev_flow->recv_buffer_count].indeterminate = 1;
1182 if (epd->rev_flow->recv_buffer_count > 1
1183 || epd->rev_flow->recv_buffer[bufid].seq_num == seqnum
1184 || epd->rev_flow->recv_buffer[bufid].indeterminate)
1186 epd->rev_flow->recv_buffer[bufid].offset = 0;
1187 epd->rev_flow->recv_buffer[bufid].indeterminate = 0;
1190 eppd = (irdmaep_packet_analysis_t *) add_eppd(pinfo);
1191 analyze_irdmaep_rbuffer(epd->rev_flow, eppd);
1193 else
1194 eppd = (irdmaep_packet_analysis_t *) get_eppd(pinfo);
1196 if (eppd)
1197 irdmaep_add_rbuf_tree(tvb, pinfo, ep_tree, eppd);
1200 static void
1201 dissect_user_recv_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1202 irdmaep_analysis_t *epd _U_, proto_tree *ep_tree)
1204 proto_item *ti;
1205 proto_tree *rbuf_tree;
1207 irdmaep_pdata_t pdata = {IRDMAEP_USERRDMA_TYPE, 0};
1209 proto_tree_add_item(ep_tree, hf_irdmaep_ulength, tvb,
1210 IRDMA_EP_USERRECV_ULENGTH, 4, ENC_BIG_ENDIAN);
1211 proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_offset, tvb,
1212 IRDMA_EP_USERRECV_OFFSET, 4, ENC_BIG_ENDIAN,
1213 &pdata.userrdma_offset);
1214 proto_tree_add_item(ep_tree, hf_irdmaep_blength, tvb,
1215 IRDMA_EP_USERRECV_RLENGTH, 4, ENC_BIG_ENDIAN);
1216 proto_tree_add_item(ep_tree, hf_irdmaep_recvid, tvb,
1217 IRDMA_EP_USERRECV_RECVID, 2, ENC_BIG_ENDIAN);
1218 ti = proto_tree_add_item(ep_tree, hf_irdmaep_rbuf, tvb,
1219 IRDMA_EP_USERRECV_RKEY, 12, ENC_NA);
1220 rbuf_tree = proto_item_add_subtree(ti, ett_irdmaep_rbuf);
1221 proto_tree_add_item(rbuf_tree, hf_irdmaep_rkey, tvb,
1222 IRDMA_EP_USERRECV_RKEY, 4, ENC_BIG_ENDIAN);
1223 proto_tree_add_item(rbuf_tree, hf_irdmaep_raddr, tvb,
1224 IRDMA_EP_USERRECV_RADDR, 8, ENC_BIG_ENDIAN);
1226 dissect_irdmaep_data(tvb_new_subset_remaining(tvb, IRDMA_EP_USERRECV_MSG_LEN),
1227 pinfo, tree, &pdata);
1230 static void
1231 dissect_user_send_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1232 irdmaep_analysis_t *epd, proto_tree *ep_tree)
1234 proto_item *ti_ofs;
1235 irdmaep_packet_analysis_t *eppd = NULL;
1236 uint32_t recvid, offset, block_length, total_length;
1238 proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_ulength, tvb,
1239 IRDMA_EP_USERSEND_ULENGTH, 4, ENC_BIG_ENDIAN,
1240 &total_length);
1241 ti_ofs = proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_offset, tvb,
1242 IRDMA_EP_USERSEND_OFFSET, 4, ENC_BIG_ENDIAN,
1243 &offset);
1244 proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_blength, tvb,
1245 IRDMA_EP_USERSEND_SLENGTH, 4, ENC_BIG_ENDIAN,
1246 &block_length);
1247 proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_recvid, tvb,
1248 IRDMA_EP_USERSEND_RECVID, 2, ENC_BIG_ENDIAN,
1249 &recvid);
1251 /* Update flow analysis only on first (in-order) pass */
1252 if (!PINFO_FD_VISITED(pinfo))
1254 if (epd->fwd_flow->recvack_valid)
1256 uint16_t nextid = epd->fwd_flow->recvack_id + 1;
1258 if ((recvid == epd->fwd_flow->recvack_id && offset == epd->fwd_flow->recvack_offset)
1259 || (recvid == nextid && offset == 0))
1261 /* Expected ID, offset */
1263 else
1265 /* Unexpected offset */
1266 eppd = (irdmaep_packet_analysis_t *) get_or_add_eppd(pinfo);
1267 if (recvid == epd->fwd_flow->recvack_id
1268 && offset < epd->fwd_flow->recvack_offset)
1269 eppd->retransmission = 1;
1270 else
1271 eppd->out_of_order = 1; /* Should never occur! */
1275 epd->fwd_flow->recvack_valid = 1;
1276 epd->fwd_flow->recvack_id = recvid;
1277 epd->fwd_flow->recvack_offset = offset + block_length;
1279 else
1280 eppd = (irdmaep_packet_analysis_t *) get_eppd(pinfo);
1282 if (eppd)
1284 if (eppd->retransmission)
1286 col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, "[Retransmission] ");
1287 expert_add_info(pinfo, ti_ofs, &ei_irdmaep_analysis_dup);
1290 if (eppd->out_of_order)
1292 col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, "[Out-of-order] ");
1293 expert_add_info(pinfo, ti_ofs, &ei_irdmaep_analysis_oos);
1297 irdmaep_pdata_t pdata = {IRDMAEP_USERRDMA_TYPE, offset};
1298 dissect_irdmaep_data(tvb_new_subset_remaining(tvb, IRDMA_EP_USERSEND_MSG_LEN),
1299 pinfo, tree, &pdata);
1302 static void
1303 dissect_connect_msg(tvbuff_t *tvb, packet_info *pinfo _U_,
1304 irdmaep_analysis_t *epd _U_, proto_tree *ep_tree)
1306 proto_item *ti;
1307 uint32_t bufsize;
1309 ti = proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_sndbufsize, tvb,
1310 IRDMA_EP_CONNECT_BUFSIZE, 2,
1311 ENC_BIG_ENDIAN, &bufsize);
1312 proto_item_append_text(ti, " (%u KB)", bufsize * 4);
1314 uint8_t msg_type = tvb_get_uint8(tvb, IRDMA_EP_TYPE);
1315 if (msg_type == IRDMA_EP_CONNREQ
1316 || msg_type == IRDMA_EP_CONNACK)
1318 ti = proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_usrblksize, tvb,
1319 IRDMA_EP_CONNECT_USRBLKSIZE, 2,
1320 ENC_BIG_ENDIAN, &bufsize);
1321 proto_item_append_text(ti, " (%u KB)", bufsize * 4);
1325 static void
1326 dissect_close_msg(tvbuff_t *tvb, packet_info *pinfo _U_,
1327 irdmaep_analysis_t *epd _U_, proto_tree *ep_tree)
1329 proto_tree_add_item(ep_tree, hf_irdmaep_reason, tvb,
1330 IRDMA_EP_CLOSE_REASON, 4, ENC_BIG_ENDIAN);
1333 static void
1334 dissect_buffer_msg_mkeyaddr(tvbuff_t *tvb, packet_info *pinfo _U_,
1335 irdmaep_analysis_t *epd _U_, proto_tree *ep_tree)
1337 proto_item *ti;
1338 proto_tree *rbuf_tree;
1340 ti = proto_tree_add_item(ep_tree, hf_irdmaep_rbuf, tvb,
1341 IRDMA_EP_BUFFER_RKEY, 24, ENC_NA);
1342 rbuf_tree = proto_item_add_subtree(ti, ett_irdmaep_rbuf);
1343 proto_tree_add_item(rbuf_tree, hf_irdmaep_rkey, tvb,
1344 IRDMA_EP_BUFFER_RKEY, 4, ENC_BIG_ENDIAN);
1345 proto_tree_add_item(rbuf_tree, hf_irdmaep_raddr, tvb,
1346 IRDMA_EP_BUFFER_RADDR, 8, ENC_BIG_ENDIAN);
1347 proto_tree_add_item(rbuf_tree, hf_irdmaep_rkey, tvb,
1348 IRDMA_EP_BUFFER_RKEY + 4, 4, ENC_BIG_ENDIAN);
1349 proto_tree_add_item(rbuf_tree, hf_irdmaep_raddr, tvb,
1350 IRDMA_EP_BUFFER_RADDR + 8, 8, ENC_BIG_ENDIAN);
1353 static void
1354 dissect_buffer_msg(tvbuff_t *tvb, packet_info *pinfo,
1355 irdmaep_analysis_t *epd, proto_tree *ep_tree)
1357 uint32_t rbufsize;
1359 dissect_buffer_msg_mkeyaddr(tvb, pinfo, epd, ep_tree);
1361 proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_rcvbufsize, tvb,
1362 IRDMA_EP_BUFFER_RBUFSIZE, 2, ENC_BIG_ENDIAN,
1363 &rbufsize);
1364 rbufsize *= 4096;
1366 /* Update receive buffer analysis only on first (in-order) pass */
1367 if (!PINFO_FD_VISITED(pinfo))
1369 if (tvb_get_uint32(tvb, IRDMA_EP_BUFFER_RKEY, ENC_BIG_ENDIAN))
1371 memset(&epd->rev_flow->recv_buffer[0], 0,
1372 sizeof epd->rev_flow->recv_buffer[0]);
1373 epd->rev_flow->recv_buffer[0].size = rbufsize;
1374 if (epd->rev_flow->recv_buffer_count < 1)
1375 epd->rev_flow->recv_buffer_count = 1;
1378 if (tvb_get_uint32(tvb, IRDMA_EP_BUFFER_RKEY + 4, ENC_BIG_ENDIAN))
1380 memset(&epd->rev_flow->recv_buffer[1], 0,
1381 sizeof epd->rev_flow->recv_buffer[1]);
1382 epd->rev_flow->recv_buffer[1].size = rbufsize;
1383 if (epd->rev_flow->recv_buffer_count < 2)
1384 epd->rev_flow->recv_buffer_count = 2;
1389 static void
1390 dissect_move_link_msg(tvbuff_t *tvb, packet_info *pinfo,
1391 irdmaep_analysis_t *epd, proto_tree *ep_tree)
1393 dissect_buffer_msg_mkeyaddr(tvb, pinfo, epd, ep_tree);
1395 proto_item *ti;
1396 proto_tree *flags_tree;
1397 uint32_t rbufsize;
1399 ti = proto_tree_add_item(ep_tree, hf_irdmaep_flags, tvb,
1400 IRDMA_EP_BUFFER_FLAGS, 1, ENC_NA);
1401 flags_tree = proto_item_add_subtree(ti, ett_irdmaep_bufflags);
1402 proto_tree_add_item(flags_tree, hf_irdmaep_flag_buf0_free, tvb,
1403 IRDMA_EP_BUFFER_FLAGS, 1, ENC_NA);
1404 proto_tree_add_item(flags_tree, hf_irdmaep_flag_buf1_free, tvb,
1405 IRDMA_EP_BUFFER_FLAGS, 1, ENC_NA);
1406 proto_tree_add_item_ret_uint(ep_tree, hf_irdmaep_rcvbufsize, tvb,
1407 IRDMA_EP_BUFFER_RBUFSIZE, 2, ENC_BIG_ENDIAN,
1408 &rbufsize);
1410 proto_tree_add_item(ep_tree, hf_irdmaep_sendseq, tvb,
1411 IRDMA_EP_MOVELINK_SENDSEQ, 2, ENC_BIG_ENDIAN);
1412 proto_tree_add_item(ep_tree, hf_irdmaep_recvseq0, tvb,
1413 IRDMA_EP_MOVELINK_RBUFSEQ, 2, ENC_BIG_ENDIAN);
1414 proto_tree_add_item(ep_tree, hf_irdmaep_recvseq1, tvb,
1415 IRDMA_EP_MOVELINK_RBUFSEQ + 2, 2, ENC_BIG_ENDIAN);
1416 proto_tree_add_item(ep_tree, hf_irdmaep_usndsent, tvb,
1417 IRDMA_EP_MOVELINK_USNDSENT, 4, ENC_BIG_ENDIAN);
1418 proto_tree_add_item(ep_tree, hf_irdmaep_usndid, tvb,
1419 IRDMA_EP_MOVELINK_USNDID, 2, ENC_BIG_ENDIAN);
1421 /* Update receive buffer analysis only on first (in-order) pass */
1422 if (!PINFO_FD_VISITED(pinfo))
1424 if (tvb_get_uint32(tvb, IRDMA_EP_BUFFER_RKEY, ENC_BIG_ENDIAN)
1425 && (rbufsize & 0x8000))
1427 memset(&epd->rev_flow->recv_buffer[0], 0,
1428 sizeof epd->rev_flow->recv_buffer[0]);
1429 epd->rev_flow->recv_buffer[0].size = (rbufsize & 0xFFF) * 4096;
1432 if (tvb_get_uint32(tvb, IRDMA_EP_BUFFER_RKEY + 4, ENC_BIG_ENDIAN)
1433 && (rbufsize & 0x4000))
1435 memset(&epd->rev_flow->recv_buffer[1], 0,
1436 sizeof epd->rev_flow->recv_buffer[1]);
1437 epd->rev_flow->recv_buffer[1].size = (rbufsize & 0xFFF) * 4096;
1442 static void
1443 dissect_move_link_ack_msg(tvbuff_t *tvb, packet_info *pinfo,
1444 irdmaep_analysis_t *epd, proto_tree *ep_tree)
1446 proto_item *ti;
1447 irdmaep_packet_analysis_t *eppd = NULL;
1449 if (!PINFO_FD_VISITED(pinfo))
1451 eppd = (irdmaep_packet_analysis_t *) get_or_add_eppd(pinfo);
1453 nstime_delta(&eppd->movelink_time, &pinfo->abs_ts, &epd->movereq_time);
1455 else
1456 eppd = (irdmaep_packet_analysis_t *) get_eppd(pinfo);
1458 dissect_move_link_msg(tvb, pinfo, epd, ep_tree);
1460 proto_tree_add_item(ep_tree, hf_irdmaep_urcvid, tvb,
1461 IRDMA_EP_MOVELINKACK_URCVID, 2, ENC_BIG_ENDIAN);
1463 ti = proto_tree_add_time(ep_tree, hf_irdmaep_move1, tvb,
1464 IRDMA_EP_TYPE, 0, &eppd->movelink_time);
1465 PROTO_ITEM_SET_GENERATED(ti);
1468 static void
1469 dissect_move_link_cmp_msg(tvbuff_t *tvb, packet_info *pinfo,
1470 irdmaep_analysis_t *epd, proto_tree *ep_tree)
1472 proto_item *ti;
1473 irdmaep_packet_analysis_t *eppd = NULL;
1475 if (!PINFO_FD_VISITED(pinfo))
1477 eppd = (irdmaep_packet_analysis_t *) get_or_add_eppd(pinfo);
1479 nstime_delta(&eppd->movelink_time, &pinfo->abs_ts, &epd->movereq_time);
1481 else
1482 eppd = (irdmaep_packet_analysis_t *) get_eppd(pinfo);
1484 proto_tree_add_item(ep_tree, hf_irdmaep_urcvid, tvb,
1485 IRDMA_EP_MOVELINKCMP_URCVID, 2, ENC_BIG_ENDIAN);
1487 ti = proto_tree_add_time(ep_tree, hf_irdmaep_move2, tvb,
1488 IRDMA_EP_TYPE, 0, &eppd->movelink_time);
1489 PROTO_ITEM_SET_GENERATED(ti);
1492 static void
1493 dissect_irdmaep_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1494 irdmaep_pdata_t *pdata)
1496 irdmaep_packet_analysis_t *eppd = NULL;
1498 /* Should we try to call subdissector based on port? */
1499 if (!irdmaep_no_subdissector_on_error
1500 || !(eppd = (irdmaep_packet_analysis_t *) get_eppd(pinfo))
1501 || !eppd->retransmission)
1503 uint32_t low_port, high_port;
1505 if (pinfo->srcport < pinfo->destport)
1507 low_port = pinfo->srcport;
1508 high_port = pinfo->destport;
1510 else
1512 low_port = pinfo->destport;
1513 high_port = pinfo->srcport;
1516 if (dissector_try_uint_with_data(irdmaep_dissector_table, low_port,
1517 tvb, pinfo, tree, true, pdata))
1518 return;
1520 if (dissector_try_uint_with_data(irdmaep_dissector_table, high_port,
1521 tvb, pinfo, tree, true, pdata))
1522 return;
1525 /* If no subdissector (or error and skipped calling), just dissect as data */
1526 call_data_dissector(tvb, pinfo, tree);
1529 static irdmaep_analysis_t *
1530 init_irdmaep_conversation_data(packet_info *pinfo)
1532 irdmaep_analysis_t *epd
1533 = wmem_new0(wmem_file_scope(), irdmaep_analysis_t);
1535 epd->stream = irdmaep_stream_count++;
1536 epd->link = -1;
1538 nstime_copy(&epd->ts_first, &pinfo->abs_ts);
1539 nstime_copy(&epd->ts_prev, &pinfo->abs_ts);
1541 return epd;
1544 static void *
1545 get_eppd(packet_info *pinfo)
1547 return p_get_proto_data(wmem_file_scope(), pinfo, proto_irdmaep,
1548 pinfo->curr_layer_num);
1551 static void *
1552 add_eppd(packet_info *pinfo)
1554 irdmaep_packet_analysis_t *eppd
1555 = wmem_new0(wmem_file_scope(), irdmaep_packet_analysis_t);
1556 p_add_proto_data(wmem_file_scope(), pinfo, proto_irdmaep,
1557 pinfo->curr_layer_num, eppd);
1559 nstime_set_unset(&eppd->delta_time);
1560 return eppd;
1563 static void *
1564 get_or_add_eppd(packet_info *pinfo)
1566 irdmaep_packet_analysis_t *eppd = (irdmaep_packet_analysis_t *) get_eppd(pinfo);
1567 if (!eppd)
1568 eppd = (irdmaep_packet_analysis_t *) add_eppd(pinfo);
1570 return eppd;
1573 static void
1574 analyze_irdmaep_rbuffer(irdmaep_flow_t *flow,
1575 irdmaep_packet_analysis_t *eppd)
1577 uint32_t bufid = flow->recv_mrb;
1579 /* Start by getting available space in the current receive
1580 buffer */
1581 if (flow->recv_buffer[bufid].size)
1582 eppd->rbuf_available
1583 = eppd->rbuf_cur
1584 = eppd->rbuf_max
1585 = flow->recv_buffer[bufid].size
1586 - flow->recv_buffer[bufid].offset;
1587 else
1589 eppd->rbuf_available
1590 = eppd->rbuf_cur
1591 = eppd->rbuf_max
1592 = flow->recv_min_size
1593 - flow->recv_buffer[bufid].offset;
1594 eppd->rbuf_estimated = 1;
1597 /* If there's a second receive buffer and it's empty, include
1598 it in receive buffer analysis */
1599 if (++bufid == IRDMAEP_MAX_DATA_BUFID)
1600 bufid = 0;
1601 if (flow->recv_buffer_count > 1
1602 && !flow->recv_buffer[bufid].indeterminate
1603 && flow->recv_buffer[bufid].offset == 0)
1605 uint32_t size = flow->recv_buffer[bufid].size
1606 ? flow->recv_buffer[bufid].size
1607 : flow->recv_min_size;
1608 eppd->rbuf_available += size;
1609 if (size > eppd->rbuf_max)
1610 eppd->rbuf_max = size;
1614 /*********************************************************************/
1615 /*********************************************************************/
1616 /* Dissector registration functions */
1617 /*********************************************************************/
1618 /*********************************************************************/
1620 /* Register the protocol with Wireshark */
1621 void
1622 proto_register_irdma(void)
1624 module_t *irdmaep_module;
1625 expert_module_t *expert_irdmaep;
1627 /*****************************************************************/
1628 /* RDMA pseudo-header field definitions */
1629 /*****************************************************************/
1630 static hf_register_info hf[] = {
1631 { &hf_irdma_hwdst,
1632 { "Destination", "irdma.dst",
1633 FT_ETHER, BASE_NONE, NULL, 0x0,
1634 "Destination Hardware Address", HFILL }},
1635 { &hf_irdma_hwsrc,
1636 { "Source", "irdma.src",
1637 FT_ETHER, BASE_NONE, NULL, 0x0,
1638 "Source Hardware Address", HFILL }},
1639 { &hf_irdma_qpindex,
1640 { "QP#", "irdma.qpidx",
1641 FT_UINT16, BASE_DEC, NULL, 0x0,
1642 "QP Index", HFILL}},
1643 { &hf_irdma_ip6src,
1644 { "Source IP", "irdma.ipv6.src",
1645 FT_IPv6, BASE_NONE, NULL, 0x0,
1646 "Source IP Address", HFILL }},
1647 { &hf_irdma_ip6dst,
1648 { "Destination IP", "irdma.ipv6.dst",
1649 FT_IPv6, BASE_NONE, NULL, 0x0,
1650 "Destination IP Address", HFILL }},
1651 { &hf_irdma_ip4src,
1652 { "Source IP", "irdma.ipv4.src",
1653 FT_IPv4, BASE_NONE, NULL, 0x0,
1654 "Source IP Address", HFILL }},
1655 { &hf_irdma_ip4dst,
1656 { "Destination IP", "irdma.ipv4.dst",
1657 FT_IPv4, BASE_NONE, NULL, 0x0,
1658 "Destination IP Address", HFILL }},
1659 { &hf_irdma_hwaddr,
1660 { "Address", "irdma.addr",
1661 FT_ETHER, BASE_NONE, NULL, 0x0,
1662 "Source or Destination Hardware Address", HFILL}},
1663 { &hf_irdma_ip6addr,
1664 { "IP Address", "irdma.ipv6.addr",
1665 FT_IPv6, BASE_NONE, NULL, 0x0,
1666 "Source or Destination IPv6 Address", HFILL}},
1667 { &hf_irdma_ip4addr,
1668 { "IP Address", "irdma.ipv4.addr",
1669 FT_IPv4, BASE_NONE, NULL, 0x0,
1670 "Source or Destination IPv4 Address", HFILL}}
1673 /*****************************************************************/
1674 /* RDMA QP field definitions */
1675 /*****************************************************************/
1676 static hf_register_info hfqp[] = {
1677 { &hf_irdmaqp_type,
1678 { "Type", "irdma.qp.type",
1679 FT_UINT16, BASE_HEX, VALS(irdmaqp_type_str), 0x0,
1680 "RDMA QP Message Type", HFILL }},
1681 { &hf_irdmaqp_id,
1682 { "Identifier", "irdma.qp.echo.id",
1683 FT_UINT16, BASE_DEC, NULL, 0x0,
1684 "RDMA QP Echo Identifier", HFILL }}
1687 /*****************************************************************/
1688 /* RDMA Link field definitions */
1689 /*****************************************************************/
1690 static hf_register_info hflink[] = {
1691 { &hf_irdmalink_type,
1692 { "Type", "irdma.link.type",
1693 FT_UINT16, BASE_HEX, VALS(irdmalink_type_str), 0x0,
1694 "RDMA Link Message Type", HFILL }},
1695 { &hf_irdmalink_groups,
1696 { "Groups", "irdma.link.status.groups",
1697 FT_UINT16, BASE_DEC, NULL, 0x0,
1698 "RDMA Link Status Active Group Count", HFILL }}
1701 /*****************************************************************/
1702 /* RDMA Endpoint field definitions */
1703 /*****************************************************************/
1704 static hf_register_info hfep[] = {
1705 { &hf_irdmaep_type,
1706 { "Type", "irdma.ep.type",
1707 FT_UINT8, BASE_DEC_HEX, VALS(irdmaep_type_str), 0x0,
1708 "RDMA Endpoint Message Type", HFILL }},
1709 { &hf_irdmaep_len,
1710 { "Length", "irdma.ep.len",
1711 FT_UINT8, BASE_DEC, NULL, 0x0,
1712 "RDMA Endpoint Message Length", HFILL }},
1713 { &hf_irdmaep_grpid,
1714 { "Group ID", "irdma.ep.grpid",
1715 FT_BYTES, BASE_NONE, NULL, 0x0,
1716 "RDMA Endpoint Group Identifier", HFILL }},
1717 { &hf_irdmaep_grpid_ctr,
1718 { "Counter", "irdma.ep.grpid.counter",
1719 FT_UINT8, BASE_HEX_DEC, NULL, 0x0,
1720 "RDMA Endpoint Group Identifier Uniqueness Counter", HFILL }},
1721 { &hf_irdmaep_grpid_time,
1722 { "Time Generated", "irdma.ep.grpid.time",
1723 FT_UINT48, BASE_HEX_DEC, NULL, 0x0,
1724 "RDMA Endpoint Group Identifier Timestamp", HFILL }},
1725 { &hf_irdmaep_grpid_hwaddr,
1726 { "Hardware Address", "irdma.ep.grpid.hwaddr",
1727 FT_ETHER, BASE_NONE, NULL, 0x0,
1728 "RDMA Endpoint Group Identifier Hardware Address", HFILL }},
1729 { &hf_irdmaep_srcport,
1730 { "Source Port", "irdma.ep.srcport",
1731 FT_UINT16, BASE_CUSTOM, CF_FUNC(irdma_custom_format_port), 0x0,
1732 "RDMA Endpoint Source Port", HFILL }},
1733 { &hf_irdmaep_dstport,
1734 { "Destination Port", "irdma.ep.dstport",
1735 FT_UINT16, BASE_CUSTOM, CF_FUNC(irdma_custom_format_port), 0x0,
1736 "RDMA Endpoint Destination Port", HFILL }},
1737 { &hf_irdmaep_port,
1738 { "Source or Destination Port", "irdma.ep.port",
1739 FT_UINT16, BASE_DEC, NULL, 0x0,
1740 "RDMA Endpoint Source or Destination Port", HFILL }},
1741 { &hf_irdmaep_stream,
1742 { "Stream index", "irdma.ep.stream",
1743 FT_UINT32, BASE_DEC, NULL, 0x0,
1744 "RDMA Endpoint Stream Index", HFILL }},
1745 { &hf_irdmaep_linkseq,
1746 { "Link Sequence", "irdma.ep.linkseq",
1747 FT_UINT16, BASE_DEC, NULL, 0x0,
1748 "RDMA Endpoint Link Switch Sequence", HFILL }},
1749 { &hf_irdmaep_sndbufsize,
1750 { "Send Buffer Size", "irdma.ep.sndbufsize",
1751 FT_UINT16, BASE_DEC, NULL, 0x0,
1752 "RDMA Endpoint Send Buffer Size", HFILL }},
1753 { &hf_irdmaep_usrblksize,
1754 { "User Block Size", "irdma.ep.usrblksize",
1755 FT_UINT16, BASE_DEC, NULL, 0x0,
1756 "RDMA Endpoint USER_RDMA Block Size", HFILL }},
1757 { &hf_irdmaep_reason,
1758 { "Reason", "irdma.ep.reason",
1759 FT_UINT32, BASE_DEC_HEX, NULL, 0x0, /* TODO - Add Strings for reason? */
1760 "RDMA Endpoint Close Reason", HFILL }},
1761 { &hf_irdmaep_rbuf,
1762 { "Remote Memory", "irdma.ep.rbuf",
1763 FT_BYTES, BASE_NONE, NULL, 0x0,
1764 "RDMA Endpoint Remote Memory Key/Address", HFILL }},
1765 { &hf_irdmaep_rkey,
1766 { "Remote Memory Key", "irdma.ep.rbuf.key",
1767 FT_UINT32, BASE_HEX, NULL, 0x0,
1768 "RDMA Endpoint Remote Memory Key", HFILL }},
1769 { &hf_irdmaep_raddr,
1770 { "Remote Memory Address", "irdma.ep.rbuf.addr",
1771 FT_UINT64, BASE_HEX, NULL, 0x0,
1772 "RDMA Endpoint Remote Memory Address", HFILL }},
1773 { &hf_irdmaep_flags,
1774 { "Flags", "irdma.ep.buffer.flags",
1775 FT_UINT8, BASE_HEX, NULL, 0xF0,
1776 "RDMA Endpoint Buffer Flags", HFILL }},
1777 { &hf_irdmaep_flag_buf0_free,
1778 { "Buffer #0", "irdma.ep.buffer.flags.buf0",
1779 FT_UINT8, 1, VALS(vals_free_inuse), 0x80,
1780 "RDMA Endpoint Buffer 0 Free Flag", HFILL }},
1781 { &hf_irdmaep_flag_buf1_free,
1782 { "Buffer #1", "irdma.ep.buffer.flags.buf1",
1783 FT_UINT8, 1, VALS(vals_free_inuse), 0x40,
1784 "RDMA Endpoint Buffer 1 Free Flag", HFILL }},
1785 { &hf_irdmaep_rcvbufsize,
1786 { "Receive Buffer Size", "irdma.ep.rcvbufsize",
1787 FT_UINT16, BASE_CUSTOM, CF_FUNC(irdma_custom_format_rbufsize), 0x0,
1788 "RDMA Endpoint Receive Buffer Size", HFILL }},
1789 { &hf_irdmaep_sendseq,
1790 { "Last Send Sequence", "irdma.ep.sendseq",
1791 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
1792 "RDMA Endpoint Last Successful Data Sequence Number", HFILL }},
1793 { &hf_irdmaep_recvseq0,
1794 { "Last Received Sequence (Buffer #0)", "irdma.ep.recvseq0",
1795 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
1796 "RDMA Endpoint Last Received Data Sequence Number", HFILL }},
1797 { &hf_irdmaep_recvseq1,
1798 { "Last Received Sequence (Buffer #1)", "irdma.ep.recvseq1",
1799 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
1800 "RDMA Endpoint Last Received Data Sequence Number", HFILL }},
1801 { &hf_irdmaep_usndsent,
1802 { "USER_RDMA Bytes Sent", "irdma.ep.usndsent",
1803 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
1804 "RDMA Endpoint Bytes Sent From Current USER_RDMA Transfer", HFILL }},
1805 { &hf_irdmaep_usndid,
1806 { "USER_RDMA Send Identifier", "irdma.ep.usndid",
1807 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
1808 "RDMA Endpoint Current USER_RDMA Send Identifier", HFILL }},
1809 { &hf_irdmaep_urcvid,
1810 { "USER_RDMA Receive Identifier Complete", "irdma.ep.urcvid",
1811 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
1812 "RDMA Endpoint Last USER_RDMA Receive Identifier Completed", HFILL }},
1813 { &hf_irdmaep_seqnum,
1814 { "Send Sequence", "irdma.ep.seqnum",
1815 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
1816 "RDMA Endpoint Data Sequence Number", HFILL }},
1817 { &hf_irdmaep_bufid,
1818 { "Buffer Identifier", "irdma.ep.bufid",
1819 FT_UINT16, BASE_DEC, NULL, 0x0,
1820 "RDMA Endpoint Buffer Identifier", HFILL }},
1821 { &hf_irdmaep_offset,
1822 { "Buffer Offset", "irdma.ep.offset",
1823 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
1824 "RDMA Endpoint Buffer Offset", HFILL }},
1825 { &hf_irdmaep_datalen,
1826 { "Length", "irdma.ep.length",
1827 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
1828 "RDMA Endpoint Data Length", HFILL }},
1829 { &hf_irdmaep_ulength,
1830 { "USER_RDMA Length", "irdma.ep.ulength",
1831 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
1832 "RDMA Endpoint USER_RDMA Total Length", HFILL }},
1833 { &hf_irdmaep_blength,
1834 { "USER_RDMA Block Length", "irdma.ep.blength",
1835 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
1836 "RDMA Endpoint USER_RDMA Block Length", HFILL }},
1837 { &hf_irdmaep_recvid,
1838 { "USER_RDMA Receive Identifier", "irdma.ep.recvid",
1839 FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
1840 "RDMA Endpoint USER_RDMA Receive Identifier", HFILL }},
1841 { &hf_irdmaep_rbufavail,
1842 { "Receive Buffer Available", "irdma.ep.analysis.rcvbuf",
1843 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
1844 "RDMA Receive Buffer Bytes Available", HFILL }},
1845 { &hf_irdmaep_rbufactive,
1846 { "Active Receive Buffer Available", "irdma.ep.analysis.rcvbuf.active",
1847 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
1848 "RDMA Active Receive Buffer Bytes Available", HFILL }},
1849 { &hf_irdmaep_rbufmax,
1850 { "Maximum Receive Buffer Available", "irdma.ep.analysis.rcvbuf.max",
1851 FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
1852 "RDMA Maximum Receive Buffer Bytes Available", HFILL }},
1853 { &hf_irdmaep_move1,
1854 { "Server link switch time", "irdma.ep.analysis.linkswt.server",
1855 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1856 "RDMA server link switch time", HFILL }},
1857 { &hf_irdmaep_move2,
1858 { "Link switch time", "irdma.ep.analysis.linkswt",
1859 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1860 "RDMA link switch time", HFILL }},
1861 { &hf_irdmaep_ts_relative,
1862 { "Time since first frame in this RDMA stream", "irdma.ep.time_relative",
1863 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1864 "Time relative to first frame in this RDMA stream", HFILL }},
1865 { &hf_irdmaep_ts_delta,
1866 { "Time since previous frame in this RDMA stream", "irdma.ep.time_delta",
1867 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1868 "Time delta from previous frame in this RDMA stream", HFILL }}
1871 /*****************************************************************/
1872 /* Protocol subtree array */
1873 /*****************************************************************/
1874 static int *ett[] = {
1875 &ett_irdma,
1876 &ett_irdmaqp,
1877 &ett_irdmalink,
1878 &ett_irdmaep,
1879 &ett_irdmaep_grpid,
1880 &ett_irdmaep_rbuf,
1881 &ett_irdmaep_bufflags,
1882 &ett_irdmaep_rcvbuf_analyze,
1883 &ett_irdmaep_timestamps
1886 /* Setup protocol expert items */
1887 static ei_register_info ei[] = {
1888 { &ei_irdmaep_analysis_stale,
1889 { "irdma.ep.analysis.stale", PI_SEQUENCE, PI_NOTE,
1890 "Packet received from prior link", EXPFILL }},
1891 { &ei_irdmaep_analysis_dup,
1892 { "irdma.ep.analysis.dup", PI_SEQUENCE, PI_CHAT,
1893 "Duplicate data packet (retransmission)", EXPFILL }},
1894 { &ei_irdmaep_analysis_oos,
1895 { "irdma.ep.analysis.oos", PI_SEQUENCE, PI_ERROR,
1896 "Out of order data packet", EXPFILL }},
1897 { &ei_irdmaep_connection_req,
1898 { "irdma.ep.connection.req", PI_SEQUENCE, PI_CHAT,
1899 "Connection request (CONNREQ)", EXPFILL }},
1900 { &ei_irdmaep_connection_ack,
1901 { "irdma.ep.connection.ack", PI_SEQUENCE, PI_CHAT,
1902 "Connection acknowledgement (CONNACK)", EXPFILL }},
1903 { &ei_irdmaep_connection_lswt,
1904 { "irdma.ep.connection.linkswt", PI_SEQUENCE, PI_NOTE,
1905 "Link switch", EXPFILL }}
1908 /*****************************************************************/
1909 /* Register the protocols */
1910 /*****************************************************************/
1911 proto_irdma = proto_register_protocol("IBM i RDMA", "iRDMA", "irdma");
1912 proto_irdmaqp = proto_register_protocol("IBM i RDMA QP", "iRDMA-QP", "irdma.qp");
1913 proto_irdmalink = proto_register_protocol("IBM i RDMA Link", "iRDMA-Link", "irdma.link");
1914 proto_irdmaep = proto_register_protocol("IBM i RDMA Endpoint", "iRDMA-EP", "irdma.ep");
1916 register_init_routine(irdma_init);
1918 /* Required function calls to register the header fields and subtrees */
1919 proto_register_field_array(proto_irdma, hf, array_length(hf));
1920 proto_register_field_array(proto_irdmaqp, hfqp, array_length(hfqp));
1921 proto_register_field_array(proto_irdmalink, hflink, array_length(hflink));
1922 proto_register_field_array(proto_irdmaep, hfep, array_length(hfep));
1924 proto_register_subtree_array(ett, array_length(ett));
1926 // Register a dissector table to allow sub-dissectors to register based on EP port
1927 irdmaep_dissector_table
1928 = register_dissector_table("irdma.ep.port", "RDMA EP Port", proto_irdmaep, FT_UINT16, BASE_DEC);
1930 /* Required function calls to register expert items */
1931 expert_irdmaep = expert_register_protocol(proto_irdmaep);
1932 expert_register_field_array(expert_irdmaep, ei, array_length(ei));
1934 /* Register a preferences module (see section 2.6 of README.dissector
1935 * for more details). Registration of a prefs callback is not required
1936 * if there are no preferences that affect protocol registration (an example
1937 * of a preference that would affect registration is a port preference).
1938 * If the prefs callback is not needed, use NULL instead of
1939 * proto_reg_handoff_irdma in the following.
1941 prefs_register_protocol(proto_irdma, proto_reg_handoff_irdma);
1942 irdmaep_module = prefs_register_protocol(proto_irdmaep, NULL);
1943 prefs_register_bool_preference(irdmaep_module, "calculate_timestamps",
1944 "Calculate conversation timestamps",
1945 "Calculate timestamps relative to the first frame and the previous frame in the RDMA conversation",
1946 &irdmaep_calculate_ts);
1947 prefs_register_bool_preference(irdmaep_module, "no_subdissector_on_error",
1948 "Do not call subdissectors for error packets",
1949 "Do not call any subdissectors for retransmitted segments",
1950 &irdmaep_no_subdissector_on_error);
1952 register_dissector("irdma", dissect_irdma, proto_irdma);
1955 /* Simpler form of proto_reg_handoff_irdma which can be used if there are
1956 * no prefs-dependent registration function calls. */
1957 void
1958 proto_reg_handoff_irdma(void)
1960 /* Use create_dissector_handle() to get the handles to IBM i RDMA
1961 * subdissectors.
1963 irdmaqp_handle = create_dissector_handle(dissect_irdmaqp, proto_irdmaqp);
1964 irdmalink_handle = create_dissector_handle(dissect_irdmalink, proto_irdmalink);
1965 irdmaep_handle = create_dissector_handle(dissect_irdmaep, proto_irdmaep);
1969 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1971 * Local variables:
1972 * c-basic-offset: 4
1973 * tab-width: 8
1974 * indent-tabs-mode: nil
1975 * End:
1977 * vi: set shiftwidth=4 tabstop=8 expandtab:
1978 * :indentSize=4:tabSize=8:noTabs=true: