uat: add a reset callback.
[metze/wireshark/wip.git] / epan / dissectors / packet-lbtrm.c
1 /* packet-lbtrm.c
2  * Routines for LBT-RM Packet dissection
3  *
4  * Copyright (c) 2005-2014 Informatica Corporation. All Rights Reserved.
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 #include "config.h"
26
27 #include <epan/packet.h>
28 #include <epan/prefs.h>
29 #include <epan/expert.h>
30 #include <epan/uat.h>
31 #include <epan/tap.h>
32 #include <epan/conversation.h>
33 #include <epan/to_str.h>
34 #include <wsutil/inet_aton.h>
35 #include <wsutil/pint.h>
36 #include "packet-lbm.h"
37 #include "packet-lbtrm.h"
38
39 void proto_register_lbtrm(void);
40 void proto_reg_handoff_lbtrm(void);
41
42 /* Protocol handle */
43 static int proto_lbtrm = -1;
44
45 /* Dissector handle */
46 static dissector_handle_t lbtrm_dissector_handle;
47
48 /* Tap handle */
49 static int lbtrm_tap_handle = -1;
50
51 /*----------------------------------------------------------------------------*/
52 /* LBT-RM transport management.                                               */
53 /*----------------------------------------------------------------------------*/
54
55 static const address lbtrm_null_address = ADDRESS_INIT_NONE;
56
57 static lbtrm_transport_t * lbtrm_transport_unicast_find(const address * source_address, guint16 source_port, guint32 session_id, guint32 frame)
58 {
59     lbtrm_transport_t * transport = NULL;
60     conversation_t * conv = NULL;
61     wmem_tree_t * session_tree = NULL;
62
63     conv = find_conversation(frame, source_address, &lbtrm_null_address, PT_UDP, source_port, 0, 0);
64     if (conv != NULL)
65     {
66         if (frame > conv->last_frame)
67         {
68             conv->last_frame = frame;
69         }
70         session_tree = (wmem_tree_t *) conversation_get_proto_data(conv, proto_lbtrm);
71         if (session_tree != NULL)
72         {
73             transport = (lbtrm_transport_t *) wmem_tree_lookup32(session_tree, session_id);
74         }
75     }
76     return (transport);
77 }
78
79 static void lbtrm_transport_unicast_add(const address * source_address, guint16 source_port, guint32 session_id, guint32 frame, lbtrm_transport_t * transport)
80 {
81     conversation_t * conv = NULL;
82     wmem_tree_t * session_tree = NULL;
83     lbtrm_transport_t * transport_entry = NULL;
84
85     conv = find_conversation(frame, source_address, &lbtrm_null_address, PT_UDP, source_port, 0, 0);
86     if (conv == NULL)
87     {
88         conv = conversation_new(frame, source_address, &lbtrm_null_address, PT_UDP, source_port, 0, 0);
89     }
90     session_tree = (wmem_tree_t *) conversation_get_proto_data(conv, proto_lbtrm);
91     if (session_tree == NULL)
92     {
93         session_tree = wmem_tree_new(wmem_file_scope());
94         conversation_add_proto_data(conv, proto_lbtrm, (void *) session_tree);
95     }
96     transport_entry = (lbtrm_transport_t *) wmem_tree_lookup32(session_tree, session_id);
97     if (transport_entry == NULL)
98     {
99         wmem_tree_insert32(session_tree, session_id, (void *) transport);
100     }
101 }
102
103 static lbtrm_transport_t * lbtrm_transport_find(const address * source_address, guint16 source_port, guint32 session_id, const address * multicast_group, guint16 dest_port, guint32 frame)
104 {
105     lbtrm_transport_t * entry = NULL;
106     wmem_tree_t * session_tree = NULL;
107     conversation_t * conv = NULL;
108
109     conv = find_conversation(frame, source_address, multicast_group, PT_UDP, source_port, dest_port, 0);
110     if (conv != NULL)
111     {
112         if (frame > conv->last_frame)
113         {
114             conv->last_frame = frame;
115         }
116         session_tree = (wmem_tree_t *) conversation_get_proto_data(conv, proto_lbtrm);
117         if (session_tree != NULL)
118         {
119             entry = (lbtrm_transport_t *) wmem_tree_lookup32(session_tree, session_id);
120         }
121     }
122     return (entry);
123 }
124
125 lbtrm_transport_t * lbtrm_transport_add(const address * source_address, guint16 source_port, guint32 session_id, const address * multicast_group, guint16 dest_port, guint32 frame)
126 {
127     lbtrm_transport_t * entry;
128     conversation_t * conv = NULL;
129     wmem_tree_t * session_tree = NULL;
130
131     conv = find_conversation(frame, source_address, multicast_group, PT_UDP, source_port, dest_port, 0);
132     if (conv == NULL)
133     {
134         conv = conversation_new(frame, source_address, multicast_group, PT_UDP, source_port, dest_port, 0);
135     }
136     if (frame > conv->last_frame)
137     {
138         conv->last_frame = frame;
139     }
140     session_tree = (wmem_tree_t *) conversation_get_proto_data(conv, proto_lbtrm);
141     if (session_tree == NULL)
142     {
143         session_tree = wmem_tree_new(wmem_file_scope());
144         conversation_add_proto_data(conv, proto_lbtrm, (void *) session_tree);
145     }
146     entry = (lbtrm_transport_t *) wmem_tree_lookup32(session_tree, session_id);
147     if (entry != NULL)
148     {
149         return (entry);
150     }
151     entry = wmem_new(wmem_file_scope(), lbtrm_transport_t);
152     copy_address_wmem(wmem_file_scope(), &(entry->source_address), source_address);
153     entry->source_port = source_port;
154     entry->session_id = session_id;
155     copy_address_wmem(wmem_file_scope(), &(entry->multicast_group), multicast_group);
156     entry->dest_port = dest_port;
157     entry->channel = lbm_channel_assign(LBM_CHANNEL_TRANSPORT_LBTRM);
158     entry->frame = wmem_tree_new(wmem_file_scope());
159     entry->last_frame = NULL;
160     entry->last_data_frame = NULL;
161     entry->last_sm_frame = NULL;
162     entry->last_nak_frame = NULL;
163     entry->last_ncf_frame = NULL;
164     entry->data_sqn = wmem_tree_new(wmem_file_scope());
165     entry->sm_sqn = wmem_tree_new(wmem_file_scope());
166     entry->data_high_sqn = 0;
167     entry->sm_high_sqn = 0;
168     wmem_tree_insert32(session_tree, session_id, (void *) entry);
169     lbtrm_transport_unicast_add(source_address, source_port, session_id, frame, entry);
170     return (entry);
171 }
172
173 static lbm_transport_sqn_t * lbtrm_transport_sqn_find(lbtrm_transport_t * transport, guint8 type, guint32 sqn)
174 {
175     lbm_transport_sqn_t * sqn_entry = NULL;
176
177     switch (type)
178     {
179         case LBTRM_PACKET_TYPE_DATA:
180             sqn_entry = (lbm_transport_sqn_t *) wmem_tree_lookup32(transport->data_sqn, sqn);
181             break;
182         case LBTRM_PACKET_TYPE_SM:
183             sqn_entry = (lbm_transport_sqn_t *) wmem_tree_lookup32(transport->sm_sqn, sqn);
184             break;
185         case LBTRM_PACKET_TYPE_NAK:
186         case LBTRM_PACKET_TYPE_NCF:
187         default:
188             sqn_entry = NULL;
189             break;
190     }
191     return (sqn_entry);
192 }
193
194 static lbm_transport_sqn_t * lbtrm_transport_sqn_add(lbtrm_transport_t * transport, lbm_transport_frame_t * frame)
195 {
196     wmem_tree_t * sqn_list = NULL;
197     lbm_transport_sqn_t * sqn_entry = NULL;
198
199     switch (frame->type)
200     {
201         case LBTRM_PACKET_TYPE_DATA:
202             sqn_list = transport->data_sqn;
203             break;
204         case LBTRM_PACKET_TYPE_SM:
205             sqn_list = transport->sm_sqn;
206             break;
207         case LBTRM_PACKET_TYPE_NAK:
208         case LBTRM_PACKET_TYPE_NCF:
209         default:
210             return (NULL);
211             break;
212     }
213
214     /* Add the sqn. */
215     sqn_entry = lbm_transport_sqn_add(sqn_list, frame);
216     return (sqn_entry);
217 }
218
219 static lbm_transport_frame_t * lbtrm_transport_frame_find(lbtrm_transport_t * transport, guint32 frame)
220 {
221     return ((lbm_transport_frame_t *) wmem_tree_lookup32(transport->frame, frame));
222 }
223
224 static lbm_transport_frame_t * lbtrm_transport_frame_add(lbtrm_transport_t * transport, guint8 type, guint32 frame, guint32 sqn, gboolean retransmission)
225 {
226     lbm_transport_sqn_t * dup_sqn_entry = NULL;
227     lbm_transport_frame_t * frame_entry = NULL;
228
229     /* Locate the frame. */
230     frame_entry = lbtrm_transport_frame_find(transport, frame);
231     if (frame_entry != NULL)
232     {
233         return (frame_entry);
234     }
235     frame_entry = lbm_transport_frame_add(transport->frame, type, frame, sqn, retransmission);
236     if (transport->last_frame != NULL)
237     {
238         frame_entry->previous_frame = transport->last_frame->frame;
239         transport->last_frame->next_frame = frame;
240     }
241     transport->last_frame = frame_entry;
242     switch (type)
243     {
244         case LBTRM_PACKET_TYPE_DATA:
245             if (transport->last_data_frame != NULL)
246             {
247                 frame_entry->previous_type_frame = transport->last_data_frame->frame;
248                 transport->last_data_frame->next_type_frame = frame;
249                 /* Ideally, this frame's sqn is 1 more than the highest data sqn seen */
250                 if (frame_entry->sqn <= transport->data_high_sqn)
251                 {
252                     dup_sqn_entry = lbtrm_transport_sqn_find(transport, type, frame_entry->sqn);
253                     if (!frame_entry->retransmission)
254                     {
255                         /* Out of order */
256                         if (dup_sqn_entry != NULL)
257                         {
258                             frame_entry->duplicate = TRUE;
259                         }
260                         if (frame_entry->sqn != transport->data_high_sqn)
261                         {
262                             frame_entry->ooo_gap = transport->data_high_sqn - frame_entry->sqn;
263                         }
264                     }
265                 }
266                 else
267                 {
268                     if (!frame_entry->retransmission)
269                     {
270                         if (frame_entry->sqn != (transport->data_high_sqn + 1))
271                         {
272                             /* Gap */
273                             frame_entry->sqn_gap = frame_entry->sqn - (transport->last_data_frame->sqn + 1);
274                         }
275                     }
276                 }
277             }
278             if ((frame_entry->sqn > transport->data_high_sqn) && !frame_entry->retransmission)
279             {
280                 transport->data_high_sqn = frame_entry->sqn;
281             }
282             transport->last_data_frame = frame_entry;
283             break;
284         case LBTRM_PACKET_TYPE_SM:
285             if (transport->last_sm_frame != NULL)
286             {
287                 frame_entry->previous_type_frame = transport->last_sm_frame->frame;
288                 transport->last_sm_frame->next_type_frame = frame;
289                 /* Ideally, this frame's sqn is 1 more than the highest SM sqn seen */
290                 if (frame_entry->sqn <= transport->sm_high_sqn)
291                 {
292                     /* Out of order */
293                     dup_sqn_entry = lbtrm_transport_sqn_find(transport, type, frame_entry->sqn);
294                     if (dup_sqn_entry != NULL)
295                     {
296                         frame_entry->duplicate = TRUE;
297                     }
298                     if (frame_entry->sqn != transport->sm_high_sqn)
299                     {
300                         frame_entry->ooo_gap = transport->sm_high_sqn - frame_entry->sqn;
301                     }
302                 }
303                 else
304                 {
305                     if (frame_entry->sqn != (transport->sm_high_sqn + 1))
306                     {
307                         /* Gap */
308                         frame_entry->sqn_gap = frame_entry->sqn - (transport->sm_high_sqn + 1);
309                     }
310                 }
311             }
312             if (frame_entry->sqn > transport->sm_high_sqn)
313             {
314                 transport->sm_high_sqn = frame_entry->sqn;
315             }
316             transport->last_sm_frame = frame_entry;
317             break;
318         case LBTRM_PACKET_TYPE_NAK:
319             if (transport->last_nak_frame != NULL)
320             {
321                 frame_entry->previous_type_frame = transport->last_nak_frame->frame;
322                 transport->last_nak_frame->next_type_frame = frame;
323             }
324             transport->last_nak_frame = frame_entry;
325             break;
326         case LBTRM_PACKET_TYPE_NCF:
327             if (transport->last_ncf_frame != NULL)
328             {
329                 frame_entry->previous_type_frame = transport->last_ncf_frame->frame;
330                 transport->last_ncf_frame->next_type_frame = frame;
331             }
332             transport->last_ncf_frame = frame_entry;
333             break;
334     }
335
336     /* Add the sqn. */
337     (void)lbtrm_transport_sqn_add(transport, frame_entry);
338     return (frame_entry);
339 }
340
341 static char * lbtrm_transport_source_string_format(const address * source_address, guint16 source_port, guint32 session_id, const address * multicast_group, guint16 dest_port)
342 {
343     /* Returns a packet-scoped string. */
344     return (wmem_strdup_printf(wmem_packet_scope(), "LBTRM:%s:%" G_GUINT16_FORMAT ":%08x:%s:%" G_GUINT16_FORMAT, address_to_str(wmem_packet_scope(), source_address), source_port, session_id,
345             address_to_str(wmem_packet_scope(), multicast_group), dest_port));
346 }
347
348 char * lbtrm_transport_source_string(const address * source_address, guint16 source_port, guint32 session_id, const address * multicast_group, guint16 dest_port)
349 {
350     /* Returns a file-scoped string. */
351     return (wmem_strdup(wmem_file_scope(), lbtrm_transport_source_string_format(source_address, source_port, session_id, multicast_group, dest_port)));
352 }
353
354 static char * lbtrm_transport_source_string_transport(lbtrm_transport_t * transport)
355 {
356     /* Returns a packet-scoped string. */
357     return (lbtrm_transport_source_string_format(&(transport->source_address), transport->source_port, transport->session_id, &(transport->multicast_group), transport->dest_port));
358 }
359
360 /*----------------------------------------------------------------------------*/
361 /* Packet definitions.                                                        */
362 /*----------------------------------------------------------------------------*/
363
364 /* LBT-RM main header */
365 typedef struct
366 {
367     lbm_uint8_t ver_type;
368     lbm_uint8_t next_hdr;
369     lbm_uint16_t ucast_port;
370     lbm_uint32_t session_id;
371 } lbtrm_hdr_t;
372 #define O_LBTRM_HDR_T_VER_TYPE OFFSETOF(lbtrm_hdr_t, ver_type)
373 #define L_LBTRM_HDR_T_VER_TYPE SIZEOF(lbtrm_hdr_t, ver_type)
374 #define O_LBTRM_HDR_T_NEXT_HDR OFFSETOF(lbtrm_hdr_t, next_hdr)
375 #define L_LBTRM_HDR_T_NEXT_HDR SIZEOF(lbtrm_hdr_t, next_hdr)
376 #define O_LBTRM_HDR_T_UCAST_PORT OFFSETOF(lbtrm_hdr_t, ucast_port)
377 #define L_LBTRM_HDR_T_UCAST_PORT SIZEOF(lbtrm_hdr_t, ucast_port)
378 #define O_LBTRM_HDR_T_SESSION_ID OFFSETOF(lbtrm_hdr_t, session_id)
379 #define L_LBTRM_HDR_T_SESSION_ID SIZEOF(lbtrm_hdr_t, session_id)
380 #define L_LBTRM_HDR_T (gint) (sizeof(lbtrm_hdr_t))
381
382 #define LBTRM_VERSION 0x00
383 #define LBTRM_HDR_VER(x) (x >> 4)
384 #define LBTRM_HDR_TYPE(x) (x & 0x0F)
385 #define LBTRM_HDR_VER_MASK 0xF0
386 #define LBTRM_HDR_TYPE_MASK 0x0F
387
388 /* LBT-RM data header */
389 typedef struct
390 {
391     lbm_uint32_t sqn;
392     lbm_uint32_t trail_sqn;
393     lbm_uint8_t flags_fec_type;
394     lbm_uint8_t flags_tgsz;
395     lbm_uint16_t fec_symbol;
396 } lbtrm_data_hdr_t;
397 #define O_LBTRM_DATA_HDR_T_SQN OFFSETOF(lbtrm_data_hdr_t, sqn)
398 #define L_LBTRM_DATA_HDR_T_SQN SIZEOF(lbtrm_data_hdr_t, sqn)
399 #define O_LBTRM_DATA_HDR_T_TRAIL_SQN OFFSETOF(lbtrm_data_hdr_t, trail_sqn)
400 #define L_LBTRM_DATA_HDR_T_TRAIL_SQN SIZEOF(lbtrm_data_hdr_t, trail_sqn)
401 #define O_LBTRM_DATA_HDR_T_FLAGS_FEC_TYPE OFFSETOF(lbtrm_data_hdr_t, flags_fec_type)
402 #define L_LBTRM_DATA_HDR_T_FLAGS_FEC_TYPE SIZEOF(lbtrm_data_hdr_t, flags_fec_type)
403 #define O_LBTRM_DATA_HDR_T_FLAGS_TGSZ OFFSETOF(lbtrm_data_hdr_t, flags_tgsz)
404 #define L_LBTRM_DATA_HDR_T_FLAGS_TGSZ SIZEOF(lbtrm_data_hdr_t, flags_tgsz)
405 #define O_LBTRM_DATA_HDR_T_FEC_SYMBOL OFFSETOF(lbtrm_data_hdr_t, fec_symbol)
406 #define L_LBTRM_DATA_HDR_T_FEC_SYMBOL SIZEOF(lbtrm_data_hdr_t, fec_symbol)
407 #define L_LBTRM_DATA_HDR_T (gint) (sizeof(lbtrm_data_hdr_t))
408
409 #define LBTRM_DATA_UNICAST_NAKS_FLAG 0x80
410 #define LBTRM_MULTICAST_NAKS_FLAG 0x40
411 #define LBTRM_DATA_RETRANSMISSION_FLAG 0x20
412 #define LBTRM_LATE_JOIN_FLAG 0x10
413 #define LBTRM_FEC_TYPE_MASK 0xF
414 #define LBTRM_DATA_FLAGS(x) (x >> 4)
415 #define LBTRM_DATA_FLAGS_MASK 0xF0
416
417 /* LBT-RM Session Message header */
418 typedef struct
419 {
420     lbm_uint32_t sm_sqn;
421     lbm_uint32_t lead_sqn;
422     lbm_uint32_t trail_sqn;
423     lbm_uint8_t flags_fec_type;
424     lbm_uint8_t flags_tgsz;
425     lbm_uint16_t reserved;
426 } lbtrm_sm_hdr_t;
427 #define O_LBTRM_SM_HDR_T_SM_SQN OFFSETOF(lbtrm_sm_hdr_t, sm_sqn)
428 #define L_LBTRM_SM_HDR_T_SM_SQN SIZEOF(lbtrm_sm_hdr_t, sm_sqn)
429 #define O_LBTRM_SM_HDR_T_LEAD_SQN OFFSETOF(lbtrm_sm_hdr_t, lead_sqn)
430 #define L_LBTRM_SM_HDR_T_LEAD_SQN SIZEOF(lbtrm_sm_hdr_t, lead_sqn)
431 #define O_LBTRM_SM_HDR_T_TRAIL_SQN OFFSETOF(lbtrm_sm_hdr_t, trail_sqn)
432 #define L_LBTRM_SM_HDR_T_TRAIL_SQN SIZEOF(lbtrm_sm_hdr_t, trail_sqn)
433 #define O_LBTRM_SM_HDR_T_FLAGS_FEC_TYPE OFFSETOF(lbtrm_sm_hdr_t, flags_fec_type)
434 #define L_LBTRM_SM_HDR_T_FLAGS_FEC_TYPE SIZEOF(lbtrm_sm_hdr_t, flags_fec_type)
435 #define O_LBTRM_SM_HDR_T_FLAGS_TGSZ OFFSETOF(lbtrm_sm_hdr_t, flags_tgsz)
436 #define L_LBTRM_SM_HDR_T_FLAGS_TGSZ SIZEOF(lbtrm_sm_hdr_t, flags_tgsz)
437 #define O_LBTRM_SM_HDR_T_RESERVED OFFSETOF(lbtrm_sm_hdr_t, reserved)
438 #define L_LBTRM_SM_HDR_T_RESERVED SIZEOF(lbtrm_sm_hdr_t, reserved)
439 #define L_LBTRM_SM_HDR_T (gint) (sizeof(lbtrm_sm_hdr_t))
440
441 #define LBTRM_SM_UNICAST_NAKS_FLAG 0x80
442 #define LBTRM_SM_FLAGS(x) (x >> 4)
443 #define LBTRM_SM_FLAGS_MASK 0xF0
444
445 /* LBT-RM NAK header */
446 typedef struct
447 {
448     lbm_uint16_t num_naks;
449     lbm_uint16_t format;
450 } lbtrm_nak_hdr_t;
451 #define O_LBTRM_NAK_HDR_T_NUM_NAKS OFFSETOF(lbtrm_nak_hdr_t, num_naks)
452 #define L_LBTRM_NAK_HDR_T_NUM_NAKS SIZEOF(lbtrm_nak_hdr_t, num_naks)
453 #define O_LBTRM_NAK_HDR_T_FORMAT OFFSETOF(lbtrm_nak_hdr_t, format)
454 #define L_LBTRM_NAK_HDR_T_FORMAT SIZEOF(lbtrm_nak_hdr_t, format)
455 #define L_LBTRM_NAK_HDR_T (gint) (sizeof(lbtrm_nak_hdr_t))
456
457 #define LBTRM_NAK_SELECTIVE_FORMAT 0x0
458 #define LBTRM_NAK_PARITY_FORMAT 0x1
459 #define LBTRM_NAK_HDR_FORMAT(x) (x & 0xF)
460 #define LBTRM_NAK_HDR_FORMAT_MASK 0x0F
461
462 /* LBT-RM NAK Confirmation */
463 typedef struct
464 {
465     lbm_uint32_t trail_sqn;
466     lbm_uint16_t num_ncfs;
467     lbm_uint8_t reserved;
468     lbm_uint8_t reason_format;
469 } lbtrm_ncf_hdr_t;
470 #define O_LBTRM_NCF_HDR_T_TRAIL_SQN OFFSETOF(lbtrm_ncf_hdr_t, trail_sqn)
471 #define L_LBTRM_NCF_HDR_T_TRAIL_SQN SIZEOF(lbtrm_ncf_hdr_t, trail_sqn)
472 #define O_LBTRM_NCF_HDR_T_NUM_NCFS OFFSETOF(lbtrm_ncf_hdr_t, num_ncfs)
473 #define L_LBTRM_NCF_HDR_T_NUM_NCFS SIZEOF(lbtrm_ncf_hdr_t, num_ncfs)
474 #define O_LBTRM_NCF_HDR_T_RESERVED OFFSETOF(lbtrm_ncf_hdr_t, reserved)
475 #define L_LBTRM_NCF_HDR_T_RESERVED SIZEOF(lbtrm_ncf_hdr_t, reserved)
476 #define O_LBTRM_NCF_HDR_T_REASON_FORMAT OFFSETOF(lbtrm_ncf_hdr_t, reason_format)
477 #define L_LBTRM_NCF_HDR_T_REASON_FORMAT SIZEOF(lbtrm_ncf_hdr_t, reason_format)
478 #define L_LBTRM_NCF_HDR_T (gint) (sizeof(lbtrm_ncf_hdr_t))
479
480 #define LBTRM_NCF_SELECTIVE_FORMAT 0x0
481 #define LBTRM_NCF_PARITY_FORMAT 0x1
482 #define LBTRM_NCF_HDR_REASON(x) ((x & 0xF0) >> 4)
483 #define LBTRM_NCF_HDR_FORMAT(x) (x & 0xF)
484 #define LBTRM_NCF_HDR_REASON_MASK 0xF0
485 #define LBTRM_NCF_HDR_FORMAT_MASK 0x0F
486
487 /* LBT-RM option header */
488 typedef struct
489 {
490     lbm_uint8_t next_hdr;
491     lbm_uint8_t hdr_len;
492     lbm_uint16_t res;
493 } lbtrm_basic_opt_t;
494 #define O_LBTRM_BASIC_OPT_T_NEXT_HDR OFFSETOF(lbtrm_basic_opt_t, next_hdr)
495 #define L_LBTRM_BASIC_OPT_T_NEXT_HDR SIZEOF(lbtrm_basic_opt_t, next_hdr)
496 #define O_LBTRM_BASIC_OPT_T_HDR_LEN OFFSETOF(lbtrm_basic_opt_t, hdr_len)
497 #define L_LBTRM_BASIC_OPT_T_HDR_LEN SIZEOF(lbtrm_basic_opt_t, hdr_len)
498 #define O_LBTRM_BASIC_OPT_T_RES OFFSETOF(lbtrm_basic_opt_t, res)
499 #define L_LBTRM_BASIC_OPT_T_RES SIZEOF(lbtrm_basic_opt_t, res)
500 #define L_LBTRM_BASIC_OPT_T (gint) (sizeof(lbtrm_basic_opt_t))
501
502 #define LBTRM_NHDR_DATA 0x0
503
504 /*----------------------------------------------------------------------------*/
505 /* Value translation tables.                                                  */
506 /*----------------------------------------------------------------------------*/
507
508 static const value_string lbtrm_packet_type[] =
509 {
510     { LBTRM_PACKET_TYPE_DATA, "DATA" },
511     { LBTRM_PACKET_TYPE_SM, "SM" },
512     { LBTRM_PACKET_TYPE_NAK, "NAK" },
513     { LBTRM_PACKET_TYPE_NCF, "NCF" },
514     { 0x0, NULL }
515 };
516
517 static const value_string lbtrm_nak_format[] =
518 {
519     { LBTRM_NAK_SELECTIVE_FORMAT, "Selective" },
520     { LBTRM_NAK_PARITY_FORMAT, "Parity" },
521     { 0x0, NULL }
522 };
523
524 static const value_string lbtrm_ncf_format[] =
525 {
526     { LBTRM_NCF_SELECTIVE_FORMAT, "Selective" },
527     { LBTRM_NCF_PARITY_FORMAT, "Parity" },
528     { 0x0, NULL }
529 };
530
531 static const value_string lbtrm_ncf_reason[] =
532 {
533     { LBTRM_NCF_REASON_NO_RETRY, "Do not retry" },
534     { LBTRM_NCF_REASON_IGNORED, "NAK Ignored" },
535     { LBTRM_NCF_REASON_RX_DELAY, "Retransmit Delay" },
536     { LBTRM_NCF_REASON_SHED, "NAK Shed" },
537     { 0x0, NULL }
538 };
539
540 static const value_string lbtrm_next_header[] =
541 {
542     { LBTRM_NHDR_DATA, "Data" },
543     { 0x0, NULL }
544 };
545
546 /*----------------------------------------------------------------------------*/
547 /* Preferences.                                                               */
548 /*----------------------------------------------------------------------------*/
549
550 /* Preferences default values. */
551 #define LBTRM_DEFAULT_DPORT_LOW 14400
552 #define LBTRM_DEFAULT_DPORT_HIGH 14400
553 #define LBTRM_DEFAULT_SPORT_HIGH 14399
554 #define LBTRM_DEFAULT_SPORT_LOW 14390
555 #define LBTRM_DEFAULT_MC_ADDRESS_LOW "224.10.10.10"
556 #define LBTRM_DEFAULT_MC_ADDRESS_HIGH "224.10.10.14"
557 #define MIM_DEFAULT_INCOMING_DPORT 14401
558 #define MIM_DEFAULT_OUTGOING_DPORT 14401
559 #define MIM_DEFAULT_MC_INCOMING_ADDRESS "224.10.10.21"
560 #define MIM_DEFAULT_MC_OUTGOING_ADDRESS "224.10.10.21"
561
562 /* Global preferences variables (altered by the preferences dialog). */
563 static const char * global_lbtrm_mc_address_low = LBTRM_DEFAULT_MC_ADDRESS_LOW;
564 static const char * global_lbtrm_mc_address_high = LBTRM_DEFAULT_MC_ADDRESS_HIGH;
565 static guint32 global_lbtrm_dest_port_low = LBTRM_DEFAULT_DPORT_LOW;
566 static guint32 global_lbtrm_dest_port_high = LBTRM_DEFAULT_DPORT_HIGH;
567 static guint32 global_lbtrm_src_port_low = LBTRM_DEFAULT_SPORT_LOW;
568 static guint32 global_lbtrm_src_port_high = LBTRM_DEFAULT_SPORT_HIGH;
569 static guint32 global_mim_incoming_dest_port = MIM_DEFAULT_INCOMING_DPORT;
570 static guint32 global_mim_outgoing_dest_port = MIM_DEFAULT_OUTGOING_DPORT;
571 static const char * global_mim_incoming_mc_address = MIM_DEFAULT_MC_INCOMING_ADDRESS;
572 static const char * global_mim_outgoing_mc_address = MIM_DEFAULT_MC_OUTGOING_ADDRESS;
573 static gboolean global_lbtrm_expert_separate_naks = FALSE;
574 static gboolean global_lbtrm_expert_separate_ncfs = FALSE;
575 static gboolean global_lbtrm_use_tag = FALSE;
576 static gboolean global_lbtrm_sequence_analysis = FALSE;
577
578 /* Local preferences variables (used by the dissector). */
579 static guint32 lbtrm_mc_address_low_host = 0;
580 static guint32 lbtrm_mc_address_high_host = 0;
581 static guint32 lbtrm_dest_port_low = LBTRM_DEFAULT_DPORT_LOW;
582 static guint32 lbtrm_dest_port_high = LBTRM_DEFAULT_DPORT_HIGH;
583 static guint32 lbtrm_src_port_low = LBTRM_DEFAULT_SPORT_LOW;
584 static guint32 lbtrm_src_port_high = LBTRM_DEFAULT_SPORT_HIGH;
585 static guint32 mim_incoming_dest_port = MIM_DEFAULT_INCOMING_DPORT;
586 static guint32 mim_outgoing_dest_port = MIM_DEFAULT_OUTGOING_DPORT;
587 static guint32 mim_incoming_mc_address_host = 0;
588 static guint32 mim_outgoing_mc_address_host = 0;
589 static gboolean lbtrm_expert_separate_naks = FALSE;
590 static gboolean lbtrm_expert_separate_ncfs = FALSE;
591 static gboolean lbtrm_use_tag = FALSE;
592 static gboolean lbtrm_sequence_analysis = FALSE;
593
594 /*----------------------------------------------------------------------------*/
595 /* Tag management.                                                            */
596 /*----------------------------------------------------------------------------*/
597 typedef struct
598 {
599     char * name;
600     char * mc_address_low;
601     guint32 mc_address_low_val_h;
602     char * mc_address_high;
603     guint32 mc_address_high_val_h;
604     guint32 dport_low;
605     guint32 dport_high;
606     guint32 sport_low;
607     guint32 sport_high;
608     guint32 mim_incoming_dport;
609     guint32 mim_outgoing_dport;
610     char * mim_mc_incoming_address;
611     guint32 mim_mc_incoming_address_val_h;
612     char * mim_mc_outgoing_address;
613     guint32 mim_mc_outgoing_address_val_h;
614 } lbtrm_tag_entry_t;
615
616 static lbtrm_tag_entry_t * lbtrm_tag_entry = NULL;
617 static guint lbtrm_tag_count = 0;
618
619 UAT_CSTRING_CB_DEF(lbtrm_tag, name, lbtrm_tag_entry_t)
620 UAT_IPV4_MC_CB_DEF(lbtrm_tag, mc_address_low, lbtrm_tag_entry_t)
621 UAT_IPV4_MC_CB_DEF(lbtrm_tag, mc_address_high, lbtrm_tag_entry_t)
622 UAT_DEC_CB_DEF(lbtrm_tag, dport_low, lbtrm_tag_entry_t)
623 UAT_DEC_CB_DEF(lbtrm_tag, dport_high, lbtrm_tag_entry_t)
624 UAT_DEC_CB_DEF(lbtrm_tag, sport_low, lbtrm_tag_entry_t)
625 UAT_DEC_CB_DEF(lbtrm_tag, sport_high, lbtrm_tag_entry_t)
626 UAT_DEC_CB_DEF(lbtrm_tag, mim_incoming_dport, lbtrm_tag_entry_t)
627 UAT_DEC_CB_DEF(lbtrm_tag, mim_outgoing_dport, lbtrm_tag_entry_t)
628 UAT_IPV4_MC_CB_DEF(lbtrm_tag, mim_mc_incoming_address, lbtrm_tag_entry_t)
629 UAT_IPV4_MC_CB_DEF(lbtrm_tag, mim_mc_outgoing_address, lbtrm_tag_entry_t)
630 static uat_field_t lbtrm_tag_array[] =
631 {
632     UAT_FLD_CSTRING(lbtrm_tag, name, "Tag name", "Tag name"),
633     UAT_FLD_IPV4_MC(lbtrm_tag, mc_address_low, "Multicast address low", "Multicast address low"),
634     UAT_FLD_IPV4_MC(lbtrm_tag, mc_address_high, "Multicast address high", "Multicast address high"),
635     UAT_FLD_DEC(lbtrm_tag, dport_low, "Destination port low", "Destination port low"),
636     UAT_FLD_DEC(lbtrm_tag, dport_high, "Destination port high", "Destination port high"),
637     UAT_FLD_DEC(lbtrm_tag, sport_low, "Source port low", "Source port low"),
638     UAT_FLD_DEC(lbtrm_tag, sport_high, "Source port high", "Source port high"),
639     UAT_FLD_DEC(lbtrm_tag, mim_incoming_dport, "MIM incoming destination port", "MIM incoming destination port"),
640     UAT_FLD_DEC(lbtrm_tag, mim_outgoing_dport, "MIM outgoing destination port", "MIM outgoing destination port"),
641     UAT_FLD_IPV4_MC(lbtrm_tag, mim_mc_incoming_address, "MIM incoming multicast address", "MIM incoming multicast address"),
642     UAT_FLD_IPV4_MC(lbtrm_tag, mim_mc_outgoing_address, "MIM outgoing multicast address", "MIM outgoing multicast address"),
643     UAT_END_FIELDS
644 };
645
646 /*----------------------------------------------------------------------------*/
647 /* UAT callback functions.                                                    */
648 /*----------------------------------------------------------------------------*/
649 static gboolean lbtrm_tag_update_cb(void * record, char * * error_string)
650 {
651     lbtrm_tag_entry_t * tag = (lbtrm_tag_entry_t *)record;
652
653     if (tag->name == NULL)
654     {
655         *error_string = g_strdup("Tag name can't be empty");
656         return FALSE;
657     }
658     else
659     {
660         g_strstrip(tag->name);
661         if (tag->name[0] == 0)
662         {
663             *error_string = g_strdup("Tag name can't be empty");
664             return FALSE;
665         }
666     }
667     return TRUE;
668 }
669
670 static void * lbtrm_tag_copy_cb(void * destination, const void * source, size_t length _U_)
671 {
672     const lbtrm_tag_entry_t * src = (const lbtrm_tag_entry_t *)source;
673     lbtrm_tag_entry_t * dest = (lbtrm_tag_entry_t *)destination;
674
675     dest->name = g_strdup(src->name);
676     dest->mc_address_low = g_strdup(src->mc_address_low);
677     dest->mc_address_low_val_h = src->mc_address_low_val_h;
678     dest->mc_address_high = g_strdup(src->mc_address_high);
679     dest->mc_address_high_val_h = src->mc_address_high_val_h;
680     dest->dport_low = src->dport_low;
681     dest->dport_high = src->dport_high;
682     dest->sport_low = src->sport_low;
683     dest->sport_high = src->sport_high;
684     dest->mim_incoming_dport = src->mim_incoming_dport;
685     dest->mim_outgoing_dport = src->mim_outgoing_dport;
686     dest->mim_mc_incoming_address = g_strdup(src->mim_mc_incoming_address);
687     dest->mim_mc_incoming_address_val_h = src->mim_mc_incoming_address_val_h;
688     dest->mim_mc_outgoing_address = g_strdup(src->mim_mc_outgoing_address);
689     dest->mim_mc_outgoing_address_val_h = src->mim_mc_outgoing_address_val_h;
690     return (dest);
691 }
692
693 static void lbtrm_tag_free_cb(void * record)
694 {
695     lbtrm_tag_entry_t * tag = (lbtrm_tag_entry_t *)record;
696
697     if (tag->name != NULL)
698     {
699         g_free(tag->name);
700         tag->name = NULL;
701     }
702     if (tag->mc_address_low != NULL)
703     {
704         g_free(tag->mc_address_low);
705         tag->mc_address_low = NULL;
706     }
707     if (tag->mc_address_high != NULL)
708     {
709         g_free(tag->mc_address_high);
710         tag->mc_address_high = NULL;
711     }
712     if (tag->mim_mc_incoming_address != NULL)
713     {
714         g_free(tag->mim_mc_incoming_address);
715         tag->mim_mc_incoming_address = NULL;
716     }
717     if (tag->mim_mc_outgoing_address != NULL)
718     {
719         g_free(tag->mim_mc_outgoing_address);
720         tag->mim_mc_outgoing_address = NULL;
721     }
722 }
723
724 static char * lbtrm_tag_find(packet_info * pinfo)
725 {
726     guint idx;
727     lbtrm_tag_entry_t * tag = NULL;
728     guint32 dest_addr_h;
729
730     if (!lbtrm_use_tag)
731     {
732         return (NULL);
733     }
734
735     dest_addr_h = pntoh32(pinfo->dst.data);
736     for (idx = 0; idx < lbtrm_tag_count; ++idx)
737     {
738         tag = &(lbtrm_tag_entry[idx]);
739         /* Is the destination a multicast address? */
740         if (IN_MULTICAST(dest_addr_h))
741         {
742             /* Check the MC address. */
743             if ((dest_addr_h >= tag->mc_address_low_val_h) && (dest_addr_h <= tag->mc_address_high_val_h))
744             {
745                 /* It's in the LBT-RM multicast range. Check the ports. */
746                 if ((pinfo->destport >= tag->dport_low) && (pinfo->destport <= tag->dport_high))
747                 {
748                     /* Must be one of ours. */
749                     return (tag->name);
750                 }
751             }
752             else if ((dest_addr_h == tag->mim_mc_incoming_address_val_h) || (dest_addr_h == tag->mim_mc_outgoing_address_val_h))
753             {
754                 /* Might be MIM. Check the port. */
755                 if (((dest_addr_h == tag->mim_mc_incoming_address_val_h) && (pinfo->destport == tag->mim_incoming_dport))
756                     || ((dest_addr_h == tag->mim_mc_outgoing_address_val_h) && (pinfo->destport == tag->mim_outgoing_dport)))
757                 {
758                     /* Must be one of ours. */
759                     return (tag->name);
760                 }
761             }
762             /* Not ours. */
763             continue;
764         }
765         else
766         {
767             /* Not multicast, might be a unicast UDP NAK. Check the destination port. */
768             if ((pinfo->destport < tag->sport_low) || (pinfo->destport > tag->sport_high))
769             {
770                 /* Wrong port. */
771                 continue;
772             }
773             /* One of ours, so handle it. */
774             return (tag->name);
775         }
776     }
777     /* Not one of ours. */
778     return (NULL);
779 }
780
781 /*----------------------------------------------------------------------------*/
782 /* Handles of all types.                                                      */
783 /*----------------------------------------------------------------------------*/
784
785 /* Dissector tree handles */
786 static gint ett_lbtrm = -1;
787 static gint ett_lbtrm_hdr = -1;
788 static gint ett_lbtrm_data = -1;
789 static gint ett_lbtrm_data_flags_fec_type = -1;
790 static gint ett_lbtrm_sm = -1;
791 static gint ett_lbtrm_sm_flags_fec_type = -1;
792 static gint ett_lbtrm_nak = -1;
793 static gint ett_lbtrm_nak_list = -1;
794 static gint ett_lbtrm_ncf = -1;
795 static gint ett_lbtrm_ncf_list = -1;
796 static gint ett_lbtrm_transport = -1;
797 static gint ett_lbtrm_transport_sqn = -1;
798
799 /* Dissector field handles */
800 static int hf_lbtrm_channel = -1;
801 static int hf_lbtrm_tag = -1;
802 static int hf_lbtrm_hdr = -1;
803 static int hf_lbtrm_hdr_ver = -1;
804 static int hf_lbtrm_hdr_type = -1;
805 static int hf_lbtrm_hdr_next_hdr = -1;
806 static int hf_lbtrm_hdr_ucast_port = -1;
807 static int hf_lbtrm_hdr_session_id = -1;
808 static int hf_lbtrm_data = -1;
809 static int hf_lbtrm_data_sqn = -1;
810 static int hf_lbtrm_data_trail_sqn = -1;
811 static int hf_lbtrm_data_flags_fec_type = -1;
812 static int hf_lbtrm_data_flags_fec_type_ucast_naks = -1;
813 static int hf_lbtrm_data_flags_fec_type_rx = -1;
814 static int hf_lbtrm_data_flags_tgsz = -1;
815 static int hf_lbtrm_data_fec_symbol = -1;
816 static int hf_lbtrm_sm = -1;
817 static int hf_lbtrm_sm_sm_sqn = -1;
818 static int hf_lbtrm_sm_lead_sqn = -1;
819 static int hf_lbtrm_sm_trail_sqn = -1;
820 static int hf_lbtrm_sm_flags_fec_type = -1;
821 static int hf_lbtrm_sm_flags_fec_type_ucast_naks = -1;
822 static int hf_lbtrm_sm_flags_tgsz = -1;
823 static int hf_lbtrm_sm_reserved = -1;
824 static int hf_lbtrm_nak = -1;
825 static int hf_lbtrm_nak_num_naks = -1;
826 static int hf_lbtrm_nak_format = -1;
827 static int hf_lbtrm_nak_list = -1;
828 static int hf_lbtrm_nak_list_nak = -1;
829 static int hf_lbtrm_ncf = -1;
830 static int hf_lbtrm_ncf_trail_sqn = -1;
831 static int hf_lbtrm_ncf_num_ncfs = -1;
832 static int hf_lbtrm_ncf_reserved = -1;
833 static int hf_lbtrm_ncf_reason = -1;
834 static int hf_lbtrm_ncf_format = -1;
835 static int hf_lbtrm_ncf_list = -1;
836 static int hf_lbtrm_ncf_list_ncf = -1;
837 static int hf_lbtrm_analysis = -1;
838 static int hf_lbtrm_analysis_prev_frame = -1;
839 static int hf_lbtrm_analysis_prev_data_frame = -1;
840 static int hf_lbtrm_analysis_prev_sm_frame = -1;
841 static int hf_lbtrm_analysis_prev_nak_frame = -1;
842 static int hf_lbtrm_analysis_prev_ncf_frame = -1;
843 static int hf_lbtrm_analysis_next_frame = -1;
844 static int hf_lbtrm_analysis_next_data_frame = -1;
845 static int hf_lbtrm_analysis_next_sm_frame = -1;
846 static int hf_lbtrm_analysis_next_nak_frame = -1;
847 static int hf_lbtrm_analysis_next_ncf_frame = -1;
848 static int hf_lbtrm_analysis_sqn = -1;
849 static int hf_lbtrm_analysis_sqn_frame = -1;
850 static int hf_lbtrm_analysis_data_retransmission = -1;
851 static int hf_lbtrm_analysis_data_sqn_gap = -1;
852 static int hf_lbtrm_analysis_data_ooo_gap = -1;
853 static int hf_lbtrm_analysis_data_duplicate = -1;
854 static int hf_lbtrm_analysis_sm_sqn_gap = -1;
855 static int hf_lbtrm_analysis_sm_ooo_gap = -1;
856 static int hf_lbtrm_analysis_sm_duplicate = -1;
857
858 /* Expert info handles */
859 static expert_field ei_lbtrm_analysis_ncf = EI_INIT;
860 static expert_field ei_lbtrm_analysis_ncf_ncf = EI_INIT;
861 static expert_field ei_lbtrm_analysis_nak = EI_INIT;
862 static expert_field ei_lbtrm_analysis_nak_nak = EI_INIT;
863 static expert_field ei_lbtrm_analysis_sm = EI_INIT;
864 static expert_field ei_lbtrm_analysis_rx = EI_INIT;
865 static expert_field ei_lbtrm_analysis_invalid_value = EI_INIT;
866 static expert_field ei_lbtrm_analysis_data_rx = EI_INIT;
867 static expert_field ei_lbtrm_analysis_data_gap = EI_INIT;
868 static expert_field ei_lbtrm_analysis_data_ooo = EI_INIT;
869 static expert_field ei_lbtrm_analysis_data_dup = EI_INIT;
870 static expert_field ei_lbtrm_analysis_sm_gap = EI_INIT;
871 static expert_field ei_lbtrm_analysis_sm_ooo = EI_INIT;
872 static expert_field ei_lbtrm_analysis_sm_dup = EI_INIT;
873
874 /*----------------------------------------------------------------------------*/
875 /* LBT-RM data payload dissection functions.                                  */
876 /*----------------------------------------------------------------------------*/
877 static int dissect_lbtrm_data_contents(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, const char * tag_name, guint64 channel)
878 {
879     tvbuff_t * next_tvb;
880
881     next_tvb = tvb_new_subset_remaining(tvb, offset);
882     return (lbmc_dissect_lbmc_packet(next_tvb, 0, pinfo, tree, tag_name, channel));
883 }
884
885 /*----------------------------------------------------------------------------*/
886 /* LBT-RM NAK confirmation packet dissection functions.                       */
887 /*----------------------------------------------------------------------------*/
888 static int dissect_lbtrm_ncf_list(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, int ncf_count, int reason, lbm_lbtrm_tap_info_t * tap_info)
889 {
890     proto_tree * ncf_tree = NULL;
891     proto_item * ncf_item = NULL;
892     lbm_uint32_t ncf;
893     int idx = 0;
894     int len = 0;
895
896     ncf_item = proto_tree_add_item(tree, hf_lbtrm_ncf_list, tvb, offset + len, (int)(sizeof(lbm_uint32_t) * ncf_count), ENC_NA);
897     ncf_tree = proto_item_add_subtree(ncf_item, ett_lbtrm_ncf_list);
898
899     for (idx = 0; idx < ncf_count; idx++)
900     {
901         proto_item * sep_ncf_item = NULL;
902
903         ncf = tvb_get_ntohl(tvb, offset + len);
904         sep_ncf_item = proto_tree_add_item(ncf_tree, hf_lbtrm_ncf_list_ncf, tvb, offset + len, sizeof(lbm_uint32_t), ENC_BIG_ENDIAN);
905         if (lbtrm_expert_separate_ncfs)
906         {
907             expert_add_info_format(pinfo, sep_ncf_item, &ei_lbtrm_analysis_ncf_ncf, "NCF 0x%08x %s", ncf, val_to_str(reason, lbtrm_ncf_reason, "Unknown (0x%02x)"));
908         }
909         tap_info->sqns[idx] = ncf;
910         len += 4;
911     }
912     return (len);
913 }
914
915 static int dissect_lbtrm_ncf(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, lbm_lbtrm_tap_info_t * tap_info)
916 {
917     int len = 0;
918     guint16 num_ncfs;
919     guint8 reason;
920     proto_tree * ncf_tree = NULL;
921     proto_item * ncf_item = NULL;
922     proto_item * reason_item = NULL;
923
924     ncf_item = proto_tree_add_item(tree, hf_lbtrm_ncf, tvb, offset, -1, ENC_NA);
925     ncf_tree = proto_item_add_subtree(ncf_item, ett_lbtrm_ncf);
926     num_ncfs = tvb_get_ntohs(tvb, offset + O_LBTRM_NCF_HDR_T_NUM_NCFS);
927     reason = tvb_get_guint8(tvb, offset + O_LBTRM_NCF_HDR_T_REASON_FORMAT);
928     proto_tree_add_item(ncf_tree, hf_lbtrm_ncf_trail_sqn, tvb, offset + O_LBTRM_NCF_HDR_T_TRAIL_SQN, L_LBTRM_NCF_HDR_T_TRAIL_SQN, ENC_BIG_ENDIAN);
929     proto_tree_add_item(ncf_tree, hf_lbtrm_ncf_num_ncfs, tvb, offset + O_LBTRM_NCF_HDR_T_NUM_NCFS, L_LBTRM_NCF_HDR_T_NUM_NCFS, ENC_BIG_ENDIAN);
930     proto_tree_add_item(ncf_tree, hf_lbtrm_ncf_reserved, tvb, offset + O_LBTRM_NCF_HDR_T_RESERVED, L_LBTRM_NCF_HDR_T_RESERVED, ENC_BIG_ENDIAN);
931     proto_tree_add_item(ncf_tree, hf_lbtrm_ncf_reason, tvb, offset + O_LBTRM_NCF_HDR_T_REASON_FORMAT, L_LBTRM_NCF_HDR_T_REASON_FORMAT, ENC_BIG_ENDIAN);
932     proto_tree_add_item(ncf_tree, hf_lbtrm_ncf_format, tvb, offset + O_LBTRM_NCF_HDR_T_REASON_FORMAT, L_LBTRM_NCF_HDR_T_REASON_FORMAT, ENC_BIG_ENDIAN);
933     len = L_LBTRM_NCF_HDR_T;
934     if (!lbtrm_expert_separate_ncfs)
935     {
936         expert_add_info_format(pinfo, reason_item, &ei_lbtrm_analysis_ncf, "NCF %s", val_to_str(LBTRM_NCF_HDR_REASON(reason), lbtrm_ncf_reason, "Unknown (0x%02x)"));
937     }
938     tap_info->ncf_reason = LBTRM_NCF_HDR_REASON(reason);
939     tap_info->num_sqns = num_ncfs;
940     tap_info->sqns = wmem_alloc_array(wmem_packet_scope(), guint32, num_ncfs);
941     len += dissect_lbtrm_ncf_list(tvb, offset + len, pinfo, ncf_tree, num_ncfs, LBTRM_NCF_HDR_REASON(reason), tap_info);
942     proto_item_set_len(ncf_item, len);
943     return (len);
944 }
945
946 /*----------------------------------------------------------------------------*/
947 /* LBT-RM NAK packet dissection functions.                                    */
948 /*----------------------------------------------------------------------------*/
949 static int dissect_lbtrm_nak_list(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, int nak_count, lbm_lbtrm_tap_info_t * tap_info)
950 {
951     proto_tree * nak_tree = NULL;
952     proto_item * nak_item = NULL;
953     lbm_uint32_t nak;
954     int idx = 0;
955     int len = 0;
956
957     nak_item = proto_tree_add_item(tree, hf_lbtrm_nak_list, tvb, offset + len, (int)(sizeof(lbm_uint32_t) * nak_count), ENC_NA);
958     nak_tree = proto_item_add_subtree(nak_item, ett_lbtrm_nak_list);
959
960     for (idx = 0; idx < nak_count; idx++)
961     {
962         proto_item * sep_nak_item = NULL;
963
964         nak = tvb_get_ntohl(tvb, offset + len);
965         sep_nak_item = proto_tree_add_item(nak_tree, hf_lbtrm_nak_list_nak, tvb, offset + len, sizeof(lbm_uint32_t), ENC_BIG_ENDIAN);
966         if (lbtrm_expert_separate_naks)
967         {
968             expert_add_info_format(pinfo, sep_nak_item, &ei_lbtrm_analysis_nak_nak, "NAK 0x%08x", nak);
969         }
970         tap_info->sqns[idx] = nak;
971         len += 4;
972     }
973     return (len);
974 }
975
976 static int dissect_lbtrm_nak(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, lbm_lbtrm_tap_info_t * tap_info)
977 {
978     int len = 0;
979     guint16 num_naks;
980     proto_tree * nak_tree = NULL;
981     proto_item * nak_item = NULL;
982
983     nak_item = proto_tree_add_item(tree, hf_lbtrm_nak, tvb, offset, -1, ENC_NA);
984     nak_tree = proto_item_add_subtree(nak_item, ett_lbtrm_nak);
985     num_naks = tvb_get_ntohs(tvb, offset + O_LBTRM_NAK_HDR_T_NUM_NAKS);
986     proto_tree_add_item(nak_tree, hf_lbtrm_nak_num_naks, tvb, offset + O_LBTRM_NAK_HDR_T_NUM_NAKS, L_LBTRM_NAK_HDR_T_NUM_NAKS, ENC_BIG_ENDIAN);
987     proto_tree_add_item(nak_tree, hf_lbtrm_nak_format, tvb, offset + O_LBTRM_NAK_HDR_T_FORMAT, L_LBTRM_NAK_HDR_T_FORMAT, ENC_BIG_ENDIAN);
988     len = L_LBTRM_NAK_HDR_T;
989     if (!lbtrm_expert_separate_naks)
990     {
991         expert_add_info(pinfo, nak_item, &ei_lbtrm_analysis_nak);
992     }
993     tap_info->num_sqns = num_naks;
994     tap_info->sqns = wmem_alloc_array(wmem_packet_scope(), guint32, num_naks);
995     len += dissect_lbtrm_nak_list(tvb, offset + len, pinfo, nak_tree, num_naks, tap_info);
996     proto_item_set_len(nak_item, len);
997     return (len);
998 }
999
1000 /*----------------------------------------------------------------------------*/
1001 /* LBT-RM session message packet dissection functions.                        */
1002 /*----------------------------------------------------------------------------*/
1003 static int dissect_lbtrm_sm(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, guint32 * sequence, lbm_lbtrm_tap_info_t * tap_info)
1004 {
1005     proto_tree * sm_tree = NULL;
1006     proto_item * sm_item = NULL;
1007     static const int * flags[] =
1008     {
1009         &hf_lbtrm_sm_flags_fec_type_ucast_naks,
1010         NULL
1011     };
1012     proto_item * sm_sqn_item = NULL;
1013     guint32 sqn;
1014
1015     sm_item = proto_tree_add_item(tree, hf_lbtrm_sm, tvb, offset, L_LBTRM_SM_HDR_T, ENC_NA);
1016     sm_tree = proto_item_add_subtree(sm_item, ett_lbtrm_sm);
1017     sm_sqn_item = proto_tree_add_item(sm_tree, hf_lbtrm_sm_sm_sqn, tvb, offset + O_LBTRM_SM_HDR_T_SM_SQN, L_LBTRM_SM_HDR_T_SM_SQN, ENC_BIG_ENDIAN);
1018     proto_tree_add_item(sm_tree, hf_lbtrm_sm_lead_sqn, tvb, offset + O_LBTRM_SM_HDR_T_LEAD_SQN, L_LBTRM_SM_HDR_T_LEAD_SQN, ENC_BIG_ENDIAN);
1019     proto_tree_add_item(sm_tree, hf_lbtrm_sm_trail_sqn, tvb, offset + O_LBTRM_SM_HDR_T_TRAIL_SQN, L_LBTRM_SM_HDR_T_TRAIL_SQN, ENC_BIG_ENDIAN);
1020     proto_tree_add_bitmask(sm_tree, tvb, offset + O_LBTRM_SM_HDR_T_FLAGS_FEC_TYPE, hf_lbtrm_sm_flags_fec_type, ett_lbtrm_sm_flags_fec_type, flags, ENC_BIG_ENDIAN);
1021     proto_tree_add_item(sm_tree, hf_lbtrm_sm_flags_tgsz, tvb, offset + O_LBTRM_SM_HDR_T_FLAGS_TGSZ, L_LBTRM_SM_HDR_T_FLAGS_TGSZ, ENC_BIG_ENDIAN);
1022     proto_tree_add_item(sm_tree, hf_lbtrm_sm_reserved, tvb, offset + O_LBTRM_SM_HDR_T_RESERVED, L_LBTRM_SM_HDR_T_RESERVED, ENC_BIG_ENDIAN);
1023     sqn = tvb_get_ntohl(tvb, offset + O_LBTRM_SM_HDR_T_SM_SQN);
1024     expert_add_info(pinfo, sm_sqn_item, &ei_lbtrm_analysis_sm);
1025     if (sequence != NULL)
1026     {
1027         *sequence = sqn;
1028     }
1029     tap_info->sqn = sqn;
1030     return (L_LBTRM_SM_HDR_T);
1031 }
1032
1033 /*----------------------------------------------------------------------------*/
1034 /* LBT-RM data packet dissection functions.                                   */
1035 /*----------------------------------------------------------------------------*/
1036 static int dissect_lbtrm_data(tvbuff_t * tvb, int offset, packet_info * pinfo, proto_tree * tree, guint32 * sequence, gboolean * retransmission, lbm_lbtrm_tap_info_t * tap_info)
1037 {
1038     proto_tree * data_tree = NULL;
1039     proto_item * data_item = NULL;
1040     static const int * flags[] =
1041     {
1042         &hf_lbtrm_data_flags_fec_type_ucast_naks,
1043         &hf_lbtrm_data_flags_fec_type_rx,
1044         NULL
1045     };
1046     proto_item * sqn_item = NULL;
1047     guint8 flags_val;
1048     guint32 sqn;
1049     gboolean is_retransmission = FALSE;
1050
1051     data_item = proto_tree_add_item(tree, hf_lbtrm_data, tvb, offset, L_LBTRM_DATA_HDR_T, ENC_NA);
1052     data_tree = proto_item_add_subtree(data_item, ett_lbtrm_data);
1053     sqn_item = proto_tree_add_item(data_tree, hf_lbtrm_data_sqn, tvb, offset + O_LBTRM_DATA_HDR_T_SQN, L_LBTRM_DATA_HDR_T_SQN, ENC_BIG_ENDIAN);
1054     proto_tree_add_item(data_tree, hf_lbtrm_data_trail_sqn, tvb, offset + O_LBTRM_DATA_HDR_T_TRAIL_SQN, L_LBTRM_DATA_HDR_T_TRAIL_SQN, ENC_BIG_ENDIAN);
1055     flags_val = tvb_get_guint8(tvb, offset + O_LBTRM_DATA_HDR_T_FLAGS_FEC_TYPE);
1056     proto_tree_add_bitmask(data_tree, tvb, offset + O_LBTRM_DATA_HDR_T_FLAGS_FEC_TYPE, hf_lbtrm_data_flags_fec_type, ett_lbtrm_data_flags_fec_type, flags, ENC_BIG_ENDIAN);
1057     proto_tree_add_item(data_tree, hf_lbtrm_data_flags_tgsz, tvb, offset + O_LBTRM_DATA_HDR_T_FLAGS_TGSZ, L_LBTRM_DATA_HDR_T_FLAGS_TGSZ, ENC_BIG_ENDIAN);
1058     proto_tree_add_item(data_tree, hf_lbtrm_data_fec_symbol, tvb, offset + O_LBTRM_DATA_HDR_T_FEC_SYMBOL, L_LBTRM_DATA_HDR_T_FEC_SYMBOL, ENC_BIG_ENDIAN);
1059     sqn = tvb_get_ntohl(tvb, offset + O_LBTRM_DATA_HDR_T_SQN);
1060     if (sequence != NULL)
1061     {
1062         *sequence = sqn;
1063     }
1064     if ((flags_val & LBTRM_DATA_RETRANSMISSION_FLAG) != 0)
1065     {
1066         is_retransmission = TRUE;
1067         expert_add_info_format(pinfo, sqn_item, &ei_lbtrm_analysis_rx, "RX 0x%08x", sqn);
1068     }
1069     if (retransmission != NULL)
1070     {
1071         *retransmission = is_retransmission;
1072     }
1073     tap_info->retransmission = is_retransmission;
1074     tap_info->sqn = sqn;
1075     return (L_LBTRM_DATA_HDR_T);
1076 }
1077
1078 /*----------------------------------------------------------------------------*/
1079 /* LBT-RM packet dissector.                                                   */
1080 /*----------------------------------------------------------------------------*/
1081 typedef struct
1082 {
1083     proto_tree * tree;
1084     tvbuff_t * tvb;
1085     guint32 current_frame;
1086 } lbtrm_sqn_frame_list_callback_data_t;
1087
1088 static gboolean dissect_lbtrm_sqn_frame_list_callback(const void *key _U_, void * frame, void * user_data)
1089 {
1090     lbtrm_sqn_frame_list_callback_data_t * cb_data = (lbtrm_sqn_frame_list_callback_data_t *) user_data;
1091     proto_item * transport_item = NULL;
1092     lbm_transport_sqn_frame_t * sqn_frame = (lbm_transport_sqn_frame_t *) frame;
1093
1094     if (sqn_frame->frame != cb_data->current_frame)
1095     {
1096         if (sqn_frame->retransmission)
1097         {
1098             transport_item = proto_tree_add_uint_format_value(cb_data->tree, hf_lbtrm_analysis_sqn_frame, cb_data->tvb, 0, 0, sqn_frame->frame, "%" G_GUINT32_FORMAT " (RX)", sqn_frame->frame);
1099         }
1100         else
1101         {
1102             transport_item = proto_tree_add_uint(cb_data->tree, hf_lbtrm_analysis_sqn_frame, cb_data->tvb, 0, 0, sqn_frame->frame);
1103         }
1104         PROTO_ITEM_SET_GENERATED(transport_item);
1105     }
1106     return (FALSE);
1107 }
1108
1109 static int dissect_lbtrm(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * user_data _U_)
1110 {
1111     proto_tree * lbtrm_tree = NULL;
1112     proto_item * lbtrm_item;
1113     int offset = 0;
1114     guint8 next_hdr = 0;
1115     char * tag_name = NULL;
1116     int dissected_len = 0;
1117     int total_dissected_len = 0;
1118     proto_tree * hdr_tree = NULL;
1119     proto_item * hdr_item = NULL;
1120     guint16 src_port = 0;
1121     guint32 session_id = 0;
1122     guint16 dest_port = 0;
1123     lbtrm_transport_t * transport = NULL;
1124     proto_tree * transport_tree = NULL;
1125     proto_item * transport_item = NULL;
1126     guint32 sequence = 0;
1127     gboolean retransmission = FALSE;
1128     guint8 packet_type = 0;
1129     guint64 channel = LBM_CHANNEL_NO_CHANNEL;
1130     guint8 ver_type = 0;
1131     guint8 flags_fec_type = 0;
1132     guint16 num_naks = 0;
1133     guint16 num_ncfs = 0;
1134     lbm_lbtrm_tap_info_t * tapinfo = NULL;
1135     proto_item * header_type_item = NULL;
1136
1137     col_add_str(pinfo->cinfo, COL_PROTOCOL, "LBT-RM");
1138     col_clear(pinfo->cinfo, COL_INFO);
1139     if (lbtrm_use_tag)
1140     {
1141         tag_name = lbtrm_tag_find(pinfo);
1142     }
1143     if (tag_name != NULL)
1144     {
1145         col_add_fstr(pinfo->cinfo, COL_INFO, "[Tag: %s]", tag_name);
1146     }
1147     col_set_fence(pinfo->cinfo, COL_INFO);
1148
1149     ver_type = tvb_get_guint8(tvb, O_LBTRM_HDR_T_VER_TYPE);
1150     packet_type = LBTRM_HDR_TYPE(ver_type);
1151     next_hdr = tvb_get_guint8(tvb, O_LBTRM_HDR_T_NEXT_HDR);
1152     src_port = tvb_get_ntohs(tvb, O_LBTRM_HDR_T_UCAST_PORT);
1153     session_id = tvb_get_ntohl(tvb, O_LBTRM_HDR_T_SESSION_ID);
1154     if (tag_name != NULL)
1155     {
1156         lbtrm_item = proto_tree_add_protocol_format(tree, proto_lbtrm, tvb, offset, -1, "LBT-RM Protocol (Tag: %s): Version %u, Type %s: Source Unicast Port %" G_GUINT16_FORMAT ", Session ID 0x%08x",
1157             tag_name, LBTRM_HDR_VER(ver_type), val_to_str(packet_type, lbtrm_packet_type, "Unknown (0x%02x)"),
1158             src_port, session_id);
1159     }
1160     else
1161     {
1162         lbtrm_item = proto_tree_add_protocol_format(tree, proto_lbtrm, tvb, offset, -1, "LBT-RM Protocol: Version %u, Type %s: Source Unicast Port %" G_GUINT16_FORMAT ", Session ID 0x%08x",
1163             LBTRM_HDR_VER(ver_type), val_to_str(packet_type, lbtrm_packet_type, "Unknown (0x%02x)"),
1164             src_port, session_id);
1165     }
1166     lbtrm_tree = proto_item_add_subtree(lbtrm_item, ett_lbtrm);
1167
1168     /* Addresses are in network order, ports in host order. */
1169     dest_port = pinfo->destport;
1170
1171     if (PINFO_FD_VISITED(pinfo) == 0)
1172     {
1173         /* First time through - add the info. */
1174         /* Note that this won't handle the case when a NAK occurs in the capture before any other packets for that transport. Oh well. */
1175         if (packet_type == LBTRM_PACKET_TYPE_NAK)
1176         {
1177             transport = lbtrm_transport_unicast_find(&(pinfo->dst), src_port, session_id, pinfo->num);
1178         }
1179         else
1180         {
1181             transport = lbtrm_transport_add(&(pinfo->src), src_port, session_id, &(pinfo->dst), dest_port, pinfo->num);
1182         }
1183     }
1184     else
1185     {
1186         if (packet_type == LBTRM_PACKET_TYPE_NAK)
1187         {
1188             transport = lbtrm_transport_unicast_find(&(pinfo->dst), src_port, session_id, pinfo->num);
1189         }
1190         else
1191         {
1192             transport = lbtrm_transport_find(&(pinfo->src), src_port, session_id, &(pinfo->dst), dest_port, pinfo->num);
1193         }
1194     }
1195     if (transport != NULL)
1196     {
1197         proto_item * item = NULL;
1198
1199         channel = transport->channel;
1200         item = proto_tree_add_uint64(lbtrm_tree, hf_lbtrm_channel, tvb, 0, 0, channel);
1201         PROTO_ITEM_SET_GENERATED(item);
1202     }
1203     if (tag_name != NULL)
1204     {
1205         proto_item * item = NULL;
1206
1207         item = proto_tree_add_string(lbtrm_tree, hf_lbtrm_tag, tvb, 0, 0, tag_name);
1208         PROTO_ITEM_SET_GENERATED(item);
1209     }
1210     tapinfo = wmem_new0(wmem_packet_scope(), lbm_lbtrm_tap_info_t);
1211     if (transport != NULL)
1212     {
1213         tapinfo->transport = lbtrm_transport_source_string_transport(transport);
1214     }
1215     tapinfo->type = packet_type;
1216
1217     hdr_item = proto_tree_add_item(lbtrm_tree, hf_lbtrm_hdr, tvb, O_LBTRM_HDR_T_VER_TYPE, L_LBTRM_HDR_T, ENC_NA);
1218     hdr_tree = proto_item_add_subtree(hdr_item, ett_lbtrm_hdr);
1219     proto_tree_add_item(hdr_tree, hf_lbtrm_hdr_ver, tvb, O_LBTRM_HDR_T_VER_TYPE, L_LBTRM_HDR_T_VER_TYPE, ENC_BIG_ENDIAN);
1220     header_type_item = proto_tree_add_item(hdr_tree, hf_lbtrm_hdr_type, tvb, O_LBTRM_HDR_T_VER_TYPE, L_LBTRM_HDR_T_VER_TYPE, ENC_BIG_ENDIAN);
1221     /* Setup the INFO column for this packet. */
1222     switch (packet_type)
1223     {
1224         case LBTRM_PACKET_TYPE_DATA:
1225             sequence = tvb_get_ntohl(tvb, L_LBTRM_HDR_T + O_LBTRM_DATA_HDR_T_SQN);
1226             flags_fec_type = tvb_get_guint8(tvb, L_LBTRM_HDR_T + O_LBTRM_DATA_HDR_T_FLAGS_FEC_TYPE);
1227             if ((flags_fec_type & LBTRM_DATA_RETRANSMISSION_FLAG) != 0)
1228             {
1229                 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "DATA(RX) sqn 0x%x Port %" G_GUINT16_FORMAT " ID 0x%08x", sequence, src_port, session_id);
1230             }
1231             else
1232             {
1233                 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "DATA sqn 0x%x Port %" G_GUINT16_FORMAT " ID 0x%08x", sequence, src_port, session_id);
1234             }
1235             break;
1236         case LBTRM_PACKET_TYPE_SM:
1237             sequence = tvb_get_ntohl(tvb, L_LBTRM_HDR_T + O_LBTRM_SM_HDR_T_SM_SQN);
1238             col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "SM sqn 0x%x Port %" G_GUINT16_FORMAT " ID 0x%08x", sequence, src_port, session_id);
1239             break;
1240         case LBTRM_PACKET_TYPE_NAK:
1241             num_naks = tvb_get_ntohs(tvb, L_LBTRM_HDR_T + O_LBTRM_NAK_HDR_T_NUM_NAKS);
1242             col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "NAK %u naks Port %" G_GUINT16_FORMAT " ID 0x%08x", num_naks, src_port, session_id);
1243             break;
1244         case LBTRM_PACKET_TYPE_NCF:
1245             num_ncfs = tvb_get_ntohs(tvb, L_LBTRM_HDR_T + O_LBTRM_NCF_HDR_T_NUM_NCFS);
1246             col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "NCF %u ncfs Port %" G_GUINT16_FORMAT " ID 0x%08x", num_ncfs, src_port, session_id);
1247             break;
1248         default:
1249             col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "Unknown (0x%02x)", packet_type);
1250             expert_add_info_format(pinfo, header_type_item, &ei_lbtrm_analysis_invalid_value, "Unrecognized type 0x%02x", packet_type);
1251             break;
1252     }
1253
1254     proto_tree_add_item(hdr_tree, hf_lbtrm_hdr_next_hdr, tvb, O_LBTRM_HDR_T_NEXT_HDR, L_LBTRM_HDR_T_NEXT_HDR, ENC_BIG_ENDIAN);
1255     proto_tree_add_item(hdr_tree, hf_lbtrm_hdr_ucast_port, tvb, O_LBTRM_HDR_T_UCAST_PORT, L_LBTRM_HDR_T_UCAST_PORT, ENC_BIG_ENDIAN);
1256     proto_tree_add_item(hdr_tree, hf_lbtrm_hdr_session_id, tvb, O_LBTRM_HDR_T_SESSION_ID, L_LBTRM_HDR_T_SESSION_ID, ENC_BIG_ENDIAN);
1257     total_dissected_len = L_LBTRM_HDR_T;
1258     offset = L_LBTRM_HDR_T;
1259     switch (packet_type)
1260     {
1261         case LBTRM_PACKET_TYPE_DATA:
1262             dissected_len = dissect_lbtrm_data(tvb, offset, pinfo, lbtrm_tree, &sequence, &retransmission, tapinfo);
1263             break;
1264         case LBTRM_PACKET_TYPE_SM:
1265             dissected_len = dissect_lbtrm_sm(tvb, offset, pinfo, lbtrm_tree, &sequence, tapinfo);
1266             break;
1267         case LBTRM_PACKET_TYPE_NAK:
1268             dissected_len = dissect_lbtrm_nak(tvb, offset, pinfo, lbtrm_tree, tapinfo);
1269             break;
1270         case LBTRM_PACKET_TYPE_NCF:
1271             dissected_len = dissect_lbtrm_ncf(tvb, offset, pinfo, lbtrm_tree, tapinfo);
1272             break;
1273         default:
1274             return (total_dissected_len);
1275             break;
1276     }
1277     total_dissected_len += dissected_len;
1278     offset += dissected_len;
1279     while (next_hdr != LBTRM_NHDR_DATA)
1280     {
1281         guint8 hdrlen = 0;
1282
1283         next_hdr = tvb_get_guint8(tvb, offset + O_LBTRM_BASIC_OPT_T_NEXT_HDR);
1284         hdrlen = tvb_get_guint8(tvb, offset + O_LBTRM_BASIC_OPT_T_HDR_LEN);
1285         if (hdrlen == 0)
1286         {
1287             break;
1288         }
1289         offset += hdrlen;
1290         total_dissected_len += hdrlen;
1291     }
1292
1293     if (lbtrm_sequence_analysis)
1294     {
1295         if (pinfo->fd->flags.visited == 0)
1296         {
1297             if (transport != NULL)
1298             {
1299                 lbtrm_transport_frame_add(transport, packet_type, pinfo->num, sequence, retransmission);
1300             }
1301         }
1302         else
1303         {
1304             if (transport != NULL)
1305             {
1306                 lbm_transport_frame_t * frame = NULL;
1307
1308                 /* Setup the tree */
1309                 transport_item = proto_tree_add_item(lbtrm_tree, hf_lbtrm_analysis, tvb, 0, 0, ENC_NA);
1310                 PROTO_ITEM_SET_GENERATED(transport_item);
1311                 transport_tree = proto_item_add_subtree(transport_item, ett_lbtrm_transport);
1312                 frame = lbtrm_transport_frame_find(transport, pinfo->num);
1313                 if (frame != NULL)
1314                 {
1315                     lbm_transport_sqn_t * sqn = NULL;
1316
1317                     if (frame->previous_frame != 0)
1318                     {
1319                         transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_prev_frame, tvb, 0, 0, frame->previous_frame);
1320                         PROTO_ITEM_SET_GENERATED(transport_item);
1321                     }
1322                     if (frame->next_frame != 0)
1323                     {
1324                         transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_next_frame, tvb, 0, 0, frame->next_frame);
1325                         PROTO_ITEM_SET_GENERATED(transport_item);
1326                     }
1327                     switch (packet_type)
1328                     {
1329                         case LBTRM_PACKET_TYPE_DATA:
1330                             if (frame->previous_type_frame != 0)
1331                             {
1332                                 transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_prev_data_frame, tvb, 0, 0, frame->previous_type_frame);
1333                                 PROTO_ITEM_SET_GENERATED(transport_item);
1334                             }
1335                             if (frame->next_type_frame != 0)
1336                             {
1337                                 transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_next_data_frame, tvb, 0, 0, frame->next_type_frame);
1338                                 PROTO_ITEM_SET_GENERATED(transport_item);
1339                             }
1340                             sqn = lbtrm_transport_sqn_find(transport, packet_type, sequence);
1341                             if (sqn != NULL)
1342                             {
1343                                 if (sqn->frame_count > 1)
1344                                 {
1345                                     proto_tree * frame_tree = NULL;
1346                                     proto_item * frame_tree_item = NULL;
1347                                     lbtrm_sqn_frame_list_callback_data_t cb_data;
1348
1349                                     frame_tree_item = proto_tree_add_item(transport_tree, hf_lbtrm_analysis_sqn, tvb, 0, 0, ENC_NA);
1350                                     PROTO_ITEM_SET_GENERATED(frame_tree_item);
1351                                     frame_tree = proto_item_add_subtree(frame_tree_item, ett_lbtrm_transport_sqn);
1352                                     cb_data.tree = frame_tree;
1353                                     cb_data.tvb = tvb;
1354                                     cb_data.current_frame = pinfo->num;
1355                                     wmem_tree_foreach(sqn->frame, dissect_lbtrm_sqn_frame_list_callback, (void *) &cb_data);
1356                                 }
1357                             }
1358                             if (frame->retransmission)
1359                             {
1360                                 transport_item = proto_tree_add_boolean(transport_tree, hf_lbtrm_analysis_data_retransmission, tvb, 0, 0, TRUE);
1361                                 PROTO_ITEM_SET_GENERATED(transport_item);
1362                                 expert_add_info(pinfo, transport_item, &ei_lbtrm_analysis_data_rx);
1363                             }
1364                             if (frame->sqn_gap != 0)
1365                             {
1366                                 transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_data_sqn_gap, tvb, 0, 0, frame->sqn_gap);
1367                                 PROTO_ITEM_SET_GENERATED(transport_item);
1368                                 expert_add_info_format(pinfo, transport_item, &ei_lbtrm_analysis_data_gap, "Data sequence gap (%" G_GUINT32_FORMAT ")", frame->sqn_gap);
1369                             }
1370                             if (frame->ooo_gap != 0)
1371                             {
1372                                 transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_data_ooo_gap, tvb, 0, 0, frame->ooo_gap);
1373                                 PROTO_ITEM_SET_GENERATED(transport_item);
1374                                 expert_add_info_format(pinfo, transport_item, &ei_lbtrm_analysis_data_ooo, "Data sequence out of order gap (%" G_GUINT32_FORMAT ")", frame->ooo_gap);
1375                             }
1376                             if (frame->duplicate)
1377                             {
1378                                 transport_item = proto_tree_add_boolean(transport_tree, hf_lbtrm_analysis_data_duplicate, tvb, 0, 0, TRUE);
1379                                 PROTO_ITEM_SET_GENERATED(transport_item);
1380                                 expert_add_info(pinfo, transport_item, &ei_lbtrm_analysis_data_dup);
1381                             }
1382                             break;
1383                         case LBTRM_PACKET_TYPE_SM:
1384                             if (frame->previous_type_frame != 0)
1385                             {
1386                                 transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_prev_sm_frame, tvb, 0, 0, frame->previous_type_frame);
1387                                 PROTO_ITEM_SET_GENERATED(transport_item);
1388                             }
1389                             if (frame->next_type_frame != 0)
1390                             {
1391                                 transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_next_sm_frame, tvb, 0, 0, frame->next_type_frame);
1392                                 PROTO_ITEM_SET_GENERATED(transport_item);
1393                             }
1394                             sqn = lbtrm_transport_sqn_find(transport, packet_type, sequence);
1395                             if (sqn != NULL)
1396                             {
1397                                 if (sqn->frame_count > 1)
1398                                 {
1399                                     proto_tree * frame_tree = NULL;
1400                                     proto_item * frame_tree_item = NULL;
1401                                     lbtrm_sqn_frame_list_callback_data_t cb_data;
1402
1403                                     frame_tree_item = proto_tree_add_item(transport_tree, hf_lbtrm_analysis_sqn, tvb, 0, 0, ENC_NA);
1404                                     PROTO_ITEM_SET_GENERATED(frame_tree_item);
1405                                     frame_tree = proto_item_add_subtree(frame_tree_item, ett_lbtrm_transport_sqn);
1406                                     cb_data.tree = frame_tree;
1407                                     cb_data.tvb = tvb;
1408                                     cb_data.current_frame = pinfo->num;
1409                                     wmem_tree_foreach(sqn->frame, dissect_lbtrm_sqn_frame_list_callback, (void *) &cb_data);
1410                                 }
1411                             }
1412                             if (frame->sqn_gap != 0)
1413                             {
1414                                 transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_sm_sqn_gap, tvb, 0, 0, frame->sqn_gap);
1415                                 PROTO_ITEM_SET_GENERATED(transport_item);
1416                                 expert_add_info_format(pinfo, transport_item, &ei_lbtrm_analysis_sm_gap, "SM sequence gap (%" G_GUINT32_FORMAT ")", frame->sqn_gap);
1417                             }
1418                             if (frame->ooo_gap != 0)
1419                             {
1420                                 transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_sm_ooo_gap, tvb, 0, 0, frame->ooo_gap);
1421                                 PROTO_ITEM_SET_GENERATED(transport_item);
1422                                 expert_add_info_format(pinfo, transport_item, &ei_lbtrm_analysis_sm_ooo, "SM sequence out of order gap (%" G_GUINT32_FORMAT ")", frame->ooo_gap);
1423                             }
1424                             if (frame->duplicate)
1425                             {
1426                                 transport_item = proto_tree_add_boolean(transport_tree, hf_lbtrm_analysis_sm_duplicate, tvb, 0, 0, TRUE);
1427                                 PROTO_ITEM_SET_GENERATED(transport_item);
1428                                 expert_add_info(pinfo, transport_item, &ei_lbtrm_analysis_sm_dup);
1429                             }
1430                             break;
1431                         case LBTRM_PACKET_TYPE_NAK:
1432                             if (frame->previous_type_frame != 0)
1433                             {
1434                                 transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_prev_nak_frame, tvb, 0, 0, frame->previous_type_frame);
1435                                 PROTO_ITEM_SET_GENERATED(transport_item);
1436                             }
1437                             if (frame->next_type_frame != 0)
1438                             {
1439                                 transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_next_nak_frame, tvb, 0, 0, frame->next_type_frame);
1440                                 PROTO_ITEM_SET_GENERATED(transport_item);
1441                             }
1442                             break;
1443                         case LBTRM_PACKET_TYPE_NCF:
1444                             if (frame->previous_type_frame != 0)
1445                             {
1446                                 transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_prev_ncf_frame, tvb, 0, 0, frame->previous_type_frame);
1447                                 PROTO_ITEM_SET_GENERATED(transport_item);
1448                             }
1449                             if (frame->next_type_frame != 0)
1450                             {
1451                                 transport_item = proto_tree_add_uint(transport_tree, hf_lbtrm_analysis_next_ncf_frame, tvb, 0, 0, frame->next_type_frame);
1452                                 PROTO_ITEM_SET_GENERATED(transport_item);
1453                             }
1454                             break;
1455                         default:
1456                             break;
1457                     }
1458                 }
1459             }
1460         }
1461     }
1462     proto_item_set_len(lbtrm_item, total_dissected_len);
1463     if ((packet_type == LBTRM_PACKET_TYPE_DATA) && (next_hdr == LBTRM_NHDR_DATA))
1464     {
1465         total_dissected_len += dissect_lbtrm_data_contents(tvb, offset, pinfo, tree, tag_name, channel);
1466     }
1467     if (tapinfo->transport != NULL)
1468     {
1469         tap_queue_packet(lbtrm_tap_handle, pinfo, (void *) tapinfo);
1470     }
1471     return (total_dissected_len);
1472 }
1473
1474 static gboolean test_lbtrm_packet(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * user_data)
1475 {
1476     guint32 dest_addr_h;
1477     gboolean valid_packet = FALSE;
1478     guint8 ver_type = 0;
1479     guint8 packet_type = 0;
1480     guint8 packet_ver = 0;
1481     guint8 next_hdr = 0;
1482
1483     /* Must be a UDP packet. */
1484     if (pinfo->ptype != PT_UDP)
1485     {
1486         return (FALSE);
1487     }
1488     /* Destination address must be IPV4 and 4 bytes in length. */
1489     if ((pinfo->dst.type != AT_IPv4) || (pinfo->dst.len != 4))
1490     {
1491         return (FALSE);
1492     }
1493     if (tvb_reported_length_remaining(tvb, 0) < L_LBTRM_HDR_T)
1494     {
1495         return (FALSE);
1496     }
1497     ver_type = tvb_get_guint8(tvb, O_LBTRM_HDR_T_VER_TYPE);
1498     packet_type = LBTRM_HDR_TYPE(ver_type);
1499     switch (packet_type)
1500     {
1501         case LBTRM_PACKET_TYPE_DATA:
1502         case LBTRM_PACKET_TYPE_SM:
1503         case LBTRM_PACKET_TYPE_NAK:
1504         case LBTRM_PACKET_TYPE_NCF:
1505             break;
1506         default:
1507             return (FALSE);
1508     }
1509     packet_ver = LBTRM_HDR_VER(ver_type);
1510     if (packet_ver != LBTRM_VERSION)
1511     {
1512         return (FALSE);
1513     }
1514     next_hdr = tvb_get_guint8(tvb, O_LBTRM_HDR_T_NEXT_HDR);
1515     if (next_hdr != LBTRM_NHDR_DATA)
1516     {
1517         return (FALSE);
1518     }
1519     if (lbtrm_use_tag)
1520     {
1521         if (lbtrm_tag_find(pinfo) != NULL)
1522         {
1523             valid_packet = TRUE;
1524         }
1525     }
1526     else
1527     {
1528         dest_addr_h = pntoh32(pinfo->dst.data);
1529
1530         /* Is the destination a multicast address? */
1531         if (IN_MULTICAST(dest_addr_h))
1532         {
1533             /* Check the MC address. */
1534             if ((dest_addr_h >= lbtrm_mc_address_low_host) && (dest_addr_h <= lbtrm_mc_address_high_host))
1535             {
1536                 /* It's in the LBT-RM multicast range. Check the ports. */
1537                 if ((pinfo->destport >= lbtrm_dest_port_low) && (pinfo->destport <= lbtrm_dest_port_high))
1538                 {
1539                     /* Must be one of ours. */
1540                     valid_packet = TRUE;
1541                 }
1542             }
1543             else if ((dest_addr_h == mim_incoming_mc_address_host) || (dest_addr_h == mim_outgoing_mc_address_host))
1544             {
1545                 /* Might be MIM. Check the port. */
1546                 if (((dest_addr_h == mim_incoming_mc_address_host) && (pinfo->destport == mim_incoming_dest_port))
1547                     || ((dest_addr_h == mim_outgoing_mc_address_host) && (pinfo->destport == mim_outgoing_dest_port)))
1548                 {
1549                     /* Must be one of ours. */
1550                     valid_packet = TRUE;
1551                 }
1552             }
1553         }
1554         else
1555         {
1556             /* Not multicast, might be a unicast UDP NAK. Check the destination port. */
1557             if ((pinfo->destport >= lbtrm_src_port_low) && (pinfo->destport <= lbtrm_src_port_high))
1558             {
1559                 valid_packet = TRUE;
1560             }
1561         }
1562     }
1563     if (valid_packet)
1564     {
1565         dissect_lbtrm(tvb, pinfo, tree, user_data);
1566         return (TRUE);
1567     }
1568     return (FALSE);
1569 }
1570
1571 /* Register all the bits needed with the filtering engine */
1572 void proto_register_lbtrm(void)
1573 {
1574     static hf_register_info hf[] =
1575     {
1576         { &hf_lbtrm_channel,
1577             { "Channel ID", "lbtrm.channel", FT_UINT64, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } },
1578         { &hf_lbtrm_tag,
1579             { "Tag", "lbtrm.tag", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1580         { &hf_lbtrm_hdr,
1581             { "Header", "lbtrm.hdr", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1582         { &hf_lbtrm_hdr_ver,
1583             { "Version", "lbtrm.hdr.ver", FT_UINT8, BASE_HEX, NULL, LBTRM_HDR_VER_MASK, NULL, HFILL } },
1584         { &hf_lbtrm_hdr_type,
1585             { "Type", "lbtrm.hdr.type", FT_UINT8, BASE_HEX, VALS(lbtrm_packet_type), LBTRM_HDR_TYPE_MASK, NULL, HFILL } },
1586         { &hf_lbtrm_hdr_next_hdr,
1587             { "Next Header", "lbtrm.hdr.next_hdr", FT_UINT8, BASE_HEX, VALS(lbtrm_next_header), 0x0, NULL, HFILL } },
1588         { &hf_lbtrm_hdr_ucast_port,
1589             { "Source Unicast Port", "lbtrm.hdr.ucast_port", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
1590         { &hf_lbtrm_hdr_session_id,
1591             { "Session ID", "lbtrm.hdr.session_id", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
1592         { &hf_lbtrm_data,
1593             { "Data Header", "lbtrm.data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1594         { &hf_lbtrm_data_sqn,
1595             { "Sequence Number", "lbtrm.data.sqn", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } },
1596         { &hf_lbtrm_data_trail_sqn,
1597             { "Trailing Edge Sequence Number", "lbtrm.data.trail_sqn", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } },
1598         { &hf_lbtrm_data_flags_fec_type,
1599             { "FEC Flags", "lbtrm.data.flags_fec_type", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
1600         { &hf_lbtrm_data_flags_fec_type_ucast_naks,
1601             { "Unicast NAKs", "lbtrm.data.flags_fec_type.ucast_naks", FT_BOOLEAN, L_LBTRM_DATA_HDR_T_FLAGS_FEC_TYPE * 8, TFS(&tfs_set_notset), LBTRM_DATA_UNICAST_NAKS_FLAG, "Set if NAKs are sent via unicast", HFILL } },
1602         { &hf_lbtrm_data_flags_fec_type_rx,
1603             { "Retransmission", "lbtrm.data.flags_fec_type.rx", FT_BOOLEAN, L_LBTRM_DATA_HDR_T_FLAGS_FEC_TYPE * 8, TFS(&tfs_set_notset), LBTRM_DATA_RETRANSMISSION_FLAG, "Set if this is a retransmission", HFILL } },
1604         { &hf_lbtrm_data_flags_tgsz,
1605             { "TGSZ Flags", "lbtrm.data.flags_tgsz", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
1606         { &hf_lbtrm_data_fec_symbol,
1607             { "FEC Symbol", "lbtrm.data.fec_symbol", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } },
1608         { &hf_lbtrm_sm,
1609             { "Session Message Header", "lbtrm.sm", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1610         { &hf_lbtrm_sm_sm_sqn,
1611             { "Sequence Number", "lbtrm.sm.sm_sqn", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } },
1612         { &hf_lbtrm_sm_lead_sqn,
1613             { "Lead Sequence Number", "lbtrm.sm.lead_sqn", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } },
1614         { &hf_lbtrm_sm_trail_sqn,
1615             { "Trail Sequence Number", "lbtrm.sm.trail_sqn", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } },
1616         { &hf_lbtrm_sm_flags_fec_type,
1617             { "FEC Flags", "lbtrm.sm.flags_fec_type", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
1618         { &hf_lbtrm_sm_flags_fec_type_ucast_naks,
1619             { "Unicast NAKs", "lbtrm.sm.flags_fec_type.ucast_naks", FT_BOOLEAN, 8, TFS(&tfs_present_not_present), LBTRM_SM_UNICAST_NAKS_FLAG, "Set if NAKs are sent via unicast", HFILL } },
1620         { &hf_lbtrm_sm_flags_tgsz,
1621             { "TGSZ Flags", "lbtrm.sm.flags_tgsz", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
1622         { &hf_lbtrm_sm_reserved,
1623             { "Reserved", "lbtrm.sm.reserved", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } },
1624         { &hf_lbtrm_nak,
1625             { "NAK Header", "lbtrm.nak", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1626         { &hf_lbtrm_nak_num_naks,
1627             { "Number of NAKs", "lbtrm.nak.num_naks", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
1628         { &hf_lbtrm_nak_format,
1629             { "Format", "lbtrm.nak.format", FT_UINT8, BASE_HEX, VALS(lbtrm_nak_format), LBTRM_NAK_HDR_FORMAT_MASK, NULL, HFILL } },
1630         { &hf_lbtrm_nak_list,
1631             { "NAK List", "lbtrm.nak.list", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1632         { &hf_lbtrm_nak_list_nak,
1633             { "NAK", "lbtrm.nak.list.nak", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
1634         { &hf_lbtrm_ncf,
1635             { "NAK Confirmation Header", "lbtrm.ncf", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1636         { &hf_lbtrm_ncf_trail_sqn,
1637             { "Trailing Sequence Number", "lbtrm.ncf.trail_sqn", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } },
1638         { &hf_lbtrm_ncf_num_ncfs,
1639             { "Number of Individual NCFs", "lbtrm.ncf.num_ncfs", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
1640         { &hf_lbtrm_ncf_reserved,
1641             { "Reserved", "lbtrm.ncf.reserved", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
1642         { &hf_lbtrm_ncf_reason,
1643             { "Reason", "lbtrm.ncf.reason", FT_UINT8, BASE_HEX, VALS(lbtrm_ncf_reason), LBTRM_NCF_HDR_REASON_MASK, NULL, HFILL } },
1644         { &hf_lbtrm_ncf_format,
1645             { "Format", "lbtrm.ncf.format", FT_UINT8, BASE_HEX, VALS(lbtrm_ncf_format), LBTRM_NCF_HDR_FORMAT_MASK, NULL, HFILL } },
1646         { &hf_lbtrm_ncf_list,
1647             { "NCF List", "lbtrm.ncf.list", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1648         { &hf_lbtrm_ncf_list_ncf,
1649             { "NCF", "lbtrm.ncf.list.ncf", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } },
1650         { &hf_lbtrm_analysis,
1651             { "Transport Analysis", "lbtrm.transport", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1652         { &hf_lbtrm_analysis_prev_frame,
1653             { "Previous Transport frame", "lbtrm.transport.prev_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1654         { &hf_lbtrm_analysis_prev_data_frame,
1655             { "Previous Transport DATA frame", "lbtrm.transport.prev_data_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1656         { &hf_lbtrm_analysis_prev_sm_frame,
1657             { "Previous Transport SM frame", "lbtrm.transport.prev_sm_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1658         { &hf_lbtrm_analysis_prev_nak_frame,
1659             { "Previous Transport NAK frame", "lbtrm.transport.prev_nak_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1660         { &hf_lbtrm_analysis_prev_ncf_frame,
1661             { "Previous Transport NCF frame", "lbtrm.transport.prev_ncf_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1662         { &hf_lbtrm_analysis_next_frame,
1663             { "Next Transport frame", "lbtrm.transport.next_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1664         { &hf_lbtrm_analysis_next_data_frame,
1665             { "Next Transport DATA frame", "lbtrm.transport.next_data_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1666         { &hf_lbtrm_analysis_next_sm_frame,
1667             { "Next Transport SM frame", "lbtrm.transport.next_sm_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1668         { &hf_lbtrm_analysis_next_nak_frame,
1669             { "Next Transport NAK frame", "lbtrm.transport.next_nak_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1670         { &hf_lbtrm_analysis_next_ncf_frame,
1671             { "Next Transport NCF frame", "lbtrm.transport.next_ncf_frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1672         { &hf_lbtrm_analysis_sqn,
1673             { "SQN Also in", "lbtrm.transport.sqn", FT_NONE, BASE_NONE, NULL, 0x0, "Sequence number also appears in these frames", HFILL } },
1674         { &hf_lbtrm_analysis_sqn_frame,
1675             { "Frame", "lbtrm.transport.sqn.frame", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1676         { &hf_lbtrm_analysis_data_retransmission,
1677             { "Frame is a Data Retransmission", "lbtrm.transport.data_retransmission", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1678         { &hf_lbtrm_analysis_data_sqn_gap,
1679             { "Gap in Data Sequence", "lbtrm.transport.data_sqn_gap", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
1680         { &hf_lbtrm_analysis_data_ooo_gap,
1681             { "Data Sequence Out of Order Gap", "lbtrm.transport.data_ooo_gap", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
1682         { &hf_lbtrm_analysis_data_duplicate,
1683             { "Duplicate Data frame", "lbtrm.transport.data_duplicate", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1684         { &hf_lbtrm_analysis_sm_sqn_gap,
1685             { "Gap in SM Sequence", "lbtrm.transport.sm_sqn_gap", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
1686         { &hf_lbtrm_analysis_sm_ooo_gap,
1687             { "SM Sequence Out of Order Gap", "lbtrm.transport.sm_ooo_gap", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
1688         { &hf_lbtrm_analysis_sm_duplicate,
1689             { "Duplicate SM frame", "lbtrm.transport.sm_duplicate", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } },
1690     };
1691     static gint * ett[] =
1692     {
1693         &ett_lbtrm,
1694         &ett_lbtrm_hdr,
1695         &ett_lbtrm_data,
1696         &ett_lbtrm_data_flags_fec_type,
1697         &ett_lbtrm_sm,
1698         &ett_lbtrm_sm_flags_fec_type,
1699         &ett_lbtrm_nak,
1700         &ett_lbtrm_nak_list,
1701         &ett_lbtrm_ncf,
1702         &ett_lbtrm_ncf_list,
1703         &ett_lbtrm_transport,
1704         &ett_lbtrm_transport_sqn
1705     };
1706     static ei_register_info ei[] =
1707     {
1708         { &ei_lbtrm_analysis_ncf, { "lbtrm.analysis.ncf", PI_SEQUENCE, PI_NOTE, "NCF", EXPFILL } },
1709         { &ei_lbtrm_analysis_ncf_ncf, { "lbtrm.analysis.ncf.ncf", PI_SEQUENCE, PI_NOTE, "NCF", EXPFILL } },
1710         { &ei_lbtrm_analysis_nak, { "lbtrm.analysis.nak", PI_SEQUENCE, PI_WARN, "NAK", EXPFILL } },
1711         { &ei_lbtrm_analysis_nak_nak, { "lbtrm.analysis.nak.nak", PI_SEQUENCE, PI_WARN, "NAK", EXPFILL } },
1712         { &ei_lbtrm_analysis_sm, { "lbtrm.analysis.sm", PI_SEQUENCE, PI_CHAT, "SM", EXPFILL } },
1713         { &ei_lbtrm_analysis_rx, { "lbtrm.analysis.rx", PI_SEQUENCE, PI_NOTE, "RX", EXPFILL } },
1714         { &ei_lbtrm_analysis_invalid_value, { "lbtrm.analysis.invalid_value", PI_MALFORMED, PI_ERROR, "Invalid value", EXPFILL } },
1715         { &ei_lbtrm_analysis_data_rx, { "lbtrm.analysis.data.rx", PI_SEQUENCE, PI_NOTE, "Data RX", EXPFILL } },
1716         { &ei_lbtrm_analysis_data_gap, { "lbtrm.analysis.data.gap", PI_SEQUENCE, PI_NOTE, "Data sequence gap", EXPFILL } },
1717         { &ei_lbtrm_analysis_data_ooo, { "lbtrm.analysis.data.ooo", PI_SEQUENCE, PI_NOTE, "Data out of order", EXPFILL } },
1718         { &ei_lbtrm_analysis_data_dup, { "lbtrm.analysis.data.dup", PI_SEQUENCE, PI_NOTE, "Duplicate data", EXPFILL } },
1719         { &ei_lbtrm_analysis_sm_gap, { "lbtrm.analysis.sm.gap", PI_SEQUENCE, PI_NOTE, "SM sequence gap", EXPFILL } },
1720         { &ei_lbtrm_analysis_sm_ooo, { "lbtrm.analysis.sm.ooo", PI_SEQUENCE, PI_NOTE, "SM out of order", EXPFILL } },
1721         { &ei_lbtrm_analysis_sm_dup, { "lbtrm.analysis.sm.dup", PI_SEQUENCE, PI_NOTE, "Duplicate SM", EXPFILL } },
1722     };
1723     module_t * lbtrm_module;
1724     struct in_addr addr;
1725     uat_t * tag_uat;
1726     expert_module_t * expert_lbtrm;
1727
1728     proto_lbtrm = proto_register_protocol("LBT Reliable Multicast Protocol",
1729         "LBT-RM", "lbtrm");
1730
1731     proto_register_field_array(proto_lbtrm, hf, array_length(hf));
1732     proto_register_subtree_array(ett, array_length(ett));
1733     expert_lbtrm = expert_register_protocol(proto_lbtrm);
1734     expert_register_field_array(expert_lbtrm, ei, array_length(ei));
1735
1736     lbtrm_module = prefs_register_protocol_subtree("29West", proto_lbtrm, proto_reg_handoff_lbtrm);
1737     inet_aton(LBTRM_DEFAULT_MC_ADDRESS_LOW, &addr);
1738     lbtrm_mc_address_low_host = g_ntohl(addr.s_addr);
1739     prefs_register_string_preference(lbtrm_module,
1740         "mc_address_low",
1741         "Multicast address range low (default " LBTRM_DEFAULT_MC_ADDRESS_LOW ")",
1742         "Set the low end of the LBT-RM multicast address range (context transport_lbtrm_multicast_address_low)",
1743         &global_lbtrm_mc_address_low);
1744
1745     inet_aton(LBTRM_DEFAULT_MC_ADDRESS_HIGH, &addr);
1746     lbtrm_mc_address_high_host = g_ntohl(addr.s_addr);
1747     prefs_register_string_preference(lbtrm_module,
1748         "mc_address_high",
1749         "Multicast address range high (default " LBTRM_DEFAULT_MC_ADDRESS_HIGH ")",
1750         "Set the high end of the LBT-RM multicast address range (context transport_lbtrm_multicast_address_high)",
1751         &global_lbtrm_mc_address_high);
1752
1753     prefs_register_uint_preference(lbtrm_module,
1754         "dport_low",
1755         "Destination port range low (default " MAKESTRING(LBTRM_DEFAULT_DPORT_LOW)")",
1756         "Set the low end of the LBT-RM UDP destination port range (source transport_lbtrm_destination_port)",
1757         10,
1758         &global_lbtrm_dest_port_low);
1759
1760     prefs_register_uint_preference(lbtrm_module,
1761         "dport_high",
1762         "Destination port range high (default " MAKESTRING(LBTRM_DEFAULT_DPORT_HIGH)")",
1763         "Set the high end of the LBT-RM UDP destination port range (source transport_lbtrm_destination_port)",
1764         10,
1765         &global_lbtrm_dest_port_high);
1766
1767     prefs_register_uint_preference(lbtrm_module,
1768         "sport_low",
1769         "Source port range low (default " MAKESTRING(LBTRM_DEFAULT_SPORT_LOW)")",
1770         "Set the low end of the LBT-RM UDP source port range (context transport_lbtrm_source_port_low)",
1771         10,
1772         &global_lbtrm_src_port_low);
1773
1774     prefs_register_uint_preference(lbtrm_module,
1775         "sport_high",
1776         "Source port range high (default " MAKESTRING(LBTRM_DEFAULT_SPORT_HIGH)")",
1777         "Set the high end of the LBT-RM UDP source port range (context transport_lbtrm_source_port_high)",
1778         10,
1779         &global_lbtrm_src_port_high);
1780
1781     inet_aton(MIM_DEFAULT_MC_INCOMING_ADDRESS, &addr);
1782     mim_incoming_mc_address_host = g_ntohl(addr.s_addr);
1783     prefs_register_string_preference(lbtrm_module,
1784         "mim_incoming_address",
1785         "MIM incoming multicast address (default " MIM_DEFAULT_MC_INCOMING_ADDRESS ")",
1786         "Set the incoming MIM multicast address (context mim_incoming_address)",
1787         &global_mim_incoming_mc_address);
1788
1789     inet_aton(MIM_DEFAULT_MC_OUTGOING_ADDRESS, &addr);
1790     mim_outgoing_mc_address_host = g_ntohl(addr.s_addr);
1791     prefs_register_string_preference(lbtrm_module,
1792         "mim_outgoing_address",
1793         "MIM outgoing multicast address (default " MIM_DEFAULT_MC_OUTGOING_ADDRESS ")",
1794         "Set the outgoing MIM multicast address (context mim_outgoing_address)",
1795         &global_mim_outgoing_mc_address);
1796
1797     prefs_register_uint_preference(lbtrm_module,
1798         "mim_incoming_dport",
1799         "MIM incoming port (default " MAKESTRING(MIM_DEFAULT_INCOMING_DPORT)")",
1800         "Set the incoming MIM UDP port (context mim_incoming_destination_port)",
1801         10,
1802         &global_mim_incoming_dest_port);
1803
1804     prefs_register_uint_preference(lbtrm_module,
1805         "mim_outgoing_dport",
1806         "MIM outgoing port (default " MAKESTRING(MIM_DEFAULT_OUTGOING_DPORT)")",
1807         "Set the outgoing MIM UDP port (context mim_outgoing_destination_port)",
1808         10,
1809         &global_mim_outgoing_dest_port);
1810
1811     lbtrm_expert_separate_naks = global_lbtrm_expert_separate_naks;
1812     prefs_register_bool_preference(lbtrm_module,
1813         "expert_separate_naks",
1814         "Separate NAKs in Expert Info",
1815         "Separate multiple NAKs from a single packet into distinct Expert Info entries",
1816         &global_lbtrm_expert_separate_naks);
1817
1818     lbtrm_expert_separate_ncfs = global_lbtrm_expert_separate_ncfs;
1819     prefs_register_bool_preference(lbtrm_module,
1820         "expert_separate_ncfs",
1821         "Separate NCFs in Expert Info",
1822         "Separate multiple NCFs from a single packet into distinct Expert Info entries",
1823         &global_lbtrm_expert_separate_ncfs);
1824
1825     lbtrm_sequence_analysis = global_lbtrm_sequence_analysis;
1826     prefs_register_bool_preference(lbtrm_module,
1827         "sequence_analysis",
1828         "Perform sequence Number Analysis",
1829         "Perform analysis on LBT-RM sequence numbers to determine out-of-order, gaps, loss, etc",
1830         &global_lbtrm_sequence_analysis);
1831
1832     lbtrm_use_tag = global_lbtrm_use_tag;
1833     prefs_register_bool_preference(lbtrm_module,
1834         "use_lbtrm_domain",
1835         "Use LBT-RM tag table",
1836         "Use table of LBT-RM tags to decode the packet instead of above values",
1837         &global_lbtrm_use_tag);
1838     tag_uat = uat_new("LBT-RM tag definitions",
1839         sizeof(lbtrm_tag_entry_t),
1840         "lbtrm_domains",
1841         TRUE,
1842         (void * *)&lbtrm_tag_entry,
1843         &lbtrm_tag_count,
1844         UAT_AFFECTS_DISSECTION,
1845         NULL,
1846         lbtrm_tag_copy_cb,
1847         lbtrm_tag_update_cb,
1848         lbtrm_tag_free_cb,
1849         NULL,
1850         NULL,
1851         lbtrm_tag_array);
1852     prefs_register_uat_preference(lbtrm_module,
1853         "tnw_lbtrm_tags",
1854         "LBT-RM Tags",
1855         "A table to define LBT-RM tags",
1856         tag_uat);
1857 }
1858
1859 /* The registration hand-off routine */
1860 void proto_reg_handoff_lbtrm(void)
1861 {
1862     static gboolean already_registered = FALSE;
1863     struct in_addr addr;
1864     guint32 dest_addr_h_low;
1865     guint32 dest_addr_h_high;
1866
1867     if (!already_registered)
1868     {
1869         lbtrm_dissector_handle = create_dissector_handle(dissect_lbtrm, proto_lbtrm);
1870         dissector_add_for_decode_as_with_preference("udp.port", lbtrm_dissector_handle);
1871         heur_dissector_add("udp", test_lbtrm_packet, "LBT Reliable Multicast over UDP", "lbtrm_udp", proto_lbtrm, HEURISTIC_ENABLE);
1872         lbtrm_tap_handle = register_tap("lbm_lbtrm");
1873     }
1874
1875     /* Make sure the low MC address is <= the high MC address. If not, don't change them. */
1876     inet_aton(global_lbtrm_mc_address_low, &addr);
1877     dest_addr_h_low = g_ntohl(addr.s_addr);
1878     inet_aton(global_lbtrm_mc_address_high, &addr);
1879     dest_addr_h_high = g_ntohl(addr.s_addr);
1880     if (dest_addr_h_low <= dest_addr_h_high)
1881     {
1882         lbtrm_mc_address_low_host = dest_addr_h_low;
1883         lbtrm_mc_address_high_host = dest_addr_h_high;
1884     }
1885
1886     /* Make sure the low destination port is <= the high destination port. If not, don't change them. */
1887     if (global_lbtrm_dest_port_low <= global_lbtrm_dest_port_high)
1888     {
1889         lbtrm_dest_port_low = global_lbtrm_dest_port_low;
1890         lbtrm_dest_port_high = global_lbtrm_dest_port_high;
1891     }
1892
1893     /* Make sure the low source port is <= the high source port. If not, don't change them. */
1894     if (global_lbtrm_src_port_low <= global_lbtrm_src_port_high)
1895     {
1896         lbtrm_src_port_low = global_lbtrm_src_port_low;
1897         lbtrm_src_port_high = global_lbtrm_src_port_high;
1898     }
1899
1900     /* Add the dissector hooks for the MIM MC groups. */
1901     inet_aton(global_mim_incoming_mc_address, &addr);
1902     mim_incoming_mc_address_host = g_htonl(addr.s_addr);
1903     inet_aton(global_mim_outgoing_mc_address, &addr);
1904     mim_outgoing_mc_address_host = g_htonl(addr.s_addr);
1905
1906     /* Add the dissector hooks for the MIM ports. */
1907     mim_incoming_dest_port = global_mim_incoming_dest_port;
1908     mim_outgoing_dest_port = global_mim_outgoing_dest_port;
1909
1910     lbtrm_expert_separate_naks = global_lbtrm_expert_separate_naks;
1911     lbtrm_expert_separate_ncfs = global_lbtrm_expert_separate_ncfs;
1912
1913     lbtrm_sequence_analysis = global_lbtrm_sequence_analysis;
1914
1915     lbtrm_use_tag = global_lbtrm_use_tag;
1916
1917     already_registered = TRUE;
1918 }
1919
1920 /*
1921  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1922  *
1923  * Local variables:
1924  * c-basic-offset: 4
1925  * tab-width: 8
1926  * indent-tabs-mode: nil
1927  * End:
1928  *
1929  * vi: set shiftwidth=4 tabstop=8 expandtab:
1930  * :indentSize=4:tabSize=8:noTabs=true:
1931  */