Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-rmt-norm.c
blob3326472e2518d9c7fa21b83c6cb173a8bfcba6f1
1 /* packet-rmt-norm.c
2 * Reliable Multicast Transport (RMT)
3 * NORM Protocol Instantiation dissector
4 * Copyright 2005, Stefano Pettini <spettini@users.sourceforge.net>
6 * Extensive changes to decode more information Julian Onions
8 * Negative-acknowledgment (NACK)-Oriented Reliable Multicast (NORM):
9 * ------------------------------------------------------------------
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.
18 * References:
19 * RFC 3940, Negative-acknowledgment (NACK)-Oriented Reliable Multicast (NORM) Protocol
21 * Wireshark - Network traffic analyzer
22 * By Gerald Combs <gerald@wireshark.org>
23 * Copyright 1998 Gerald Combs
25 * SPDX-License-Identifier: GPL-2.0-or-later
28 #include "config.h"
30 #include <math.h>
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"
38 void proto_register_norm(void);
39 void proto_reg_handoff_norm(void);
41 static dissector_handle_t norm_handle;
43 /* String tables */
45 #define NORM_INFO 1
46 #define NORM_DATA 2
47 #define NORM_CMD 3
48 #define NORM_NACK 4
49 #define NORM_ACK 5
50 #define NORM_REPORT 6
52 static const value_string string_norm_type[] =
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 }
63 #define NORM_CMD_FLUSH 1
64 #define NORM_CMD_EOT 2
65 #define NORM_CMD_SQUELCH 3
66 #define NORM_CMD_CC 4
67 #define NORM_CMD_REPAIR_ADV 5
68 #define NORM_CMD_ACK_REQ 6
69 #define NORM_CMD_APPLICATION 7
71 static const value_string string_norm_cmd_type[] =
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 }
83 #define NORM_ACK_CC 1
84 #define NORM_ACK_FLUSH 2
86 static const value_string string_norm_ack_type[] =
88 { NORM_ACK_CC, "ACK CC" },
89 { NORM_ACK_FLUSH, "ACK FLUSH" },
90 { 0, NULL }
93 #define NORM_NACK_ITEMS 1
94 #define NORM_NACK_RANGES 2
95 #define NORM_NACK_ERASURES 3
97 static const value_string string_norm_nack_form[] =
99 { NORM_NACK_ITEMS, "Items" },
100 { NORM_NACK_RANGES, "Ranges" },
101 { NORM_NACK_ERASURES, "Erasures" },
102 { 0, NULL }
105 #define NORM_FLAG_REPAIR 0x01
106 #define NORM_FLAG_EXPLICIT 0x02
107 #define NORM_FLAG_INFO 0x04
108 #define NORM_FLAG_UNRELIABLE 0x08
109 #define NORM_FLAG_FILE 0x10
110 #define NORM_FLAG_STREAM 0x20
111 #define NORM_FLAG_MSG_START 0x40
113 #define NORM_NACK_SEGMENT 0x01
114 #define NORM_NACK_BLOCK 0x02
115 #define NORM_NACK_INFO 0x04
116 #define NORM_NACK_OBJECT 0x08
118 #define NORM_FLAG_CC_CLR 0x01
119 #define NORM_FLAG_CC_PLR 0x02
120 #define NORM_FLAG_CC_RTT 0x04
121 #define NORM_FLAG_CC_START 0x08
122 #define NORM_FLAG_CC_LEAVE 0x10
124 #define hdrlen2bytes(x) ((x)*4U)
126 typedef struct norm_packet_data
128 uint8_t encoding_id;
129 } norm_packet_data_t;
131 /* Initialize the protocol and registered fields */
132 /* ============================================= */
133 static dissector_handle_t rmt_fec_handle;
135 static int proto_rmt_norm;
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;
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;
198 static expert_field ei_version1_only;
200 static const double RTT_MIN = 1.0e-06;
201 static const double RTT_MAX = 1000;
203 static double UnquantizeRtt(unsigned char qrtt)
205 return ((qrtt <= 31) ? (((double)(qrtt+1))*(double)RTT_MIN) :
206 (RTT_MAX/exp(((double)(255-qrtt))/(double)13.0)));
209 static double UnquantizeGSize(uint8_t gsizex)
211 unsigned mant = (gsizex & 0x8) ? 5 : 1;
212 unsigned exponent = gsizex & 0x7;
214 exponent += 1;
215 return mant * pow(10, exponent);
218 /* code to dissect fairly common sequence in NORM packets */
219 static unsigned dissect_grrtetc(proto_tree *tree, tvbuff_t *tvb, unsigned offset)
221 uint8_t backoff;
222 double gsizex;
223 double grtt;
225 proto_tree_add_item(tree, hf_instance_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset+=2;
226 grtt = UnquantizeRtt(tvb_get_uint8(tvb, offset));
227 proto_tree_add_double(tree, hf_grtt, tvb, offset, 1, grtt); offset += 1;
228 backoff = hi_nibble(tvb_get_uint8(tvb, offset));
229 gsizex = UnquantizeGSize((uint8_t)lo_nibble(tvb_get_uint8(tvb, offset)));
230 proto_tree_add_uint(tree, hf_backoff, tvb, offset, 1, backoff);
231 proto_tree_add_double(tree, hf_gsize, tvb, offset, 1, gsizex);
232 offset += 1;
233 return offset;
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)
240 norm_packet_data_t *norm_data;
241 uint8_t encoding_id = tvb_get_uint8(tvb, offset);
243 /* Save encoding ID */
244 norm_data = wmem_new0(wmem_file_scope(), norm_packet_data_t);
245 norm_data->encoding_id = encoding_id;
247 p_add_proto_data(wmem_file_scope(), pinfo, proto_rmt_norm, 0, norm_data);
249 proto_tree_add_item(tree, hf_fec_encoding_id, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
250 if (reserved) {
251 proto_tree_add_item(tree, hf_reserved, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
253 proto_tree_add_item(tree, hf_object_transport_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset+=2;
255 if (tvb_reported_length_remaining(tvb, offset) > 0) {
256 fec_data_exchange_t fec;
257 tvbuff_t *new_tvb;
258 int len;
260 new_tvb = tvb_new_subset_remaining(tvb, offset);
262 fec.encoding_id = encoding_id;
263 len = call_dissector_with_data(rmt_fec_handle, new_tvb, pinfo, tree, &fec);
264 if (len > 0)
265 offset += len;
268 return offset;
271 static unsigned dissect_norm_hdrext(proto_tree *tree, packet_info *pinfo,
272 tvbuff_t *tvb, unsigned offset, uint8_t hlen)
274 lct_data_exchange_t data_exchange;
275 norm_packet_data_t *packet_data = (norm_packet_data_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rmt_norm, 0);
277 memset(&data_exchange, 0, sizeof(data_exchange));
279 if (packet_data != NULL)
280 data_exchange.codepoint = packet_data->encoding_id;
282 offset += lct_ext_decode(tree, tvb, pinfo, offset, hdrlen2bytes(hlen), &data_exchange,
283 hf_extension, ett_hdrext);
285 return offset;
288 static unsigned dissect_nack_data(proto_tree *tree, tvbuff_t *tvb, unsigned offset,
289 packet_info *pinfo)
291 proto_item *ti, *tif;
292 proto_tree *nack_tree, *flag_tree;
293 uint16_t len;
295 nack_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_nackdata, &ti, "NACK Data");
296 proto_tree_add_item(nack_tree, hf_nack_form, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
298 tif = proto_tree_add_item(nack_tree, hf_nack_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
299 flag_tree = proto_item_add_subtree(tif, ett_flags);
300 proto_tree_add_item(flag_tree, hf_nack_flags_segment, tvb, offset, 1, ENC_BIG_ENDIAN);
301 proto_tree_add_item(flag_tree, hf_nack_flags_block, tvb, offset, 1, ENC_BIG_ENDIAN);
302 proto_tree_add_item(flag_tree, hf_nack_flags_info, tvb, offset, 1, ENC_BIG_ENDIAN);
303 proto_tree_add_item(flag_tree, hf_nack_flags_object, tvb, offset, 1, ENC_BIG_ENDIAN);
304 offset += 1;
305 len = tvb_get_ntohs(tvb, offset);
306 proto_tree_add_item(nack_tree, hf_nack_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
307 proto_item_set_len(ti, 4+len);
308 if (len > 4) {
309 dissect_feccode(nack_tree, tvb, offset, pinfo, 1);
311 offset += len;
312 return offset;
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)
319 uint8_t flags;
320 proto_item *ti;
321 proto_tree *flag_tree;
323 offset = dissect_grrtetc(tree, tvb, offset);
325 ti = proto_tree_add_item(tree, hf_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
326 flags = tvb_get_uint8(tvb, offset);
327 flag_tree = proto_item_add_subtree(ti, ett_flags);
328 proto_tree_add_item(flag_tree, hf_flag_repair, tvb, offset, 1, ENC_BIG_ENDIAN);
329 proto_tree_add_item(flag_tree, hf_flag_norm_explicit, tvb, offset, 1, ENC_BIG_ENDIAN);
330 proto_tree_add_item(flag_tree, hf_flag_info, tvb, offset, 1, ENC_BIG_ENDIAN);
331 proto_tree_add_item(flag_tree, hf_flag_unreliable, tvb, offset, 1, ENC_BIG_ENDIAN);
332 proto_tree_add_item(flag_tree, hf_flag_file, tvb, offset, 1, ENC_BIG_ENDIAN);
333 proto_tree_add_item(flag_tree, hf_flag_stream, tvb, offset, 1, ENC_BIG_ENDIAN);
334 proto_tree_add_item(flag_tree, hf_flag_msgstart, tvb, offset, 1, ENC_BIG_ENDIAN);
335 offset += 1;
337 offset = dissect_feccode(tree, tvb, offset, pinfo, 0);
339 if (offset < hdrlen2bytes(hlen)) {
340 offset = dissect_norm_hdrext(tree, pinfo, tvb, offset, hlen);
342 if (flags & NORM_FLAG_STREAM) {
343 flag_tree = proto_tree_add_subtree(tree, tvb, offset, 8, ett_streampayload, NULL, "Stream Data");
344 proto_tree_add_item(flag_tree, hf_reserved, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
345 proto_tree_add_item(flag_tree, hf_payload_len, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
346 proto_tree_add_item(flag_tree, hf_payload_offset, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
349 if (tvb_reported_length_remaining(tvb, offset) > 0)
350 proto_tree_add_item(tree, hf_payload, tvb, offset, -1, ENC_NA);
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)
356 proto_item *ti;
357 proto_tree *flag_tree;
358 norm_packet_data_t *norm_data;
360 offset = dissect_grrtetc(tree, tvb, offset);
362 ti = proto_tree_add_item(tree, hf_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
363 flag_tree = proto_item_add_subtree(ti, ett_flags);
364 proto_tree_add_item(flag_tree, hf_flag_repair, tvb, offset, 1, ENC_BIG_ENDIAN);
365 proto_tree_add_item(flag_tree, hf_flag_norm_explicit, tvb, offset, 1, ENC_BIG_ENDIAN);
366 proto_tree_add_item(flag_tree, hf_flag_info, tvb, offset, 1, ENC_BIG_ENDIAN);
367 proto_tree_add_item(flag_tree, hf_flag_unreliable, tvb, offset, 1, ENC_BIG_ENDIAN);
368 proto_tree_add_item(flag_tree, hf_flag_file, tvb, offset, 1, ENC_BIG_ENDIAN);
369 proto_tree_add_item(flag_tree, hf_flag_stream, tvb, offset, 1, ENC_BIG_ENDIAN);
370 proto_tree_add_item(flag_tree, hf_flag_msgstart, tvb, offset, 1, ENC_BIG_ENDIAN);
371 offset += 1;
373 /* Save encoding ID */
374 norm_data = wmem_new0(wmem_file_scope(), norm_packet_data_t);
375 norm_data->encoding_id = tvb_get_uint8(tvb, offset);
377 p_add_proto_data(wmem_file_scope(), pinfo, proto_rmt_norm, 0, norm_data);
379 proto_tree_add_item(tree, hf_fec_encoding_id, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
380 proto_tree_add_item(tree, hf_object_transport_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
382 if (offset < hdrlen2bytes(hlen)) {
383 offset = dissect_norm_hdrext(tree, pinfo, tvb, offset, hlen);
385 if (tvb_reported_length_remaining(tvb, offset) > 0)
386 proto_tree_add_item(tree, hf_payload, tvb, offset, -1, ENC_NA);
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)
393 offset = dissect_feccode(tree, tvb, offset, pinfo, 0);
394 if (offset < hdrlen2bytes(hlen)) {
395 offset = dissect_norm_hdrext(tree, pinfo, tvb, offset, hlen);
397 return offset;
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)
404 proto_tree_add_item(tree, hf_flags, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
405 proto_tree_add_item(tree, hf_reserved, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
407 if (offset < hdrlen2bytes(hlen)) {
408 offset = dissect_norm_hdrext(tree, pinfo, tvb, offset, hlen);
410 while (tvb_reported_length_remaining(tvb, offset) > 0) {
411 offset = dissect_nack_data(tree, tvb, offset, pinfo);
413 return offset;
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)
420 proto_tree_add_item(tree, hf_reserved, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
421 proto_tree_add_item(tree, hf_cc_sequence, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
423 proto_tree_add_item(tree, hf_cc_sts, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
424 proto_tree_add_item(tree, hf_cc_stus, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
425 if (offset < hdrlen2bytes(hlen)) {
426 offset = dissect_norm_hdrext(tree, pinfo, tvb, offset, hlen);
428 while (offset < hdrlen2bytes(hlen)) {
429 proto_item *tif;
430 proto_tree *cc_tree, *flag_tree;
431 double grtt;
432 cc_tree = proto_tree_add_subtree(tree, tvb, offset, 8, ett_congestioncontrol, NULL, "Congestion Control");
433 proto_tree_add_item(cc_tree, hf_cc_node_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
434 tif = proto_tree_add_item(cc_tree, hf_cc_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
435 flag_tree = proto_item_add_subtree(tif, ett_flags);
436 proto_tree_add_item(flag_tree, hf_cc_flags_clr, tvb, offset, 1, ENC_BIG_ENDIAN);
437 proto_tree_add_item(flag_tree, hf_cc_flags_plr, tvb, offset, 1, ENC_BIG_ENDIAN);
438 proto_tree_add_item(flag_tree, hf_cc_flags_rtt, tvb, offset, 1, ENC_BIG_ENDIAN);
439 proto_tree_add_item(flag_tree, hf_cc_flags_start, tvb, offset, 1, ENC_BIG_ENDIAN);
440 proto_tree_add_item(flag_tree, hf_cc_flags_leave, tvb, offset, 1, ENC_BIG_ENDIAN);
441 offset += 1;
442 grtt = UnquantizeRtt(tvb_get_uint8(tvb, offset));
443 proto_tree_add_double(cc_tree, hf_cc_rtt, tvb, offset, 1, grtt); offset += 1;
444 grtt = rmt_decode_send_rate(tvb_get_ntohs(tvb, offset));
445 proto_tree_add_double(cc_tree, hf_cc_rate, tvb, offset, 2, grtt); offset += 2;
447 return offset;
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)
454 offset = dissect_feccode(tree, tvb, offset, pinfo, 0);
456 while (tvb_reported_length_remaining(tvb, offset) > 0) {
457 proto_tree_add_item(tree, hf_cc_transport_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
459 return offset;
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)
466 proto_tree_add_item(tree, hf_reserved, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
467 proto_tree_add_item(tree, hf_ack_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
468 proto_tree_add_item(tree, hf_ack_id, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
469 return offset;
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)
476 uint8_t flavor;
478 offset = dissect_grrtetc(tree, tvb, offset);
479 flavor = tvb_get_uint8(tvb, offset);
481 col_append_sep_str(pinfo->cinfo, COL_INFO, " ",
482 val_to_str(flavor, string_norm_cmd_type, "Unknown Cmd Type (0x%04x)"));
483 proto_tree_add_item(tree, hf_cmd_flavor, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
484 switch(flavor) {
485 case NORM_CMD_CC:
486 offset = dissect_norm_cmd_cc(tree, pinfo, tvb, offset, hlen);
487 break;
488 case NORM_CMD_FLUSH:
489 offset = dissect_norm_cmd_flush(tree, pinfo, tvb, offset, hlen);
490 break;
491 case NORM_CMD_SQUELCH:
492 offset = dissect_norm_cmd_squelch(tree, pinfo, tvb, offset);
493 break;
494 case NORM_CMD_REPAIR_ADV:
495 offset = dissect_norm_cmd_repairadv(tree, pinfo, tvb, offset, hlen);
496 break;
497 case NORM_CMD_ACK_REQ:
498 offset = dissect_norm_cmd_ackreq(tree, pinfo, tvb, offset);
499 break;
501 if (tvb_reported_length_remaining(tvb, offset) > 0)
502 proto_tree_add_item(tree, hf_payload, tvb, offset, -1, ENC_NA);
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)
509 uint8_t acktype;
511 proto_tree_add_item(tree, hf_ack_source, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
512 proto_tree_add_item(tree, hf_instance_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
513 acktype = tvb_get_uint8(tvb, offset);
515 col_append_sep_str(pinfo->cinfo, COL_INFO, " ",
516 val_to_str(acktype, string_norm_ack_type, "Unknown Ack Type (0x%04x)"));
517 proto_tree_add_item(tree, hf_ack_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
518 proto_tree_add_item(tree, hf_ack_id, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1;
519 proto_tree_add_item(tree, hf_ack_grtt_sec, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
520 proto_tree_add_item(tree, hf_ack_grtt_usec, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
521 if (offset < hdrlen2bytes(hlen)) {
522 offset = dissect_norm_hdrext(tree, pinfo, tvb, offset, hlen);
525 if (tvb_reported_length_remaining(tvb, offset) > 0)
526 proto_tree_add_item(tree, hf_payload, tvb, offset, -1, ENC_NA);
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)
533 proto_tree_add_item(tree, hf_nack_server, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
534 proto_tree_add_item(tree, hf_instance_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
535 proto_tree_add_item(tree, hf_reserved, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2;
536 proto_tree_add_item(tree, hf_nack_grtt_sec, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
537 proto_tree_add_item(tree, hf_nack_grtt_usec, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4;
538 if (offset < hdrlen2bytes(hlen)) {
539 offset = dissect_norm_hdrext(tree, pinfo, tvb, offset, hlen);
542 while (tvb_reported_length_remaining(tvb, offset) > 0) {
543 offset = dissect_nack_data(tree, tvb, offset, pinfo);
545 if (tvb_reported_length_remaining(tvb, offset) > 0)
546 proto_tree_add_item(tree, hf_payload, tvb, offset, -1, ENC_NA);
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_)
554 /* Logical packet representation */
555 uint8_t version;
556 uint8_t type;
557 uint8_t hlen;
559 /* Offset for subpacket dissection */
560 unsigned offset = 0;
562 /* Set up structures needed to add the protocol subtree and manage it */
563 proto_item *ti;
564 proto_tree *norm_tree;
566 /* Make entries in Protocol column and Info column on summary display */
567 col_set_str(pinfo->cinfo, COL_PROTOCOL, "NORM");
568 col_clear(pinfo->cinfo, COL_INFO);
570 /* NORM header dissection, part 1 */
571 /* ------------------------------ */
573 version = hi_nibble(tvb_get_uint8(tvb, offset));
575 /* Create subtree for the NORM protocol */
576 ti = proto_tree_add_item(tree, proto_rmt_norm, tvb, offset, -1, ENC_NA);
577 norm_tree = proto_item_add_subtree(ti, ett_main);
579 /* Fill the NORM subtree */
580 proto_tree_add_uint(norm_tree, hf_version, tvb, offset, 1, version);
582 /* This dissector supports only NORMv1 packets.
583 * If version > 1 print only version field and quit.
585 if (version != 1) {
586 expert_add_info(pinfo, ti, &ei_version1_only);
588 /* Complete entry in Info column on summary display */
589 col_add_fstr(pinfo->cinfo, COL_INFO, "Version: %u (not supported)", version);
590 return 0;
593 /* NORM header dissection, part 2 */
594 /* ------------------------------ */
596 type = lo_nibble(tvb_get_uint8(tvb, offset));
597 hlen = tvb_get_uint8(tvb, offset+1);
599 if (tree) {
600 proto_tree_add_uint(norm_tree, hf_type, tvb, offset, 1, type);
601 proto_tree_add_item(norm_tree, hf_hlen, tvb, offset+1, 1, ENC_BIG_ENDIAN);
602 proto_tree_add_item(norm_tree, hf_sequence, tvb, offset+2, 2, ENC_BIG_ENDIAN);
603 proto_tree_add_item(norm_tree, hf_source_id, tvb, offset+4, 4, ENC_BIG_ENDIAN);
606 offset += 8;
609 /* Complete entry in Info column on summary display */
610 /* ------------------------------------------------ */
611 col_append_sep_str(pinfo->cinfo, COL_INFO, " ",
612 val_to_str(type, string_norm_type, "Unknown Type (0x%04x)"));
615 switch(type) {
616 case NORM_INFO:
617 dissect_norm_info(norm_tree, pinfo, tvb, offset, hlen);
618 break;
619 case NORM_DATA:
620 dissect_norm_data(norm_tree, pinfo, tvb, offset, hlen);
621 break;
622 case NORM_CMD:
623 dissect_norm_cmd(norm_tree, pinfo, tvb, offset, hlen);
624 break;
625 case NORM_ACK:
626 dissect_norm_ack(norm_tree, pinfo, tvb, offset, hlen);
627 break;
628 case NORM_NACK:
629 dissect_norm_nack(norm_tree, pinfo, tvb, offset, hlen);
630 break;
631 default:
632 /* Add the Payload item */
633 if (tvb_reported_length_remaining(tvb, offset) > 0)
634 proto_tree_add_item(norm_tree, hf_payload, tvb, offset, -1, ENC_NA);
635 break;
638 return tvb_reported_length(tvb);
641 static bool
642 dissect_norm_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
644 uint8_t byte1;
646 if (tvb_reported_length(tvb) < 12)
647 return false; /* not enough to check */
648 byte1 = tvb_get_uint8(tvb, 0);
650 if (hi_nibble(byte1) != 1) return false;
651 if (lo_nibble(byte1) < 1 || lo_nibble(byte1) > 6) return false;
652 if (tvb_get_uint8(tvb, 1) > 20) return false;
654 dissect_norm(tvb, pinfo, tree, data);
655 return true; /* appears to be a NORM packet */
658 void proto_register_norm(void)
660 /* Setup NORM header fields */
661 static hf_register_info hf[] = {
663 { &hf_version,
664 { "Version", "norm.version",
665 FT_UINT8, BASE_DEC, NULL, 0x0,
666 NULL, HFILL }
668 { &hf_type,
669 { "Message Type", "norm.type",
670 FT_UINT8, BASE_DEC, VALS(string_norm_type), 0x0,
671 NULL, HFILL }
673 { &hf_hlen,
674 { "Header length", "norm.hlen",
675 FT_UINT8, BASE_DEC, NULL, 0x0,
676 NULL, HFILL }
678 { &hf_sequence,
679 { "Sequence", "norm.sequence",
680 FT_UINT16, BASE_DEC, NULL, 0x0,
681 NULL, HFILL }
683 { &hf_source_id,
684 { "Source ID", "norm.source_id",
685 FT_IPv4, BASE_NONE, NULL, 0x0,
686 NULL, HFILL }
688 { &hf_instance_id,
689 { "Instance", "norm.instance_id",
690 FT_UINT16, BASE_DEC, NULL, 0x0,
691 NULL, HFILL}
693 { &hf_grtt,
694 { "grtt", "norm.grtt",
695 FT_DOUBLE, BASE_NONE, NULL, 0x0,
696 NULL, HFILL}
698 { &hf_backoff,
699 { "Backoff", "norm.backoff",
700 FT_UINT8, BASE_DEC, NULL, 0x0,
701 NULL, HFILL}
703 { &hf_gsize,
704 { "Group Size", "norm.gsize",
705 FT_DOUBLE, BASE_NONE, NULL, 0x0,
706 NULL, HFILL}
708 { &hf_flags,
709 { "Flags", "norm.flags",
710 FT_UINT8, BASE_HEX, NULL, 0x0,
711 NULL, HFILL}
713 { &hf_flag_repair,
714 { "Repair Flag", "norm.flag.repair",
715 FT_BOOLEAN, 8, NULL, NORM_FLAG_REPAIR,
716 NULL, HFILL }
718 { &hf_flag_norm_explicit,
719 { "Explicit Flag", "norm.flag.explicit",
720 FT_BOOLEAN, 8, NULL, NORM_FLAG_EXPLICIT,
721 NULL, HFILL }
723 { &hf_flag_info,
724 { "Info Flag", "norm.flag.info",
725 FT_BOOLEAN, 8, NULL, NORM_FLAG_INFO,
726 NULL, HFILL }
728 { &hf_flag_unreliable,
729 { "Unreliable Flag", "norm.flag.unreliable",
730 FT_BOOLEAN, 8, NULL, NORM_FLAG_UNRELIABLE,
731 NULL, HFILL }
733 { &hf_flag_file,
734 { "File Flag", "norm.flag.file",
735 FT_BOOLEAN, 8, NULL, NORM_FLAG_FILE,
736 NULL, HFILL }
738 { &hf_flag_stream,
739 { "Stream Flag", "norm.flag.stream",
740 FT_BOOLEAN, 8, NULL, NORM_FLAG_STREAM,
741 NULL, HFILL }
743 { &hf_flag_msgstart,
744 { "Msg Start Flag", "norm.flag.msgstart",
745 FT_BOOLEAN, 8, NULL, NORM_FLAG_MSG_START,
746 NULL, HFILL }
748 { &hf_object_transport_id,
749 { "Object Transport ID", "norm.object_transport_id",
750 FT_UINT16, BASE_HEX, NULL, 0x0,
751 NULL, HFILL}
753 { &hf_extension,
754 { "Hdr Extension", "norm.hexext",
755 FT_UINT16, BASE_DEC, NULL, 0x0,
756 NULL, HFILL}
758 { &hf_reserved,
759 { "Reserved", "norm.reserved",
760 FT_UINT16, BASE_HEX, NULL, 0x0,
761 NULL, HFILL}
763 { &hf_payload_len,
764 { "Payload Len", "norm.payload.len",
765 FT_UINT16, BASE_DEC, NULL, 0x0,
766 NULL, HFILL}
768 { &hf_payload_offset,
769 { "Payload Offset", "norm.payload.offset",
770 FT_UINT32, BASE_DEC, NULL, 0x0,
771 NULL, HFILL}
774 { &hf_cmd_flavor,
775 { "Flavor", "norm.flavor",
776 FT_UINT8, BASE_DEC, VALS(string_norm_cmd_type), 0x0,
777 NULL, HFILL}
779 { &hf_cc_sequence,
780 { "CC Sequence", "norm.ccsequence",
781 FT_UINT16, BASE_DEC, NULL, 0x0,
782 NULL, HFILL}
784 { &hf_cc_sts,
785 { "Send Time secs", "norm.cc_sts",
786 FT_UINT32, BASE_DEC, NULL, 0x0,
787 NULL, HFILL}
789 { &hf_cc_stus,
790 { "Send Time usecs", "norm.cc_stus",
791 FT_UINT32, BASE_DEC, NULL, 0x0,
792 NULL, HFILL}
794 { &hf_cc_node_id,
795 { "CC Node ID", "norm.cc_node_id",
796 FT_IPv4, BASE_NONE, NULL, 0x0,
797 NULL, HFILL}
799 { &hf_cc_flags,
800 { "CC Flags", "norm.cc_flags",
801 FT_UINT8, BASE_DEC, NULL, 0x0,
802 NULL, HFILL}
804 { &hf_cc_flags_clr,
805 { "CLR", "norm.cc_flags.clr",
806 FT_BOOLEAN, 8, NULL, NORM_FLAG_CC_CLR,
807 NULL, HFILL}
809 { &hf_cc_flags_plr,
810 { "PLR", "norm.cc_flags.plr",
811 FT_BOOLEAN, 8, NULL, NORM_FLAG_CC_PLR,
812 NULL, HFILL}
814 { &hf_cc_flags_rtt,
815 { "RTT", "norm.cc_flags.rtt",
816 FT_BOOLEAN, 8, NULL, NORM_FLAG_CC_RTT,
817 NULL, HFILL}
819 { &hf_cc_flags_start,
820 { "Start", "norm.cc_flags.start",
821 FT_BOOLEAN, 8, NULL, NORM_FLAG_CC_START,
822 NULL, HFILL}
824 { &hf_cc_flags_leave,
825 { "Leave", "norm.cc_flags.leave",
826 FT_BOOLEAN, 8, NULL, NORM_FLAG_CC_LEAVE,
827 NULL, HFILL}
829 { &hf_cc_rtt,
830 { "CC RTT", "norm.cc_rtt",
831 FT_DOUBLE, BASE_NONE, NULL, 0x0,
832 NULL, HFILL}
834 { &hf_cc_rate,
835 { "CC Rate", "norm.cc_rate",
836 FT_DOUBLE, BASE_NONE, NULL, 0x0,
837 NULL, HFILL}
839 { &hf_cc_transport_id,
840 { "CC Transport ID", "norm.cc_transport_id",
841 FT_UINT16, BASE_DEC, NULL, 0x0,
842 NULL, HFILL}
845 { &hf_ack_source,
846 { "Ack Source", "norm.ack.source",
847 FT_IPv4, BASE_NONE, NULL, 0x0,
848 NULL, HFILL}
850 { &hf_ack_type,
851 { "Ack Type", "norm.ack.type",
852 FT_UINT8, BASE_DEC, VALS(string_norm_ack_type), 0x0,
853 NULL, HFILL}
855 { &hf_ack_id,
856 { "Ack ID", "norm.ack.id",
857 FT_UINT8, BASE_DEC, NULL, 0x0,
858 NULL, HFILL}
860 { &hf_ack_grtt_sec,
861 { "Ack GRTT Sec", "norm.ack.grtt_sec",
862 FT_UINT32, BASE_DEC, NULL, 0x0,
863 NULL, HFILL}
865 { &hf_ack_grtt_usec,
866 { "Ack GRTT usec", "norm.ack.grtt_usec",
867 FT_UINT32, BASE_DEC, NULL, 0x0,
868 NULL, HFILL}
871 { &hf_nack_server,
872 { "NAck Server", "norm.nack.server",
873 FT_IPv4, BASE_NONE, NULL, 0x0,
874 NULL, HFILL}
876 { &hf_nack_grtt_sec,
877 { "NAck GRTT Sec", "norm.nack.grtt_sec",
878 FT_UINT32, BASE_DEC, NULL, 0x0,
879 NULL, HFILL}
881 { &hf_nack_grtt_usec,
882 { "NAck GRTT usec", "norm.nack.grtt_usec",
883 FT_UINT32, BASE_DEC, NULL, 0x0,
884 NULL, HFILL}
886 { &hf_nack_form,
887 { "NAck FORM", "norm.nack.form",
888 FT_UINT8, BASE_DEC, VALS(string_norm_nack_form), 0x0,
889 NULL, HFILL}
891 { &hf_nack_flags,
892 { "NAck Flags", "norm.nack.flags",
893 FT_UINT8, BASE_DEC, NULL, 0x0,
894 NULL, HFILL}
896 { &hf_nack_flags_segment,
897 { "Segment", "norm.nack.flags.segment",
898 FT_BOOLEAN, 8, NULL, NORM_NACK_SEGMENT,
899 NULL, HFILL}
901 { &hf_nack_flags_block,
902 { "Block", "norm.nack.flags.block",
903 FT_BOOLEAN, 8, NULL, NORM_NACK_BLOCK,
904 NULL, HFILL}
906 { &hf_nack_flags_info,
907 { "Info", "norm.nack.flags.info",
908 FT_BOOLEAN, 8, NULL, NORM_NACK_INFO,
909 NULL, HFILL}
911 { &hf_nack_flags_object,
912 { "Object", "norm.nack.flags.object",
913 FT_BOOLEAN, 8, NULL, NORM_NACK_OBJECT,
914 NULL, HFILL}
916 { &hf_nack_length,
917 { "NAck Length", "norm.nack.length",
918 FT_UINT16, BASE_DEC, NULL, 0x0,
919 NULL, HFILL}
921 { &hf_payload,
922 { "Payload", "norm.payload",
923 FT_BYTES, BASE_NONE, NULL, 0x0,
924 NULL, HFILL }
926 { &hf_fec_encoding_id,
927 { "FEC Encoding ID", "norm.fec_encoding_id",
928 FT_UINT8, BASE_DEC, VALS(string_fec_encoding_id), 0x0,
929 NULL, HFILL}
933 /* Setup protocol subtree array */
934 static int *ett[] = {
935 &ett_main,
936 &ett_hdrext,
937 &ett_flags,
938 &ett_streampayload,
939 &ett_congestioncontrol,
940 &ett_nackdata
943 static ei_register_info ei[] = {
944 { &ei_version1_only, { "norm.version1_only", PI_PROTOCOL, PI_WARN, "Sorry, this dissector supports NORM version 1 only", EXPFILL }}
947 module_t *module;
948 expert_module_t* expert_rmt_norm;
950 /* Register the protocol name and description */
951 proto_rmt_norm = proto_register_protocol("Negative-acknowledgment Oriented Reliable Multicast", "NORM", "norm");
953 /* Register the header fields and subtrees used */
954 proto_register_field_array(proto_rmt_norm, hf, array_length(hf));
955 proto_register_subtree_array(ett, array_length(ett));
956 expert_rmt_norm = expert_register_protocol(proto_rmt_norm);
957 expert_register_field_array(expert_rmt_norm, ei, array_length(ei));
959 /* Register the subdissector handle */
960 norm_handle = register_dissector("norm", dissect_norm, proto_rmt_norm);
962 /* Register preferences */
963 module = prefs_register_protocol(proto_rmt_norm, NULL);
964 prefs_register_obsolete_preference(module, "heuristic_norm");
967 void proto_reg_handoff_norm(void)
969 dissector_add_for_decode_as_with_preference("udp.port", norm_handle);
970 heur_dissector_add("udp", dissect_norm_heur, "NORM over UDP", "rmt_norm_udp", proto_rmt_norm, HEURISTIC_DISABLE);
972 rmt_fec_handle = find_dissector_add_dependency("rmt-fec", proto_rmt_norm);
976 * Editor modelines - https://www.wireshark.org/tools/modelines.html
978 * Local variables:
979 * c-basic-offset: 4
980 * tab-width: 8
981 * indent-tabs-mode: nil
982 * End:
984 * ex: set shiftwidth=4 tabstop=8 expandtab:
985 * :indentSize=4:tabSize=8:noTabs=true: