Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-rmt-norm.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-rmt-norm.c
2
 * Reliable Multicast Transport (RMT)
3
 * NORM Protocol Instantiation dissector
4
 * Copyright 2005, Stefano Pettini <spettini@users.sourceforge.net>
5
 *
6
 * Extensive changes to decode more information Julian Onions
7
 *
8
 * Negative-acknowledgment (NACK)-Oriented Reliable Multicast (NORM):
9
 * ------------------------------------------------------------------
10
 *
11
 * This protocol is designed to provide end-to-end reliable transport of
12
 * bulk data objects or streams over generic IP multicast routing and
13
 * forwarding services.  NORM uses a selective, negative acknowledgment
14
 * mechanism for transport reliability and offers additional protocol
15
 * mechanisms to allow for operation with minimal "a priori"
16
 * coordination among senders and receivers.
17
 *
18
 * References:
19
 *     RFC 3940, Negative-acknowledgment (NACK)-Oriented Reliable Multicast (NORM) Protocol
20
 *
21
 * Wireshark - Network traffic analyzer
22
 * By Gerald Combs <gerald@wireshark.org>
23
 * Copyright 1998 Gerald Combs
24
 *
25
 * SPDX-License-Identifier: GPL-2.0-or-later
26
 */
27
28
#include "config.h"
29
30
#include <math.h>
31
32
#include <epan/packet.h>
33
#include <epan/prefs.h>
34
#include <epan/expert.h>
35
#include <epan/proto_data.h>
36
#include "packet-rmt-common.h"
37
38
void proto_register_norm(void);
39
void proto_reg_handoff_norm(void);
40
41
static dissector_handle_t norm_handle;
42
43
/* String tables */
44
45
0
#define NORM_INFO       1
46
0
#define NORM_DATA       2
47
0
#define NORM_CMD        3
48
0
#define NORM_NACK       4
49
0
#define NORM_ACK        5
50
#define NORM_REPORT     6
51
52
static const value_string string_norm_type[] =
53
{
54
    { NORM_INFO,   "INFO" },
55
    { NORM_DATA,   "DATA" },
56
    { NORM_CMD,    "CMD" },
57
    { NORM_NACK,   "NACK" },
58
    { NORM_ACK,    "ACK" },
59
    { NORM_REPORT, "REPORT" },
60
    { 0, NULL }
61
};
62
63
0
#define NORM_CMD_FLUSH          1
64
#define NORM_CMD_EOT            2
65
0
#define NORM_CMD_SQUELCH        3
66
0
#define NORM_CMD_CC             4
67
0
#define NORM_CMD_REPAIR_ADV     5
68
0
#define NORM_CMD_ACK_REQ        6
69
#define NORM_CMD_APPLICATION    7
70
71
static const value_string string_norm_cmd_type[] =
72
{
73
    { NORM_CMD_FLUSH,       "FLUSH" },
74
    { NORM_CMD_EOT,         "EOT" },
75
    { NORM_CMD_SQUELCH,     "SQUELCH" },
76
    { NORM_CMD_CC,          "CC" },
77
    { NORM_CMD_REPAIR_ADV,  "REPAIR_ADV" },
78
    { NORM_CMD_ACK_REQ,     "ACK_REQ" },
79
    { NORM_CMD_APPLICATION, "APPLICATION" },
80
    { 0, NULL }
81
};
82
83
#define NORM_ACK_CC         1
84
#define NORM_ACK_FLUSH      2
85
86
static const value_string string_norm_ack_type[] =
87
{
88
    { NORM_ACK_CC,    "ACK CC" },
89
    { NORM_ACK_FLUSH, "ACK FLUSH" },
90
    { 0, NULL }
91
};
92
93
#define NORM_NACK_ITEMS         1
94
#define NORM_NACK_RANGES        2
95
#define NORM_NACK_ERASURES      3
96
97
static const value_string string_norm_nack_form[] =
98
{
99
    { NORM_NACK_ITEMS,    "Items" },
100
    { NORM_NACK_RANGES,   "Ranges" },
101
    { NORM_NACK_ERASURES, "Erasures" },
102
    { 0, NULL }
103
};
104
105
14
#define NORM_FLAG_REPAIR        0x01
106
14
#define NORM_FLAG_EXPLICIT      0x02
107
14
#define NORM_FLAG_INFO          0x04
108
14
#define NORM_FLAG_UNRELIABLE    0x08
109
14
#define NORM_FLAG_FILE          0x10
110
14
#define NORM_FLAG_STREAM        0x20
111
14
#define NORM_FLAG_MSG_START     0x40
112
113
14
#define NORM_NACK_SEGMENT       0x01
114
14
#define NORM_NACK_BLOCK         0x02
115
14
#define NORM_NACK_INFO          0x04
116
14
#define NORM_NACK_OBJECT        0x08
117
118
14
#define NORM_FLAG_CC_CLR        0x01
119
14
#define NORM_FLAG_CC_PLR        0x02
120
14
#define NORM_FLAG_CC_RTT        0x04
121
14
#define NORM_FLAG_CC_START      0x08
122
14
#define NORM_FLAG_CC_LEAVE      0x10
123
124
0
#define hdrlen2bytes(x) ((x)*4U)
125
126
typedef struct norm_packet_data
127
{
128
    uint8_t encoding_id;
129
} norm_packet_data_t;
130
131
/* Initialize the protocol and registered fields */
132
/* ============================================= */
133
static dissector_handle_t rmt_fec_handle;
134
135
static int proto_rmt_norm;
136
137
static int hf_version;
138
static int hf_type;
139
static int hf_hlen;
140
static int hf_sequence;
141
static int hf_source_id;
142
static int hf_instance_id;
143
static int hf_grtt;
144
static int hf_backoff;
145
static int hf_gsize;
146
static int hf_flags;
147
static int hf_flag_repair;
148
static int hf_flag_norm_explicit;
149
static int hf_flag_info;
150
static int hf_flag_unreliable;
151
static int hf_flag_file;
152
static int hf_flag_stream;
153
static int hf_flag_msgstart;
154
static int hf_object_transport_id;
155
static int hf_extension;
156
static int hf_reserved;
157
static int hf_payload_len;
158
static int hf_payload_offset;
159
static int hf_cmd_flavor;
160
static int hf_cc_sequence;
161
static int hf_cc_sts;
162
static int hf_cc_stus;
163
static int hf_cc_node_id;
164
static int hf_cc_flags;
165
static int hf_cc_flags_clr;
166
static int hf_cc_flags_plr;
167
static int hf_cc_flags_rtt;
168
static int hf_cc_flags_start;
169
static int hf_cc_flags_leave;
170
static int hf_cc_rtt;
171
static int hf_cc_rate;
172
static int hf_cc_transport_id;
173
static int hf_ack_source;
174
static int hf_ack_type;
175
static int hf_ack_id;
176
static int hf_ack_grtt_sec;
177
static int hf_ack_grtt_usec;
178
static int hf_nack_server;
179
static int hf_nack_grtt_sec;
180
static int hf_nack_grtt_usec;
181
static int hf_nack_form;
182
static int hf_nack_flags;
183
static int hf_nack_flags_segment;
184
static int hf_nack_flags_block;
185
static int hf_nack_flags_info;
186
static int hf_nack_flags_object;
187
static int hf_nack_length;
188
static int hf_payload;
189
static int hf_fec_encoding_id;
190
191
static int ett_main;
192
static int ett_hdrext;
193
static int ett_flags;
194
static int ett_streampayload;
195
static int ett_congestioncontrol;
196
static int ett_nackdata;
197
198
static expert_field ei_version1_only;
199
200
static const double RTT_MIN = 1.0e-06;
201
static const double RTT_MAX = 1000;
202
203
static double UnquantizeRtt(unsigned char qrtt)
204
0
{
205
0
    return ((qrtt <= 31) ? (((double)(qrtt+1))*(double)RTT_MIN) :
206
0
            (RTT_MAX/exp(((double)(255-qrtt))/(double)13.0)));
207
0
}
208
209
static double UnquantizeGSize(uint8_t gsizex)
210
0
{
211
0
    unsigned mant = (gsizex & 0x8) ? 5 : 1;
212
0
    unsigned exponent = gsizex & 0x7;
213
214
0
    exponent += 1;
215
0
    return mant * pow(10, exponent);
216
0
}
217
218
/* code to dissect fairly common sequence in NORM packets */
219
static unsigned dissect_grrtetc(proto_tree *tree, tvbuff_t *tvb, unsigned offset)
220
0
{
221
0
    uint8_t backoff;
222
0
    double gsizex;
223
0
    double grtt;
224
225
0
    proto_tree_add_item(tree, hf_instance_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset+=2;
226
0
    grtt    = UnquantizeRtt(tvb_get_uint8(tvb, offset));
227
0
    proto_tree_add_double(tree, hf_grtt, tvb, offset, 1, grtt); offset += 1;
228
0
    backoff = hi_nibble(tvb_get_uint8(tvb, offset));
229
0
    gsizex  = UnquantizeGSize((uint8_t)lo_nibble(tvb_get_uint8(tvb, offset)));
230
0
    proto_tree_add_uint(tree, hf_backoff, tvb, offset, 1, backoff);
231
0
    proto_tree_add_double(tree, hf_gsize, tvb, offset, 1, gsizex);
232
0
    offset += 1;
233
0
    return offset;
234
0
}
235
236
/* split out some common FEC handling */
237
static unsigned dissect_feccode(proto_tree *tree, tvbuff_t *tvb, unsigned offset,
238
                             packet_info *pinfo, int reserved)
239
0
{
240
0
    norm_packet_data_t *norm_data;
241
0
    uint8_t             encoding_id = tvb_get_uint8(tvb, offset);
242
243
    /* Save encoding ID */
244
0
    norm_data = wmem_new0(wmem_file_scope(), norm_packet_data_t);
245
0
    norm_data->encoding_id = encoding_id;
246
247
0
    p_add_proto_data(wmem_file_scope(), pinfo, proto_rmt_norm, 0, norm_data);
248
249
0
    proto_tree_add_item(tree, hf_fec_encoding_id, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
250
0
    if (reserved) {
251
0
        proto_tree_add_item(tree, hf_reserved, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
252
0
    }
253
0
    proto_tree_add_item(tree, hf_object_transport_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset+=2;
254
255
0
    if (tvb_reported_length_remaining(tvb, offset) > 0) {
256
0
        fec_data_exchange_t  fec;
257
0
        tvbuff_t            *new_tvb;
258
0
        int                  len;
259
260
0
        new_tvb = tvb_new_subset_remaining(tvb, offset);
261
262
0
        fec.encoding_id = encoding_id;
263
0
        len = call_dissector_with_data(rmt_fec_handle, new_tvb, pinfo, tree, &fec);
264
0
        if (len > 0)
265
0
            offset += len;
266
0
    }
267
268
0
    return offset;
269
0
}
270
271
static unsigned dissect_norm_hdrext(proto_tree *tree, packet_info *pinfo,
272
                                 tvbuff_t *tvb, unsigned offset, uint8_t hlen)
273
0
{
274
0
    lct_data_exchange_t  data_exchange;
275
0
    norm_packet_data_t  *packet_data = (norm_packet_data_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rmt_norm, 0);
276
277
0
    memset(&data_exchange, 0, sizeof(data_exchange));
278
279
0
    if (packet_data != NULL)
280
0
        data_exchange.codepoint = packet_data->encoding_id;
281
282
0
    offset += lct_ext_decode(tree, tvb, pinfo, offset, hdrlen2bytes(hlen), &data_exchange,
283
0
                             hf_extension, ett_hdrext);
284
285
0
    return offset;
286
0
}
287
288
static unsigned dissect_nack_data(proto_tree *tree, tvbuff_t *tvb, unsigned offset,
289
                               packet_info *pinfo)
290
0
{
291
0
    proto_item *ti, *tif;
292
0
    proto_tree *nack_tree, *flag_tree;
293
0
    uint16_t    len;
294
295
0
    nack_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_nackdata, &ti, "NACK Data");
296
0
    proto_tree_add_item(nack_tree, hf_nack_form, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
297
298
0
    tif = proto_tree_add_item(nack_tree, hf_nack_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
299
0
    flag_tree = proto_item_add_subtree(tif, ett_flags);
300
0
    proto_tree_add_item(flag_tree, hf_nack_flags_segment, tvb, offset, 1, ENC_BIG_ENDIAN);
301
0
    proto_tree_add_item(flag_tree, hf_nack_flags_block,   tvb, offset, 1, ENC_BIG_ENDIAN);
302
0
    proto_tree_add_item(flag_tree, hf_nack_flags_info,    tvb, offset, 1, ENC_BIG_ENDIAN);
303
0
    proto_tree_add_item(flag_tree, hf_nack_flags_object,  tvb, offset, 1, ENC_BIG_ENDIAN);
304
0
    offset += 1;
305
0
    len = tvb_get_ntohs(tvb, offset);
306
0
    proto_tree_add_item(nack_tree, hf_nack_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
307
0
    proto_item_set_len(ti, 4+len);
308
0
    if (len > 4) {
309
0
        dissect_feccode(nack_tree, tvb, offset, pinfo, 1);
310
0
    }
311
0
    offset += len;
312
0
    return offset;
313
0
}
314
315
/* code to dissect NORM data packets */
316
static void dissect_norm_data(proto_tree *tree, packet_info *pinfo,
317
                              tvbuff_t *tvb, unsigned offset, uint8_t hlen)
318
0
{
319
0
    uint8_t     flags;
320
0
    proto_item *ti;
321
0
    proto_tree *flag_tree;
322
323
0
    offset = dissect_grrtetc(tree, tvb, offset);
324
325
0
    ti = proto_tree_add_item(tree, hf_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
326
0
    flags = tvb_get_uint8(tvb, offset);
327
0
    flag_tree = proto_item_add_subtree(ti, ett_flags);
328
0
    proto_tree_add_item(flag_tree, hf_flag_repair,        tvb, offset, 1, ENC_BIG_ENDIAN);
329
0
    proto_tree_add_item(flag_tree, hf_flag_norm_explicit, tvb, offset, 1, ENC_BIG_ENDIAN);
330
0
    proto_tree_add_item(flag_tree, hf_flag_info,          tvb, offset, 1, ENC_BIG_ENDIAN);
331
0
    proto_tree_add_item(flag_tree, hf_flag_unreliable,    tvb, offset, 1, ENC_BIG_ENDIAN);
332
0
    proto_tree_add_item(flag_tree, hf_flag_file,          tvb, offset, 1, ENC_BIG_ENDIAN);
333
0
    proto_tree_add_item(flag_tree, hf_flag_stream,        tvb, offset, 1, ENC_BIG_ENDIAN);
334
0
    proto_tree_add_item(flag_tree, hf_flag_msgstart,      tvb, offset, 1, ENC_BIG_ENDIAN);
335
0
    offset += 1;
336
337
0
    offset = dissect_feccode(tree, tvb, offset, pinfo, 0);
338
339
0
    if (offset < hdrlen2bytes(hlen)) {
340
0
        offset = dissect_norm_hdrext(tree, pinfo, tvb, offset, hlen);
341
0
    }
342
0
    if (flags & NORM_FLAG_STREAM) {
343
0
        flag_tree = proto_tree_add_subtree(tree, tvb, offset, 8, ett_streampayload, NULL, "Stream Data");
344
0
        proto_tree_add_item(flag_tree, hf_reserved,       tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
345
0
        proto_tree_add_item(flag_tree, hf_payload_len,    tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
346
0
        proto_tree_add_item(flag_tree, hf_payload_offset, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
347
348
0
    }
349
0
    if (tvb_reported_length_remaining(tvb, offset) > 0)
350
0
        proto_tree_add_item(tree, hf_payload, tvb, offset, -1, ENC_NA);
351
0
}
352
353
/* code to dissect NORM info packets */
354
static void dissect_norm_info(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, unsigned offset, uint8_t hlen)
355
0
{
356
0
    proto_item         *ti;
357
0
    proto_tree         *flag_tree;
358
0
    norm_packet_data_t *norm_data;
359
360
0
    offset = dissect_grrtetc(tree, tvb, offset);
361
362
0
    ti = proto_tree_add_item(tree, hf_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
363
0
    flag_tree = proto_item_add_subtree(ti, ett_flags);
364
0
    proto_tree_add_item(flag_tree, hf_flag_repair,        tvb, offset, 1, ENC_BIG_ENDIAN);
365
0
    proto_tree_add_item(flag_tree, hf_flag_norm_explicit, tvb, offset, 1, ENC_BIG_ENDIAN);
366
0
    proto_tree_add_item(flag_tree, hf_flag_info,          tvb, offset, 1, ENC_BIG_ENDIAN);
367
0
    proto_tree_add_item(flag_tree, hf_flag_unreliable,    tvb, offset, 1, ENC_BIG_ENDIAN);
368
0
    proto_tree_add_item(flag_tree, hf_flag_file,          tvb, offset, 1, ENC_BIG_ENDIAN);
369
0
    proto_tree_add_item(flag_tree, hf_flag_stream,        tvb, offset, 1, ENC_BIG_ENDIAN);
370
0
    proto_tree_add_item(flag_tree, hf_flag_msgstart,      tvb, offset, 1, ENC_BIG_ENDIAN);
371
0
    offset += 1;
372
373
    /* Save encoding ID */
374
0
    norm_data = wmem_new0(wmem_file_scope(), norm_packet_data_t);
375
0
    norm_data->encoding_id = tvb_get_uint8(tvb, offset);
376
377
0
    p_add_proto_data(wmem_file_scope(), pinfo, proto_rmt_norm, 0, norm_data);
378
379
0
    proto_tree_add_item(tree, hf_fec_encoding_id,     tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
380
0
    proto_tree_add_item(tree, hf_object_transport_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
381
382
0
    if (offset < hdrlen2bytes(hlen)) {
383
0
        offset = dissect_norm_hdrext(tree, pinfo, tvb, offset, hlen);
384
0
    }
385
0
    if (tvb_reported_length_remaining(tvb, offset) > 0)
386
0
        proto_tree_add_item(tree, hf_payload, tvb, offset, -1, ENC_NA);
387
0
}
388
389
/* code to dissect NORM cmd(flush) packets */
390
static unsigned dissect_norm_cmd_flush(proto_tree *tree, packet_info *pinfo,
391
                                    tvbuff_t *tvb, unsigned offset, uint8_t hlen)
392
0
{
393
0
    offset = dissect_feccode(tree, tvb, offset, pinfo, 0);
394
0
    if (offset < hdrlen2bytes(hlen)) {
395
0
        offset = dissect_norm_hdrext(tree, pinfo, tvb, offset, hlen);
396
0
    }
397
0
    return offset;
398
0
}
399
400
/* code to dissect NORM cmd(flush) packets */
401
static unsigned dissect_norm_cmd_repairadv(proto_tree *tree, packet_info *pinfo,
402
                                        tvbuff_t *tvb, unsigned offset, uint8_t hlen)
403
0
{
404
0
    proto_tree_add_item(tree, hf_flags,    tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
405
0
    proto_tree_add_item(tree, hf_reserved, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
406
407
0
    if (offset < hdrlen2bytes(hlen)) {
408
0
        offset = dissect_norm_hdrext(tree, pinfo, tvb, offset, hlen);
409
0
    }
410
0
    while (tvb_reported_length_remaining(tvb, offset) > 0) {
411
0
        offset = dissect_nack_data(tree, tvb, offset, pinfo);
412
0
    }
413
0
    return offset;
414
0
}
415
416
/* code to dissect NORM cmd(cc) packets */
417
static unsigned dissect_norm_cmd_cc(proto_tree *tree, packet_info *pinfo,
418
                                 tvbuff_t *tvb, unsigned offset, uint8_t hlen)
419
0
{
420
0
    proto_tree_add_item(tree, hf_reserved,    tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
421
0
    proto_tree_add_item(tree, hf_cc_sequence, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
422
423
0
    proto_tree_add_item(tree, hf_cc_sts, tvb, offset, 4,  ENC_BIG_ENDIAN); offset += 4;
424
0
    proto_tree_add_item(tree, hf_cc_stus, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
425
0
    if (offset < hdrlen2bytes(hlen)) {
426
0
        offset = dissect_norm_hdrext(tree, pinfo, tvb, offset, hlen);
427
0
    }
428
0
    while (offset < hdrlen2bytes(hlen)) {
429
0
        proto_item *tif;
430
0
        proto_tree *cc_tree, *flag_tree;
431
0
        double grtt;
432
0
        cc_tree = proto_tree_add_subtree(tree, tvb, offset, 8, ett_congestioncontrol, NULL, "Congestion Control");
433
0
        proto_tree_add_item(cc_tree, hf_cc_node_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
434
0
        tif = proto_tree_add_item(cc_tree, hf_cc_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
435
0
        flag_tree = proto_item_add_subtree(tif, ett_flags);
436
0
        proto_tree_add_item(flag_tree, hf_cc_flags_clr,   tvb, offset, 1, ENC_BIG_ENDIAN);
437
0
        proto_tree_add_item(flag_tree, hf_cc_flags_plr,   tvb, offset, 1, ENC_BIG_ENDIAN);
438
0
        proto_tree_add_item(flag_tree, hf_cc_flags_rtt,   tvb, offset, 1, ENC_BIG_ENDIAN);
439
0
        proto_tree_add_item(flag_tree, hf_cc_flags_start, tvb, offset, 1, ENC_BIG_ENDIAN);
440
0
        proto_tree_add_item(flag_tree, hf_cc_flags_leave, tvb, offset, 1, ENC_BIG_ENDIAN);
441
0
        offset += 1;
442
0
        grtt = UnquantizeRtt(tvb_get_uint8(tvb, offset));
443
0
        proto_tree_add_double(cc_tree, hf_cc_rtt,  tvb, offset, 1, grtt); offset += 1;
444
0
        grtt = rmt_decode_send_rate(tvb_get_ntohs(tvb, offset));
445
0
        proto_tree_add_double(cc_tree, hf_cc_rate, tvb, offset, 2, grtt); offset += 2;
446
0
    }
447
0
    return offset;
448
0
}
449
450
/* code to dissect NORM cmd(squelch) packets */
451
static unsigned dissect_norm_cmd_squelch(proto_tree *tree, packet_info *pinfo,
452
                                      tvbuff_t *tvb, unsigned offset)
453
0
{
454
0
    offset = dissect_feccode(tree, tvb, offset, pinfo, 0);
455
456
0
    while (tvb_reported_length_remaining(tvb, offset) > 0) {
457
0
        proto_tree_add_item(tree, hf_cc_transport_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
458
0
    }
459
0
    return offset;
460
0
}
461
462
/* code to dissect NORM cmd(squelch) packets */
463
static unsigned dissect_norm_cmd_ackreq(proto_tree *tree, packet_info *pinfo _U_,
464
                                     tvbuff_t *tvb, unsigned offset)
465
0
{
466
0
    proto_tree_add_item(tree, hf_reserved, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
467
0
    proto_tree_add_item(tree, hf_ack_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
468
0
    proto_tree_add_item(tree, hf_ack_id,   tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
469
0
    return offset;
470
0
}
471
472
/* code to dissect NORM cmd packets */
473
static void dissect_norm_cmd(proto_tree *tree, packet_info *pinfo,
474
                             tvbuff_t *tvb, unsigned offset, uint8_t hlen)
475
0
{
476
0
    uint8_t flavor;
477
478
0
    offset = dissect_grrtetc(tree, tvb, offset);
479
0
    flavor = tvb_get_uint8(tvb, offset);
480
481
0
    col_append_sep_str(pinfo->cinfo, COL_INFO, " ",
482
0
                       val_to_str(flavor, string_norm_cmd_type, "Unknown Cmd Type (0x%04x)"));
483
0
    proto_tree_add_item(tree, hf_cmd_flavor, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
484
0
    switch(flavor) {
485
0
    case NORM_CMD_CC:
486
0
        offset = dissect_norm_cmd_cc(tree, pinfo, tvb, offset, hlen);
487
0
        break;
488
0
    case NORM_CMD_FLUSH:
489
0
        offset = dissect_norm_cmd_flush(tree, pinfo, tvb, offset, hlen);
490
0
        break;
491
0
    case NORM_CMD_SQUELCH:
492
0
        offset = dissect_norm_cmd_squelch(tree, pinfo, tvb, offset);
493
0
        break;
494
0
    case NORM_CMD_REPAIR_ADV:
495
0
        offset = dissect_norm_cmd_repairadv(tree, pinfo, tvb, offset, hlen);
496
0
        break;
497
0
    case NORM_CMD_ACK_REQ:
498
0
        offset = dissect_norm_cmd_ackreq(tree, pinfo, tvb, offset);
499
0
        break;
500
0
    }
501
0
    if (tvb_reported_length_remaining(tvb, offset) > 0)
502
0
        proto_tree_add_item(tree, hf_payload, tvb, offset, -1, ENC_NA);
503
0
}
504
505
/* code to dissect NORM ack packets */
506
static void dissect_norm_ack(proto_tree *tree, packet_info *pinfo,
507
                             tvbuff_t *tvb, unsigned offset, uint8_t hlen)
508
0
{
509
0
    uint8_t acktype;
510
511
0
    proto_tree_add_item(tree, hf_ack_source,  tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
512
0
    proto_tree_add_item(tree, hf_instance_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
513
0
    acktype = tvb_get_uint8(tvb, offset);
514
515
0
    col_append_sep_str(pinfo->cinfo, COL_INFO, " ",
516
0
                       val_to_str(acktype, string_norm_ack_type, "Unknown Ack Type (0x%04x)"));
517
0
    proto_tree_add_item(tree, hf_ack_type,      tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
518
0
    proto_tree_add_item(tree, hf_ack_id,        tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
519
0
    proto_tree_add_item(tree, hf_ack_grtt_sec,  tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
520
0
    proto_tree_add_item(tree, hf_ack_grtt_usec, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
521
0
    if (offset < hdrlen2bytes(hlen)) {
522
0
        offset = dissect_norm_hdrext(tree, pinfo, tvb, offset, hlen);
523
0
    }
524
525
0
    if (tvb_reported_length_remaining(tvb, offset) > 0)
526
0
        proto_tree_add_item(tree, hf_payload, tvb, offset, -1, ENC_NA);
527
0
}
528
529
/* code to dissect NORM nack packets */
530
static void dissect_norm_nack(proto_tree *tree, packet_info *pinfo,
531
                              tvbuff_t *tvb, unsigned offset, uint8_t hlen)
532
0
{
533
0
    proto_tree_add_item(tree, hf_nack_server,    tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
534
0
    proto_tree_add_item(tree, hf_instance_id,    tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
535
0
    proto_tree_add_item(tree, hf_reserved,       tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
536
0
    proto_tree_add_item(tree, hf_nack_grtt_sec,  tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
537
0
    proto_tree_add_item(tree, hf_nack_grtt_usec, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
538
0
    if (offset < hdrlen2bytes(hlen)) {
539
0
        offset = dissect_norm_hdrext(tree, pinfo, tvb, offset, hlen);
540
0
    }
541
542
0
    while (tvb_reported_length_remaining(tvb, offset) > 0) {
543
0
        offset = dissect_nack_data(tree, tvb, offset, pinfo);
544
0
    }
545
0
    if (tvb_reported_length_remaining(tvb, offset) > 0)
546
0
        proto_tree_add_item(tree, hf_payload, tvb, offset, -1, ENC_NA);
547
0
}
548
549
/* Code to actually dissect the packets */
550
/* ==================================== */
551
static int
552
dissect_norm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
553
0
{
554
    /* Logical packet representation */
555
0
    uint8_t version;
556
0
    uint8_t type;
557
0
    uint8_t hlen;
558
559
    /* Offset for subpacket dissection */
560
0
    unsigned offset = 0;
561
562
    /* Set up structures needed to add the protocol subtree and manage it */
563
0
    proto_item *ti;
564
0
    proto_tree *norm_tree;
565
566
    /* Make entries in Protocol column and Info column on summary display */
567
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "NORM");
568
0
    col_clear(pinfo->cinfo, COL_INFO);
569
570
    /* NORM header dissection, part 1 */
571
    /* ------------------------------ */
572
573
0
    version = hi_nibble(tvb_get_uint8(tvb, offset));
574
575
    /* Create subtree for the NORM protocol */
576
0
    ti = proto_tree_add_item(tree, proto_rmt_norm, tvb, offset, -1, ENC_NA);
577
0
    norm_tree = proto_item_add_subtree(ti, ett_main);
578
579
    /* Fill the NORM subtree */
580
0
    proto_tree_add_uint(norm_tree, hf_version, tvb, offset, 1, version);
581
582
    /* This dissector supports only NORMv1 packets.
583
     * If version > 1 print only version field and quit.
584
     */
585
0
    if (version != 1) {
586
0
        expert_add_info(pinfo, ti, &ei_version1_only);
587
588
        /* Complete entry in Info column on summary display */
589
0
        col_add_fstr(pinfo->cinfo, COL_INFO, "Version: %u (not supported)", version);
590
0
        return 0;
591
0
    }
592
593
    /* NORM header dissection, part 2 */
594
    /* ------------------------------ */
595
596
0
    type = lo_nibble(tvb_get_uint8(tvb, offset));
597
0
    hlen = tvb_get_uint8(tvb, offset+1);
598
599
0
    if (tree) {
600
0
        proto_tree_add_uint(norm_tree, hf_type, tvb, offset, 1, type);
601
0
        proto_tree_add_item(norm_tree, hf_hlen, tvb, offset+1, 1, ENC_BIG_ENDIAN);
602
0
        proto_tree_add_item(norm_tree, hf_sequence, tvb, offset+2, 2, ENC_BIG_ENDIAN);
603
0
        proto_tree_add_item(norm_tree, hf_source_id, tvb, offset+4, 4, ENC_BIG_ENDIAN);
604
0
    }
605
606
0
    offset += 8;
607
608
609
    /* Complete entry in Info column on summary display */
610
    /* ------------------------------------------------ */
611
0
    col_append_sep_str(pinfo->cinfo, COL_INFO, " ",
612
0
                       val_to_str(type, string_norm_type, "Unknown Type (0x%04x)"));
613
614
615
0
    switch(type) {
616
0
    case NORM_INFO:
617
0
        dissect_norm_info(norm_tree, pinfo, tvb, offset, hlen);
618
0
        break;
619
0
    case NORM_DATA:
620
0
        dissect_norm_data(norm_tree, pinfo, tvb, offset, hlen);
621
0
        break;
622
0
    case NORM_CMD:
623
0
        dissect_norm_cmd(norm_tree, pinfo, tvb, offset, hlen);
624
0
        break;
625
0
    case NORM_ACK:
626
0
        dissect_norm_ack(norm_tree, pinfo, tvb, offset, hlen);
627
0
        break;
628
0
    case NORM_NACK:
629
0
        dissect_norm_nack(norm_tree, pinfo, tvb, offset, hlen);
630
0
        break;
631
0
    default:
632
        /* Add the Payload item */
633
0
        if (tvb_reported_length_remaining(tvb, offset) > 0)
634
0
            proto_tree_add_item(norm_tree, hf_payload, tvb, offset, -1, ENC_NA);
635
0
        break;
636
0
    }
637
638
0
    return tvb_reported_length(tvb);
639
0
}
640
641
static bool
642
dissect_norm_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
643
0
{
644
0
    uint8_t byte1;
645
646
0
    if (tvb_reported_length(tvb) < 12)
647
0
        return false;  /* not enough to check */
648
0
    byte1 = tvb_get_uint8(tvb, 0);
649
650
0
    if (hi_nibble(byte1) != 1) return false;
651
0
    if (lo_nibble(byte1) < 1 || lo_nibble(byte1) > 6) return false;
652
0
    if (tvb_get_uint8(tvb, 1) > 20) return false;
653
654
0
    dissect_norm(tvb, pinfo, tree, data);
655
0
    return true; /* appears to be a NORM packet */
656
0
}
657
658
void proto_register_norm(void)
659
14
{
660
    /* Setup NORM header fields */
661
14
    static hf_register_info hf[] = {
662
663
14
        { &hf_version,
664
14
          { "Version", "norm.version",
665
14
            FT_UINT8, BASE_DEC, NULL, 0x0,
666
14
            NULL, HFILL }
667
14
        },
668
14
        { &hf_type,
669
14
          { "Message Type", "norm.type",
670
14
            FT_UINT8, BASE_DEC, VALS(string_norm_type), 0x0,
671
14
            NULL, HFILL }
672
14
        },
673
14
        { &hf_hlen,
674
14
          { "Header length", "norm.hlen",
675
14
            FT_UINT8, BASE_DEC, NULL, 0x0,
676
14
            NULL, HFILL }
677
14
        },
678
14
        { &hf_sequence,
679
14
          { "Sequence", "norm.sequence",
680
14
            FT_UINT16, BASE_DEC, NULL, 0x0,
681
14
            NULL, HFILL }
682
14
        },
683
14
        { &hf_source_id,
684
14
          { "Source ID", "norm.source_id",
685
14
            FT_IPv4, BASE_NONE, NULL, 0x0,
686
14
            NULL, HFILL }
687
14
        },
688
14
        { &hf_instance_id,
689
14
          { "Instance", "norm.instance_id",
690
14
            FT_UINT16, BASE_DEC, NULL, 0x0,
691
14
            NULL, HFILL}
692
14
        },
693
14
        { &hf_grtt,
694
14
          { "grtt", "norm.grtt",
695
14
            FT_DOUBLE, BASE_NONE, NULL, 0x0,
696
14
            NULL, HFILL}
697
14
        },
698
14
        { &hf_backoff,
699
14
          { "Backoff", "norm.backoff",
700
14
            FT_UINT8, BASE_DEC, NULL, 0x0,
701
14
            NULL, HFILL}
702
14
        },
703
14
        { &hf_gsize,
704
14
          { "Group Size", "norm.gsize",
705
14
            FT_DOUBLE, BASE_NONE, NULL, 0x0,
706
14
            NULL, HFILL}
707
14
        },
708
14
        { &hf_flags,
709
14
          { "Flags", "norm.flags",
710
14
            FT_UINT8, BASE_HEX, NULL, 0x0,
711
14
            NULL, HFILL}
712
14
        },
713
14
        { &hf_flag_repair,
714
14
          { "Repair Flag", "norm.flag.repair",
715
14
            FT_BOOLEAN, 8, NULL, NORM_FLAG_REPAIR,
716
14
            NULL, HFILL }
717
14
        },
718
14
        { &hf_flag_norm_explicit,
719
14
          { "Explicit Flag", "norm.flag.explicit",
720
14
            FT_BOOLEAN, 8, NULL, NORM_FLAG_EXPLICIT,
721
14
            NULL, HFILL }
722
14
        },
723
14
        { &hf_flag_info,
724
14
          { "Info Flag", "norm.flag.info",
725
14
            FT_BOOLEAN, 8, NULL, NORM_FLAG_INFO,
726
14
            NULL, HFILL }
727
14
        },
728
14
        { &hf_flag_unreliable,
729
14
          { "Unreliable Flag", "norm.flag.unreliable",
730
14
            FT_BOOLEAN, 8, NULL, NORM_FLAG_UNRELIABLE,
731
14
            NULL, HFILL }
732
14
        },
733
14
        { &hf_flag_file,
734
14
          { "File Flag", "norm.flag.file",
735
14
            FT_BOOLEAN, 8, NULL, NORM_FLAG_FILE,
736
14
            NULL, HFILL }
737
14
        },
738
14
        { &hf_flag_stream,
739
14
          { "Stream Flag", "norm.flag.stream",
740
14
            FT_BOOLEAN, 8, NULL, NORM_FLAG_STREAM,
741
14
            NULL, HFILL }
742
14
        },
743
14
        { &hf_flag_msgstart,
744
14
          { "Msg Start Flag", "norm.flag.msgstart",
745
14
            FT_BOOLEAN, 8, NULL, NORM_FLAG_MSG_START,
746
14
            NULL, HFILL }
747
14
        },
748
14
        { &hf_object_transport_id,
749
14
          { "Object Transport ID", "norm.object_transport_id",
750
14
            FT_UINT16, BASE_HEX, NULL, 0x0,
751
14
            NULL, HFILL}
752
14
        },
753
14
        { &hf_extension,
754
14
          { "Hdr Extension", "norm.hexext",
755
14
            FT_UINT16, BASE_DEC, NULL, 0x0,
756
14
            NULL, HFILL}
757
14
        },
758
14
        { &hf_reserved,
759
14
          { "Reserved", "norm.reserved",
760
14
            FT_UINT16, BASE_HEX, NULL, 0x0,
761
14
            NULL, HFILL}
762
14
        },
763
14
        { &hf_payload_len,
764
14
          { "Payload Len", "norm.payload.len",
765
14
            FT_UINT16, BASE_DEC, NULL, 0x0,
766
14
            NULL, HFILL}
767
14
        },
768
14
        { &hf_payload_offset,
769
14
          { "Payload Offset", "norm.payload.offset",
770
14
            FT_UINT32, BASE_DEC, NULL, 0x0,
771
14
            NULL, HFILL}
772
14
        },
773
774
14
        { &hf_cmd_flavor,
775
14
          { "Flavor", "norm.flavor",
776
14
            FT_UINT8, BASE_DEC, VALS(string_norm_cmd_type), 0x0,
777
14
            NULL, HFILL}
778
14
        },
779
14
        { &hf_cc_sequence,
780
14
          { "CC Sequence", "norm.ccsequence",
781
14
            FT_UINT16, BASE_DEC, NULL, 0x0,
782
14
            NULL, HFILL}
783
14
        },
784
14
        { &hf_cc_sts,
785
14
          { "Send Time secs", "norm.cc_sts",
786
14
            FT_UINT32, BASE_DEC, NULL, 0x0,
787
14
            NULL, HFILL}
788
14
        },
789
14
        { &hf_cc_stus,
790
14
          { "Send Time usecs", "norm.cc_stus",
791
14
            FT_UINT32, BASE_DEC, NULL, 0x0,
792
14
            NULL, HFILL}
793
14
        },
794
14
        { &hf_cc_node_id,
795
14
          { "CC Node ID", "norm.cc_node_id",
796
14
            FT_IPv4, BASE_NONE, NULL, 0x0,
797
14
            NULL, HFILL}
798
14
        },
799
14
        { &hf_cc_flags,
800
14
          { "CC Flags", "norm.cc_flags",
801
14
            FT_UINT8, BASE_DEC, NULL, 0x0,
802
14
            NULL, HFILL}
803
14
        },
804
14
        { &hf_cc_flags_clr,
805
14
          { "CLR", "norm.cc_flags.clr",
806
14
            FT_BOOLEAN, 8, NULL, NORM_FLAG_CC_CLR,
807
14
            NULL, HFILL}
808
14
        },
809
14
        { &hf_cc_flags_plr,
810
14
          { "PLR", "norm.cc_flags.plr",
811
14
            FT_BOOLEAN, 8, NULL, NORM_FLAG_CC_PLR,
812
14
            NULL, HFILL}
813
14
        },
814
14
        { &hf_cc_flags_rtt,
815
14
          { "RTT", "norm.cc_flags.rtt",
816
14
            FT_BOOLEAN, 8, NULL, NORM_FLAG_CC_RTT,
817
14
            NULL, HFILL}
818
14
        },
819
14
        { &hf_cc_flags_start,
820
14
          { "Start", "norm.cc_flags.start",
821
14
            FT_BOOLEAN, 8, NULL, NORM_FLAG_CC_START,
822
14
            NULL, HFILL}
823
14
        },
824
14
        { &hf_cc_flags_leave,
825
14
          { "Leave", "norm.cc_flags.leave",
826
14
            FT_BOOLEAN, 8, NULL, NORM_FLAG_CC_LEAVE,
827
14
            NULL, HFILL}
828
14
        },
829
14
        { &hf_cc_rtt,
830
14
          { "CC RTT", "norm.cc_rtt",
831
14
            FT_DOUBLE, BASE_NONE, NULL, 0x0,
832
14
            NULL, HFILL}
833
14
        },
834
14
        { &hf_cc_rate,
835
14
          { "CC Rate", "norm.cc_rate",
836
14
            FT_DOUBLE, BASE_NONE, NULL, 0x0,
837
14
            NULL, HFILL}
838
14
        },
839
14
        { &hf_cc_transport_id,
840
14
          { "CC Transport ID", "norm.cc_transport_id",
841
14
            FT_UINT16, BASE_DEC, NULL, 0x0,
842
14
            NULL, HFILL}
843
14
        },
844
845
14
        { &hf_ack_source,
846
14
          { "Ack Source", "norm.ack.source",
847
14
            FT_IPv4, BASE_NONE, NULL, 0x0,
848
14
            NULL, HFILL}
849
14
        },
850
14
        { &hf_ack_type,
851
14
          { "Ack Type", "norm.ack.type",
852
14
            FT_UINT8, BASE_DEC, VALS(string_norm_ack_type), 0x0,
853
14
            NULL, HFILL}
854
14
        },
855
14
        { &hf_ack_id,
856
14
          { "Ack ID", "norm.ack.id",
857
14
            FT_UINT8, BASE_DEC, NULL, 0x0,
858
14
            NULL, HFILL}
859
14
        },
860
14
        { &hf_ack_grtt_sec,
861
14
          { "Ack GRTT Sec", "norm.ack.grtt_sec",
862
14
            FT_UINT32, BASE_DEC, NULL, 0x0,
863
14
            NULL, HFILL}
864
14
        },
865
14
        { &hf_ack_grtt_usec,
866
14
          { "Ack GRTT usec", "norm.ack.grtt_usec",
867
14
            FT_UINT32, BASE_DEC, NULL, 0x0,
868
14
            NULL, HFILL}
869
14
        },
870
871
14
        { &hf_nack_server,
872
14
          { "NAck Server", "norm.nack.server",
873
14
            FT_IPv4, BASE_NONE, NULL, 0x0,
874
14
            NULL, HFILL}
875
14
        },
876
14
        { &hf_nack_grtt_sec,
877
14
          { "NAck GRTT Sec", "norm.nack.grtt_sec",
878
14
            FT_UINT32, BASE_DEC, NULL, 0x0,
879
14
            NULL, HFILL}
880
14
        },
881
14
        { &hf_nack_grtt_usec,
882
14
          { "NAck GRTT usec", "norm.nack.grtt_usec",
883
14
            FT_UINT32, BASE_DEC, NULL, 0x0,
884
14
            NULL, HFILL}
885
14
        },
886
14
        { &hf_nack_form,
887
14
          { "NAck FORM", "norm.nack.form",
888
14
            FT_UINT8, BASE_DEC, VALS(string_norm_nack_form), 0x0,
889
14
            NULL, HFILL}
890
14
        },
891
14
        { &hf_nack_flags,
892
14
          { "NAck Flags", "norm.nack.flags",
893
14
            FT_UINT8, BASE_DEC, NULL, 0x0,
894
14
            NULL, HFILL}
895
14
        },
896
14
        { &hf_nack_flags_segment,
897
14
          { "Segment", "norm.nack.flags.segment",
898
14
            FT_BOOLEAN, 8, NULL, NORM_NACK_SEGMENT,
899
14
            NULL, HFILL}
900
14
        },
901
14
        { &hf_nack_flags_block,
902
14
          { "Block", "norm.nack.flags.block",
903
14
            FT_BOOLEAN, 8, NULL, NORM_NACK_BLOCK,
904
14
            NULL, HFILL}
905
14
        },
906
14
        { &hf_nack_flags_info,
907
14
          { "Info", "norm.nack.flags.info",
908
14
            FT_BOOLEAN, 8, NULL, NORM_NACK_INFO,
909
14
            NULL, HFILL}
910
14
        },
911
14
        { &hf_nack_flags_object,
912
14
          { "Object", "norm.nack.flags.object",
913
14
            FT_BOOLEAN, 8, NULL, NORM_NACK_OBJECT,
914
14
            NULL, HFILL}
915
14
        },
916
14
        { &hf_nack_length,
917
14
          { "NAck Length", "norm.nack.length",
918
14
            FT_UINT16, BASE_DEC, NULL, 0x0,
919
14
            NULL, HFILL}
920
14
        },
921
14
        { &hf_payload,
922
14
          { "Payload", "norm.payload",
923
14
            FT_BYTES, BASE_NONE, NULL, 0x0,
924
14
            NULL, HFILL }
925
14
        },
926
14
        { &hf_fec_encoding_id,
927
14
          { "FEC Encoding ID", "norm.fec_encoding_id",
928
14
            FT_UINT8, BASE_DEC, VALS(string_fec_encoding_id), 0x0,
929
14
            NULL, HFILL}
930
14
        }
931
14
    };
932
933
    /* Setup protocol subtree array */
934
14
    static int *ett[] = {
935
14
        &ett_main,
936
14
        &ett_hdrext,
937
14
        &ett_flags,
938
14
        &ett_streampayload,
939
14
        &ett_congestioncontrol,
940
14
        &ett_nackdata
941
14
    };
942
943
14
    static ei_register_info ei[] = {
944
14
        { &ei_version1_only, { "norm.version1_only", PI_PROTOCOL, PI_WARN, "Sorry, this dissector supports NORM version 1 only", EXPFILL }}
945
14
    };
946
947
14
    module_t *module;
948
14
    expert_module_t* expert_rmt_norm;
949
950
    /* Register the protocol name and description */
951
14
    proto_rmt_norm = proto_register_protocol("Negative-acknowledgment Oriented Reliable Multicast", "NORM", "norm");
952
953
    /* Register the header fields and subtrees used */
954
14
    proto_register_field_array(proto_rmt_norm, hf, array_length(hf));
955
14
    proto_register_subtree_array(ett, array_length(ett));
956
14
    expert_rmt_norm = expert_register_protocol(proto_rmt_norm);
957
14
    expert_register_field_array(expert_rmt_norm, ei, array_length(ei));
958
959
    /* Register the subdissector handle */
960
14
    norm_handle = register_dissector("norm", dissect_norm, proto_rmt_norm);
961
962
    /* Register preferences */
963
14
    module = prefs_register_protocol(proto_rmt_norm, NULL);
964
14
    prefs_register_obsolete_preference(module, "heuristic_norm");
965
14
}
966
967
void proto_reg_handoff_norm(void)
968
14
{
969
14
    dissector_add_for_decode_as_with_preference("udp.port", norm_handle);
970
14
    heur_dissector_add("udp", dissect_norm_heur, "NORM over UDP", "rmt_norm_udp", proto_rmt_norm, HEURISTIC_DISABLE);
971
972
14
    rmt_fec_handle = find_dissector_add_dependency("rmt-fec", proto_rmt_norm);
973
14
}
974
975
/*
976
 * Editor modelines - https://www.wireshark.org/tools/modelines.html
977
 *
978
 * Local variables:
979
 * c-basic-offset: 4
980
 * tab-width: 8
981
 * indent-tabs-mode: nil
982
 * End:
983
 *
984
 * ex: set shiftwidth=4 tabstop=8 expandtab:
985
 * :indentSize=4:tabSize=8:noTabs=true:
986
 */