aeron: fix infinite loop
[metze/wireshark/wip.git] / epan / dissectors / packet-aeron.c
1 /* packet-aeron.c
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "config.h"
23 #ifdef HAVE_ARPA_INET_H
24     #include <arpa/inet.h>
25 #endif
26 #if HAVE_WINSOCK2_H
27     #include <winsock2.h>
28 #endif
29 #include <epan/packet.h>
30 #include <epan/prefs.h>
31 #include <epan/expert.h>
32 #include <epan/uat.h>
33 #include <epan/tap.h>
34 #include <epan/conversation.h>
35 #include <epan/to_str.h>
36 #ifndef HAVE_INET_ATON
37     #include <wsutil/inet_aton.h>
38 #endif
39 #include <wsutil/pint.h>
40
41 /* The Aeron protocol is defined at https://github.com/real-logic/Aeron/wiki/Protocol-Specification */
42
43 void proto_register_aeron(void);
44 void proto_reg_handoff_aeron(void);
45
46 /* Protocol handle */
47 static int proto_aeron = -1;
48
49 /* Dissector handles */
50 static dissector_handle_t aeron_dissector_handle;
51 static dissector_handle_t aeron_data_dissector_handle;
52 static heur_dissector_list_t aeron_heuristic_subdissector_list;
53
54 /*----------------------------------------------------------------------------*/
55 /* Preferences.                                                               */
56 /*----------------------------------------------------------------------------*/
57
58 static gboolean aeron_sequence_analysis = FALSE;
59 static gboolean aeron_stream_analysis = FALSE;
60 static gboolean aeron_reassemble_fragments = FALSE;
61 static gboolean aeron_use_heuristic_subdissectors = FALSE;
62
63 /*----------------------------------------------------------------------------*/
64 /* Aeron position routines.                                                   */
65 /*----------------------------------------------------------------------------*/
66 typedef struct
67 {
68     guint32 term_id;
69     guint32 term_offset;
70 } aeron_pos_t;
71
72 static int aeron_pos_roundup(int offset)
73 {
74     return ((offset+7) & 0xfffffff8);
75 }
76
77 static int aeron_pos_compare(const aeron_pos_t * pos1, const aeron_pos_t * pos2)
78 {
79     /* Returns:
80         < 0  if pos1 < pos2
81         == 0 if pos1 == pos2
82         > 0  if pos1 > pos2
83     */
84     if (pos1->term_id == pos2->term_id)
85     {
86         if (pos1->term_offset == pos2->term_offset)
87         {
88             return (0);
89         }
90         else
91         {
92             return ((pos1->term_offset < pos2->term_offset) ? -1 : 1);
93         }
94     }
95     else
96     {
97         return ((pos1->term_id < pos2->term_id) ? -1 : 1);
98     }
99 }
100
101 static guint32 aeron_pos_delta(const aeron_pos_t * pos1, const aeron_pos_t * pos2, guint32 term_size)
102 {
103     const aeron_pos_t * p1;
104     const aeron_pos_t * p2;
105     guint64 p1_val;
106     guint64 p2_val;
107     guint64 delta;
108     int rc;
109
110     rc = aeron_pos_compare(pos1, pos2);
111     if (rc >= 0)
112     {
113         p1 = pos1;
114         p2 = pos2;
115     }
116     else
117     {
118         p1 = pos2;
119         p2 = pos1;
120     }
121     p1_val = (guint64) (p1->term_id * term_size) + ((guint64) p1->term_offset);
122     p2_val = (guint64) (p2->term_id * term_size) + ((guint64) p2->term_offset);
123     delta = p1_val - p2_val;
124     return ((guint32) (delta & G_GUINT64_CONSTANT(0x00000000ffffffff)));
125 }
126
127 static void aeron_pos_add_length(aeron_pos_t * pos, guint32 length, guint32 term_length)
128 {
129     guint32 next_term_offset = aeron_pos_roundup(pos->term_offset + length);
130
131     if (next_term_offset >= term_length)
132     {
133         pos->term_offset = 0;
134         pos->term_id++;
135     }
136     else
137     {
138         pos->term_offset = next_term_offset;
139     }
140 }
141
142 /*----------------------------------------------------------------------------*/
143 /* Aeron frame information management.                                        */
144 /*----------------------------------------------------------------------------*/
145 static wmem_tree_t * aeron_frame_info_tree = NULL;
146
147 struct aeron_frame_info_t_stct;
148 typedef struct aeron_frame_info_t_stct aeron_frame_info_t;
149
150 typedef struct
151 {
152     aeron_frame_info_t * frame_info;        /* Frame (aeron_frame_info_t) containing the RX data */
153     guint32 term_offset;                 /* Term offset of RX data */
154     guint32 length;                      /* Length of RX data */
155 } aeron_rx_info_t;
156
157 typedef struct
158 {
159     aeron_frame_info_t * frame_info;        /* Frame (aeron_frame_info_t) in which this NAK occurs */
160     wmem_list_t * rx;                       /* List of RX frames for this NAK */
161     guint32 flags;
162     guint32 nak_term_offset;                /* Term offset specified by this NAK */
163     guint32 nak_length;                     /* NAK length */
164     guint32 unrecovered_length;             /* Number of bytes unrecovered via RX */
165 } aeron_nak_analysis_t;
166
167 typedef struct
168 {
169     guint32 flags;
170     guint32 flags2;
171     aeron_pos_t high;
172     aeron_pos_t completed;
173     guint32 receiver_window;
174     guint32 outstanding_bytes;
175 } aeron_stream_analysis_t;
176 #define AERON_STREAM_ANALYSIS_FLAGS_WINDOW_FULL      0x00000001
177 #define AERON_STREAM_ANALYSIS_FLAGS_IDLE_RX          0x00000002
178 #define AERON_STREAM_ANALYSIS_FLAGS_PACING_RX        0x00000004
179 #define AERON_STREAM_ANALYSIS_FLAGS_OOO              0x00000008
180 #define AERON_STREAM_ANALYSIS_FLAGS_OOO_GAP          0x00000010
181 #define AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE        0x00000020
182 #define AERON_STREAM_ANALYSIS_FLAGS_WINDOW_RESIZE    0x00000040
183 #define AERON_STREAM_ANALYSIS_FLAGS_OOO_SM           0x00000080
184 #define AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE_SM     0x00000100
185 #define AERON_STREAM_ANALYSIS_FLAGS_RX               0x00000200
186 #define AERON_STREAM_ANALYSIS_FLAGS_TERM_ID_CHANGE   0x00000400
187
188 #define AERON_STREAM_ANALYSIS_FLAGS2_RCV_VALID       0x00000001
189
190 typedef struct
191 {
192     guint32 previous;
193     guint32 next;
194 } aeron_frame_link_t;
195
196 struct aeron_msg_t_stct;
197 typedef struct aeron_msg_t_stct aeron_msg_t;
198
199 struct aeron_frame_info_t_stct
200 {
201     guint32 frame;
202     guint32 ofs;
203     aeron_frame_link_t transport;
204     aeron_frame_link_t stream;
205     aeron_frame_link_t term;
206     aeron_frame_link_t fragment;
207     aeron_stream_analysis_t * stream_analysis;
208     aeron_nak_analysis_t * nak_analysis;
209     aeron_msg_t * message;
210     wmem_list_t * rx;
211     guint32 flags;
212 };
213 #define AERON_FRAME_INFO_FLAGS_RETRANSMISSION  0x00000001
214 #define AERON_FRAME_INFO_FLAGS_KEEPALIVE       0x00000002
215 #define AERON_FRAME_INFO_FLAGS_REASSEMBLED_MSG 0x00000004
216
217 static wmem_tree_key_t * aeron_frame_info_key_build(guint32 frame, guint32 ofs)
218 {
219     wmem_tree_key_t * fkey;
220     guint32 * key;
221
222     fkey = wmem_alloc_array(wmem_packet_scope(), wmem_tree_key_t, 2);
223     key = wmem_alloc_array(wmem_packet_scope(), guint32, 2);
224     key[0] = frame;
225     key[1] = ofs;
226     fkey[0].length = 2;
227     fkey[0].key = key;
228     fkey[1].length = 0;
229     fkey[1].key = NULL;
230     return (fkey);
231 }
232
233 static aeron_frame_info_t * aeron_frame_info_lookup(wmem_tree_key_t * key)
234 {
235     aeron_frame_info_t * fi = NULL;
236
237     fi = (aeron_frame_info_t *) wmem_tree_lookup32_array(aeron_frame_info_tree, key);
238     return (fi);
239 }
240
241 static aeron_frame_info_t * aeron_frame_info_find(guint32 frame, guint32 ofs)
242 {
243     wmem_tree_key_t * key = aeron_frame_info_key_build(frame, ofs);
244     return (aeron_frame_info_lookup(key));
245 }
246
247 static aeron_frame_info_t * aeron_frame_info_add(guint32 frame, guint32 ofs)
248 {
249     aeron_frame_info_t * fi = NULL;
250     wmem_tree_key_t * key = aeron_frame_info_key_build(frame, ofs);
251
252     fi = aeron_frame_info_lookup(key);
253     if (fi == NULL)
254     {
255         fi = wmem_new0(wmem_file_scope(), aeron_frame_info_t);
256         fi->frame = frame;
257         fi->ofs = ofs;
258         if (aeron_sequence_analysis && aeron_stream_analysis)
259         {
260             fi->rx = wmem_list_new(wmem_file_scope());
261         }
262         wmem_tree_insert32_array(aeron_frame_info_tree, key, (void *) fi);
263     }
264     return (fi);
265 }
266
267 /*----------------------------------------------------------------------------*/
268 /* Aeron channel ID management.                                               */
269 /*----------------------------------------------------------------------------*/
270 static guint64 aeron_channel_id = 1;
271
272 static guint64 aeron_channel_id_assign(void)
273 {
274     return (aeron_channel_id++);
275 }
276
277 static void aeron_channel_id_init(void)
278 {
279     aeron_channel_id = 1;
280 }
281
282 /*----------------------------------------------------------------------------*/
283 /* Aeron transport, stream, term, and fragment structures.                    */
284 /*----------------------------------------------------------------------------*/
285 typedef struct
286 {
287     address * addr1;
288     address * addr2;
289     port_type ptype;
290     guint16 port1;
291     guint16 port2;
292 } aeron_conversation_info_t;
293
294 struct aeron_transport_t_stct;
295 typedef struct aeron_transport_t_stct aeron_transport_t;
296
297 struct aeron_stream_t_stct;
298 typedef struct aeron_stream_t_stct aeron_stream_t;
299
300 struct aeron_term_t_stct;
301 typedef struct aeron_term_t_stct aeron_term_t;
302
303 struct aeron_fragment_t_stct;
304 typedef struct aeron_fragment_t_stct aeron_fragment_t;
305
306 struct aeron_transport_t_stct
307 {
308     guint64 channel_id;
309     wmem_map_t * stream;                    /* Map of all streams (aeron_stream_t) in this transport, keyed by stream ID */
310     aeron_frame_info_t * last_frame;
311     address addr1;
312     address addr2;
313     guint32 session_id;
314     guint16 port1;
315     guint16 port2;
316 };
317
318 struct aeron_stream_rcv_t_stct;
319 typedef struct aeron_stream_rcv_t_stct aeron_stream_rcv_t;
320
321 struct aeron_stream_rcv_t_stct
322 {
323     address addr;                           /* Receiver's IP address */
324     guint16 port;                           /* Receiver's (sending) port */
325     aeron_pos_t completed;
326     guint32 receiver_window;
327 };
328
329 struct aeron_stream_t_stct
330 {
331     aeron_transport_t * transport;          /* Parent transport */
332     wmem_map_t * term;                      /* Map of all terms (aeron_term_t) in this stream, keyed by term ID */
333     wmem_list_t * rcv;                      /* List of receivers (aeron_stream_rcv_t) */
334     guint32 rcv_count;
335     aeron_frame_info_t * last_frame;
336     guint32 stream_id;
337     guint32 term_length;
338     guint32 mtu;
339     guint32 flags;
340     aeron_pos_t high;
341 };
342 #define AERON_STREAM_FLAGS_HIGH_VALID 0x1
343
344 typedef struct
345 {
346     aeron_term_t * term;                    /* Parent term */
347     aeron_frame_info_t * frame_info;        /* Frame info (aeron_frame_info_t) in which this NAK occurred */
348     guint32 term_offset;                    /* NAK term offset */
349     guint32 length;                         /* Length of NAK */
350 } aeron_nak_t;
351
352 struct aeron_term_t_stct
353 {
354     aeron_stream_t * stream;                /* Parent stream */
355     wmem_map_t * fragment;                  /* Map of all fragments (aeron_fragment_t) in this term, keyed by term offset */
356     wmem_tree_t * message;                  /* Tree of all fragmented messages (aeron_msg_t) in this term, keyed by lowest term offset */
357     wmem_list_t * orphan_fragment;
358     aeron_frame_info_t * last_frame;        /* Pointer to last frame seen for this term */
359     wmem_list_t * nak;                      /* List of all NAKs (aeron_nak_t) in this term */
360     guint32 term_id;
361 };
362
363 struct aeron_fragment_t_stct
364 {
365     aeron_term_t * term;                    /* Parent term */
366     wmem_list_t * frame;                    /* List of frames (aeron_frame_info_t) containing this fragment (term offset) */
367     aeron_frame_info_t * first_frame;       /* First frame which contains this fragment (term offset) */
368     aeron_frame_info_t * last_frame;        /* Last frame which contains this fragment (term offset) */
369     aeron_frame_info_t * first_data_frame;  /* First frame which contains this fragment (term offset) as actual data (not as a KA) */
370     guint32 term_offset;
371     guint32 length;
372     guint32 data_length;
373     guint32 frame_count;
374 };
375
376 /*----------------------------------------------------------------------------*/
377 /* Aeron transport management.                                                */
378 /*----------------------------------------------------------------------------*/
379 static guint aeron_guint32_hash_func(gconstpointer key)
380 {
381     guint32 value = *((const guint32 *) key);
382     return ((guint) value);
383 }
384
385 static gboolean aeron_guint32_compare_func(gconstpointer lhs, gconstpointer rhs)
386 {
387     guint32 key1 = *((const guint32 *) lhs);
388     guint32 key2 = *((const guint32 *) rhs);
389     return ((key1 == key2) ? TRUE : FALSE);
390 }
391
392 static aeron_transport_t * aeron_transport_add(const aeron_conversation_info_t * cinfo, guint32 session_id, guint32 frame)
393 {
394     aeron_transport_t * transport;
395     conversation_t * conv = NULL;
396     wmem_map_t * session_map = NULL;
397
398     conv = find_conversation(frame, cinfo->addr1, cinfo->addr2, cinfo->ptype, cinfo->port1, cinfo->port2, 0);
399     if (conv == NULL)
400     {
401         conv = conversation_new(frame, cinfo->addr1, cinfo->addr2, cinfo->ptype, cinfo->port1, cinfo->port2, 0);
402     }
403     if (frame > conv->last_frame)
404     {
405         conv->last_frame = frame;
406     }
407     session_map = (wmem_map_t *) conversation_get_proto_data(conv, proto_aeron);
408     if (session_map == NULL)
409     {
410         session_map = wmem_map_new(wmem_file_scope(), aeron_guint32_hash_func, aeron_guint32_compare_func);
411         conversation_add_proto_data(conv, proto_aeron, (void *) session_map);
412     }
413     transport = (aeron_transport_t *) wmem_map_lookup(session_map, (const void *) &session_id);
414     if (transport != NULL)
415     {
416         return (transport);
417     }
418     transport = wmem_new0(wmem_file_scope(), aeron_transport_t);
419     transport->channel_id = aeron_channel_id_assign();
420     transport->stream = wmem_map_new(wmem_file_scope(), aeron_guint32_hash_func, aeron_guint32_compare_func);
421     transport->last_frame = NULL;
422     WMEM_COPY_ADDRESS(wmem_file_scope(), &(transport->addr1), cinfo->addr1);
423     WMEM_COPY_ADDRESS(wmem_file_scope(), &(transport->addr2), cinfo->addr2);
424     transport->session_id = session_id;
425     transport->port1 = cinfo->port1;
426     transport->port2 = cinfo->port2;
427     wmem_map_insert(session_map, (const void *) &(transport->session_id), (void *) transport);
428     return (transport);
429 }
430
431 static aeron_stream_t * aeron_transport_stream_find(aeron_transport_t * transport, guint32 stream_id)
432 {
433     aeron_stream_t * stream = NULL;
434
435     stream = (aeron_stream_t *) wmem_map_lookup(transport->stream, (const void *) &stream_id);
436     return (stream);
437 }
438
439 static aeron_stream_t * aeron_transport_stream_add(aeron_transport_t * transport, guint32 stream_id)
440 {
441     aeron_stream_t * stream = NULL;
442
443     stream = aeron_transport_stream_find(transport, stream_id);
444     if (stream == NULL)
445     {
446         stream = wmem_new0(wmem_file_scope(), aeron_stream_t);
447         stream->transport = transport;
448         stream->term = wmem_map_new(wmem_file_scope(), aeron_guint32_hash_func, aeron_guint32_compare_func);
449         stream->rcv = wmem_list_new(wmem_file_scope());
450         stream->rcv_count = 0;
451         stream->last_frame = NULL;
452         stream->stream_id = stream_id;
453         stream->term_length = 0;
454         stream->mtu = 0;
455         stream->flags = 0;
456         stream->high.term_id = 0;
457         stream->high.term_offset = 0;
458         wmem_map_insert(transport->stream, (const void *) &(stream->stream_id), (void *) stream);
459     }
460     return (stream);
461 }
462
463 static void aeron_transport_frame_add(aeron_transport_t * transport, aeron_frame_info_t * finfo, guint32 flags)
464 {
465     if (flags != 0)
466     {
467         finfo->flags = flags;
468     }
469     if (transport->last_frame != NULL)
470     {
471         finfo->transport.previous = transport->last_frame->frame;
472         transport->last_frame->transport.next = finfo->frame;
473     }
474     finfo->transport.next = 0;
475     transport->last_frame = finfo;
476 }
477
478 /*----------------------------------------------------------------------------*/
479 /* Aeron stream management.                                                   */
480 /*----------------------------------------------------------------------------*/
481 static aeron_term_t * aeron_stream_term_find(aeron_stream_t * stream, guint32 term_id)
482 {
483     aeron_term_t * term = NULL;
484
485     term = (aeron_term_t *) wmem_map_lookup(stream->term, (const void *) &term_id);
486     return (term);
487 }
488
489 static aeron_term_t * aeron_stream_term_add(aeron_stream_t * stream, guint32 term_id)
490 {
491     aeron_term_t * term = NULL;
492
493     term = aeron_stream_term_find(stream, term_id);
494     if (term == NULL)
495     {
496         term = wmem_new0(wmem_file_scope(), aeron_term_t);
497         term->stream = stream;
498         term->fragment = wmem_map_new(wmem_file_scope(), aeron_guint32_hash_func, aeron_guint32_compare_func);
499         term->message = wmem_tree_new(wmem_file_scope());
500         term->orphan_fragment = wmem_list_new(wmem_file_scope());
501         term->nak = wmem_list_new(wmem_file_scope());
502         term->term_id = term_id;
503         wmem_map_insert(stream->term, (const void *) &(term->term_id), (void *) term);
504     }
505     return (term);
506 }
507
508 static aeron_stream_rcv_t * aeron_stream_rcv_find(aeron_stream_t * stream, const address * addr, guint16 port)
509 {
510     wmem_list_frame_t * lf = wmem_list_head(stream->rcv);
511     aeron_stream_rcv_t * rcv = NULL;
512
513     while (lf != NULL)
514     {
515         aeron_stream_rcv_t * cur = (aeron_stream_rcv_t *) wmem_list_frame_data(lf);
516         if (cur != NULL)
517         {
518             if ((cmp_address(&(cur->addr), addr) == 0) && (cur->port == port))
519             {
520                 rcv = cur;
521                 break;
522             }
523         }
524         lf = wmem_list_frame_next(lf);
525     }
526     return (rcv);
527 }
528
529 static aeron_stream_rcv_t * aeron_stream_rcv_add(aeron_stream_t * stream, const address * addr, guint16 port)
530 {
531     aeron_stream_rcv_t * rcv = NULL;
532
533     rcv = aeron_stream_rcv_find(stream, addr, port);
534     if (rcv != NULL)
535     {
536         return (rcv);
537     }
538     rcv = wmem_new0(wmem_file_scope(), aeron_stream_rcv_t);
539     WMEM_COPY_ADDRESS(wmem_file_scope(), &(rcv->addr), addr);
540     rcv->port = port;
541     rcv->completed.term_id = 0;
542     rcv->completed.term_offset = 0;
543     rcv->receiver_window = 0;
544     wmem_list_append(stream->rcv, (void *) rcv);
545     stream->rcv_count++;
546     return (rcv);
547 }
548
549 static void aeron_stream_frame_add(aeron_stream_t * stream, aeron_frame_info_t * finfo, guint32 flags)
550 {
551     if (flags != 0)
552     {
553         finfo->flags = flags;
554     }
555     if (stream->last_frame != NULL)
556     {
557         finfo->stream.previous = stream->last_frame->frame;
558         stream->last_frame->stream.next = finfo->frame;
559     }
560     finfo->stream.next = 0;
561     stream->last_frame = finfo;
562     aeron_transport_frame_add(stream->transport, finfo, 0);
563 }
564
565 /*----------------------------------------------------------------------------*/
566 /* Aeron term management.                                                     */
567 /*----------------------------------------------------------------------------*/
568 static aeron_fragment_t * aeron_term_fragment_find(aeron_term_t * term, guint32 term_offset)
569 {
570     aeron_fragment_t * fragment = NULL;
571
572     fragment = (aeron_fragment_t *) wmem_map_lookup(term->fragment, (const void *) &term_offset);
573     return (fragment);
574 }
575
576 static aeron_fragment_t * aeron_term_fragment_add(aeron_term_t * term, guint32 term_offset, guint32 length, guint32 data_length)
577 {
578     aeron_fragment_t * fragment = NULL;
579
580     fragment = aeron_term_fragment_find(term, term_offset);
581     if (fragment == NULL)
582     {
583         fragment = wmem_new0(wmem_file_scope(), aeron_fragment_t);
584         fragment->term = term;
585         fragment->frame = wmem_list_new(wmem_file_scope());
586         fragment->first_frame = NULL;
587         fragment->last_frame = NULL;
588         fragment->first_data_frame = NULL;
589         fragment->term_offset = term_offset;
590         fragment->length = length;
591         fragment->data_length = data_length;
592         fragment->frame_count = 0;
593         wmem_map_insert(term->fragment, (const void *) &(fragment->term_offset), (void *) fragment);
594     }
595     return (fragment);
596 }
597
598 static void aeron_term_frame_add(aeron_term_t * term, aeron_frame_info_t * finfo, guint32 flags)
599 {
600     if (flags != 0)
601     {
602         finfo->flags = flags;
603     }
604     if (term->last_frame != NULL)
605     {
606         finfo->term.previous = term->last_frame->frame;
607         term->last_frame->term.next = finfo->frame;
608     }
609     finfo->term.next = 0;
610     term->last_frame = finfo;
611     aeron_stream_frame_add(term->stream, finfo, 0);
612 }
613
614 /*----------------------------------------------------------------------------*/
615 /* Aeron fragment management.                                                 */
616 /*----------------------------------------------------------------------------*/
617 static void aeron_fragment_frame_add(aeron_fragment_t * fragment, aeron_frame_info_t * finfo, guint32 flags, guint32 length)
618 {
619     if (flags != 0)
620     {
621         finfo->flags = flags;
622     }
623     wmem_list_append(fragment->frame, (void *) finfo);
624     fragment->frame_count++;
625     if (fragment->last_frame != NULL)
626     {
627         finfo->fragment.previous = fragment->last_frame->frame;
628         fragment->last_frame->fragment.next = finfo->frame;
629     }
630     if (fragment->first_frame == NULL)
631     {
632         fragment->first_frame = finfo;
633     }
634     if (length != 0)
635     {
636         if (fragment->first_data_frame == NULL)
637         {
638             fragment->first_data_frame = finfo;
639         }
640     }
641     finfo->fragment.next = 0;
642     fragment->last_frame = finfo;
643     aeron_term_frame_add(fragment->term, finfo, 0);
644 }
645
646 /*----------------------------------------------------------------------------*/
647 /* Utilioty functions.                                                        */
648 /*----------------------------------------------------------------------------*/
649 static gboolean aeron_is_address_multicast(const address * addr)
650 {
651     guint8 * addr_data = (guint8 *) addr->data;
652
653     switch (addr->type)
654     {
655         case AT_IPv4:
656             if ((addr_data[0] & 0xf0) == 0xe0)
657             {
658                 return (TRUE);
659             }
660             break;
661         case AT_IPv6:
662             if (addr_data[0] == 0xff)
663             {
664                 return (TRUE);
665             }
666             break;
667         default:
668             break;
669     }
670     return (FALSE);
671 }
672
673 static char * aeron_format_transport_uri(const aeron_conversation_info_t * cinfo)
674 {
675     wmem_strbuf_t * uri = NULL;
676
677     uri = wmem_strbuf_new(wmem_packet_scope(), "aeron:");
678     switch (cinfo->ptype)
679     {
680         case PT_UDP:
681             wmem_strbuf_append(uri, "udp");
682             break;
683         default:
684             wmem_strbuf_append(uri, "unknown");
685             break;
686     }
687     wmem_strbuf_append_c(uri, '?');
688     if (aeron_is_address_multicast(cinfo->addr2))
689     {
690         switch (cinfo->addr2->type)
691         {
692             case AT_IPv6:
693                 wmem_strbuf_append_printf(uri, "group=[%s]:%" G_GUINT16_FORMAT, address_to_str(wmem_packet_scope(), cinfo->addr2), cinfo->port2);
694                 break;
695             case AT_IPv4:
696             default:
697                 wmem_strbuf_append_printf(uri, "group=%s:%" G_GUINT16_FORMAT, address_to_str(wmem_packet_scope(), cinfo->addr2), cinfo->port2);
698                 break;
699         }
700     }
701     else
702     {
703         switch (cinfo->addr2->type)
704         {
705             case AT_IPv6:
706                 wmem_strbuf_append_printf(uri, "remote=[%s]:%" G_GUINT16_FORMAT, address_to_str(wmem_packet_scope(), cinfo->addr2), cinfo->port2);
707                 break;
708             case AT_IPv4:
709             default:
710                 wmem_strbuf_append_printf(uri, "remote=%s:%" G_GUINT16_FORMAT, address_to_str(wmem_packet_scope(), cinfo->addr2), cinfo->port2);
711                 break;
712         }
713     }
714     return (wmem_strbuf_finalize(uri));
715 }
716
717 /*----------------------------------------------------------------------------*/
718 /* Packet definitions.                                                        */
719 /*----------------------------------------------------------------------------*/
720
721 /* Basic frame offsets */
722 #define O_AERON_BASIC_FRAME_LENGTH 0
723 #define O_AERON_BASIC_VERSION 4
724 #define O_AERON_BASIC_FLAGS 5
725 #define O_AERON_BASIC_TYPE 6
726
727 #define HDR_LENGTH_MIN 12
728
729 /* Padding frame */
730 #define O_AERON_PAD_FRAME_LENGTH 0
731 #define O_AERON_PAD_VERSION 4
732 #define O_AERON_PAD_FLAGS 5
733 #define O_AERON_PAD_TYPE 6
734 #define O_AERON_PAD_TERM_OFFSET 8
735 #define O_AERON_PAD_SESSION_ID 12
736 #define O_AERON_PAD_STREAM_ID 16
737 #define O_AERON_PAD_TERM_ID 20
738 #define L_AERON_PAD 24
739
740 /* Data frame */
741 #define O_AERON_DATA_FRAME_LENGTH 0
742 #define O_AERON_DATA_VERSION 4
743 #define O_AERON_DATA_FLAGS 5
744 #define O_AERON_DATA_TYPE 6
745 #define O_AERON_DATA_TERM_OFFSET 8
746 #define O_AERON_DATA_SESSION_ID 12
747 #define O_AERON_DATA_STREAM_ID 16
748 #define O_AERON_DATA_TERM_ID 20
749 #define O_AERON_DATA_DATA 24
750 #define L_AERON_DATA 24
751
752 /* NAK frame */
753 #define O_AERON_NAK_FRAME_LENGTH 0
754 #define O_AERON_NAK_VERSION 4
755 #define O_AERON_NAK_FLAGS 5
756 #define O_AERON_NAK_TYPE 6
757 #define O_AERON_NAK_SESSION_ID 8
758 #define O_AERON_NAK_STREAM_ID 12
759 #define O_AERON_NAK_TERM_ID 16
760 #define O_AERON_NAK_TERM_OFFSET 20
761 #define O_AERON_NAK_LENGTH 24
762
763 /* Status message */
764 #define O_AERON_SM_FRAME_LENGTH 0
765 #define O_AERON_SM_VERSION 4
766 #define O_AERON_SM_FLAGS 5
767 #define O_AERON_SM_TYPE 6
768 #define O_AERON_SM_SESSION_ID 8
769 #define O_AERON_SM_STREAM_ID 12
770 #define O_AERON_SM_TERM_ID 16
771 #define O_AERON_SM_COMPLETED_TERM_OFFSET 20
772 #define O_AERON_SM_RECEIVER_WINDOW 24
773 #define O_AERON_SM_FEEDBACK 28
774
775 /* Error header */
776 #define O_AERON_ERR_FRAME_LENGTH 0
777 #define O_AERON_ERR_VERSION 4
778 #define O_AERON_ERR_CODE 5
779 #define O_AERON_ERR_TYPE 6
780 #define O_AERON_ERR_OFFENDING_FRAME_LENGTH 8
781 #define O_AERON_ERR_OFFENDING_HEADER 12
782 #define O_AERON_ERR_TERM_ID 16
783 #define O_AERON_ERR_COMPLETED_TERM_OFFSET 20
784 #define O_AERON_ERR_RECEIVER_WINDOW 24
785 #define O_AERON_ERR_FEEDBACK 28
786
787 /* Setup frame */
788 #define O_AERON_SETUP_FRAME_LENGTH 0
789 #define O_AERON_SETUP_VERSION 4
790 #define O_AERON_SETUP_FLAGS 5
791 #define O_AERON_SETUP_TYPE 6
792 #define O_AERON_SETUP_TERM_OFFSET 8
793 #define O_AERON_SETUP_SESSION_ID 12
794 #define O_AERON_SETUP_STREAM_ID 16
795 #define O_AERON_SETUP_INITIAL_TERM_ID 20
796 #define O_AERON_SETUP_ACTIVE_TERM_ID 24
797 #define O_AERON_SETUP_TERM_LENGTH 28
798 #define O_AERON_SETUP_MTU 32
799
800 #define HDR_TYPE_PAD 0x0000
801 #define HDR_TYPE_DATA 0x0001
802 #define HDR_TYPE_NAK 0x0002
803 #define HDR_TYPE_SM 0x0003
804 #define HDR_TYPE_ERR 0x0004
805 #define HDR_TYPE_SETUP 0x0005
806 #define HDR_TYPE_EXT 0xFFFF
807
808 #define DATA_FLAGS_BEGIN 0x80
809 #define DATA_FLAGS_END 0x40
810 #define DATA_FLAGS_COMPLETE (DATA_FLAGS_BEGIN | DATA_FLAGS_END)
811
812 #define STATUS_FLAGS_SETUP 0x80
813
814 /*----------------------------------------------------------------------------*/
815 /* Value translation tables.                                                  */
816 /*----------------------------------------------------------------------------*/
817
818 static const value_string aeron_frame_type[] =
819 {
820     { HDR_TYPE_PAD, "Pad" },
821     { HDR_TYPE_DATA, "Data" },
822     { HDR_TYPE_NAK, "NAK" },
823     { HDR_TYPE_SM, "Status" },
824     { HDR_TYPE_ERR, "Error" },
825     { HDR_TYPE_SETUP, "Setup" },
826     { HDR_TYPE_EXT, "Extension" },
827     { 0x0, NULL }
828 };
829
830 /*
831     Aeron conversations:
832
833     UDP unicast:
834     - The URL specifies the subscriber address and UDP port, and the publisher "connects" to the single subscriber.
835     - The publisher sends Pad, Data, and Setup frames to the subscriber address and port.
836     - The subscriber sends NAK and SM frames to the publisher, using as the destination the address and port from
837       which the Setup and Data frames were received
838     - So the conversation is defined by [A(publisher),A(subscriber),P(publisher),P(subscriber),PT_UDP]
839
840     UDP multicast:
841     - The URL specifies the data multicast group and UDP port, and must be an odd-numbered address. The control multicast
842       group is automatically set to be one greater than the data multicast group, and the same port is used.
843     - The publisher sends Pad, Data, and Setup frames to the data multicast group and port.
844     - The subscriber sends NAK and SM frames to the control multicast group and port.
845     - So the conversation is defined by [ControlGroup,DataGroup,port,port,PT_UDP]
846
847 */
848
849 static aeron_conversation_info_t * aeron_setup_conversation_info(const packet_info * pinfo, guint16 type)
850 {
851     aeron_conversation_info_t * cinfo;
852     int addr_len = pinfo->dst.len;
853
854     cinfo = wmem_new0(wmem_packet_scope(), aeron_conversation_info_t);
855     cinfo->ptype = pinfo->ptype;
856     switch (pinfo->dst.type)
857     {
858         case AT_IPv4:
859             {
860                 guint8 * dst_addr = (guint8 *) pinfo->dst.data;
861
862                 cinfo->addr1 = wmem_new0(wmem_packet_scope(), address);
863                 cinfo->addr2 = wmem_new0(wmem_packet_scope(), address);
864                 if (aeron_is_address_multicast(&(pinfo->dst)))
865                 {
866                     guint8 * addr1 = NULL;
867                     guint8 * addr2 = NULL;
868
869                     addr1 = (guint8 *) wmem_alloc(wmem_packet_scope(), (size_t) addr_len);
870                     addr2 = (guint8 *) wmem_alloc(wmem_packet_scope(), (size_t) addr_len);
871                     memcpy((void *) addr1, (void *) dst_addr, (size_t) addr_len);
872                     memcpy((void *) addr2, (void *) dst_addr, (size_t) addr_len);
873                     if ((dst_addr[addr_len - 1] & 0x1) != 0)
874                     {
875                         /* Address is odd, so it's the data group (in addr2). Increment the last byte of addr1 for the control group. */
876                         addr1[addr_len - 1]++;
877                     }
878                     else
879                     {
880                         /* Address is even, so it's the control group (in addr1). Decrement the last byte of addr2 for the data group. */
881                         addr2[addr_len - 1]--;
882                     }
883                     SET_ADDRESS(cinfo->addr1, AT_IPv4, addr_len, (void *) addr1);
884                     SET_ADDRESS(cinfo->addr2, AT_IPv4, addr_len, (void *) addr2);
885                     cinfo->port1 = pinfo->destport;
886                     cinfo->port2 = cinfo->port1;
887                 }
888                 else
889                 {
890                     switch (type)
891                     {
892                         case HDR_TYPE_PAD:
893                         case HDR_TYPE_DATA:
894                         case HDR_TYPE_SETUP:
895                             /* Destination is a receiver */
896                             WMEM_COPY_ADDRESS(wmem_packet_scope(), cinfo->addr1, &(pinfo->src));
897                             cinfo->port1 = pinfo->srcport;
898                             WMEM_COPY_ADDRESS(wmem_packet_scope(), cinfo->addr2, &(pinfo->dst));
899                             cinfo->port2 = pinfo->destport;
900                             break;
901                         case HDR_TYPE_NAK:
902                         case HDR_TYPE_SM:
903                             /* Destination is the source */
904                             WMEM_COPY_ADDRESS(wmem_packet_scope(), cinfo->addr1, &(pinfo->dst));
905                             cinfo->port1 = pinfo->destport;
906                             WMEM_COPY_ADDRESS(wmem_packet_scope(), cinfo->addr2, &(pinfo->src));
907                             cinfo->port2 = pinfo->srcport;
908                             break;
909                         default:
910                             break;
911                     }
912                 }
913             }
914             break;
915         case AT_IPv6:
916             {
917                 guint8 * dst_addr = (guint8 *) pinfo->dst.data;
918
919                 cinfo->addr1 = wmem_new0(wmem_packet_scope(), address);
920                 cinfo->addr2 = wmem_new0(wmem_packet_scope(), address);
921                 if (aeron_is_address_multicast(&(pinfo->dst)))
922                 {
923                     guint8 * addr1 = NULL;
924                     guint8 * addr2 = NULL;
925
926                     addr1 = (guint8 *) wmem_alloc(wmem_packet_scope(), (size_t) addr_len);
927                     addr2 = (guint8 *) wmem_alloc(wmem_packet_scope(), (size_t) addr_len);
928                     memcpy((void *) addr1, (void *) dst_addr, (size_t) addr_len);
929                     memcpy((void *) addr2, (void *) dst_addr, (size_t) addr_len);
930                     if ((dst_addr[addr_len - 1] & 0x1) != 0)
931                     {
932                         /* Address is odd, so it's the data group (in addr2). Increment the last byte of addr1 for the control group. */
933                         addr1[addr_len - 1]++;
934                     }
935                     else
936                     {
937                         /* Address is even, so it's the control group (in addr1). Decrement the last byte of addr2 for the data group. */
938                         addr2[addr_len - 1]--;
939                     }
940                     SET_ADDRESS(cinfo->addr1, AT_IPv6, addr_len, (void *) addr1);
941                     SET_ADDRESS(cinfo->addr2, AT_IPv6, addr_len, (void *) addr2);
942                     cinfo->port1 = pinfo->destport;
943                     cinfo->port2 = cinfo->port1;
944                 }
945                 else
946                 {
947                     switch (type)
948                     {
949                         case HDR_TYPE_PAD:
950                         case HDR_TYPE_DATA:
951                         case HDR_TYPE_SETUP:
952                             /* Destination is a receiver */
953                             WMEM_COPY_ADDRESS(wmem_packet_scope(), cinfo->addr1, &(pinfo->src));
954                             cinfo->port1 = pinfo->srcport;
955                             WMEM_COPY_ADDRESS(wmem_packet_scope(), cinfo->addr2, &(pinfo->dst));
956                             cinfo->port2 = pinfo->destport;
957                             break;
958                         case HDR_TYPE_NAK:
959                         case HDR_TYPE_SM:
960                             /* Destination is the source */
961                             WMEM_COPY_ADDRESS(wmem_packet_scope(), cinfo->addr1, &(pinfo->dst));
962                             cinfo->port1 = pinfo->destport;
963                             WMEM_COPY_ADDRESS(wmem_packet_scope(), cinfo->addr2, &(pinfo->src));
964                             cinfo->port2 = pinfo->srcport;
965                             break;
966                         default:
967                             break;
968                     }
969                 }
970             }
971             break;
972         default:
973             return (NULL);
974     }
975     return (cinfo);
976 }
977
978 /*----------------------------------------------------------------------------*/
979 /* Handles of all types.                                                      */
980 /*----------------------------------------------------------------------------*/
981
982 /* Dissector tree handles */
983 static gint ett_aeron = -1;
984 static gint ett_aeron_pad = -1;
985 static gint ett_aeron_data = -1;
986 static gint ett_aeron_data_flags = -1;
987 static gint ett_aeron_data_reassembly = -1;
988 static gint ett_aeron_nak = -1;
989 static gint ett_aeron_sm = -1;
990 static gint ett_aeron_sm_flags = -1;
991 static gint ett_aeron_err = -1;
992 static gint ett_aeron_setup = -1;
993 static gint ett_aeron_ext = -1;
994 static gint ett_aeron_sequence_analysis = -1;
995 static gint ett_aeron_sequence_analysis_retransmission_rx = -1;
996 static gint ett_aeron_sequence_analysis_nak_rx = -1;
997 static gint ett_aeron_sequence_analysis_term_offset = -1;
998 static gint ett_aeron_stream_analysis = -1;
999
1000 /* Dissector field handles */
1001 static int hf_aeron_channel_id = -1;
1002 static int hf_aeron_pad = -1;
1003 static int hf_aeron_pad_frame_length = -1;
1004 static int hf_aeron_pad_version = -1;
1005 static int hf_aeron_pad_flags = -1;
1006 static int hf_aeron_pad_type = -1;
1007 static int hf_aeron_pad_term_offset = -1;
1008 static int hf_aeron_pad_session_id = -1;
1009 static int hf_aeron_pad_stream_id = -1;
1010 static int hf_aeron_pad_term_id = -1;
1011 static int hf_aeron_data = -1;
1012 static int hf_aeron_data_frame_length = -1;
1013 static int hf_aeron_data_version = -1;
1014 static int hf_aeron_data_flags = -1;
1015 static int hf_aeron_data_flags_b = -1;
1016 static int hf_aeron_data_flags_e = -1;
1017 static int hf_aeron_data_type = -1;
1018 static int hf_aeron_data_term_offset = -1;
1019 static int hf_aeron_data_next_offset = -1;
1020 static int hf_aeron_data_next_offset_term = -1;
1021 static int hf_aeron_data_next_offset_first_frame = -1;
1022 static int hf_aeron_data_session_id = -1;
1023 static int hf_aeron_data_stream_id = -1;
1024 static int hf_aeron_data_term_id = -1;
1025 static int hf_aeron_data_reassembly = -1;
1026 static int hf_aeron_data_reassembly_fragment = -1;
1027 static int hf_aeron_nak = -1;
1028 static int hf_aeron_nak_frame_length = -1;
1029 static int hf_aeron_nak_version = -1;
1030 static int hf_aeron_nak_flags = -1;
1031 static int hf_aeron_nak_type = -1;
1032 static int hf_aeron_nak_session_id = -1;
1033 static int hf_aeron_nak_stream_id = -1;
1034 static int hf_aeron_nak_term_id = -1;
1035 static int hf_aeron_nak_term_offset = -1;
1036 static int hf_aeron_nak_length = -1;
1037 static int hf_aeron_sm = -1;
1038 static int hf_aeron_sm_frame_length = -1;
1039 static int hf_aeron_sm_version = -1;
1040 static int hf_aeron_sm_flags = -1;
1041 static int hf_aeron_sm_flags_s = -1;
1042 static int hf_aeron_sm_type = -1;
1043 static int hf_aeron_sm_session_id = -1;
1044 static int hf_aeron_sm_stream_id = -1;
1045 static int hf_aeron_sm_consumption_term_id = -1;
1046 static int hf_aeron_sm_consumption_term_offset = -1;
1047 static int hf_aeron_sm_receiver_window = -1;
1048 static int hf_aeron_sm_feedback = -1;
1049 static int hf_aeron_err = -1;
1050 static int hf_aeron_err_frame_length = -1;
1051 static int hf_aeron_err_version = -1;
1052 static int hf_aeron_err_code = -1;
1053 static int hf_aeron_err_type = -1;
1054 static int hf_aeron_err_off_frame_length = -1;
1055 static int hf_aeron_err_off_hdr = -1;
1056 static int hf_aeron_err_string = -1;
1057 static int hf_aeron_setup = -1;
1058 static int hf_aeron_setup_frame_length = -1;
1059 static int hf_aeron_setup_version = -1;
1060 static int hf_aeron_setup_flags = -1;
1061 static int hf_aeron_setup_type = -1;
1062 static int hf_aeron_setup_term_offset = -1;
1063 static int hf_aeron_setup_session_id = -1;
1064 static int hf_aeron_setup_stream_id = -1;
1065 static int hf_aeron_setup_initial_term_id = -1;
1066 static int hf_aeron_setup_active_term_id = -1;
1067 static int hf_aeron_setup_term_length = -1;
1068 static int hf_aeron_setup_mtu = -1;
1069 static int hf_aeron_sequence_analysis = -1;
1070 static int hf_aeron_sequence_analysis_channel_prev_frame = -1;
1071 static int hf_aeron_sequence_analysis_channel_next_frame = -1;
1072 static int hf_aeron_sequence_analysis_stream_prev_frame = -1;
1073 static int hf_aeron_sequence_analysis_stream_next_frame = -1;
1074 static int hf_aeron_sequence_analysis_term_prev_frame = -1;
1075 static int hf_aeron_sequence_analysis_term_next_frame = -1;
1076 static int hf_aeron_sequence_analysis_term_offset = -1;
1077 static int hf_aeron_sequence_analysis_term_offset_frame = -1;
1078 static int hf_aeron_sequence_analysis_retransmission = -1;
1079 static int hf_aeron_sequence_analysis_retransmission_rx = -1;
1080 static int hf_aeron_sequence_analysis_retransmission_rx_frame = -1;
1081 static int hf_aeron_sequence_analysis_keepalive = -1;
1082 static int hf_aeron_sequence_analysis_nak_unrecovered = -1;
1083 static int hf_aeron_sequence_analysis_nak_rx = -1;
1084 static int hf_aeron_sequence_analysis_nak_rx_frame = -1;
1085 static int hf_aeron_stream_analysis = -1;
1086 static int hf_aeron_stream_analysis_high_term_id = -1;
1087 static int hf_aeron_stream_analysis_high_term_offset = -1;
1088 static int hf_aeron_stream_analysis_completed_term_id = -1;
1089 static int hf_aeron_stream_analysis_completed_term_offset = -1;
1090 static int hf_aeron_stream_analysis_outstanding_bytes = -1;
1091
1092 /* Expert info handles */
1093 static expert_field ei_aeron_analysis_nak = EI_INIT;
1094 static expert_field ei_aeron_analysis_window_full = EI_INIT;
1095 static expert_field ei_aeron_analysis_idle_rx = EI_INIT;
1096 static expert_field ei_aeron_analysis_pacing_rx = EI_INIT;
1097 static expert_field ei_aeron_analysis_ooo = EI_INIT;
1098 static expert_field ei_aeron_analysis_ooo_gap = EI_INIT;
1099 static expert_field ei_aeron_analysis_keepalive = EI_INIT;
1100 static expert_field ei_aeron_analysis_ooo_sm = EI_INIT;
1101 static expert_field ei_aeron_analysis_keepalive_sm = EI_INIT;
1102 static expert_field ei_aeron_analysis_window_resize = EI_INIT;
1103 static expert_field ei_aeron_analysis_rx = EI_INIT;
1104 static expert_field ei_aeron_analysis_term_id_change = EI_INIT;
1105
1106 /*----------------------------------------------------------------------------*/
1107 /* Setup packet information                                                   */
1108 /*----------------------------------------------------------------------------*/
1109 typedef struct
1110 {
1111     guint32 info_flags;
1112     guint32 stream_id;
1113     guint32 term_id;
1114     guint32 term_offset;
1115     guint32 length;
1116     guint32 data_length;
1117     guint32 receiver_window;
1118     guint32 nak_term_offset;
1119     guint32 nak_length;
1120     guint16 type;
1121     guint8 flags;
1122 } aeron_packet_info_t;
1123 #define AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID   0x00000001
1124 #define AERON_PACKET_INFO_FLAGS_TERM_ID_VALID     0x00000002
1125 #define AERON_PACKET_INFO_FLAGS_TERM_OFFSET_VALID 0x00000004
1126
1127 static void aeron_frame_nak_rx_add(aeron_frame_info_t * nak_info, aeron_frame_info_t * rx_info, guint32 term_offset, guint32 length)
1128 {
1129     if (nak_info->nak_analysis->unrecovered_length >= length)
1130     {
1131         wmem_list_frame_t * lf = wmem_list_head(nak_info->nak_analysis->rx);
1132         aeron_rx_info_t * rx = NULL;
1133
1134         while (lf != NULL)
1135         {
1136             rx = (aeron_rx_info_t *) wmem_list_frame_data(lf);
1137             if (rx != NULL)
1138             {
1139                 if ((rx->term_offset == term_offset) && (rx->length == length))
1140                 {
1141                     /* Already have this RX */
1142                     return;
1143                 }
1144             }
1145             lf = wmem_list_frame_next(lf);
1146         }
1147         /* This RX frame isn't in the list, so add it */
1148         rx = wmem_new0(wmem_file_scope(), aeron_rx_info_t);
1149         rx->frame_info = rx_info;
1150         rx->term_offset = term_offset;
1151         rx->length = length;
1152         wmem_list_append(nak_info->nak_analysis->rx, (void *) rx);
1153         nak_info->nak_analysis->unrecovered_length -= length;
1154         wmem_list_append(rx_info->rx, (void *) nak_info);
1155     }
1156 }
1157
1158 static void aeron_frame_process_rx(aeron_packet_info_t * info, aeron_frame_info_t * finfo, aeron_term_t * term)
1159 {
1160     wmem_list_frame_t * lf = NULL;
1161
1162     lf = wmem_list_head(term->nak);
1163     while (lf != NULL)
1164     {
1165         aeron_nak_t * nak = (aeron_nak_t *) wmem_list_frame_data(lf);
1166         if (nak != NULL)
1167         {
1168             if (nak->frame_info->frame <= finfo->frame)
1169             {
1170                 if ((nak->term_offset <= info->term_offset) && (nak->length >= info->length))
1171                 {
1172                     /* This data frame falls entirely within the NAK range */
1173                     aeron_frame_nak_rx_add(nak->frame_info, finfo, info->term_offset, info->length);
1174                 }
1175             }
1176         }
1177         lf = wmem_list_frame_next(lf);
1178     }
1179 }
1180
1181 static void aeron_frame_nak_analysis_setup(aeron_packet_info_t * info, aeron_frame_info_t * finfo, aeron_term_t * term)
1182 {
1183     aeron_nak_t * nak = wmem_new0(wmem_file_scope(), aeron_nak_t);
1184     nak->term = term;
1185     nak->frame_info = finfo;
1186     nak->term_offset = info->nak_term_offset;
1187     nak->length = info->nak_length;
1188     wmem_list_append(term->nak, (void *) nak);
1189
1190     finfo->nak_analysis = wmem_new0(wmem_file_scope(), aeron_nak_analysis_t);
1191     finfo->nak_analysis->frame_info = finfo;
1192     finfo->nak_analysis->rx = wmem_list_new(wmem_file_scope());
1193     finfo->nak_analysis->nak_term_offset = info->nak_term_offset;
1194     finfo->nak_analysis->nak_length = info->nak_length;
1195     finfo->nak_analysis->unrecovered_length = info->nak_length;
1196 }
1197
1198 static void aeron_frame_stream_analysis_setup(packet_info * pinfo, aeron_packet_info_t * info, aeron_frame_info_t * finfo, aeron_stream_t * stream, aeron_term_t * term, gboolean new_term)
1199 {
1200     aeron_stream_rcv_t * rcv = NULL;
1201     /*  dp is the current data position (from this frame). */
1202     aeron_pos_t dp = { 0, 0 };
1203     /*
1204         pdp is the previous (high) data position (from the stream).
1205         pdpv is TRUE if pdp is valid (meaning we previously saw a data message).
1206     */
1207     aeron_pos_t pdp = stream->high;
1208     gboolean pdpv = ((stream->flags & AERON_STREAM_FLAGS_HIGH_VALID) != 0);
1209     /*  rp is the current receiver position (from this frame). */
1210     aeron_pos_t rp = { 0, 0 };
1211     /*
1212         prp is the previous (high) receiver completed position (from the stream receiver).
1213         prpv is TRUE if prp is valid (meaning we previously saw a status message).
1214     */
1215     aeron_pos_t prp = { 0, 0 };
1216     gboolean prpv = FALSE;
1217     guint32 cur_receiver_window = 0;
1218     /* Flags to be used when creating the fragment frame entry */
1219     guint32 frame_flags = 0;
1220
1221     if (info->type == HDR_TYPE_SM)
1222     {
1223         /* Locate the receiver */
1224         rcv = aeron_stream_rcv_find(stream, &(pinfo->src), pinfo->srcport);
1225         if (rcv == NULL)
1226         {
1227             rcv = aeron_stream_rcv_add(stream, &(pinfo->src), pinfo->srcport);
1228         }
1229         else
1230         {
1231             prpv = TRUE;
1232             prp = rcv->completed;
1233             cur_receiver_window = rcv->receiver_window;
1234         }
1235     }
1236     switch (info->type)
1237     {
1238         case HDR_TYPE_DATA:
1239         case HDR_TYPE_PAD:
1240             dp.term_id = info->term_id;
1241             dp.term_offset = info->term_offset;
1242             aeron_pos_add_length(&dp, info->length, stream->term_length);
1243             if (pdpv)
1244             {
1245                 if (dp.term_id > stream->high.term_id)
1246                 {
1247                     stream->high.term_id = dp.term_id;
1248                     stream->high.term_offset = dp.term_offset;
1249                 }
1250                 else if (dp.term_offset > stream->high.term_offset)
1251                 {
1252                     stream->high.term_offset = dp.term_offset;
1253                 }
1254             }
1255             else
1256             {
1257                 stream->flags |= AERON_STREAM_FLAGS_HIGH_VALID;
1258                 stream->high.term_id = dp.term_id;
1259                 stream->high.term_offset = dp.term_offset;
1260             }
1261             break;
1262         case HDR_TYPE_SM:
1263             rp.term_id = info->term_id;
1264             rp.term_offset = info->term_offset;
1265             if (prpv)
1266             {
1267                 if (rp.term_id > rcv->completed.term_id)
1268                 {
1269                     rcv->completed.term_id = rp.term_id;
1270                     rcv->completed.term_offset = rp.term_offset;
1271                 }
1272                 else if (rp.term_offset > rcv->completed.term_offset)
1273                 {
1274                     rcv->completed.term_offset = rp.term_offset;
1275                 }
1276             }
1277             else
1278             {
1279                 rcv->completed.term_id = rp.term_id;
1280                 rcv->completed.term_offset = rp.term_offset;
1281             }
1282             rcv->receiver_window = info->receiver_window;
1283             break;
1284         default:
1285             break;
1286     }
1287     if (aeron_stream_analysis)
1288     {
1289         if ((stream->flags & AERON_STREAM_FLAGS_HIGH_VALID) != 0)
1290         {
1291             finfo->stream_analysis = wmem_new0(wmem_file_scope(), aeron_stream_analysis_t);
1292         }
1293     }
1294     if (finfo->stream_analysis != NULL)
1295     {
1296         switch (info->type)
1297         {
1298             case HDR_TYPE_DATA:
1299             case HDR_TYPE_SM:
1300             case HDR_TYPE_PAD:
1301                 finfo->stream_analysis->high.term_id = stream->high.term_id;
1302                 finfo->stream_analysis->high.term_offset = stream->high.term_offset;
1303                 if (rcv != NULL)
1304                 {
1305                     finfo->stream_analysis->flags2 |= AERON_STREAM_ANALYSIS_FLAGS2_RCV_VALID;
1306                     finfo->stream_analysis->completed.term_id = rcv->completed.term_id;
1307                     finfo->stream_analysis->completed.term_offset = rcv->completed.term_offset;
1308                     finfo->stream_analysis->receiver_window = rcv->receiver_window;
1309                     finfo->stream_analysis->outstanding_bytes = aeron_pos_delta(&(finfo->stream_analysis->high), &(finfo->stream_analysis->completed), stream->term_length);
1310                     if (finfo->stream_analysis->outstanding_bytes >= finfo->stream_analysis->receiver_window)
1311                     {
1312                         finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_WINDOW_FULL;
1313                     }
1314                 }
1315                 else
1316                 {
1317                     finfo->stream_analysis->completed.term_id = 0;
1318                     finfo->stream_analysis->completed.term_offset = 0;
1319                     finfo->stream_analysis->receiver_window = 0;
1320                     finfo->stream_analysis->outstanding_bytes = 0;
1321                 }
1322                 break;
1323             default:
1324                 break;
1325         }
1326         switch (info->type)
1327         {
1328             case HDR_TYPE_DATA:
1329             case HDR_TYPE_PAD:
1330                 if (pdpv)
1331                 {
1332                     /* We have a previous data position. */
1333                     int rc = aeron_pos_compare(&dp, &pdp);
1334                     if (rc == 0)
1335                     {
1336                         /* Data position is the same as previous data position. */
1337                         if (info->length == 0)
1338                         {
1339                             finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE;
1340                             frame_flags |= AERON_FRAME_INFO_FLAGS_KEEPALIVE;
1341                         }
1342                         else
1343                         {
1344                             if (prpv)
1345                             {
1346                                 /* Previous receiver position is valid */
1347                                 if (aeron_pos_compare(&dp, &prp) == 0)
1348                                 {
1349                                     finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_IDLE_RX;
1350                                 }
1351                                 else
1352                                 {
1353                                     finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_PACING_RX;
1354                                 }
1355                             }
1356                             else
1357                             {
1358                                 finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_IDLE_RX;
1359                             }
1360                             frame_flags |= AERON_FRAME_INFO_FLAGS_RETRANSMISSION;
1361                         }
1362                     }
1363                     else
1364                     {
1365                         aeron_pos_t expected_dp;
1366                         int erc;
1367
1368                         expected_dp.term_id = pdp.term_id;
1369                         expected_dp.term_offset = pdp.term_offset;
1370                         aeron_pos_add_length(&expected_dp, info->length, stream->term_length);
1371                         erc = aeron_pos_compare(&expected_dp, &dp);
1372                         if (erc > 0)
1373                         {
1374                             /* Could be OOO - but for now assume it's a RX */
1375                             finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_RX;
1376                             frame_flags |= AERON_FRAME_INFO_FLAGS_RETRANSMISSION;
1377                             aeron_frame_process_rx(info, finfo, term);
1378                         }
1379                         else if (erc < 0)
1380                         {
1381                             finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_OOO_GAP;
1382                         }
1383                     }
1384                 }
1385                 if (new_term && (info->term_offset == 0))
1386                 {
1387                     finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_TERM_ID_CHANGE;
1388                 }
1389                 break;
1390             case HDR_TYPE_SM:
1391                 if (prpv)
1392                 {
1393                     int rc = aeron_pos_compare(&rp, &prp);
1394                     if (rc == 0)
1395                     {
1396                         /* Completed term ID and term offset stayed the same. */
1397                        finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE_SM;
1398                     }
1399                     else if (rc < 0)
1400                     {
1401                         finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_OOO_SM;
1402                     }
1403                     if (cur_receiver_window != finfo->stream_analysis->receiver_window)
1404                     {
1405                         finfo->stream_analysis->flags |= AERON_STREAM_ANALYSIS_FLAGS_WINDOW_RESIZE;
1406                     }
1407                 }
1408                 break;
1409             default:
1410                 break;
1411         }
1412     }
1413     if ((info->type == HDR_TYPE_DATA) || (info->type == HDR_TYPE_PAD))
1414     {
1415         aeron_fragment_t * fragment = NULL;
1416
1417         fragment = aeron_term_fragment_find(term, info->term_offset);
1418         if (fragment == NULL)
1419         {
1420             fragment = aeron_term_fragment_add(term, info->term_offset, info->length, info->data_length);
1421         }
1422         aeron_fragment_frame_add(fragment, finfo, frame_flags, info->length);
1423     }
1424     else
1425     {
1426         aeron_term_frame_add(term, finfo, frame_flags);
1427     }
1428 }
1429
1430 static void aeron_frame_info_setup(packet_info * pinfo, aeron_transport_t * transport, aeron_packet_info_t * info, aeron_frame_info_t * finfo)
1431 {
1432     if (transport != NULL)
1433     {
1434         if (aeron_sequence_analysis && (finfo != NULL))
1435         {
1436             if (PINFO_FD_VISITED(pinfo) == 0)
1437             {
1438                 if ((info->info_flags & AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID) != 0)
1439                 {
1440                     aeron_stream_t * stream = NULL;
1441
1442                     stream = aeron_transport_stream_find(transport, info->stream_id);
1443                     if (stream == NULL)
1444                     {
1445                         stream = aeron_transport_stream_add(transport, info->stream_id);
1446                     }
1447                     if ((info->info_flags & AERON_PACKET_INFO_FLAGS_TERM_ID_VALID) != 0)
1448                     {
1449                         aeron_term_t * term = NULL;
1450                         gboolean new_term = FALSE;
1451
1452                         term = aeron_stream_term_find(stream, info->term_id);
1453                         if (term == NULL)
1454                         {
1455                             term = aeron_stream_term_add(stream, info->term_id);
1456                             new_term = TRUE;
1457                         }
1458                         if ((info->info_flags & AERON_PACKET_INFO_FLAGS_TERM_OFFSET_VALID) != 0)
1459                         {
1460                             aeron_frame_stream_analysis_setup(pinfo, info, finfo, stream, term, new_term);
1461                         }
1462                         else
1463                         {
1464                             aeron_term_frame_add(term, finfo, 0);
1465                             if (info->type == HDR_TYPE_NAK)
1466                             {
1467                                 aeron_frame_nak_analysis_setup(info, finfo, term);
1468                             }
1469                         }
1470                     }
1471                     else
1472                     {
1473                         aeron_stream_frame_add(stream, finfo, 0);
1474                     }
1475                 }
1476                 else
1477                 {
1478                     aeron_transport_frame_add(transport, finfo, 0);
1479                 }
1480             }
1481         }
1482     }
1483 }
1484
1485 static void aeron_sequence_report_frame(tvbuff_t * tvb, proto_tree * tree, aeron_frame_info_t * finfo)
1486 {
1487     proto_item * item = NULL;
1488
1489     if ((finfo->flags & AERON_FRAME_INFO_FLAGS_RETRANSMISSION) != 0)
1490     {
1491         item = proto_tree_add_uint_format_value(tree, hf_aeron_sequence_analysis_term_offset_frame, tvb, 0, 0, finfo->frame, "%" G_GUINT32_FORMAT " (RX)", finfo->frame);
1492     }
1493     else if ((finfo->flags & AERON_FRAME_INFO_FLAGS_KEEPALIVE) != 0)
1494     {
1495         item = proto_tree_add_uint_format_value(tree, hf_aeron_sequence_analysis_term_offset_frame, tvb, 0, 0, finfo->frame, "%" G_GUINT32_FORMAT " (KA)", finfo->frame);
1496     }
1497     else
1498     {
1499         item = proto_tree_add_uint(tree, hf_aeron_sequence_analysis_term_offset_frame, tvb, 0, 0, finfo->frame);
1500     }
1501     PROTO_ITEM_SET_GENERATED(item);
1502 }
1503
1504 static void aeron_sequence_report(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, aeron_transport_t * transport, aeron_packet_info_t * info, aeron_frame_info_t * finfo)
1505 {
1506     if (transport != NULL)
1507     {
1508         if (aeron_sequence_analysis && (finfo != NULL))
1509         {
1510             proto_tree * subtree = NULL;
1511             proto_item * item = NULL;
1512
1513             item = proto_tree_add_item(tree, hf_aeron_sequence_analysis, tvb, 0, 0, ENC_NA);
1514             PROTO_ITEM_SET_GENERATED(item);
1515             subtree = proto_item_add_subtree(item, ett_aeron_sequence_analysis);
1516             if (finfo->transport.previous != 0)
1517             {
1518                 item = proto_tree_add_uint(subtree, hf_aeron_sequence_analysis_channel_prev_frame, tvb, 0, 0, finfo->transport.previous);
1519                 PROTO_ITEM_SET_GENERATED(item);
1520             }
1521             if (finfo->transport.next != 0)
1522             {
1523                 item = proto_tree_add_uint(subtree, hf_aeron_sequence_analysis_channel_next_frame, tvb, 0, 0, finfo->transport.next);
1524                 PROTO_ITEM_SET_GENERATED(item);
1525             }
1526             if ((info->info_flags & AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID) != 0)
1527             {
1528                 aeron_stream_t * stream = NULL;
1529
1530                 stream = aeron_transport_stream_find(transport, info->stream_id);
1531                 if (stream != NULL)
1532                 {
1533                     if (finfo->stream.previous != 0)
1534                     {
1535                         item = proto_tree_add_uint(subtree, hf_aeron_sequence_analysis_stream_prev_frame, tvb, 0, 0, finfo->stream.previous);
1536                         PROTO_ITEM_SET_GENERATED(item);
1537                     }
1538                     if (finfo->stream.next != 0)
1539                     {
1540                         item = proto_tree_add_uint(subtree, hf_aeron_sequence_analysis_stream_next_frame, tvb, 0, 0, finfo->stream.next);
1541                         PROTO_ITEM_SET_GENERATED(item);
1542                     }
1543                     if ((info->info_flags & AERON_PACKET_INFO_FLAGS_TERM_ID_VALID) != 0)
1544                     {
1545                         aeron_term_t * term = NULL;
1546
1547                         term = aeron_stream_term_find(stream, info->term_id);
1548                         if (term != NULL)
1549                         {
1550                             if (finfo->term.previous != 0)
1551                             {
1552                                 item = proto_tree_add_uint(subtree, hf_aeron_sequence_analysis_term_prev_frame, tvb, 0, 0, finfo->term.previous);
1553                                 PROTO_ITEM_SET_GENERATED(item);
1554                             }
1555                             if (finfo->term.next != 0)
1556                             {
1557                                 item = proto_tree_add_uint(subtree, hf_aeron_sequence_analysis_term_next_frame, tvb, 0, 0, finfo->term.next);
1558                                 PROTO_ITEM_SET_GENERATED(item);
1559                             }
1560                             if ((info->info_flags & AERON_PACKET_INFO_FLAGS_TERM_OFFSET_VALID) != 0)
1561                             {
1562                                 if ((info->type == HDR_TYPE_DATA) || (info->type == HDR_TYPE_PAD))
1563                                 {
1564                                     aeron_fragment_t * fragment = NULL;
1565
1566                                     fragment = aeron_term_fragment_find(term, info->term_offset);
1567                                     if (fragment != NULL)
1568                                     {
1569                                         proto_item * fei_item = NULL;
1570                                         gboolean rx = ((finfo->flags & AERON_FRAME_INFO_FLAGS_RETRANSMISSION) != 0);
1571                                         gboolean ka = ((finfo->flags & AERON_FRAME_INFO_FLAGS_KEEPALIVE) != 0);
1572
1573                                         if (fragment->frame_count > 1)
1574                                         {
1575                                             proto_tree * frame_tree = NULL;
1576                                             proto_item * frame_item = NULL;
1577                                             wmem_list_frame_t * lf = NULL;
1578
1579                                             frame_item = proto_tree_add_item(subtree, hf_aeron_sequence_analysis_term_offset, tvb, 0, 0, ENC_NA);
1580                                             PROTO_ITEM_SET_GENERATED(frame_item);
1581                                             frame_tree = proto_item_add_subtree(frame_item, ett_aeron_sequence_analysis_term_offset);
1582                                             lf = wmem_list_head(fragment->frame);
1583                                             while (lf != NULL)
1584                                             {
1585                                                 aeron_frame_info_t * frag_frame = (aeron_frame_info_t *) wmem_list_frame_data(lf);
1586                                                 if (frag_frame != NULL)
1587                                                 {
1588                                                     if (frag_frame->frame != pinfo->fd->num)
1589                                                     {
1590                                                         aeron_sequence_report_frame(tvb, frame_tree, frag_frame);
1591                                                     }
1592                                                 }
1593                                                 lf = wmem_list_frame_next(lf);
1594                                             }
1595                                         }
1596                                         fei_item = proto_tree_add_boolean(subtree, hf_aeron_sequence_analysis_retransmission, tvb, 0, 0, rx);
1597                                         PROTO_ITEM_SET_GENERATED(fei_item);
1598                                         if (rx)
1599                                         {
1600                                             if (wmem_list_count(finfo->rx) > 0)
1601                                             {
1602                                                 proto_tree * rx_tree = NULL;
1603                                                 proto_item * rx_item = NULL;
1604                                                 wmem_list_frame_t * lf = NULL;
1605
1606                                                 rx_item = proto_tree_add_item(subtree, hf_aeron_sequence_analysis_retransmission_rx, tvb, 0, 0, ENC_NA);
1607                                                 PROTO_ITEM_SET_GENERATED(rx_item);
1608                                                 rx_tree = proto_item_add_subtree(rx_item, ett_aeron_sequence_analysis_retransmission_rx);
1609                                                 lf = wmem_list_head(finfo->rx);
1610                                                 while (lf != NULL)
1611                                                 {
1612                                                     aeron_frame_info_t * nak = (aeron_frame_info_t *) wmem_list_frame_data(lf);
1613                                                     if (nak != NULL)
1614                                                     {
1615                                                         rx_item = proto_tree_add_uint(rx_tree, hf_aeron_sequence_analysis_retransmission_rx_frame, tvb, 0, 0, nak->frame);
1616                                                         PROTO_ITEM_SET_GENERATED(rx_item);
1617                                                     }
1618                                                     lf = wmem_list_frame_next(lf);
1619                                                 }
1620                                             }
1621                                         }
1622                                         fei_item = proto_tree_add_boolean(subtree, hf_aeron_sequence_analysis_keepalive, tvb, 0, 0, ka);
1623                                         PROTO_ITEM_SET_GENERATED(fei_item);
1624                                     }
1625                                 }
1626                             }
1627                             else if ((info->type == HDR_TYPE_NAK) && (finfo->nak_analysis != NULL))
1628                             {
1629                                 proto_item * nak_item = NULL;
1630
1631                                 nak_item = proto_tree_add_uint(subtree, hf_aeron_sequence_analysis_nak_unrecovered, tvb, 0, 0, finfo->nak_analysis->unrecovered_length);
1632                                 PROTO_ITEM_SET_GENERATED(nak_item);
1633                                 if (wmem_list_count(finfo->nak_analysis->rx) > 0)
1634                                 {
1635                                     proto_tree * rx_tree = NULL;
1636                                     proto_item * rx_item = NULL;
1637                                     wmem_list_frame_t * lf = NULL;
1638
1639                                     rx_item = proto_tree_add_item(subtree, hf_aeron_sequence_analysis_nak_rx, tvb, 0, 0, ENC_NA);
1640                                     PROTO_ITEM_SET_GENERATED(rx_item);
1641                                     rx_tree = proto_item_add_subtree(rx_item, ett_aeron_sequence_analysis_nak_rx);
1642                                     lf = wmem_list_head(finfo->nak_analysis->rx);
1643                                     while (lf != NULL)
1644                                     {
1645                                         aeron_rx_info_t * rx = (aeron_rx_info_t *) wmem_list_frame_data(lf);
1646                                         if (rx != NULL)
1647                                         {
1648                                             rx_item = proto_tree_add_uint_format_value(rx_tree, hf_aeron_sequence_analysis_nak_rx_frame, tvb, 0, 0, rx->frame_info->frame,
1649                                                 "%" G_GUINT32_FORMAT ", Term offset=%" G_GUINT32_FORMAT " (0x%08x), Length=%" G_GUINT32_FORMAT, rx->frame_info->frame, rx->term_offset, rx->term_offset, rx->length);
1650                                             PROTO_ITEM_SET_GENERATED(rx_item);
1651                                         }
1652                                         lf = wmem_list_frame_next(lf);
1653                                     }
1654                                 }
1655                             }
1656                         }
1657                     }
1658                 }
1659             }
1660         }
1661     }
1662 }
1663
1664 static void aeron_stream_report(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, aeron_transport_t * transport, aeron_frame_info_t * finfo)
1665 {
1666     if (transport != NULL)
1667     {
1668         if (aeron_sequence_analysis && aeron_stream_analysis && (finfo != NULL) && (finfo->stream_analysis != NULL))
1669         {
1670             proto_tree * subtree = NULL;
1671             proto_item * item = NULL;
1672
1673             item = proto_tree_add_item(tree, hf_aeron_stream_analysis, tvb, 0, 0, ENC_NA);
1674             PROTO_ITEM_SET_GENERATED(item);
1675             subtree = proto_item_add_subtree(item, ett_aeron_stream_analysis);
1676             item = proto_tree_add_uint(subtree, hf_aeron_stream_analysis_high_term_id, tvb, 0, 0, finfo->stream_analysis->high.term_id);
1677             if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_TERM_ID_CHANGE) != 0)
1678             {
1679                 expert_add_info(pinfo, item, &ei_aeron_analysis_term_id_change);
1680             }
1681             PROTO_ITEM_SET_GENERATED(item);
1682             item = proto_tree_add_uint(subtree, hf_aeron_stream_analysis_high_term_offset, tvb, 0, 0, finfo->stream_analysis->high.term_offset);
1683             PROTO_ITEM_SET_GENERATED(item);
1684             if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_IDLE_RX) != 0)
1685             {
1686                 expert_add_info(pinfo, item, &ei_aeron_analysis_idle_rx);
1687             }
1688             if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_PACING_RX) != 0)
1689             {
1690                 expert_add_info(pinfo, item, &ei_aeron_analysis_pacing_rx);
1691             }
1692             if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_OOO) != 0)
1693             {
1694                 expert_add_info(pinfo, item, &ei_aeron_analysis_ooo);
1695             }
1696             if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_OOO_GAP) != 0)
1697             {
1698                 expert_add_info(pinfo, item, &ei_aeron_analysis_ooo_gap);
1699             }
1700             if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE) != 0)
1701             {
1702                 expert_add_info(pinfo, item, &ei_aeron_analysis_keepalive);
1703             }
1704             if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_RX) != 0)
1705             {
1706                 expert_add_info(pinfo, item, &ei_aeron_analysis_rx);
1707             }
1708             if ((finfo->stream_analysis->flags2 & AERON_STREAM_ANALYSIS_FLAGS2_RCV_VALID) != 0)
1709             {
1710                 item = proto_tree_add_uint(subtree, hf_aeron_stream_analysis_completed_term_id, tvb, 0, 0, finfo->stream_analysis->completed.term_id);
1711                 PROTO_ITEM_SET_GENERATED(item);
1712                 item = proto_tree_add_uint(subtree, hf_aeron_stream_analysis_completed_term_offset, tvb, 0, 0, finfo->stream_analysis->completed.term_offset);
1713                 PROTO_ITEM_SET_GENERATED(item);
1714                 if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_OOO_SM) != 0)
1715                 {
1716                     expert_add_info(pinfo, item, &ei_aeron_analysis_ooo_sm);
1717                 }
1718                 if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE_SM) != 0)
1719                 {
1720                     expert_add_info(pinfo, item, &ei_aeron_analysis_keepalive_sm);
1721                 }
1722                 item = proto_tree_add_uint(subtree, hf_aeron_stream_analysis_outstanding_bytes, tvb, 0, 0, finfo->stream_analysis->outstanding_bytes);
1723                 PROTO_ITEM_SET_GENERATED(item);
1724                 if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_WINDOW_FULL) != 0)
1725                 {
1726                     expert_add_info(pinfo, item, &ei_aeron_analysis_window_full);
1727                 }
1728             }
1729         }
1730     }
1731 }
1732
1733 static void aeron_next_offset_report(tvbuff_t * tvb, proto_tree * tree, aeron_transport_t * transport, guint32 stream_id, guint32 term_id, guint32 term_offset, guint32 length)
1734 {
1735     aeron_stream_t * stream = NULL;
1736     proto_item * item = NULL;
1737
1738     stream = aeron_transport_stream_find(transport, stream_id);
1739     if (stream != NULL)
1740     {
1741         aeron_term_t * term = NULL;
1742         if (stream->term_length == 0)
1743         {
1744             stream->term_length = length;
1745         }
1746         term = aeron_stream_term_find(stream, term_id);
1747         if (term != NULL)
1748         {
1749             aeron_fragment_t * fragment = aeron_term_fragment_find(term, term_offset);
1750             if (fragment != NULL)
1751             {
1752                 guint32 next_offset = term_offset + length;
1753                 guint32 next_offset_term_id = term_id;
1754                 guint32 next_offset_first_frame = 0;
1755                 aeron_fragment_t * next_offset_fragment = NULL;
1756                 aeron_term_t * next_offset_term = NULL;
1757
1758                 if (next_offset >= stream->term_length)
1759                 {
1760                     next_offset = 0;
1761                     next_offset_term_id++;
1762                 }
1763                 item = proto_tree_add_uint(tree, hf_aeron_data_next_offset, tvb, 0, 0, next_offset);
1764                 PROTO_ITEM_SET_GENERATED(item);
1765                 if (next_offset_term_id != term_id)
1766                 {
1767                     next_offset_term = aeron_stream_term_find(stream, next_offset_term_id);
1768                     item = proto_tree_add_uint(tree, hf_aeron_data_next_offset_term, tvb, 0, 0, next_offset_term_id);
1769                     PROTO_ITEM_SET_GENERATED(item);
1770                 }
1771                 else
1772                 {
1773                     next_offset_term = term;
1774                 }
1775                 if (next_offset_term != NULL)
1776                 {
1777                     next_offset_fragment = aeron_term_fragment_find(next_offset_term, next_offset);
1778                     if (next_offset_fragment != NULL)
1779                     {
1780                         if (next_offset_fragment->first_frame != NULL)
1781                         {
1782                             next_offset_first_frame = next_offset_fragment->first_frame->frame;
1783                             item = proto_tree_add_uint(tree, hf_aeron_data_next_offset_first_frame, tvb, 0, 0, next_offset_first_frame);
1784                             PROTO_ITEM_SET_GENERATED(item);
1785                         }
1786                     }
1787                 }
1788             }
1789         }
1790     }
1791 }
1792
1793 static void aeron_info_stream_progress_report(packet_info * pinfo, guint16 msgtype, guint8 flags, guint32 term_id, guint32 term_offset, aeron_frame_info_t * finfo)
1794 {
1795     const gchar * type_string = val_to_str_const((guint32) msgtype, aeron_frame_type, "Unknown");
1796
1797     if (aeron_sequence_analysis && aeron_stream_analysis && (finfo != NULL) && (finfo->stream_analysis != NULL))
1798     {
1799         switch (msgtype)
1800         {
1801             case HDR_TYPE_PAD:
1802             case HDR_TYPE_DATA:
1803                 if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE) != 0)
1804                 {
1805                     col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s-KA", type_string);
1806                 }
1807                 else
1808                 {
1809                     col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s (0x%08x:%" G_GUINT32_FORMAT ")",
1810                         type_string, term_id, term_offset);
1811                 }
1812                 break;
1813             case HDR_TYPE_SM:
1814                 if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_KEEPALIVE_SM) != 0)
1815                 {
1816                     col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s-KA", type_string);
1817                 }
1818                 else
1819                 {
1820                     if (finfo->stream_analysis->high.term_id == finfo->stream_analysis->completed.term_id)
1821                     {
1822                         col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s (%" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT " [%" G_GUINT32_FORMAT "])",
1823                             type_string, finfo->stream_analysis->high.term_offset, finfo->stream_analysis->completed.term_offset, finfo->stream_analysis->outstanding_bytes);
1824                     }
1825                     else
1826                     {
1827                         col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s (0x%08x:%" G_GUINT32_FORMAT "/0x%08x:%" G_GUINT32_FORMAT " [%" G_GUINT32_FORMAT "])",
1828                             type_string, finfo->stream_analysis->high.term_id, finfo->stream_analysis->high.term_offset, finfo->stream_analysis->completed.term_id, finfo->stream_analysis->completed.term_offset, finfo->stream_analysis->outstanding_bytes);
1829                     }
1830                 }
1831                 break;
1832         }
1833     }
1834     else
1835     {
1836         if ((msgtype == HDR_TYPE_SM) && ((flags & STATUS_FLAGS_SETUP) != 0))
1837         {
1838             col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s-SETUP", type_string);
1839         }
1840         else
1841         {
1842             col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", type_string);
1843         }
1844     }
1845 }
1846
1847 /*----------------------------------------------------------------------------*/
1848 /* Payload reassembly.                                                        */
1849 /*----------------------------------------------------------------------------*/
1850 struct aeron_msg_fragment_t_stct;
1851 typedef struct aeron_msg_fragment_t_stct aeron_msg_fragment_t;
1852
1853 struct aeron_msg_t_stct
1854 {
1855     wmem_list_t * fragment;
1856     aeron_term_t * term;
1857     tvbuff_t * reassembled_data;
1858     guint32 first_fragment_term_offset;
1859     guint32 next_expected_term_offset;
1860     guint32 length;                 /* Total message payload length */
1861     guint32 frame_length;           /* Total length of all message frames accumulated */
1862     guint32 fragment_count;         /* Number of fragments in this message */
1863     guint32 contiguous_length;      /* Number of contiguous frame bytes accumulated for this message */
1864     guint32 begin_frame;            /* Data frame in which the B flag was set */
1865     guint32 first_frame;            /* Lowest-numbered frame which is part of this message */
1866     guint32 end_frame;              /* Data frame in which the E flag was set */
1867     guint32 last_frame;             /* Highest-numbered frame which is part of this message */
1868     gboolean complete;
1869 };
1870
1871 struct aeron_msg_fragment_t_stct
1872 {
1873     gchar * data;
1874     guint32 term_offset;            /* Term offset for entire fragment */
1875     guint32 frame_length;           /* Length of entire frame/fragment */
1876     guint32 data_length;            /* Payload length */
1877     guint32 frame;                  /* Frame in which the fragment resides */
1878     gint frame_offset;              /* Offset into the frame for the entire Aeron message */
1879     guint8 flags;                   /* Frame data flags */
1880 };
1881
1882 static void aeron_msg_fragment_add(aeron_msg_t * msg, aeron_msg_fragment_t * fragment)
1883 {
1884     /* Add the fragment to the message */
1885     wmem_list_append(msg->fragment, (void *) fragment);
1886     /* Update the message */
1887     msg->length += fragment->data_length;
1888     msg->contiguous_length += fragment->data_length;
1889     msg->fragment_count++;
1890     if (msg->first_frame > fragment->frame)
1891     {
1892         msg->first_frame = fragment->frame;
1893     }
1894     if (msg->last_frame < fragment->frame)
1895     {
1896         msg->last_frame = fragment->frame;
1897     }
1898     msg->next_expected_term_offset += fragment->frame_length;
1899     if ((fragment->flags & DATA_FLAGS_END) == DATA_FLAGS_END)
1900     {
1901         gchar * buf = NULL;
1902         wmem_list_frame_t * lf = NULL;
1903         size_t ofs = 0;
1904         size_t accum_len = 0;
1905         guint32 last_frame_offset = 0;
1906         gboolean last_frame_found = FALSE;
1907         aeron_frame_info_t * finfo = NULL;
1908
1909         msg->complete = TRUE;
1910         msg->end_frame = fragment->frame;
1911         buf = (gchar *) wmem_alloc(wmem_file_scope(), (size_t) msg->length);
1912         lf = wmem_list_head(msg->fragment);
1913         while (lf != NULL)
1914         {
1915             aeron_msg_fragment_t * cur_frag = (aeron_msg_fragment_t *) wmem_list_frame_data(lf);
1916             if (cur_frag != NULL)
1917             {
1918                 if (cur_frag->frame == msg->last_frame)
1919                 {
1920                     last_frame_offset = cur_frag->frame_offset;
1921                     last_frame_found = TRUE;
1922                 }
1923                 memcpy((void *) (buf + ofs), (void *) cur_frag->data, (size_t) cur_frag->data_length);
1924                 ofs += (size_t) cur_frag->data_length;
1925                 accum_len += (size_t) cur_frag->data_length;
1926             }
1927             lf = wmem_list_frame_next(lf);
1928         }
1929         DISSECTOR_ASSERT(accum_len == (size_t) msg->length);
1930         DISSECTOR_ASSERT(last_frame_found == TRUE);
1931         if (last_frame_found)
1932         {
1933             finfo = aeron_frame_info_find(msg->last_frame, last_frame_offset);
1934         }
1935         msg->reassembled_data = tvb_new_real_data(buf, msg->length, msg->length);
1936         DISSECTOR_ASSERT(finfo != NULL);
1937         if (finfo != NULL)
1938         {
1939             finfo->flags |= AERON_FRAME_INFO_FLAGS_REASSEMBLED_MSG;
1940             finfo->message = msg;
1941         }
1942     }
1943 }
1944
1945 static gboolean aeron_msg_process_orphan_fragments_msg_cb(void * value, void * userdata)
1946 {
1947     aeron_msg_t * msg = (aeron_msg_t *) value;
1948     aeron_term_t * term = (aeron_term_t *) userdata;
1949     gboolean frag_found = FALSE;
1950     wmem_list_frame_t * lf = NULL;
1951     aeron_msg_fragment_t * frag = NULL;
1952
1953     if (msg->complete)
1954     {
1955         /* This message is complete, no need to check for orphans */
1956         return (FALSE);
1957     }
1958     /* Scan through the orphan fragments */
1959     while (TRUE)
1960     {
1961         lf = wmem_list_head(term->orphan_fragment);
1962         while (lf != NULL)
1963         {
1964             frag = (aeron_msg_fragment_t *) wmem_list_frame_data(lf);
1965             if (frag != NULL)
1966             {
1967                 if (msg->next_expected_term_offset == frag->term_offset)
1968                 {
1969                     /* Found one! Remove it from the orphan list, and add it to the message */
1970                     wmem_list_remove_frame(term->orphan_fragment, lf);
1971                     aeron_msg_fragment_add(msg, frag);
1972                     frag_found = TRUE;
1973                     break;
1974                 }
1975             }
1976             lf = wmem_list_frame_next(lf);
1977         }
1978         if (!frag_found)
1979         {
1980             break;
1981         }
1982         frag_found = FALSE;
1983     }
1984     return (FALSE);
1985 }
1986
1987 static void aeron_msg_process_orphan_fragments(aeron_term_t * term)
1988 {
1989     /* If we have no orphan fragments to process, nothing to do. */
1990     if (wmem_list_count(term->orphan_fragment) == 0)
1991     {
1992         return;
1993     }
1994     wmem_tree_foreach(term->message, aeron_msg_process_orphan_fragments_msg_cb, (void *) term);
1995 }
1996
1997 static aeron_msg_fragment_t * aeron_msg_fragment_create(tvbuff_t * tvb, int offset, packet_info * pinfo, aeron_packet_info_t * info)
1998 {
1999     aeron_msg_fragment_t * frag = NULL;
2000
2001     frag = wmem_new0(wmem_file_scope(), aeron_msg_fragment_t);
2002     frag->term_offset = info->term_offset;
2003     frag->frame_length = info->length;
2004     frag->data_length = info->data_length;
2005     frag->frame = pinfo->fd->num;
2006     frag->frame_offset = offset;
2007     frag->data = (gchar *) tvb_memdup(wmem_file_scope(), tvb, frag->frame_offset + O_AERON_DATA_DATA, (size_t) frag->data_length);
2008     frag->flags = info->flags;
2009     return (frag);
2010 }
2011
2012 static aeron_msg_fragment_t * aeron_msg_fragment_find(aeron_msg_t * message, aeron_packet_info_t * info)
2013 {
2014     aeron_msg_fragment_t * frag = NULL;
2015     wmem_list_frame_t * lf = NULL;
2016
2017     if (message->next_expected_term_offset < info->term_offset)
2018     {
2019         return (NULL);
2020     }
2021     lf = wmem_list_head(message->fragment);
2022     while (lf != NULL)
2023     {
2024         frag = (aeron_msg_fragment_t *) wmem_list_frame_data(lf);
2025         if (frag != NULL)
2026         {
2027             if (frag->term_offset == info->term_offset)
2028             {
2029                 break;
2030             }
2031         }
2032         lf = wmem_list_frame_next(lf);
2033     }
2034     return (frag);
2035 }
2036
2037 static aeron_msg_t * aeron_term_msg_find_le(aeron_term_t * term, guint32 term_offset)
2038 {
2039     /* Return the last aeron_msg_t with starting_fragment_term_offset <= offset */
2040     aeron_msg_t * msg = (aeron_msg_t *) wmem_tree_lookup32_le(term->message, term_offset);
2041     return (msg);
2042 }
2043
2044 static aeron_msg_t * aeron_term_msg_add(aeron_term_t * term, packet_info * pinfo, aeron_packet_info_t * info)
2045 {
2046     aeron_msg_t * pos = NULL;
2047     aeron_msg_t * msg = NULL;
2048
2049     pos = aeron_term_msg_find_le(term, info->term_offset);
2050     if ((pos != NULL) && (pos->first_fragment_term_offset == info->term_offset))
2051     {
2052         return (pos);
2053     }
2054     msg = wmem_new0(wmem_file_scope(), aeron_msg_t);
2055     msg->fragment = wmem_list_new(wmem_file_scope());
2056     msg->term = term;
2057     msg->reassembled_data = NULL;
2058     msg->first_fragment_term_offset = info->term_offset;
2059     msg->next_expected_term_offset = info->term_offset;
2060     msg->length = 0;
2061     msg->frame_length = 0;
2062     msg->fragment_count = 0;
2063     msg->contiguous_length = 0;
2064     msg->begin_frame = pinfo->fd->num;
2065     msg->first_frame = pinfo->fd->num;
2066     msg->end_frame = 0;
2067     msg->last_frame = 0;
2068     msg->complete = FALSE;
2069     wmem_tree_insert32(term->message, msg->first_fragment_term_offset, (void *) msg);
2070     return (msg);
2071 }
2072
2073 static void aeron_msg_process(tvbuff_t * tvb, int offset, packet_info * pinfo, aeron_transport_t * transport, aeron_packet_info_t * info, aeron_frame_info_t * finfo _U_)
2074 {
2075     if (aeron_reassemble_fragments && (PINFO_FD_VISITED(pinfo) == 0))
2076     {
2077         if ((info->flags & DATA_FLAGS_COMPLETE) != DATA_FLAGS_COMPLETE)
2078         {
2079             aeron_stream_t * stream = aeron_transport_stream_find(transport, info->stream_id);
2080             if (stream != NULL)
2081             {
2082                 aeron_term_t * term = aeron_stream_term_find(stream, info->term_id);
2083                 if (term != NULL)
2084                 {
2085                     aeron_msg_t * msg = NULL;
2086                     aeron_msg_fragment_t * frag = NULL;
2087
2088                     if ((info->flags & DATA_FLAGS_BEGIN) == DATA_FLAGS_BEGIN)
2089                     {
2090                         /* Beginning of a message. First see if this message already exists. */
2091                         msg = aeron_term_msg_find_le(term, info->term_offset);
2092                         if (msg != NULL)
2093                         {
2094                             if (msg->first_fragment_term_offset != info->term_offset)
2095                             {
2096                                 /*
2097                                     A message start with a term offset:
2098                                         1) Between two existing messages for this term, or
2099                                         2) Less than the first message for this term
2100                                     Likely this was caused by an RX or out-of-order packet. Need to create a new one.
2101                                 */
2102                                 msg = NULL;
2103                             }
2104                         }
2105                         if (msg == NULL)
2106                         {
2107                             msg = aeron_term_msg_add(term, pinfo, info);
2108                         }
2109                     }
2110                     else
2111                     {
2112                         /* End of message, or middle of message. See if we already have a message with a smaller starting term offset */
2113                         msg = aeron_term_msg_find_le(term, info->term_offset);
2114                         if (msg != NULL)
2115                         {
2116                             /* Is this the next expexted term offset? */
2117                             if (msg->next_expected_term_offset == info->term_offset)
2118                             {
2119                                 /* Yes - we can add the fragment to the message */
2120                             }
2121                             else
2122                             {
2123                                 /* Do we already have this fragment? */
2124                                 frag = aeron_msg_fragment_find(msg, info);
2125                                 if (frag != NULL)
2126                                 {
2127                                     /* Already have it, so nothing to do */
2128                                     return;
2129                                 }
2130                                 else
2131                                 {
2132                                     /* Not the next fragment, so no known message associated with it. */
2133                                     msg = NULL;
2134                                 }
2135                             }
2136                         }
2137                     }
2138                     /* Create the fragment */
2139                     frag = aeron_msg_fragment_create(tvb, offset, pinfo, info);
2140                     if (msg == NULL)
2141                     {
2142                         /* Add the fragment to the list of orphaned fragments */
2143                         wmem_list_append(term->orphan_fragment, (void *) frag);
2144                     }
2145                     else
2146                     {
2147                         /* Add the fragment to the message */
2148                         aeron_msg_fragment_add(msg, frag);
2149                     }
2150                     /* Process the orphan list */
2151                     aeron_msg_process_orphan_fragments(term);
2152                 }
2153             }
2154         }
2155     }
2156 }
2157
2158 /*----------------------------------------------------------------------------*/
2159 /* Aeron pad message packet dissection functions.                             */
2160 /*----------------------------------------------------------------------------*/
2161 static int dissect_aeron_pad(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, aeron_conversation_info_t * cinfo, aeron_frame_info_t * finfo)
2162 {
2163     proto_tree * subtree = NULL;
2164     proto_item * item = NULL;
2165     proto_item * channel_item = NULL;
2166     guint32 frame_length;
2167     guint32 pad_length;
2168     aeron_transport_t * transport;
2169     guint32 session_id;
2170     guint32 stream_id;
2171     guint32 term_id;
2172     guint32 term_offset;
2173     int rounded_length = 0;
2174     aeron_packet_info_t pktinfo;
2175
2176     frame_length = tvb_get_letohl(tvb, offset + O_AERON_PAD_FRAME_LENGTH);
2177     rounded_length = (int) aeron_pos_roundup(frame_length);
2178     term_offset = tvb_get_letohl(tvb, offset + O_AERON_PAD_TERM_OFFSET);
2179     session_id = tvb_get_letohl(tvb, offset + O_AERON_PAD_SESSION_ID);
2180     transport = aeron_transport_add(cinfo, session_id, pinfo->fd->num);
2181     stream_id = tvb_get_letohl(tvb, offset + O_AERON_PAD_STREAM_ID);
2182     term_id = tvb_get_letohl(tvb, offset + O_AERON_PAD_TERM_ID);
2183     pad_length = frame_length - L_AERON_PAD;
2184     memset((void *) &pktinfo, 0, sizeof(aeron_packet_info_t));
2185     pktinfo.stream_id = stream_id;
2186     pktinfo.term_id = term_id;
2187     pktinfo.term_offset = term_offset;
2188     pktinfo.info_flags = AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID | AERON_PACKET_INFO_FLAGS_TERM_ID_VALID | AERON_PACKET_INFO_FLAGS_TERM_OFFSET_VALID;
2189     pktinfo.length = frame_length;
2190     pktinfo.data_length = pad_length;
2191     pktinfo.type = HDR_TYPE_PAD;
2192     pktinfo.flags = tvb_get_guint8(tvb, offset + O_AERON_PAD_FLAGS);
2193     aeron_frame_info_setup(pinfo, transport, &pktinfo, finfo);
2194
2195     aeron_info_stream_progress_report(pinfo, HDR_TYPE_PAD, pktinfo.flags, term_id, term_offset, finfo);
2196     item = proto_tree_add_none_format(tree, hf_aeron_pad, tvb, offset, -1, "Pad Frame: Term 0x%x, Ofs %" G_GUINT32_FORMAT ", Len %" G_GUINT32_FORMAT "(%d)",
2197         term_id, term_offset, frame_length, rounded_length);
2198     subtree = proto_item_add_subtree(item, ett_aeron_pad);
2199     channel_item = proto_tree_add_uint64(subtree, hf_aeron_channel_id, tvb, 0, 0, transport->channel_id);
2200     PROTO_ITEM_SET_GENERATED(channel_item);
2201     proto_tree_add_item(subtree, hf_aeron_pad_frame_length, tvb, offset + O_AERON_PAD_FRAME_LENGTH, 4, ENC_LITTLE_ENDIAN);
2202     proto_tree_add_item(subtree, hf_aeron_pad_version, tvb, offset + O_AERON_PAD_VERSION, 1, ENC_LITTLE_ENDIAN);
2203     proto_tree_add_item(subtree, hf_aeron_pad_flags, tvb, offset + O_AERON_PAD_FLAGS, 1, ENC_LITTLE_ENDIAN);
2204     proto_tree_add_item(subtree, hf_aeron_pad_type, tvb, offset + O_AERON_PAD_TYPE, 2, ENC_LITTLE_ENDIAN);
2205     proto_tree_add_item(subtree, hf_aeron_pad_term_offset, tvb, offset + O_AERON_PAD_TERM_OFFSET, 4, ENC_LITTLE_ENDIAN);
2206     aeron_next_offset_report(tvb, subtree, transport, stream_id, term_id, term_offset, (guint32) rounded_length);
2207     proto_tree_add_item(subtree, hf_aeron_pad_session_id, tvb, offset + O_AERON_PAD_SESSION_ID, 4, ENC_LITTLE_ENDIAN);
2208     proto_tree_add_item(subtree, hf_aeron_pad_stream_id, tvb, offset + O_AERON_PAD_STREAM_ID, 4, ENC_LITTLE_ENDIAN);
2209     proto_tree_add_item(subtree, hf_aeron_pad_term_id, tvb, offset + O_AERON_PAD_TERM_ID, 4, ENC_LITTLE_ENDIAN);
2210     aeron_sequence_report(tvb, pinfo, subtree, transport, &pktinfo, finfo);
2211     aeron_stream_report(tvb, pinfo, subtree, transport, finfo);
2212     proto_item_set_len(item, L_AERON_PAD);
2213     return (L_AERON_PAD);
2214 }
2215
2216 /*----------------------------------------------------------------------------*/
2217 /* Aeron data message packet dissection functions.                            */
2218 /*----------------------------------------------------------------------------*/
2219 static void dissect_aeron_reassembled_data(packet_info * pinfo, proto_tree * tree, aeron_frame_info_t * finfo)
2220 {
2221     proto_item * frag_item = NULL;
2222     proto_tree * frag_tree = NULL;
2223     proto_item * pi = NULL;
2224     aeron_msg_t * msg = NULL;
2225     wmem_list_frame_t * lf = NULL;
2226     gboolean first_item = TRUE;
2227     guint32 msg_ofs = 0;
2228
2229     if (finfo->message == NULL)
2230     {
2231         return;
2232     }
2233     msg = finfo->message;
2234     add_new_data_source(pinfo, msg->reassembled_data, "Reassembled Data");
2235     frag_item = proto_tree_add_none_format(tree,
2236         hf_aeron_data_reassembly,
2237         msg->reassembled_data,
2238         0,
2239         tvb_reported_length_remaining(msg->reassembled_data, 0),
2240         "%" G_GUINT32_FORMAT " Reassembled Fragments (%" G_GUINT32_FORMAT " bytes):",
2241         msg->fragment_count,
2242         msg->length);
2243     frag_tree = proto_item_add_subtree(frag_item, ett_aeron_data_reassembly);
2244     lf = wmem_list_head(msg->fragment);
2245     while (lf != NULL)
2246     {
2247         aeron_msg_fragment_t * frag = (aeron_msg_fragment_t *) wmem_list_frame_data(lf);
2248         if (frag != NULL)
2249         {
2250             pi = proto_tree_add_uint_format_value(frag_tree,
2251                 hf_aeron_data_reassembly_fragment,
2252                 msg->reassembled_data,
2253                 msg_ofs,
2254                 frag->data_length,
2255                 frag->frame,
2256                 "Frame: %" G_GUINT32_FORMAT ", payload: %" G_GUINT32_FORMAT "-%" G_GUINT32_FORMAT " (%" G_GUINT32_FORMAT " bytes)",
2257                 frag->frame,
2258                 msg_ofs,
2259                 (msg_ofs + frag->data_length) - 1,
2260                 frag->data_length);
2261             PROTO_ITEM_SET_GENERATED(pi);
2262             if (first_item)
2263             {
2264                 proto_item_append_text(frag_item, " #%" G_GUINT32_FORMAT "(%" G_GUINT32_FORMAT ")", frag->frame, frag->data_length);
2265             }
2266             else
2267             {
2268                 proto_item_append_text(frag_item, ", #%" G_GUINT32_FORMAT "(%" G_GUINT32_FORMAT ")", frag->frame, frag->data_length);
2269             }
2270             msg_ofs += frag->data_length;
2271             first_item = FALSE;
2272         }
2273         lf = wmem_list_frame_next(lf);
2274     }
2275     PROTO_ITEM_SET_GENERATED(frag_item);
2276 }
2277
2278 static int dissect_aeron_data(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, aeron_conversation_info_t * cinfo, aeron_frame_info_t * finfo)
2279 {
2280     proto_tree * subtree = NULL;
2281     proto_item * item = NULL;
2282     guint32 frame_length;
2283     static const int * flags[] =
2284     {
2285         &hf_aeron_data_flags_b,
2286         &hf_aeron_data_flags_e,
2287         NULL
2288     };
2289     aeron_transport_t * transport;
2290     guint32 session_id;
2291     guint32 stream_id;
2292     guint32 term_id;
2293     guint32 term_offset;
2294     guint32 data_length;
2295     int rounded_length = 0;
2296     aeron_packet_info_t pktinfo;
2297     guint32 offset_increment = 0;
2298
2299     frame_length = tvb_get_letohl(tvb, offset + O_AERON_DATA_FRAME_LENGTH);
2300     if (frame_length == 0)
2301     {
2302         rounded_length = O_AERON_DATA_DATA;
2303         data_length = 0;
2304         offset_increment = 0;
2305     }
2306     else
2307     {
2308         offset_increment = aeron_pos_roundup(frame_length);
2309         rounded_length = (int) offset_increment;
2310         data_length = frame_length - O_AERON_DATA_DATA;
2311     }
2312     term_offset = tvb_get_letohl(tvb, offset + O_AERON_DATA_TERM_OFFSET);
2313     session_id = tvb_get_letohl(tvb, offset + O_AERON_DATA_SESSION_ID);
2314     transport = aeron_transport_add(cinfo, session_id, pinfo->fd->num);
2315     stream_id = tvb_get_letohl(tvb, offset + O_AERON_DATA_STREAM_ID);
2316     term_id = tvb_get_letohl(tvb, offset + O_AERON_DATA_TERM_ID);
2317     memset((void *) &pktinfo, 0, sizeof(aeron_packet_info_t));
2318     pktinfo.stream_id = stream_id;
2319     pktinfo.term_id = term_id;
2320     pktinfo.term_offset = term_offset;
2321     pktinfo.info_flags = AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID | AERON_PACKET_INFO_FLAGS_TERM_ID_VALID | AERON_PACKET_INFO_FLAGS_TERM_OFFSET_VALID;
2322     pktinfo.length = frame_length;
2323     pktinfo.data_length = data_length;
2324     pktinfo.type = HDR_TYPE_DATA;
2325     pktinfo.flags = tvb_get_guint8(tvb, offset + O_AERON_DATA_FLAGS);
2326     aeron_frame_info_setup(pinfo, transport, &pktinfo, finfo);
2327
2328     aeron_info_stream_progress_report(pinfo, HDR_TYPE_DATA, pktinfo.flags, term_id, term_offset, finfo);
2329     item = proto_tree_add_none_format(tree, hf_aeron_data, tvb, offset, -1, "Data Frame: Term 0x%x, Ofs %" G_GUINT32_FORMAT ", Len %" G_GUINT32_FORMAT "(%d)",
2330         (guint32) term_id, term_offset, frame_length, rounded_length);
2331     subtree = proto_item_add_subtree(item, ett_aeron_data);
2332     item = proto_tree_add_uint64(subtree, hf_aeron_channel_id, tvb, 0, 0, transport->channel_id);
2333     PROTO_ITEM_SET_GENERATED(item);
2334     proto_tree_add_item(subtree, hf_aeron_data_frame_length, tvb, offset + O_AERON_DATA_FRAME_LENGTH, 4, ENC_LITTLE_ENDIAN);
2335     proto_tree_add_item(subtree, hf_aeron_data_version, tvb, offset + O_AERON_DATA_VERSION, 1, ENC_LITTLE_ENDIAN);
2336     proto_tree_add_bitmask(subtree, tvb, offset + O_AERON_DATA_FLAGS, hf_aeron_data_flags, ett_aeron_data_flags, flags, ENC_LITTLE_ENDIAN);
2337     proto_tree_add_item(subtree, hf_aeron_data_type, tvb, offset + O_AERON_DATA_TYPE, 2, ENC_LITTLE_ENDIAN);
2338     proto_tree_add_item(subtree, hf_aeron_data_term_offset, tvb, offset + O_AERON_DATA_TERM_OFFSET, 4, ENC_LITTLE_ENDIAN);
2339     aeron_next_offset_report(tvb, subtree, transport, stream_id, term_id, term_offset, offset_increment);
2340     proto_tree_add_item(subtree, hf_aeron_data_session_id, tvb, offset + O_AERON_DATA_SESSION_ID, 4, ENC_LITTLE_ENDIAN);
2341     proto_tree_add_item(subtree, hf_aeron_data_stream_id, tvb, offset + O_AERON_DATA_STREAM_ID, 4, ENC_LITTLE_ENDIAN);
2342     proto_tree_add_item(subtree, hf_aeron_data_term_id, tvb, offset + O_AERON_DATA_TERM_ID, 4, ENC_LITTLE_ENDIAN);
2343     if (data_length > 0)
2344     {
2345         tvbuff_t * data_tvb = NULL;
2346         gboolean can_call_subdissector = FALSE;
2347         gboolean dissector_found = FALSE;
2348         heur_dtbl_entry_t * hdtbl_entry;
2349
2350         aeron_msg_process(tvb, offset, pinfo, transport, &pktinfo, finfo);
2351         if ((pktinfo.flags & DATA_FLAGS_COMPLETE) == DATA_FLAGS_COMPLETE)
2352         {
2353             can_call_subdissector = TRUE;
2354         }
2355         if (finfo != NULL)
2356         {
2357             if ((finfo->flags & AERON_FRAME_INFO_FLAGS_REASSEMBLED_MSG) != 0)
2358             {
2359                 dissect_aeron_reassembled_data(pinfo, subtree, finfo);
2360                 data_tvb = finfo->message->reassembled_data;
2361                 can_call_subdissector = TRUE;
2362             }
2363             else
2364             {
2365                 data_tvb = tvb_new_subset_length(tvb, offset + O_AERON_DATA_DATA, data_length);
2366             }
2367         }
2368         else
2369         {
2370             data_tvb = tvb_new_subset_length(tvb, offset + O_AERON_DATA_DATA, data_length);
2371         }
2372         if (can_call_subdissector && aeron_use_heuristic_subdissectors)
2373         {
2374             dissector_found = dissector_try_heuristic(aeron_heuristic_subdissector_list, data_tvb, pinfo, subtree, &hdtbl_entry, NULL);
2375         }
2376         if (!dissector_found)
2377         {
2378             call_dissector(aeron_data_dissector_handle, data_tvb, pinfo, subtree);
2379         }
2380     }
2381     aeron_sequence_report(tvb, pinfo, subtree, transport, &pktinfo, finfo);
2382     aeron_stream_report(tvb, pinfo, subtree, transport, finfo);
2383     proto_item_set_len(item, rounded_length);
2384     return (rounded_length);
2385 }
2386
2387 /*----------------------------------------------------------------------------*/
2388 /* Aeron NAK packet dissection functions.                                     */
2389 /*----------------------------------------------------------------------------*/
2390 static int dissect_aeron_nak(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, aeron_conversation_info_t * cinfo, aeron_frame_info_t * finfo)
2391 {
2392     proto_tree * subtree = NULL;
2393     proto_item * item = NULL;
2394     proto_item * channel_item = NULL;
2395     proto_item * nak_item = NULL;
2396     guint32 frame_length;
2397     aeron_transport_t * transport;
2398     guint32 session_id;
2399     guint32 stream_id;
2400     guint32 term_id;
2401     guint32 nak_term_offset;
2402     guint32 nak_length;
2403     int rounded_length = 0;
2404     aeron_packet_info_t pktinfo;
2405
2406     frame_length = tvb_get_letohl(tvb, offset + O_AERON_NAK_FRAME_LENGTH);
2407     rounded_length = (int) aeron_pos_roundup(frame_length);
2408     session_id = tvb_get_letohl(tvb, offset + O_AERON_NAK_SESSION_ID);
2409     transport = aeron_transport_add(cinfo, session_id, pinfo->fd->num);
2410     stream_id = tvb_get_letohl(tvb, offset + O_AERON_NAK_STREAM_ID);
2411     term_id = tvb_get_letohl(tvb, offset + O_AERON_NAK_TERM_ID);
2412     nak_term_offset = tvb_get_letohl(tvb, offset + O_AERON_NAK_TERM_OFFSET);
2413     nak_length = tvb_get_letohl(tvb, offset + O_AERON_NAK_LENGTH);
2414     memset((void *) &pktinfo, 0, sizeof(aeron_packet_info_t));
2415     pktinfo.stream_id = stream_id;
2416     pktinfo.term_id = term_id;
2417     pktinfo.info_flags = AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID | AERON_PACKET_INFO_FLAGS_TERM_ID_VALID;
2418     pktinfo.nak_term_offset = nak_term_offset;
2419     pktinfo.nak_length = nak_length;
2420     pktinfo.type = HDR_TYPE_NAK;
2421     pktinfo.flags = tvb_get_guint8(tvb, offset + O_AERON_NAK_FLAGS);
2422     aeron_frame_info_setup(pinfo, transport, &pktinfo, finfo);
2423
2424     col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", "NAK");
2425     item = proto_tree_add_none_format(tree, hf_aeron_nak, tvb, offset, -1, "NAK Frame: Term 0x%x, Ofs %" G_GUINT32_FORMAT ", Len %" G_GUINT32_FORMAT,
2426         term_id, nak_term_offset, nak_length);
2427     subtree = proto_item_add_subtree(item, ett_aeron_nak);
2428     channel_item = proto_tree_add_uint64(subtree, hf_aeron_channel_id, tvb, 0, 0, transport->channel_id);
2429     PROTO_ITEM_SET_GENERATED(channel_item);
2430     proto_tree_add_item(subtree, hf_aeron_nak_frame_length, tvb, offset + O_AERON_NAK_FRAME_LENGTH, 4, ENC_LITTLE_ENDIAN);
2431     proto_tree_add_item(subtree, hf_aeron_nak_version, tvb, offset + O_AERON_NAK_VERSION, 1, ENC_LITTLE_ENDIAN);
2432     proto_tree_add_item(subtree, hf_aeron_nak_flags, tvb, offset + O_AERON_NAK_FLAGS, 1, ENC_LITTLE_ENDIAN);
2433     proto_tree_add_item(subtree, hf_aeron_nak_type, tvb, offset + O_AERON_NAK_TYPE, 2, ENC_LITTLE_ENDIAN);
2434     proto_tree_add_item(subtree, hf_aeron_nak_session_id, tvb, offset + O_AERON_NAK_SESSION_ID, 4, ENC_LITTLE_ENDIAN);
2435     proto_tree_add_item(subtree, hf_aeron_nak_stream_id, tvb, offset + O_AERON_NAK_STREAM_ID, 4, ENC_LITTLE_ENDIAN);
2436     proto_tree_add_item(subtree, hf_aeron_nak_term_id, tvb, offset + O_AERON_NAK_TERM_ID, 4, ENC_LITTLE_ENDIAN);
2437     nak_item = proto_tree_add_item(subtree, hf_aeron_nak_term_offset, tvb, offset + O_AERON_NAK_TERM_OFFSET, 4, ENC_LITTLE_ENDIAN);
2438     proto_tree_add_item(subtree, hf_aeron_nak_length, tvb, offset + O_AERON_NAK_LENGTH, 4, ENC_LITTLE_ENDIAN);
2439     expert_add_info_format(pinfo, nak_item, &ei_aeron_analysis_nak, "NAK offset %" G_GUINT32_FORMAT " length %" G_GUINT32_FORMAT, nak_term_offset, nak_length);
2440     aeron_sequence_report(tvb, pinfo, subtree, transport, &pktinfo, finfo);
2441     proto_item_set_len(item, rounded_length);
2442     return (rounded_length);
2443 }
2444
2445 /*----------------------------------------------------------------------------*/
2446 /* Aeron status message packet dissection functions.                          */
2447 /*----------------------------------------------------------------------------*/
2448 static void aeron_window_resize_report(packet_info * pinfo, proto_item * item, aeron_frame_info_t * finfo)
2449 {
2450     if (aeron_sequence_analysis && aeron_stream_analysis && (finfo != NULL) && (finfo->stream_analysis != NULL))
2451     {
2452         if ((finfo->stream_analysis->flags & AERON_STREAM_ANALYSIS_FLAGS_WINDOW_RESIZE) != 0)
2453         {
2454             expert_add_info(pinfo, item, &ei_aeron_analysis_window_resize);
2455         }
2456     }
2457 }
2458
2459 static int dissect_aeron_sm(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, aeron_conversation_info_t * cinfo, aeron_frame_info_t * finfo)
2460 {
2461     proto_tree * subtree = NULL;
2462     proto_item * item = NULL;
2463     proto_item * channel_item = NULL;
2464     guint32 frame_length;
2465     static const int * flags[] =
2466     {
2467         &hf_aeron_sm_flags_s,
2468         NULL
2469     };
2470     guint32 feedback_length;
2471     aeron_transport_t * transport;
2472     guint32 session_id;
2473     guint32 stream_id;
2474     guint32 term_id;
2475     guint32 consumption_offset;
2476     guint32 rcv_window;
2477     int rounded_length = 0;
2478     aeron_packet_info_t pktinfo;
2479
2480     frame_length = tvb_get_letohl(tvb, offset + O_AERON_SM_FRAME_LENGTH);
2481     feedback_length = frame_length - O_AERON_SM_FEEDBACK;
2482     rounded_length = (int) aeron_pos_roundup(frame_length);
2483     session_id = tvb_get_letohl(tvb, offset + O_AERON_SM_SESSION_ID);
2484     transport = aeron_transport_add(cinfo, session_id, pinfo->fd->num);
2485     stream_id = tvb_get_letohl(tvb, offset + O_AERON_SM_STREAM_ID);
2486     term_id = tvb_get_letohl(tvb, offset + O_AERON_SM_TERM_ID);
2487     consumption_offset = tvb_get_letohl(tvb, offset + O_AERON_SM_COMPLETED_TERM_OFFSET);
2488     rcv_window = tvb_get_letohl(tvb, offset + O_AERON_SM_RECEIVER_WINDOW);
2489     memset((void *) &pktinfo, 0, sizeof(aeron_packet_info_t));
2490     pktinfo.stream_id = stream_id;
2491     pktinfo.info_flags = AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID;
2492     pktinfo.flags = tvb_get_guint8(tvb, offset + O_AERON_SM_FLAGS);
2493     if ((pktinfo.flags & STATUS_FLAGS_SETUP) == 0)
2494     {
2495         pktinfo.term_id = term_id;
2496         pktinfo.term_offset = consumption_offset;
2497         pktinfo.info_flags |= (AERON_PACKET_INFO_FLAGS_TERM_ID_VALID | AERON_PACKET_INFO_FLAGS_TERM_OFFSET_VALID);
2498         pktinfo.receiver_window = rcv_window;
2499     }
2500     else
2501     {
2502         pktinfo.term_id = 0;
2503         pktinfo.term_offset = 0;
2504         pktinfo.receiver_window = 0;
2505     }
2506     pktinfo.length = 0;
2507     pktinfo.data_length = 0;
2508     pktinfo.type = HDR_TYPE_SM;
2509     aeron_frame_info_setup(pinfo, transport, &pktinfo, finfo);
2510
2511     aeron_info_stream_progress_report(pinfo, HDR_TYPE_SM, pktinfo.flags, term_id, consumption_offset, finfo);
2512     item = proto_tree_add_none_format(tree, hf_aeron_sm, tvb, offset, -1, "Status Message: Term 0x%x, ConsumptionOfs %" G_GUINT32_FORMAT ", RcvWindow %" G_GUINT32_FORMAT,
2513         term_id, consumption_offset, rcv_window);
2514     subtree = proto_item_add_subtree(item, ett_aeron_sm);
2515     channel_item = proto_tree_add_uint64(subtree, hf_aeron_channel_id, tvb, 0, 0, transport->channel_id);
2516     PROTO_ITEM_SET_GENERATED(channel_item);
2517     proto_tree_add_item(subtree, hf_aeron_sm_frame_length, tvb, offset + O_AERON_SM_FRAME_LENGTH, 4, ENC_LITTLE_ENDIAN);
2518     proto_tree_add_item(subtree, hf_aeron_sm_version, tvb, offset + O_AERON_SM_VERSION, 1, ENC_LITTLE_ENDIAN);
2519     proto_tree_add_bitmask(subtree, tvb, offset + O_AERON_SM_FLAGS, hf_aeron_sm_flags, ett_aeron_sm_flags, flags, ENC_LITTLE_ENDIAN);
2520     proto_tree_add_item(subtree, hf_aeron_sm_type, tvb, offset + O_AERON_SM_TYPE, 2, ENC_LITTLE_ENDIAN);
2521     proto_tree_add_item(subtree, hf_aeron_sm_session_id, tvb, offset + O_AERON_SM_SESSION_ID, 4, ENC_LITTLE_ENDIAN);
2522     proto_tree_add_item(subtree, hf_aeron_sm_stream_id, tvb, offset + O_AERON_SM_STREAM_ID, 4, ENC_LITTLE_ENDIAN);
2523     proto_tree_add_item(subtree, hf_aeron_sm_consumption_term_id, tvb, offset + O_AERON_SM_TERM_ID, 4, ENC_LITTLE_ENDIAN);
2524     proto_tree_add_item(subtree, hf_aeron_sm_consumption_term_offset, tvb, offset + O_AERON_SM_COMPLETED_TERM_OFFSET, 4, ENC_LITTLE_ENDIAN);
2525     item = proto_tree_add_item(subtree, hf_aeron_sm_receiver_window, tvb, offset + O_AERON_SM_RECEIVER_WINDOW, 4, ENC_LITTLE_ENDIAN);
2526     aeron_window_resize_report(pinfo, item, finfo);
2527     if (feedback_length > 0)
2528     {
2529         proto_tree_add_item(subtree, hf_aeron_sm_feedback, tvb, offset + O_AERON_SM_FEEDBACK, feedback_length, ENC_NA);
2530     }
2531     aeron_sequence_report(tvb, pinfo, subtree, transport, &pktinfo, finfo);
2532     aeron_stream_report(tvb, pinfo, subtree, transport, finfo);
2533     proto_item_set_len(item, rounded_length);
2534     return (rounded_length);
2535 }
2536
2537 /*----------------------------------------------------------------------------*/
2538 /* Aeron error packet dissection functions.                                   */
2539 /*----------------------------------------------------------------------------*/
2540 static int dissect_aeron_err(tvbuff_t * tvb, int offset, packet_info * pinfo _U_, proto_tree * tree)
2541 {
2542     proto_tree * subtree = NULL;
2543     proto_item * item = NULL;
2544     guint32 length;
2545     guint32 bad_frame_length;
2546     gint string_length = 0;
2547     int ofs;
2548
2549     col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", "Error");
2550     item = proto_tree_add_item(tree, hf_aeron_err, tvb, offset, -1, ENC_NA);
2551     subtree = proto_item_add_subtree(item, ett_aeron_err);
2552     proto_tree_add_item(subtree, hf_aeron_err_frame_length, tvb, offset + O_AERON_ERR_FRAME_LENGTH, 4, ENC_LITTLE_ENDIAN);
2553     proto_tree_add_item(subtree, hf_aeron_err_version, tvb, offset + O_AERON_ERR_VERSION, 1, ENC_LITTLE_ENDIAN);
2554     proto_tree_add_item(subtree, hf_aeron_err_code, tvb, offset + O_AERON_ERR_CODE, 1, ENC_LITTLE_ENDIAN);
2555     proto_tree_add_item(subtree, hf_aeron_err_type, tvb, offset + O_AERON_ERR_TYPE, 2, ENC_LITTLE_ENDIAN);
2556     length = tvb_get_letohl(tvb, offset + O_AERON_ERR_FRAME_LENGTH);
2557     proto_tree_add_item(subtree, hf_aeron_err_off_frame_length, tvb, offset + O_AERON_ERR_OFFENDING_FRAME_LENGTH, 4, ENC_LITTLE_ENDIAN);
2558     bad_frame_length = tvb_get_letohl(tvb, offset + O_AERON_ERR_OFFENDING_FRAME_LENGTH);
2559     ofs = offset + O_AERON_ERR_OFFENDING_HEADER;
2560     proto_tree_add_item(subtree, hf_aeron_err_off_hdr, tvb, offset + ofs, bad_frame_length, ENC_NA);
2561     ofs += bad_frame_length;
2562     string_length = length - ofs;
2563     if (string_length > 0)
2564     {
2565         proto_tree_add_item(subtree, hf_aeron_err_string, tvb, offset + ofs, string_length, ENC_ASCII|ENC_NA);
2566     }
2567     length = aeron_pos_roundup(length);
2568     proto_item_set_len(item, (int) length);
2569     return ((int) length);
2570 }
2571
2572 /*----------------------------------------------------------------------------*/
2573 /* Aeron setup packet dissection functions.                                   */
2574 /*----------------------------------------------------------------------------*/
2575 static void aeron_set_stream_mtu_term_length(packet_info * pinfo, aeron_transport_t * transport, guint32 stream_id, guint32 mtu, guint32 term_length)
2576 {
2577     if (PINFO_FD_VISITED(pinfo) == 0)
2578     {
2579         aeron_stream_t * stream = aeron_transport_stream_find(transport, stream_id);
2580         if (stream != NULL)
2581         {
2582             stream->term_length = term_length;
2583             stream->mtu = mtu;
2584         }
2585     }
2586 }
2587
2588 static int dissect_aeron_setup(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, aeron_conversation_info_t * cinfo, aeron_frame_info_t * finfo)
2589 {
2590     proto_tree * subtree = NULL;
2591     proto_item * item = NULL;
2592     guint32 frame_length;
2593     proto_item * channel_item = NULL;
2594     aeron_transport_t * transport;
2595     guint32 session_id;
2596     guint32 stream_id;
2597     guint32 active_term_id;
2598     guint32 initial_term_id;
2599     guint32 term_offset;
2600     guint32 term_length;
2601     guint32 mtu;
2602     int rounded_length;
2603     aeron_packet_info_t pktinfo;
2604
2605     frame_length = tvb_get_letohl(tvb, offset + O_AERON_SETUP_FRAME_LENGTH);
2606     rounded_length = (int) aeron_pos_roundup(frame_length);
2607     term_offset = tvb_get_letohl(tvb, offset + O_AERON_SETUP_TERM_OFFSET);
2608     session_id = tvb_get_letohl(tvb, offset + O_AERON_SETUP_SESSION_ID);
2609     transport = aeron_transport_add(cinfo, session_id, pinfo->fd->num);
2610     stream_id = tvb_get_letohl(tvb, offset + O_AERON_SETUP_STREAM_ID);
2611     initial_term_id = tvb_get_letohl(tvb, offset + O_AERON_SETUP_INITIAL_TERM_ID);
2612     active_term_id = tvb_get_letohl(tvb, offset + O_AERON_SETUP_ACTIVE_TERM_ID);
2613     memset((void *) &pktinfo, 0, sizeof(aeron_packet_info_t));
2614     pktinfo.stream_id = stream_id;
2615     pktinfo.term_id = active_term_id;
2616     pktinfo.term_offset = 0;
2617     pktinfo.info_flags = AERON_PACKET_INFO_FLAGS_STREAM_ID_VALID | AERON_PACKET_INFO_FLAGS_TERM_ID_VALID;
2618     pktinfo.length = 0;
2619     pktinfo.data_length = 0;
2620     pktinfo.receiver_window = 0;
2621     pktinfo.type = HDR_TYPE_SETUP;
2622     pktinfo.flags = 0;
2623     aeron_frame_info_setup(pinfo, transport, &pktinfo, finfo);
2624     term_length = tvb_get_letohl(tvb, offset + O_AERON_SETUP_TERM_LENGTH);
2625     mtu = tvb_get_letohl(tvb, offset + O_AERON_SETUP_MTU);
2626     aeron_set_stream_mtu_term_length(pinfo, transport, stream_id, mtu, term_length);
2627
2628     col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", "Setup");
2629     item = proto_tree_add_none_format(tree, hf_aeron_setup, tvb, offset, -1, "Setup Frame: InitTerm 0x%x, ActiveTerm 0x%x, TermLen %" G_GUINT32_FORMAT ", Ofs %" G_GUINT32_FORMAT ", MTU %" G_GUINT32_FORMAT,
2630         initial_term_id, (guint32) active_term_id, term_length, term_offset, mtu);
2631     subtree = proto_item_add_subtree(item, ett_aeron_setup);
2632     channel_item = proto_tree_add_uint64(subtree, hf_aeron_channel_id, tvb, 0, 0, transport->channel_id);
2633     PROTO_ITEM_SET_GENERATED(channel_item);
2634     proto_tree_add_item(subtree, hf_aeron_setup_frame_length, tvb, offset + O_AERON_SETUP_FRAME_LENGTH, 4, ENC_LITTLE_ENDIAN);
2635     proto_tree_add_item(subtree, hf_aeron_setup_version, tvb, offset + O_AERON_SETUP_VERSION, 1, ENC_LITTLE_ENDIAN);
2636     proto_tree_add_item(subtree, hf_aeron_setup_flags, tvb, offset + O_AERON_SETUP_FLAGS, 1, ENC_LITTLE_ENDIAN);
2637     proto_tree_add_item(subtree, hf_aeron_setup_type, tvb, offset + O_AERON_SETUP_TYPE, 2, ENC_LITTLE_ENDIAN);
2638     proto_tree_add_item(subtree, hf_aeron_setup_term_offset, tvb, offset + O_AERON_SETUP_TERM_OFFSET, 4, ENC_LITTLE_ENDIAN);
2639     proto_tree_add_item(subtree, hf_aeron_setup_session_id, tvb, offset + O_AERON_SETUP_SESSION_ID, 4, ENC_LITTLE_ENDIAN);
2640     proto_tree_add_item(subtree, hf_aeron_setup_stream_id, tvb, offset + O_AERON_SETUP_STREAM_ID, 4, ENC_LITTLE_ENDIAN);
2641     proto_tree_add_item(subtree, hf_aeron_setup_initial_term_id, tvb, offset + O_AERON_SETUP_INITIAL_TERM_ID, 4, ENC_LITTLE_ENDIAN);
2642     proto_tree_add_item(subtree, hf_aeron_setup_active_term_id, tvb, offset + O_AERON_SETUP_ACTIVE_TERM_ID, 4, ENC_LITTLE_ENDIAN);
2643     proto_tree_add_item(subtree, hf_aeron_setup_term_length, tvb, offset + O_AERON_SETUP_TERM_LENGTH, 4, ENC_LITTLE_ENDIAN);
2644     proto_tree_add_item(subtree, hf_aeron_setup_mtu, tvb, offset + O_AERON_SETUP_MTU, 4, ENC_LITTLE_ENDIAN);
2645     aeron_sequence_report(tvb, pinfo, subtree, transport, &pktinfo, finfo);
2646     proto_item_set_len(item, rounded_length);
2647     return (rounded_length);
2648 }
2649
2650 /*----------------------------------------------------------------------------*/
2651 /* Aeron packet dissector.                                                    */
2652 /*----------------------------------------------------------------------------*/
2653 static int dissect_aeron(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * user_data _U_)
2654 {
2655     int total_dissected_length = 0;
2656     guint16 frame_type;
2657     proto_tree * aeron_tree = NULL;
2658     proto_item * aeron_item;
2659     int dissected_length = 0;
2660     int offset = 0;
2661     int length_remaining = 0;
2662     aeron_conversation_info_t * cinfo = NULL;
2663
2664     /* Get enough information to determine the conversation info */
2665     frame_type = tvb_get_letohs(tvb, offset + O_AERON_BASIC_TYPE);
2666     cinfo = aeron_setup_conversation_info(pinfo, frame_type);
2667     if (cinfo == NULL)
2668     {
2669         return (-1);
2670     }
2671     col_add_str(pinfo->cinfo, COL_PROTOCOL, "Aeron");
2672     col_clear(pinfo->cinfo, COL_INFO);
2673     col_add_str(pinfo->cinfo, COL_INFO, aeron_format_transport_uri(cinfo));
2674     col_set_fence(pinfo->cinfo, COL_INFO);
2675
2676     length_remaining = tvb_reported_length(tvb);
2677     aeron_item = proto_tree_add_protocol_format(tree, proto_aeron, tvb, offset, -1, "Aeron Protocol");
2678     aeron_tree = proto_item_add_subtree(aeron_item, ett_aeron);
2679     while (length_remaining > 0)
2680     {
2681         aeron_frame_info_t * finfo = NULL;
2682
2683         if (aeron_sequence_analysis)
2684         {
2685             finfo = aeron_frame_info_add(pinfo->fd->num, (guint32) offset);
2686         }
2687         frame_type = tvb_get_letohs(tvb, offset + O_AERON_BASIC_TYPE);
2688         cinfo = aeron_setup_conversation_info(pinfo, frame_type);
2689         switch (frame_type)
2690         {
2691             case HDR_TYPE_PAD:
2692                 dissected_length = dissect_aeron_pad(tvb, offset, pinfo, aeron_tree, cinfo, finfo);
2693                 break;
2694             case HDR_TYPE_DATA:
2695                 dissected_length = dissect_aeron_data(tvb, offset, pinfo, aeron_tree, cinfo, finfo);
2696                 break;
2697             case HDR_TYPE_NAK:
2698                 dissected_length = dissect_aeron_nak(tvb, offset, pinfo, aeron_tree, cinfo, finfo);
2699                 break;
2700             case HDR_TYPE_SM:
2701                 dissected_length = dissect_aeron_sm(tvb, offset, pinfo, aeron_tree, cinfo, finfo);
2702                 break;
2703             case HDR_TYPE_ERR:
2704                 dissected_length = dissect_aeron_err(tvb, offset, pinfo, aeron_tree);
2705                 break;
2706             case HDR_TYPE_SETUP:
2707                 dissected_length = dissect_aeron_setup(tvb, offset, pinfo, aeron_tree, cinfo, finfo);
2708                 break;
2709             case HDR_TYPE_EXT:
2710             default:
2711                 return (total_dissected_length);
2712         }
2713         if (length_remaining - dissected_length >= length_remaining) {
2714             return (total_dissected_length);
2715         }
2716         total_dissected_length += dissected_length;
2717         offset += dissected_length;
2718         length_remaining -= dissected_length;
2719         proto_item_set_len(aeron_item, dissected_length);
2720     }
2721     return (total_dissected_length);
2722 }
2723
2724 static gboolean test_aeron_packet(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * user_data)
2725 {
2726     guint8 ver = 0;
2727     guint16 packet_type = 0;
2728     gint length;
2729     gint length_remaining;
2730     int rc;
2731
2732     length_remaining = tvb_captured_length_remaining(tvb, 0);
2733     if (length_remaining < HDR_LENGTH_MIN)
2734     {
2735         return (FALSE);
2736     }
2737     /* We know we have at least HDR_LENGTH_MIN (12) bytes captured */
2738     ver = tvb_get_guint8(tvb, O_AERON_BASIC_VERSION);
2739     if (ver != 0)
2740     {
2741         return (FALSE);
2742     }
2743     packet_type = tvb_get_letohs(tvb, O_AERON_BASIC_TYPE);
2744     switch (packet_type)
2745     {
2746         case HDR_TYPE_PAD:
2747         case HDR_TYPE_DATA:
2748         case HDR_TYPE_NAK:
2749         case HDR_TYPE_SM:
2750         case HDR_TYPE_ERR:
2751         case HDR_TYPE_SETUP:
2752         case HDR_TYPE_EXT:
2753             break;
2754         default:
2755             return (FALSE);
2756     }
2757     length = (gint) (tvb_get_letohl(tvb, O_AERON_BASIC_FRAME_LENGTH) & 0x7fffffff);
2758     if (!((packet_type == HDR_TYPE_DATA) && (length == 0)))
2759     {
2760         if (length < HDR_LENGTH_MIN)
2761         {
2762             return (FALSE);
2763         }
2764     }
2765     if (packet_type == HDR_TYPE_PAD)
2766     {
2767         /* Pad frames can't have a zero term offset */
2768         guint32 term_offset = tvb_get_letohl(tvb, O_AERON_PAD_TERM_OFFSET);
2769         if (term_offset == 0)
2770         {
2771             return (FALSE);
2772         }
2773     }
2774     else
2775     {
2776         if (length > length_remaining)
2777         {
2778             return (FALSE);
2779         }
2780     }
2781     rc = dissect_aeron(tvb, pinfo, tree, user_data);
2782     if (rc == -1)
2783     {
2784         return (FALSE);
2785     }
2786     return (TRUE);
2787 }
2788
2789 static void aeron_init(void)
2790 {
2791     aeron_channel_id_init();
2792 }
2793
2794 /* Register all the bits needed with the filtering engine */
2795 void proto_register_aeron(void)
2796 {
2797     static hf_register_info hf[] =
2798     {
2799         { &hf_aeron_channel_id,
2800             { "Channel ID", "aeron.channel_id", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
2801         { &hf_aeron_pad,
2802             { "Pad Frame", "aeron.pad", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2803         { &hf_aeron_pad_frame_length,
2804             { "Frame Length", "aeron.pad.frame_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2805         { &hf_aeron_pad_version,
2806             { "Version", "aeron.pad.version", FT_UINT8, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2807         { &hf_aeron_pad_flags,
2808             { "Flags", "aeron.pad.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2809         { &hf_aeron_pad_type,
2810             { "Type", "aeron.pad.type", FT_UINT16, BASE_DEC_HEX, VALS(aeron_frame_type), 0x0, NULL, HFILL } },
2811         { &hf_aeron_pad_term_offset,
2812             { "Term Offset", "aeron.pad.term_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2813         { &hf_aeron_pad_session_id,
2814             { "Session ID", "aeron.pad.session_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2815         { &hf_aeron_pad_stream_id,
2816             { "Stream ID", "aeron.pad.stream_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2817         { &hf_aeron_pad_term_id,
2818             { "Term ID", "aeron.pad.term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2819         { &hf_aeron_data,
2820             { "Data Frame", "aeron.data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2821         { &hf_aeron_data_frame_length,
2822             { "Frame Length", "aeron.data.frame_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2823         { &hf_aeron_data_version,
2824             { "Version", "aeron.data.version", FT_UINT8, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2825         { &hf_aeron_data_flags,
2826             { "Flags", "aeron.data.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2827         { &hf_aeron_data_flags_b,
2828             { "Begin Message", "aeron.data.flags.b", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DATA_FLAGS_BEGIN, NULL, HFILL } },
2829         { &hf_aeron_data_flags_e,
2830             { "End Message", "aeron.data.flags.e", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DATA_FLAGS_END, NULL, HFILL } },
2831         { &hf_aeron_data_type,
2832             { "Type", "aeron.data.type", FT_UINT16, BASE_DEC_HEX, VALS(aeron_frame_type), 0x0, NULL, HFILL } },
2833         { &hf_aeron_data_term_offset,
2834             { "Term Offset", "aeron.data.term_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2835         { &hf_aeron_data_next_offset,
2836             { "Next Offset", "aeron.data.next_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2837         { &hf_aeron_data_next_offset_term,
2838             { "Next Offset Term", "aeron.data.next_offset_term", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2839         { &hf_aeron_data_next_offset_first_frame,
2840             { "Next Offset First Frame", "aeron.data.next_offset_first_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2841         { &hf_aeron_data_session_id,
2842             { "Session ID", "aeron.data.session_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2843         { &hf_aeron_data_stream_id,
2844             { "Stream ID", "aeron.data.stream_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2845         { &hf_aeron_data_term_id,
2846             { "Term ID", "aeron.data.term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2847         { &hf_aeron_data_reassembly,
2848             { "Reassembled Fragments", "aeron.data.reassembly", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2849         { &hf_aeron_data_reassembly_fragment,
2850             { "Fragment", "aeron.data.reassembly.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2851         { &hf_aeron_nak,
2852             { "NAK Frame", "aeron.nak", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2853         { &hf_aeron_nak_frame_length,
2854             { "Frame Length", "aeron.nak.frame_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2855         { &hf_aeron_nak_version,
2856             { "Version", "aeron.nak.version", FT_UINT8, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2857         { &hf_aeron_nak_flags,
2858             { "Flags", "aeron.nak.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2859         { &hf_aeron_nak_type,
2860             { "Type", "aeron.nak.type", FT_UINT16, BASE_DEC_HEX, VALS(aeron_frame_type), 0x0, NULL, HFILL } },
2861         { &hf_aeron_nak_session_id,
2862             { "Session ID", "aeron.nak.session_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2863         { &hf_aeron_nak_stream_id,
2864             { "Stream ID", "aeron.nak.stream_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2865         { &hf_aeron_nak_term_id,
2866             { "Term ID", "aeron.nak.term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2867         { &hf_aeron_nak_term_offset,
2868             { "Term Offset", "aeron.nak.term_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2869         { &hf_aeron_nak_length,
2870             { "Length", "aeron.nak.length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2871         { &hf_aeron_sm,
2872             { "Status Message", "aeron.sm", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2873         { &hf_aeron_sm_frame_length,
2874             { "Frame Length", "aeron.sm.frame_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2875         { &hf_aeron_sm_version,
2876             { "Version", "aeron.sm.version", FT_UINT8, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2877         { &hf_aeron_sm_flags,
2878             { "Flags", "aeron.sm.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2879         { &hf_aeron_sm_flags_s,
2880             { "Setup", "aeron.sm.flags.s", FT_BOOLEAN, 8, TFS(&tfs_set_notset), STATUS_FLAGS_SETUP, NULL, HFILL } },
2881         { &hf_aeron_sm_type,
2882             { "Type", "aeron.sm.type", FT_UINT16, BASE_DEC_HEX, VALS(aeron_frame_type), 0x0, NULL, HFILL } },
2883         { &hf_aeron_sm_session_id,
2884             { "Session ID", "aeron.sm.session_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2885         { &hf_aeron_sm_stream_id,
2886             { "Stream ID", "aeron.sm.stream_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2887         { &hf_aeron_sm_consumption_term_id,
2888             { "Consumption Term ID", "aeron.sm.consumption_term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2889         { &hf_aeron_sm_consumption_term_offset,
2890             { "Consumption Term Offset", "aeron.sm.consumption_term_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2891         { &hf_aeron_sm_receiver_window,
2892             { "Receiver Window", "aeron.sm.receiver_window", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2893         { &hf_aeron_sm_feedback,
2894             { "Application-specific Feedback", "aeron.sm.feedback", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2895         { &hf_aeron_err,
2896             { "Error Header", "aeron.err", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2897         { &hf_aeron_err_frame_length,
2898             { "Frame Length", "aeron.err.frame_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2899         { &hf_aeron_err_version,
2900             { "Version", "aeron.err.version", FT_UINT8, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2901         { &hf_aeron_err_code,
2902             { "Error Code", "aeron.err.code", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2903         { &hf_aeron_err_type,
2904             { "Type", "aeron.err.type", FT_UINT16, BASE_DEC_HEX, VALS(aeron_frame_type), 0x0, NULL, HFILL } },
2905         { &hf_aeron_err_off_frame_length,
2906             { "Offending Frame Length", "aeron.err.off_frame_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2907         { &hf_aeron_err_off_hdr,
2908             { "Offending Header", "aeron.err.off_hdr", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2909         { &hf_aeron_err_string,
2910             { "Error String", "aeron.err.string", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2911         { &hf_aeron_setup,
2912             { "Setup Frame", "aeron.setup", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2913         { &hf_aeron_setup_frame_length,
2914             { "Frame Length", "aeron.setup.frame_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2915         { &hf_aeron_setup_version,
2916             { "Version", "aeron.setup.version", FT_UINT8, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2917         { &hf_aeron_setup_flags,
2918             { "Flags", "aeron.setup.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2919         { &hf_aeron_setup_type,
2920             { "Type", "aeron.setup.type", FT_UINT16, BASE_DEC_HEX, VALS(aeron_frame_type), 0x0, NULL, HFILL } },
2921         { &hf_aeron_setup_term_offset,
2922             { "Term Offset", "aeron.setup.term_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2923         { &hf_aeron_setup_session_id,
2924             { "Session ID", "aeron.setup.session_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2925         { &hf_aeron_setup_stream_id,
2926             { "Stream ID", "aeron.setup.stream_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2927         { &hf_aeron_setup_initial_term_id,
2928             { "Initial Term ID", "aeron.setup.initial_term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2929         { &hf_aeron_setup_active_term_id,
2930             { "Active Term ID", "aeron.setup.active_term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2931         { &hf_aeron_setup_term_length,
2932             { "Term Length", "aeron.setup.term_length", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2933         { &hf_aeron_setup_mtu,
2934             { "MTU", "aeron.setup.mtu", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2935         { &hf_aeron_sequence_analysis,
2936             { "Sequence Analysis", "aeron.sequence_analysis", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2937         { &hf_aeron_sequence_analysis_channel_prev_frame,
2938             { "Previous Channel Frame", "aeron.sequence_analysis.prev_channel_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2939         { &hf_aeron_sequence_analysis_channel_next_frame,
2940             { "Next Channel Frame", "aeron.sequence_analysis.next_channel_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2941         { &hf_aeron_sequence_analysis_stream_prev_frame,
2942             { "Previous Stream Frame", "aeron.sequence_analysis.prev_stream_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2943         { &hf_aeron_sequence_analysis_stream_next_frame,
2944             { "Next Stream Frame", "aeron.sequence_analysis.next_stream_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2945         { &hf_aeron_sequence_analysis_term_prev_frame,
2946             { "Previous Term Frame", "aeron.sequence_analysis.prev_term_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2947         { &hf_aeron_sequence_analysis_term_next_frame,
2948             { "Next Term Frame", "aeron.sequence_analysis.next_term_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2949         { &hf_aeron_sequence_analysis_term_offset,
2950             { "Offset also in", "aeron.sequence_analysis.term_offset", FT_NONE, BASE_NONE, NULL, 0x0, "Offset also appears in these frames", HFILL } },
2951         { &hf_aeron_sequence_analysis_term_offset_frame,
2952             { "Frame", "aeron.sequence_analysis.term_offset.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2953         { &hf_aeron_sequence_analysis_retransmission,
2954             { "Frame is a retransmission", "aeron.sequence_analysis.retransmission", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2955         { &hf_aeron_sequence_analysis_retransmission_rx,
2956             { "List of NAK frames to which this retransmission applies", "aeron.sequence_analysis.retransmission.rx", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2957         { &hf_aeron_sequence_analysis_retransmission_rx_frame,
2958             { "Retransmission applies to frame", "aeron.sequence_analysis.retransmission.rx.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2959         { &hf_aeron_sequence_analysis_nak_unrecovered,
2960             { "Unrecovered Bytes", "aeron.sequence_analysis.nak_unrecovered", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
2961         { &hf_aeron_sequence_analysis_nak_rx,
2962             { "List of RX Frames for this NAK", "aeron.sequence_analysis.nak_rx", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2963         { &hf_aeron_sequence_analysis_nak_rx_frame,
2964             { "RX Frame for this NAK", "aeron.sequence_analysis.nak_rx.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2965         { &hf_aeron_sequence_analysis_keepalive,
2966             { "Frame is a keepalive", "aeron.sequence_analysis.keepalive", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2967         { &hf_aeron_stream_analysis,
2968             { "Stream Analysis", "aeron.stream_analysis", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2969         { &hf_aeron_stream_analysis_high_term_id,
2970             { "Highest sent term ID", "aeron.stream_analysis.high_term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2971         { &hf_aeron_stream_analysis_high_term_offset,
2972             { "Highest sent term offset", "aeron.stream_analysis.high_term_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2973         { &hf_aeron_stream_analysis_completed_term_id,
2974             { "Completed term ID", "aeron.stream_analysis.completed_term_id", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2975         { &hf_aeron_stream_analysis_completed_term_offset,
2976             { "Completed term offset", "aeron.stream_analysis.completed_term_offset", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
2977         { &hf_aeron_stream_analysis_outstanding_bytes,
2978             { "Outstanding bytes", "aeron.stream_analysis.outstanding_bytes", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }
2979     };
2980     static gint * ett[] =
2981     {
2982         &ett_aeron,
2983         &ett_aeron_pad,
2984         &ett_aeron_data,
2985         &ett_aeron_data_flags,
2986         &ett_aeron_data_reassembly,
2987         &ett_aeron_nak,
2988         &ett_aeron_sm,
2989         &ett_aeron_sm_flags,
2990         &ett_aeron_err,
2991         &ett_aeron_setup,
2992         &ett_aeron_ext,
2993         &ett_aeron_sequence_analysis,
2994         &ett_aeron_sequence_analysis_retransmission_rx,
2995         &ett_aeron_sequence_analysis_nak_rx,
2996         &ett_aeron_sequence_analysis_term_offset,
2997         &ett_aeron_stream_analysis
2998     };
2999     static ei_register_info ei[] =
3000     {
3001         { &ei_aeron_analysis_nak, { "aeron.analysis.nak", PI_SEQUENCE, PI_NOTE, "NAK", EXPFILL } },
3002         { &ei_aeron_analysis_window_full, { "aeron.analysis.window_full", PI_SEQUENCE, PI_NOTE, "Receiver window is full", EXPFILL } },
3003         { &ei_aeron_analysis_idle_rx, { "aeron.analysis.idle_rx", PI_SEQUENCE, PI_NOTE, "This frame contains an Idle RX", EXPFILL } },
3004         { &ei_aeron_analysis_pacing_rx, { "aeron.analysis.pacing_rx", PI_SEQUENCE, PI_NOTE, "This frame contains a Pacing RX", EXPFILL } },
3005         { &ei_aeron_analysis_ooo, { "aeron.analysis.ooo", PI_SEQUENCE, PI_NOTE, "This frame contains Out-of-order data", EXPFILL } },
3006         { &ei_aeron_analysis_ooo_gap, { "aeron.analysis.ooo_gap", PI_SEQUENCE, PI_NOTE, "This frame is an Out-of-order gap", EXPFILL } },
3007         { &ei_aeron_analysis_keepalive, { "aeron.analysis.keepalive", PI_SEQUENCE, PI_NOTE, "This frame contains a Keepalive", EXPFILL } },
3008         { &ei_aeron_analysis_window_resize, { "aeron.analysis.window_resize", PI_SEQUENCE, PI_NOTE, "Receiver window resized", EXPFILL } },
3009         { &ei_aeron_analysis_ooo_sm, { "aeron.analysis.ooo_sm", PI_SEQUENCE, PI_NOTE, "This frame contains an Out-of-order SM", EXPFILL } },
3010         { &ei_aeron_analysis_keepalive_sm, { "aeron.analysis.keepalive_sm", PI_SEQUENCE, PI_NOTE, "This frame contains a Keepalive SM", EXPFILL } },
3011         { &ei_aeron_analysis_rx, { "aeron.analysis.rx", PI_SEQUENCE, PI_NOTE, "This frame contains a (likely) retransmission", EXPFILL } },
3012         { &ei_aeron_analysis_term_id_change, { "aeron.analysis.term_id_change", PI_SEQUENCE, PI_CHAT, "This frame contains a new term ID", EXPFILL } }
3013     };
3014     module_t * aeron_module;
3015     expert_module_t * expert_aeron;
3016
3017     proto_aeron = proto_register_protocol("Aeron Protocol", "Aeron", "aeron");
3018
3019     proto_register_field_array(proto_aeron, hf, array_length(hf));
3020     proto_register_subtree_array(ett, array_length(ett));
3021     expert_aeron = expert_register_protocol(proto_aeron);
3022     expert_register_field_array(expert_aeron, ei, array_length(ei));
3023     aeron_module = prefs_register_protocol(proto_aeron, proto_reg_handoff_aeron);
3024     aeron_heuristic_subdissector_list = register_heur_dissector_list("aeron_msg_payload");
3025
3026     prefs_register_bool_preference(aeron_module,
3027         "sequence_analysis",
3028         "Analyze transport sequencing",
3029         "Include next/previous frame for channel, stream, and term, and other transport sequence analysis.",
3030         &aeron_sequence_analysis);
3031     prefs_register_bool_preference(aeron_module,
3032         "stream_analysis",
3033         "Analyze stream sequencing",
3034         "Include stream analysis, tracking publisher and subscriber positions. Requires \"Analyze transport sequencing\".",
3035         &aeron_stream_analysis);
3036     prefs_register_bool_preference(aeron_module,
3037         "reassemble_fragments",
3038         "Reassemble fragmented data",
3039         "Reassemble fragmented data messages. Requires \"Analyze transport sequencing\" and \"Analyze stream sequencing\".",
3040         &aeron_reassemble_fragments);
3041     prefs_register_bool_preference(aeron_module,
3042         "use_heuristic_subdissectors",
3043         "Use heuristic sub-dissectors",
3044         "Use a registered heuristic sub-dissector to decode the payload data. Requires \"Analyze transport sequencing\", \"Analyze stream sequencing\", and \"Reassemble fragmented data\".",
3045         &aeron_use_heuristic_subdissectors);
3046     register_init_routine(aeron_init);
3047     aeron_frame_info_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
3048 }
3049
3050 /* The registration hand-off routine */
3051 void proto_reg_handoff_aeron(void)
3052 {
3053     aeron_dissector_handle = new_create_dissector_handle(dissect_aeron, proto_aeron);
3054     dissector_add_for_decode_as("udp.port", aeron_dissector_handle);
3055     heur_dissector_add("udp", test_aeron_packet, proto_aeron);
3056     aeron_data_dissector_handle = find_dissector("data");
3057 }
3058
3059 /*
3060  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
3061  *
3062  * Local variables:
3063  * c-basic-offset: 4
3064  * tab-width: 8
3065  * indent-tabs-mode: nil
3066  * End:
3067  *
3068  * vi: set shiftwidth=4 tabstop=8 expandtab:
3069  * :indentSize=4:tabSize=8:noTabs=true:
3070  */