/src/wireshark/epan/dissectors/packet-pgm.c
Line | Count | Source |
1 | | /* packet-pgm.c |
2 | | * Routines for PGM packet disassembly, RFC 3208 |
3 | | * |
4 | | * Copyright (c) 2000 by Talarian Corp |
5 | | * Rewritten by Jaap Keuter |
6 | | * |
7 | | * Wireshark - Network traffic analyzer |
8 | | * By Gerald Combs <gerald@wireshark.org> |
9 | | * Copyright 1999 Gerald Combs |
10 | | * |
11 | | * SPDX-License-Identifier: GPL-2.0-or-later |
12 | | */ |
13 | | |
14 | | #include "config.h" |
15 | | |
16 | | #include <epan/packet.h> |
17 | | #include <epan/in_cksum.h> |
18 | | #include <epan/prefs.h> |
19 | | #include <epan/ptvcursor.h> |
20 | | #include <epan/expert.h> |
21 | | #include <epan/tfs.h> |
22 | | #include <wsutil/array.h> |
23 | | |
24 | | #include "packet-iana-data.h" |
25 | | /* |
26 | | * RFC 3208 |
27 | | * |
28 | | * Plus https://dl.acm.org/doi/pdf/10.1145/347057.347390 for PGMCC, |
29 | | * whence the ACK packet type comes; there are some I-Ds for PGMCC, |
30 | | * draft-ietf-rmt-bb-pgmcc-00 through draft-ietf-rmt-bb-pgmcc-03, |
31 | | * but none of them give any description of the packet-level |
32 | | * changes to PGM, unlike the paper in question, which merely gives |
33 | | * an *insufficient* description of said changes. In particular, |
34 | | * it doesn't indicate what the packet type code for ACK is. |
35 | | * |
36 | | * Luigi Rizzo's PGMCC code for FreeBSD, at |
37 | | * |
38 | | * https://web.archive.org/web/20020302084503/http://info.iet.unipi.it/~luigi/pgm-code/ |
39 | | * |
40 | | * uses 0x0b (11) for ACK, as does tcpdump's dissector. |
41 | | * |
42 | | * A capture file attached to |
43 | | * |
44 | | * https://gitlab.com/wireshark/wireshark/-/issues/4798 |
45 | | * |
46 | | * has packets that use 0x0d for ACK, as did this dissector, and |
47 | | * as does OpenPGM at https://github.com/steve-o/openpgm. It may |
48 | | * be that some proprietary PGMCC implementations, such as SmartPGM, |
49 | | * do so as well. |
50 | | * |
51 | | * We use *both*, treating *either one* as a PGMCC ACK, pending |
52 | | * more information, such as an answer to |
53 | | * |
54 | | * https://github.com/steve-o/openpgm/issues/75. |
55 | | */ |
56 | | |
57 | | void proto_register_pgm(void); |
58 | | void proto_reg_handoff_pgm(void); |
59 | | |
60 | | static dissector_handle_t pgm_handle; |
61 | | |
62 | | /* |
63 | | * Flag to control whether to check the PGM checksum. |
64 | | */ |
65 | | static bool pgm_check_checksum = true; |
66 | | |
67 | | /* constants for hdr types */ |
68 | 19 | #define PGM_SPM_PCKT 0x00 |
69 | 250 | #define PGM_ODATA_PCKT 0x04 |
70 | 260 | #define PGM_RDATA_PCKT 0x05 |
71 | 4 | #define PGM_NAK_PCKT 0x08 |
72 | 7 | #define PGM_NNAK_PCKT 0x09 |
73 | 10 | #define PGM_NCF_PCKT 0x0A |
74 | 12 | #define PGM_POLL_PCKT 0x01 |
75 | 8 | #define PGM_POLR_PCKT 0x02 |
76 | | |
77 | | /* |
78 | | * See above comment for why there are two values for the PGMCC |
79 | | * ACK packet's packet type. |
80 | | */ |
81 | 2 | #define PGM_ACK_PCKT 0x0B |
82 | 4 | #define PGM_ACK2_PCKT 0x0D |
83 | | |
84 | | /* option flags (main PGM header) */ |
85 | 452 | #define PGM_OPT 0x01 |
86 | 240 | #define PGM_OPT_NETSIG 0x02 |
87 | 240 | #define PGM_OPT_VAR_PKTLEN 0x40 |
88 | 240 | #define PGM_OPT_PARITY 0x80 |
89 | | |
90 | | /* option types */ |
91 | 205 | #define PGM_OPT_LENGTH 0x00 |
92 | 1.60k | #define PGM_OPT_END 0x80 |
93 | 25 | #define PGM_OPT_FRAGMENT 0x01 |
94 | 31 | #define PGM_OPT_NAK_LIST 0x02 |
95 | 18 | #define PGM_OPT_JOIN 0x03 |
96 | 401 | #define PGM_OPT_REDIRECT 0x07 |
97 | | #define PGM_OPT_SYN 0x0D |
98 | | #define PGM_OPT_FIN 0x0E |
99 | | #define PGM_OPT_RST 0x0F |
100 | 116 | #define PGM_OPT_PARITY_PRM 0x08 |
101 | 37 | #define PGM_OPT_PARITY_GRP 0x09 |
102 | | #define PGM_OPT_CURR_TGSIZE 0x0A |
103 | 26 | #define PGM_OPT_PGMCC_DATA 0x12 |
104 | 44 | #define PGM_OPT_PGMCC_FEEDBACK 0x13 |
105 | 175 | #define PGM_OPT_NAK_BO_IVL 0x04 |
106 | 391 | #define PGM_OPT_NAK_BO_RNG 0x05 |
107 | | |
108 | | /* POLL subtypes */ |
109 | | #define PGM_POLL_GENERAL 0x0 |
110 | | #define PGM_POLL_DLR 0x1 |
111 | | |
112 | | /* OPX bit values */ |
113 | | #define PGM_OPX_IGNORE 0x00 |
114 | | #define PGM_OPX_INVAL 0x01 |
115 | | #define PGM_OPX_DISCARD 0x10 |
116 | | |
117 | 27 | #define PGM_OPT_NAK_LIST_SIZE 4 |
118 | | |
119 | | /* |
120 | | * To squeeze the whole option into 255 bytes, we |
121 | | * can only have 62 in the list |
122 | | */ |
123 | | #define PGM_MAX_NAK_LIST_SZ (62) |
124 | | |
125 | 11 | #define PGM_OPT_JOIN_SIZE 8 |
126 | 125 | #define PGM_OPT_PARITY_PRM_SIZE 8 |
127 | | |
128 | | /* OPT_PARITY_PRM P and O bits */ |
129 | 95 | #define PGM_OPT_PARITY_PRM_PRO 0x2 |
130 | 95 | #define PGM_OPT_PARITY_PRM_OND 0x1 |
131 | | |
132 | 37 | #define PGM_OPT_PARITY_GRP_SIZE 8 |
133 | | #define PGM_OPT_CURR_TGSIZE_SIZE 8 |
134 | 26 | #define PGM_OPT_PGMCC_DATA_SIZE 16 |
135 | 44 | #define PGM_OPT_PGMCC_FEEDBACK_SIZE 16 |
136 | 323 | #define PGM_OPT_NAK_BO_IVL_SIZE 12 |
137 | 721 | #define PGM_OPT_NAK_BO_RNG_SIZE 12 |
138 | 747 | #define PGM_OPT_REDIRECT_SIZE 12 |
139 | 27 | #define PGM_OPT_FRAGMENT_SIZE 16 |
140 | | |
141 | | static int proto_pgm; |
142 | | static int ett_pgm; |
143 | | static int ett_pgm_optbits; |
144 | | static int ett_pgm_opts; |
145 | | static int ett_pgm_spm; |
146 | | static int ett_pgm_data; |
147 | | static int ett_pgm_nak; |
148 | | static int ett_pgm_poll; |
149 | | static int ett_pgm_polr; |
150 | | static int ett_pgm_ack; |
151 | | static int ett_pgm_opts_join; |
152 | | static int ett_pgm_opts_parityprm; |
153 | | static int ett_pgm_opts_paritygrp; |
154 | | static int ett_pgm_opts_naklist; |
155 | | static int ett_pgm_opts_ccdata; |
156 | | static int ett_pgm_opts_nak_bo_ivl; |
157 | | static int ett_pgm_opts_nak_bo_rng; |
158 | | static int ett_pgm_opts_redirect; |
159 | | static int ett_pgm_opts_fragment; |
160 | | |
161 | | static int hf_pgm_main_sport; |
162 | | static int hf_pgm_main_dport; |
163 | | static int hf_pgm_port; |
164 | | static int hf_pgm_main_type; |
165 | | static int hf_pgm_main_opts; |
166 | | static int hf_pgm_main_opts_opt; |
167 | | static int hf_pgm_main_opts_netsig; |
168 | | static int hf_pgm_main_opts_varlen; |
169 | | static int hf_pgm_main_opts_parity; |
170 | | static int hf_pgm_main_cksum; |
171 | | static int hf_pgm_main_cksum_status; |
172 | | static int hf_pgm_main_gsi; |
173 | | static int hf_pgm_main_tsdulen; |
174 | | static int hf_pgm_spm_sqn; |
175 | | static int hf_pgm_spm_lead; |
176 | | static int hf_pgm_spm_trail; |
177 | | static int hf_pgm_spm_pathafi; |
178 | | static int hf_pgm_spm_res; |
179 | | static int hf_pgm_spm_path; |
180 | | static int hf_pgm_spm_path6; |
181 | | /* static int hf_pgm_data_sqn; */ |
182 | | /* static int hf_pgm_data_trail; */ |
183 | | static int hf_pgm_nak_sqn; |
184 | | static int hf_pgm_nak_srcafi; |
185 | | static int hf_pgm_nak_srcres; |
186 | | static int hf_pgm_nak_src; |
187 | | static int hf_pgm_nak_src6; |
188 | | static int hf_pgm_nak_grpafi; |
189 | | static int hf_pgm_nak_grpres; |
190 | | static int hf_pgm_nak_grp; |
191 | | static int hf_pgm_nak_grp6; |
192 | | static int hf_pgm_poll_sqn; |
193 | | static int hf_pgm_poll_round; |
194 | | static int hf_pgm_poll_subtype; |
195 | | static int hf_pgm_poll_pathafi; |
196 | | static int hf_pgm_poll_res; |
197 | | static int hf_pgm_poll_path; |
198 | | static int hf_pgm_poll_path6; |
199 | | static int hf_pgm_poll_backoff_ivl; |
200 | | static int hf_pgm_poll_rand_str; |
201 | | static int hf_pgm_poll_matching_bmask; |
202 | | static int hf_pgm_polr_sqn; |
203 | | static int hf_pgm_polr_round; |
204 | | static int hf_pgm_polr_res; |
205 | | static int hf_pgm_ack_sqn; |
206 | | static int hf_pgm_ack_bitmap; |
207 | | |
208 | | static int hf_pgm_opt_type; |
209 | | static int hf_pgm_opt_len; |
210 | | static int hf_pgm_opt_tlen; |
211 | | |
212 | | static int hf_pgm_genopt_end; |
213 | | static int hf_pgm_genopt_type; |
214 | | static int hf_pgm_genopt_len; |
215 | | static int hf_pgm_genopt_opx; |
216 | | |
217 | | static int hf_pgm_opt_join_res; |
218 | | static int hf_pgm_opt_join_minjoin; |
219 | | |
220 | | static int hf_pgm_opt_parity_prm_po; |
221 | | static int hf_pgm_opt_parity_prm_prmtgsz; |
222 | | |
223 | | static int hf_pgm_opt_parity_grp_res; |
224 | | static int hf_pgm_opt_parity_grp_prmgrp; |
225 | | |
226 | | static int hf_pgm_opt_nak_res; |
227 | | static int hf_pgm_opt_nak_list; |
228 | | |
229 | | static int hf_pgm_opt_ccdata_res; |
230 | | static int hf_pgm_opt_ccdata_tsp; |
231 | | static int hf_pgm_opt_ccdata_afi; |
232 | | static int hf_pgm_opt_ccdata_res2; |
233 | | static int hf_pgm_opt_ccdata_acker; |
234 | | static int hf_pgm_opt_ccdata_acker6; |
235 | | |
236 | | static int hf_pgm_opt_ccfeedbk_res; |
237 | | static int hf_pgm_opt_ccfeedbk_tsp; |
238 | | static int hf_pgm_opt_ccfeedbk_afi; |
239 | | static int hf_pgm_opt_ccfeedbk_lossrate; |
240 | | static int hf_pgm_opt_ccfeedbk_acker; |
241 | | static int hf_pgm_opt_ccfeedbk_acker6; |
242 | | |
243 | | static int hf_pgm_opt_nak_bo_ivl_res; |
244 | | static int hf_pgm_opt_nak_bo_ivl_bo_ivl; |
245 | | static int hf_pgm_opt_nak_bo_ivl_bo_ivl_sqn; |
246 | | |
247 | | static int hf_pgm_opt_nak_bo_rng_res; |
248 | | static int hf_pgm_opt_nak_bo_rng_min_bo_ivl; |
249 | | static int hf_pgm_opt_nak_bo_rng_max_bo_ivl; |
250 | | |
251 | | static int hf_pgm_opt_redirect_res; |
252 | | static int hf_pgm_opt_redirect_afi; |
253 | | static int hf_pgm_opt_redirect_res2; |
254 | | static int hf_pgm_opt_redirect_dlr; |
255 | | static int hf_pgm_opt_redirect_dlr6; |
256 | | |
257 | | static int hf_pgm_opt_fragment_res; |
258 | | static int hf_pgm_opt_fragment_first_sqn; |
259 | | static int hf_pgm_opt_fragment_offset; |
260 | | static int hf_pgm_opt_fragment_total_length; |
261 | | |
262 | | static expert_field ei_pgm_genopt_len; |
263 | | static expert_field ei_pgm_opt_tlen; |
264 | | static expert_field ei_pgm_opt_type; |
265 | | static expert_field ei_address_format_invalid; |
266 | | static expert_field ei_pgm_main_cksum; |
267 | | |
268 | | static dissector_table_t subdissector_table; |
269 | | static heur_dissector_list_t heur_subdissector_list; |
270 | | |
271 | | |
272 | | static const char * |
273 | | optsstr(wmem_allocator_t *pool, uint8_t opts) |
274 | 246 | { |
275 | 246 | char *msg; |
276 | 246 | int returned_length, idx = 0; |
277 | 246 | const int MAX_STR_LEN = 256; |
278 | | |
279 | 246 | if (opts == 0) |
280 | 20 | return ""; |
281 | | |
282 | 226 | msg=(char *)wmem_alloc(pool, MAX_STR_LEN); |
283 | 226 | if (opts & PGM_OPT){ |
284 | 192 | returned_length = snprintf(&msg[idx], MAX_STR_LEN-idx, "Present"); |
285 | 192 | idx += MIN(returned_length, MAX_STR_LEN-idx); |
286 | 192 | } |
287 | 226 | if (opts & PGM_OPT_NETSIG){ |
288 | 139 | returned_length = snprintf(&msg[idx], MAX_STR_LEN-idx, "%sNetSig", (!idx)?"":","); |
289 | 139 | idx += MIN(returned_length, MAX_STR_LEN-idx); |
290 | 139 | } |
291 | 226 | if (opts & PGM_OPT_VAR_PKTLEN){ |
292 | 121 | returned_length = snprintf(&msg[idx], MAX_STR_LEN-idx, "%sVarLen", (!idx)?"":","); |
293 | 121 | idx += MIN(returned_length, MAX_STR_LEN-idx); |
294 | 121 | } |
295 | 226 | if (opts & PGM_OPT_PARITY){ |
296 | 90 | returned_length = snprintf(&msg[idx], MAX_STR_LEN-idx, "%sParity", (!idx)?"":","); |
297 | 90 | idx += MIN(returned_length, MAX_STR_LEN-idx); |
298 | 90 | } |
299 | 226 | if (!idx) { |
300 | 5 | snprintf(&msg[idx], MAX_STR_LEN-idx, "0x%x", opts); |
301 | 5 | } |
302 | 226 | return msg; |
303 | 246 | } |
304 | | static const char * |
305 | | paritystr(wmem_allocator_t *pool, uint8_t parity) |
306 | 100 | { |
307 | 100 | char *msg; |
308 | 100 | int returned_length, idx = 0; |
309 | 100 | const int MAX_STR_LEN = 256; |
310 | | |
311 | 100 | if (parity == 0) |
312 | 5 | return ""; |
313 | | |
314 | 95 | msg=(char *)wmem_alloc(pool, MAX_STR_LEN); |
315 | 95 | if (parity & PGM_OPT_PARITY_PRM_PRO){ |
316 | 19 | returned_length = snprintf(&msg[idx], MAX_STR_LEN-idx, "Pro-active"); |
317 | 19 | idx += MIN(returned_length, MAX_STR_LEN-idx); |
318 | 19 | } |
319 | 95 | if (parity & PGM_OPT_PARITY_PRM_OND){ |
320 | 27 | returned_length = snprintf(&msg[idx], MAX_STR_LEN-idx, "%sOn-demand", (!idx)?"":","); |
321 | 27 | idx += MIN(returned_length, MAX_STR_LEN-idx); |
322 | 27 | } |
323 | 95 | if (!idx) { |
324 | 64 | snprintf(&msg[idx], MAX_STR_LEN-idx, "0x%x", parity); |
325 | 64 | } |
326 | 95 | return msg; |
327 | 100 | } |
328 | | |
329 | | static const value_string opt_vals[] = { |
330 | | { PGM_OPT_LENGTH, "Length" }, |
331 | | { PGM_OPT_END, "End" }, |
332 | | { PGM_OPT_FRAGMENT, "Fragment" }, |
333 | | { PGM_OPT_NAK_LIST, "NakList" }, |
334 | | { PGM_OPT_JOIN, "Join" }, |
335 | | { PGM_OPT_REDIRECT, "ReDirect" }, |
336 | | { PGM_OPT_SYN, "Syn" }, |
337 | | { PGM_OPT_FIN, "Fin" }, |
338 | | { PGM_OPT_RST, "Rst" }, |
339 | | { PGM_OPT_PARITY_PRM, "ParityPrm" }, |
340 | | { PGM_OPT_PARITY_GRP, "ParityGrp" }, |
341 | | { PGM_OPT_CURR_TGSIZE, "CurrTgsiz" }, |
342 | | { PGM_OPT_PGMCC_DATA, "CcData" }, |
343 | | { PGM_OPT_PGMCC_FEEDBACK, "CcFeedBack" }, |
344 | | { PGM_OPT_NAK_BO_IVL, "NakBackOffIvl" }, |
345 | | { PGM_OPT_NAK_BO_RNG, "NakBackOffRng" }, |
346 | | { 0, NULL } |
347 | | }; |
348 | | |
349 | | static const value_string opx_vals[] = { |
350 | | { PGM_OPX_IGNORE, "Ignore" }, |
351 | | { PGM_OPX_INVAL, "Inval" }, |
352 | | { PGM_OPX_DISCARD, "DisCard" }, |
353 | | { 0, NULL } |
354 | | }; |
355 | | |
356 | | #define TLV_CHECK(ett) \ |
357 | 1.52k | opt_tree = proto_tree_add_subtree_format(opts_tree, tvb, ptvcursor_current_offset(cursor), genopts_len, \ |
358 | 1.52k | ett, &tf, "Option: %s, Length: %u", \ |
359 | 1.52k | val_to_str(pinfo->pool, genopts_type, opt_vals, "Unknown (0x%02x)"), genopts_len); \ |
360 | 1.52k | if (genopts_len < 4) { \ |
361 | 53 | expert_add_info_format(pinfo, tf, &ei_pgm_genopt_len, \ |
362 | 53 | "Length %u invalid, must be >= 4", genopts_len); \ |
363 | 53 | return; \ |
364 | 53 | } \ |
365 | 1.52k | if (opts_total_len < genopts_len) { \ |
366 | 18 | expert_add_info_format(pinfo, tf, &ei_pgm_genopt_len, \ |
367 | 18 | "Length %u > remaining total options length", genopts_len); \ |
368 | 18 | return; \ |
369 | 18 | } \ |
370 | | |
371 | | |
372 | | static void |
373 | | dissect_pgmopts(ptvcursor_t* cursor, packet_info *pinfo, const char *pktname) |
374 | 182 | { |
375 | 182 | proto_item *tf, *ti, *ti_len; |
376 | 182 | proto_tree *opts_tree = NULL; |
377 | 182 | proto_tree *opt_tree = NULL; |
378 | 182 | tvbuff_t *tvb = ptvcursor_tvbuff(cursor); |
379 | | |
380 | 182 | bool theend = false; |
381 | | |
382 | 182 | uint16_t opts_total_len; |
383 | 182 | uint8_t genopts_type; |
384 | 182 | uint8_t genopts_len; |
385 | 182 | uint8_t opts_type; |
386 | | |
387 | 182 | opts_tree = proto_tree_add_subtree_format(ptvcursor_tree(cursor), tvb, ptvcursor_current_offset(cursor), -1, |
388 | 182 | ett_pgm_opts, &tf, "%s Options", pktname); |
389 | 182 | ptvcursor_set_tree(cursor, opts_tree); |
390 | 182 | opts_type = tvb_get_uint8(tvb, ptvcursor_current_offset(cursor)); |
391 | 182 | ti = ptvcursor_add(cursor, hf_pgm_opt_type, 1, ENC_BIG_ENDIAN); |
392 | 182 | if (opts_type != PGM_OPT_LENGTH) { |
393 | 23 | expert_add_info_format(pinfo, ti, &ei_pgm_opt_type, |
394 | 23 | "%s Options - initial option is %s, should be %s", |
395 | 23 | pktname, |
396 | 23 | val_to_str(pinfo->pool, opts_type, opt_vals, "Unknown (0x%02x)"), |
397 | 23 | val_to_str(pinfo->pool, PGM_OPT_LENGTH, opt_vals, "Unknown (0x%02x)")); |
398 | 23 | return; |
399 | 23 | } |
400 | 159 | ptvcursor_add(cursor, hf_pgm_opt_len, 1, ENC_BIG_ENDIAN); |
401 | 159 | opts_total_len = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); |
402 | 159 | proto_item_append_text(tf, " (Total Length %d)", opts_total_len); |
403 | 159 | proto_item_set_len(tf, opts_total_len); |
404 | 159 | ti_len = ptvcursor_add(cursor, hf_pgm_opt_tlen, 2, ENC_BIG_ENDIAN); |
405 | 159 | if (opts_total_len < 4) { |
406 | 4 | expert_add_info_format(pinfo, ti_len, &ei_pgm_opt_tlen, |
407 | 4 | "%s Options (Total Length %u - invalid, must be >= 4)", |
408 | 4 | pktname, opts_total_len); |
409 | 4 | return; |
410 | 4 | } |
411 | | |
412 | 1.59k | for (opts_total_len -= 4; !theend && opts_total_len != 0;){ |
413 | 1.55k | if (opts_total_len < 4) { |
414 | 2 | expert_add_info_format(pinfo, ti_len, &ei_pgm_opt_tlen, |
415 | 2 | "Remaining total options length doesn't have enough for an options header"); |
416 | 2 | break; |
417 | 2 | } |
418 | | |
419 | 1.55k | genopts_type = tvb_get_uint8(tvb, ptvcursor_current_offset(cursor)); |
420 | 1.55k | genopts_len = tvb_get_uint8(tvb, ptvcursor_current_offset(cursor)+1); |
421 | | |
422 | 1.55k | if (genopts_type & PGM_OPT_END) { |
423 | 46 | genopts_type &= ~PGM_OPT_END; |
424 | 46 | theend = true; |
425 | 46 | } |
426 | | |
427 | 1.55k | switch(genopts_type) { |
428 | 18 | case PGM_OPT_JOIN:{ |
429 | 18 | TLV_CHECK(ett_pgm_opts_join); |
430 | 10 | ptvcursor_set_tree(cursor, opt_tree); |
431 | | |
432 | 10 | ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); |
433 | 10 | ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); |
434 | | |
435 | 10 | if (genopts_len < PGM_OPT_JOIN_SIZE) { |
436 | 1 | proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, |
437 | 1 | ptvcursor_current_offset(cursor), 1, genopts_len, |
438 | 1 | "%u (bogus, must be >= %u)", |
439 | 1 | genopts_len, PGM_OPT_JOIN_SIZE); |
440 | 1 | break; |
441 | 1 | } |
442 | 9 | ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); |
443 | 9 | ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); |
444 | 9 | ptvcursor_add(cursor, hf_pgm_opt_join_res, 1, ENC_BIG_ENDIAN); |
445 | 9 | ptvcursor_add(cursor, hf_pgm_opt_join_minjoin, 4, ENC_BIG_ENDIAN); |
446 | | |
447 | 9 | break; |
448 | 10 | } |
449 | 116 | case PGM_OPT_PARITY_PRM:{ |
450 | 116 | uint8_t optdata_po; |
451 | | |
452 | 116 | TLV_CHECK(ett_pgm_opts_parityprm); |
453 | 113 | ptvcursor_set_tree(cursor, opt_tree); |
454 | | |
455 | 113 | ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); |
456 | 113 | ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); |
457 | | |
458 | | |
459 | 113 | if (genopts_len < PGM_OPT_PARITY_PRM_SIZE) { |
460 | 12 | proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, ptvcursor_tvbuff(cursor), |
461 | 12 | ptvcursor_current_offset(cursor), 1, genopts_len, |
462 | 12 | "%u (bogus, must be >= %u)", |
463 | 12 | genopts_len, PGM_OPT_PARITY_PRM_SIZE); |
464 | 12 | break; |
465 | 12 | } |
466 | 101 | ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); |
467 | 101 | ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); |
468 | 101 | optdata_po = tvb_get_uint8(tvb, ptvcursor_current_offset(cursor)); |
469 | 101 | proto_tree_add_uint_format_value(opt_tree, hf_pgm_opt_parity_prm_po, tvb, |
470 | 101 | ptvcursor_current_offset(cursor), 1, optdata_po, "%s (0x%x)", |
471 | 101 | paritystr(pinfo->pool, optdata_po), optdata_po); |
472 | 101 | ptvcursor_advance(cursor, 1); |
473 | | |
474 | 101 | ptvcursor_add(cursor, hf_pgm_opt_parity_prm_prmtgsz, 4, ENC_BIG_ENDIAN); |
475 | | |
476 | 101 | break; |
477 | 113 | } |
478 | 37 | case PGM_OPT_PARITY_GRP:{ |
479 | 37 | TLV_CHECK(ett_pgm_opts_paritygrp); |
480 | 35 | ptvcursor_set_tree(cursor, opt_tree); |
481 | | |
482 | 35 | ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); |
483 | 35 | ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); |
484 | | |
485 | 35 | if (genopts_len < PGM_OPT_PARITY_GRP_SIZE) { |
486 | 2 | proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, |
487 | 2 | ptvcursor_current_offset(cursor), 1, genopts_len, |
488 | 2 | "%u (bogus, must be >= %u)", |
489 | 2 | genopts_len, PGM_OPT_PARITY_GRP_SIZE); |
490 | 2 | break; |
491 | 2 | } |
492 | 33 | ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); |
493 | 33 | ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); |
494 | 33 | ptvcursor_add(cursor, hf_pgm_opt_parity_grp_res, 1, ENC_BIG_ENDIAN); |
495 | 33 | ptvcursor_add(cursor, hf_pgm_opt_parity_grp_prmgrp, 4, ENC_BIG_ENDIAN); |
496 | | |
497 | 33 | break; |
498 | 35 | } |
499 | 31 | case PGM_OPT_NAK_LIST:{ |
500 | 31 | uint8_t optdata_len; |
501 | 31 | uint32_t naklist[PGM_MAX_NAK_LIST_SZ+1]; |
502 | 31 | wmem_strbuf_t *nakbuf; |
503 | 31 | bool firsttime; |
504 | 31 | int i, j, naks; |
505 | | |
506 | 31 | TLV_CHECK(ett_pgm_opts_naklist); |
507 | 27 | ptvcursor_set_tree(cursor, opt_tree); |
508 | | |
509 | 27 | ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); |
510 | 27 | ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); |
511 | | |
512 | 27 | optdata_len = tvb_get_uint8(tvb, ptvcursor_current_offset(cursor)); |
513 | 27 | ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); |
514 | 27 | ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); |
515 | 27 | ptvcursor_add(cursor, hf_pgm_opt_nak_res, 1, ENC_BIG_ENDIAN); |
516 | | |
517 | 27 | optdata_len -= PGM_OPT_NAK_LIST_SIZE; |
518 | 27 | tvb_memcpy(tvb, (uint8_t *)naklist, ptvcursor_current_offset(cursor), optdata_len); |
519 | 27 | firsttime = true; |
520 | 27 | naks = (int)(optdata_len/sizeof(uint32_t)); |
521 | 27 | nakbuf = wmem_strbuf_new_sized(pinfo->pool, 64); |
522 | 27 | j = 0; |
523 | | /* |
524 | | * Print out 8 per line |
525 | | */ |
526 | 421 | for (i=0; i < naks; i++) { |
527 | 394 | wmem_strbuf_append_printf(nakbuf, "0x%x ", g_ntohl(naklist[i])); |
528 | 394 | if ((++j % 8) == 0) { |
529 | 41 | if (firsttime) { |
530 | 15 | proto_tree_add_bytes_format(opt_tree, |
531 | 15 | hf_pgm_opt_nak_list, tvb, ptvcursor_current_offset(cursor), j*4, |
532 | 15 | NULL, "List(%d): %s", naks, wmem_strbuf_get_str(nakbuf)); |
533 | 15 | firsttime = false; |
534 | 26 | } else { |
535 | 26 | proto_tree_add_bytes_format_value(opt_tree, |
536 | 26 | hf_pgm_opt_nak_list, tvb, ptvcursor_current_offset(cursor), j*4, |
537 | 26 | NULL, "%s", wmem_strbuf_get_str(nakbuf)); |
538 | 26 | } |
539 | 41 | wmem_strbuf_truncate(nakbuf, 0); |
540 | 41 | ptvcursor_advance(cursor, j*4); |
541 | 41 | j = 0; |
542 | 41 | } |
543 | 394 | } |
544 | 27 | if (j) { |
545 | 20 | if (firsttime) { |
546 | 8 | proto_tree_add_bytes_format(opt_tree, |
547 | 8 | hf_pgm_opt_nak_list, tvb, ptvcursor_current_offset(cursor), j*4, |
548 | 8 | NULL, "List(%d): %s", naks, wmem_strbuf_get_str(nakbuf)); |
549 | 12 | } else { |
550 | 12 | proto_tree_add_bytes_format_value(opt_tree, |
551 | 12 | hf_pgm_opt_nak_list, tvb, ptvcursor_current_offset(cursor), j*4, |
552 | 12 | NULL, "%s", wmem_strbuf_get_str(nakbuf)); |
553 | 12 | } |
554 | 20 | ptvcursor_advance(cursor, j*4); |
555 | 20 | } |
556 | 27 | wmem_strbuf_destroy(nakbuf); |
557 | 27 | break; |
558 | 28 | } |
559 | 26 | case PGM_OPT_PGMCC_DATA:{ |
560 | 26 | uint16_t optdata_afi; |
561 | | |
562 | 26 | TLV_CHECK(ett_pgm_opts_ccdata); |
563 | 25 | ptvcursor_set_tree(cursor, opt_tree); |
564 | | |
565 | 25 | ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); |
566 | 25 | ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); |
567 | | |
568 | 25 | if (genopts_len < PGM_OPT_PGMCC_DATA_SIZE) { |
569 | 1 | proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, |
570 | 1 | ptvcursor_current_offset(cursor), 1, genopts_len, |
571 | 1 | "%u (bogus, must be >= %u)", |
572 | 1 | genopts_len, PGM_OPT_PGMCC_DATA_SIZE); |
573 | 1 | break; |
574 | 1 | } |
575 | 24 | ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); |
576 | 24 | ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); |
577 | 24 | ptvcursor_add(cursor, hf_pgm_opt_ccdata_res, 1, ENC_BIG_ENDIAN); |
578 | 24 | ptvcursor_add(cursor, hf_pgm_opt_ccdata_tsp, 4, ENC_BIG_ENDIAN); |
579 | 24 | optdata_afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); |
580 | 24 | ti = ptvcursor_add(cursor, hf_pgm_opt_ccdata_afi, 2, ENC_BIG_ENDIAN); |
581 | 24 | ptvcursor_add(cursor, hf_pgm_opt_ccdata_res2, 2, ENC_BIG_ENDIAN); |
582 | | |
583 | 24 | switch (optdata_afi) { |
584 | | |
585 | 0 | case AFNUM_IP: |
586 | 0 | ptvcursor_add(cursor, hf_pgm_opt_ccdata_acker, 4, ENC_BIG_ENDIAN); |
587 | 0 | break; |
588 | | |
589 | 0 | case AFNUM_IP6: |
590 | 0 | ptvcursor_add(cursor, hf_pgm_opt_ccdata_acker6, 16, ENC_NA); |
591 | 0 | break; |
592 | | |
593 | 24 | default: |
594 | 24 | expert_add_info(pinfo, ti, &ei_address_format_invalid); |
595 | 24 | break; |
596 | 24 | } |
597 | | |
598 | 24 | break; |
599 | 24 | } |
600 | 44 | case PGM_OPT_PGMCC_FEEDBACK:{ |
601 | 44 | uint16_t optdata_afi; |
602 | | |
603 | 44 | TLV_CHECK(ett_pgm_opts_ccdata); |
604 | 43 | ptvcursor_set_tree(cursor, opt_tree); |
605 | | |
606 | 43 | ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); |
607 | 43 | ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); |
608 | | |
609 | 43 | if (genopts_len < PGM_OPT_PGMCC_FEEDBACK_SIZE) { |
610 | 1 | proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, |
611 | 1 | ptvcursor_current_offset(cursor), 1, genopts_len, |
612 | 1 | "%u (bogus, must be >= %u)", |
613 | 1 | genopts_len, PGM_OPT_PGMCC_FEEDBACK_SIZE); |
614 | 1 | break; |
615 | 1 | } |
616 | 42 | ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); |
617 | 42 | ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); |
618 | 42 | ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_res, 1, ENC_BIG_ENDIAN); |
619 | 42 | ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_tsp, 4, ENC_BIG_ENDIAN); |
620 | 42 | optdata_afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); |
621 | 42 | ti = ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_afi, 2, ENC_BIG_ENDIAN); |
622 | 42 | ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_lossrate, 2, ENC_BIG_ENDIAN); |
623 | | |
624 | 42 | switch (optdata_afi) { |
625 | | |
626 | 0 | case AFNUM_IP: |
627 | 0 | ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_acker, 4, ENC_BIG_ENDIAN); |
628 | 0 | break; |
629 | | |
630 | 0 | case AFNUM_IP6: |
631 | 0 | ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_acker6, 16, ENC_NA); |
632 | 0 | break; |
633 | | |
634 | 42 | default: |
635 | 42 | expert_add_info(pinfo, ti, &ei_address_format_invalid); |
636 | 42 | break; |
637 | 42 | } |
638 | | |
639 | 42 | break; |
640 | 42 | } |
641 | 175 | case PGM_OPT_NAK_BO_IVL:{ |
642 | 175 | TLV_CHECK(ett_pgm_opts_nak_bo_ivl); |
643 | 171 | ptvcursor_set_tree(cursor, opt_tree); |
644 | | |
645 | 171 | ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); |
646 | 171 | ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); |
647 | | |
648 | 171 | if (genopts_len < PGM_OPT_NAK_BO_IVL_SIZE) { |
649 | 152 | proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, |
650 | 152 | ptvcursor_current_offset(cursor), 1, genopts_len, |
651 | 152 | "%u (bogus, must be >= %u)", |
652 | 152 | genopts_len, PGM_OPT_NAK_BO_IVL_SIZE); |
653 | 152 | break; |
654 | 152 | } |
655 | 19 | ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); |
656 | 19 | ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); |
657 | 19 | ptvcursor_add(cursor, hf_pgm_opt_nak_bo_ivl_res, 1, ENC_BIG_ENDIAN); |
658 | 19 | ptvcursor_add(cursor, hf_pgm_opt_nak_bo_ivl_bo_ivl, 4, ENC_BIG_ENDIAN); |
659 | 19 | ptvcursor_add(cursor, hf_pgm_opt_nak_bo_ivl_bo_ivl_sqn, 4, ENC_BIG_ENDIAN); |
660 | | |
661 | 19 | break; |
662 | 171 | } |
663 | 391 | case PGM_OPT_NAK_BO_RNG:{ |
664 | 391 | TLV_CHECK(ett_pgm_opts_nak_bo_rng); |
665 | 387 | ptvcursor_set_tree(cursor, opt_tree); |
666 | | |
667 | 387 | ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); |
668 | 387 | ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); |
669 | | |
670 | 387 | if (genopts_len < PGM_OPT_NAK_BO_RNG_SIZE) { |
671 | 334 | proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, |
672 | 334 | ptvcursor_current_offset(cursor), 1, genopts_len, |
673 | 334 | "%u (bogus, must be >= %u)", |
674 | 334 | genopts_len, PGM_OPT_NAK_BO_RNG_SIZE); |
675 | 334 | break; |
676 | 334 | } |
677 | 53 | ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); |
678 | 53 | ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); |
679 | 53 | ptvcursor_add(cursor, hf_pgm_opt_nak_bo_rng_res, 1, ENC_BIG_ENDIAN); |
680 | 53 | ptvcursor_add(cursor, hf_pgm_opt_nak_bo_rng_min_bo_ivl, 4, ENC_BIG_ENDIAN); |
681 | 53 | ptvcursor_add(cursor, hf_pgm_opt_nak_bo_rng_max_bo_ivl, 4, ENC_BIG_ENDIAN); |
682 | | |
683 | 53 | break; |
684 | 387 | } |
685 | 401 | case PGM_OPT_REDIRECT:{ |
686 | 401 | uint16_t optdata_afi; |
687 | | |
688 | 401 | TLV_CHECK(ett_pgm_opts_redirect); |
689 | 398 | ptvcursor_set_tree(cursor, opt_tree); |
690 | | |
691 | 398 | ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); |
692 | 398 | ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); |
693 | | |
694 | 398 | if (genopts_len < PGM_OPT_REDIRECT_SIZE) { |
695 | 349 | proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, |
696 | 349 | ptvcursor_current_offset(cursor), 1, genopts_len, |
697 | 349 | "%u (bogus, must be >= %u)", |
698 | 349 | genopts_len, PGM_OPT_REDIRECT_SIZE); |
699 | 349 | break; |
700 | 349 | } |
701 | 49 | ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); |
702 | 49 | ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); |
703 | 49 | ptvcursor_add(cursor, hf_pgm_opt_redirect_res, 1, ENC_BIG_ENDIAN); |
704 | 49 | optdata_afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); |
705 | 49 | ti = ptvcursor_add(cursor, hf_pgm_opt_redirect_afi, 2, ENC_BIG_ENDIAN); |
706 | 49 | ptvcursor_add(cursor, hf_pgm_opt_redirect_res2, 2, ENC_BIG_ENDIAN); |
707 | | |
708 | 49 | switch (optdata_afi) { |
709 | | |
710 | 0 | case AFNUM_IP: |
711 | 0 | ptvcursor_add(cursor, hf_pgm_opt_redirect_dlr, 4, ENC_BIG_ENDIAN); |
712 | 0 | break; |
713 | | |
714 | 4 | case AFNUM_IP6: |
715 | 4 | ptvcursor_add(cursor, hf_pgm_opt_redirect_dlr6, 16, ENC_NA); |
716 | 4 | break; |
717 | | |
718 | 43 | default: |
719 | 43 | expert_add_info(pinfo, ti, &ei_address_format_invalid); |
720 | 43 | break; |
721 | 49 | } |
722 | | |
723 | 47 | break; |
724 | 49 | } |
725 | 47 | case PGM_OPT_FRAGMENT:{ |
726 | 25 | TLV_CHECK(ett_pgm_opts_fragment); |
727 | 20 | ptvcursor_set_tree(cursor, opt_tree); |
728 | | |
729 | 20 | ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); |
730 | 20 | ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); |
731 | | |
732 | 20 | if (genopts_len < PGM_OPT_FRAGMENT_SIZE) { |
733 | 7 | proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, |
734 | 7 | ptvcursor_current_offset(cursor), 1, genopts_len, |
735 | 7 | "%u (bogus, must be >= %u)", |
736 | 7 | genopts_len, PGM_OPT_FRAGMENT_SIZE); |
737 | 7 | break; |
738 | 7 | } |
739 | 13 | ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); |
740 | 13 | ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); |
741 | 13 | ptvcursor_add(cursor, hf_pgm_opt_fragment_res, 1, ENC_BIG_ENDIAN); |
742 | 13 | ptvcursor_add(cursor, hf_pgm_opt_fragment_first_sqn, 4, ENC_BIG_ENDIAN); |
743 | 13 | ptvcursor_add(cursor, hf_pgm_opt_fragment_offset, 4, ENC_BIG_ENDIAN); |
744 | 13 | ptvcursor_add(cursor, hf_pgm_opt_fragment_total_length, 4, ENC_BIG_ENDIAN); |
745 | | |
746 | 13 | break; |
747 | 20 | } |
748 | 260 | default:{ |
749 | 260 | TLV_CHECK(ett_pgm_opts); |
750 | 224 | ptvcursor_advance(cursor, genopts_len); |
751 | 224 | break; |
752 | 233 | } |
753 | 1.55k | } |
754 | | |
755 | 1.43k | opts_total_len -= genopts_len; |
756 | 1.43k | } |
757 | 37 | return; |
758 | 155 | } |
759 | | |
760 | | static const value_string type_vals[] = { |
761 | | { PGM_SPM_PCKT, "SPM" }, |
762 | | { PGM_RDATA_PCKT, "RDATA" }, |
763 | | { PGM_ODATA_PCKT, "ODATA" }, |
764 | | { PGM_NAK_PCKT, "NAK" }, |
765 | | { PGM_NNAK_PCKT, "NNAK" }, |
766 | | { PGM_NCF_PCKT, "NCF" }, |
767 | | { PGM_POLL_PCKT, "POLL" }, |
768 | | { PGM_POLR_PCKT, "POLR" }, |
769 | | { PGM_ACK_PCKT, "ACK" }, |
770 | | { PGM_ACK2_PCKT, "ACK" }, |
771 | | { 0, NULL } |
772 | | }; |
773 | | |
774 | | static const value_string poll_subtype_vals[] = { |
775 | | { PGM_POLL_GENERAL, "General" }, |
776 | | { PGM_POLL_DLR, "DLR" }, |
777 | | { 0, NULL } |
778 | | }; |
779 | | |
780 | | /* Determine if there is a sub-dissector and call it. This has been */ |
781 | | /* separated into a stand alone routine to other protocol dissectors */ |
782 | | /* can call to it, ie. socks */ |
783 | | |
784 | | static void |
785 | | decode_pgm_ports(tvbuff_t *tvb, int offset, packet_info *pinfo, |
786 | | proto_tree *tree, uint16_t pgmhdr_sport, uint16_t pgmhdr_dport) |
787 | 13 | { |
788 | 13 | tvbuff_t *next_tvb; |
789 | 13 | int found = 0; |
790 | 13 | heur_dtbl_entry_t *hdtbl_entry; |
791 | | |
792 | 13 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
793 | | |
794 | | /* do lookup with the subdissector table */ |
795 | 13 | found = dissector_try_uint(subdissector_table, pgmhdr_sport, |
796 | 13 | next_tvb, pinfo, tree); |
797 | 13 | if (found) |
798 | 0 | return; |
799 | | |
800 | 13 | found = dissector_try_uint(subdissector_table, pgmhdr_dport, |
801 | 13 | next_tvb, pinfo, tree); |
802 | 13 | if (found) |
803 | 0 | return; |
804 | | |
805 | | /* do lookup with the heuristic subdissector table */ |
806 | 13 | if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, &hdtbl_entry, NULL)) |
807 | 0 | return; |
808 | | |
809 | | /* Oh, well, we don't know this; dissect it as data. */ |
810 | 13 | call_data_dissector(next_tvb, pinfo, tree); |
811 | 13 | } |
812 | | |
813 | | /* |
814 | | * dissect_pgm - The dissector for Pragmatic General Multicast |
815 | | */ |
816 | | static int |
817 | | dissect_pgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
818 | 302 | { |
819 | 302 | uint32_t pgmhdr_sport; |
820 | 302 | uint32_t pgmhdr_dport; |
821 | 302 | uint32_t pgmhdr_type; |
822 | 302 | uint8_t pgmhdr_opts; |
823 | 302 | uint16_t pgmhdr_cksum; |
824 | 302 | uint32_t pgmhdr_tsdulen; |
825 | 302 | uint32_t sqn; |
826 | 302 | uint16_t afi; |
827 | | |
828 | 302 | proto_tree *pgm_tree = NULL; |
829 | 302 | proto_tree *opt_tree = NULL; |
830 | 302 | proto_tree *type_tree = NULL; |
831 | 302 | proto_item *tf, *hidden_item; |
832 | 302 | ptvcursor_t* cursor; |
833 | | |
834 | 302 | unsigned plen = 0; |
835 | 302 | proto_item *ti; |
836 | 302 | const char *pktname; |
837 | 302 | char *gsi; |
838 | 302 | bool isdata = false; |
839 | 302 | unsigned pgmlen, reportedlen; |
840 | | |
841 | 302 | if (tvb_reported_length_remaining(tvb, 0) < 18) |
842 | 56 | return 0; |
843 | | |
844 | 246 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "PGM"); |
845 | 246 | col_clear(pinfo->cinfo, COL_INFO); |
846 | | |
847 | 246 | ti = proto_tree_add_protocol_format(tree, proto_pgm, tvb, 0, -1, |
848 | 246 | "Pragmatic General Multicast"); |
849 | 246 | pgm_tree = proto_item_add_subtree(ti, ett_pgm); |
850 | | |
851 | 246 | cursor = ptvcursor_new(pinfo->pool, pgm_tree, tvb, 0); |
852 | | |
853 | 246 | hidden_item = proto_tree_add_item(pgm_tree, hf_pgm_port, tvb, 0, 2, ENC_BIG_ENDIAN); |
854 | 246 | proto_item_set_hidden(hidden_item); |
855 | 246 | hidden_item = proto_tree_add_item(pgm_tree, hf_pgm_port, tvb, 2, 2, ENC_BIG_ENDIAN); |
856 | 246 | proto_item_set_hidden(hidden_item); |
857 | 246 | ptvcursor_add_ret_uint(cursor, hf_pgm_main_sport, 2, ENC_BIG_ENDIAN, &pgmhdr_sport); |
858 | 246 | pinfo->srcport = pgmhdr_sport; |
859 | 246 | ptvcursor_add_ret_uint(cursor, hf_pgm_main_dport, 2, ENC_BIG_ENDIAN, &pgmhdr_dport); |
860 | 246 | pinfo->destport = pgmhdr_dport; |
861 | 246 | ptvcursor_add_ret_uint(cursor, hf_pgm_main_type, 1, ENC_BIG_ENDIAN, &pgmhdr_type); |
862 | 246 | pktname = val_to_str(pinfo->pool, pgmhdr_type, type_vals, "Unknown (0x%02x)"); |
863 | 246 | proto_item_append_text(ti, ": Type %s Src Port %u, Dst Port %u", |
864 | 246 | pktname, pgmhdr_sport, pgmhdr_dport); |
865 | 246 | col_append_fstr(pinfo->cinfo, COL_INFO, "%-5s", pktname); |
866 | | |
867 | 246 | pgmhdr_opts = tvb_get_uint8(tvb, 5); |
868 | 246 | tf = proto_tree_add_uint_format_value(pgm_tree, hf_pgm_main_opts, tvb, |
869 | 246 | ptvcursor_current_offset(cursor), 1, pgmhdr_opts, "%s (0x%x)", |
870 | 246 | optsstr(pinfo->pool, pgmhdr_opts), pgmhdr_opts); |
871 | 246 | opt_tree = proto_item_add_subtree(tf, ett_pgm_optbits); |
872 | 246 | ptvcursor_set_tree(cursor, opt_tree); |
873 | | |
874 | 246 | ptvcursor_add_no_advance(cursor, hf_pgm_main_opts_opt, 1, ENC_BIG_ENDIAN); |
875 | 246 | ptvcursor_add_no_advance(cursor, hf_pgm_main_opts_netsig, 1, ENC_BIG_ENDIAN); |
876 | 246 | ptvcursor_add_no_advance(cursor, hf_pgm_main_opts_varlen, 1, ENC_BIG_ENDIAN); |
877 | 246 | ptvcursor_add(cursor, hf_pgm_main_opts_parity, 1, ENC_BIG_ENDIAN); |
878 | 246 | ptvcursor_set_tree(cursor, pgm_tree); |
879 | | |
880 | | /* Checksum may be 0 (not available), but not for DATA packets */ |
881 | 246 | pgmhdr_cksum = tvb_get_ntohs(tvb, 6); |
882 | 246 | if ((pgmhdr_type != PGM_RDATA_PCKT) && (pgmhdr_type != PGM_ODATA_PCKT) && |
883 | 228 | (pgmhdr_cksum == 0)) |
884 | 33 | { |
885 | 33 | proto_tree_add_checksum(pgm_tree, tvb, ptvcursor_current_offset(cursor), hf_pgm_main_cksum, hf_pgm_main_cksum_status, &ei_pgm_main_cksum, |
886 | 33 | pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NOT_PRESENT); |
887 | 213 | } else { |
888 | 213 | reportedlen = tvb_reported_length(tvb); |
889 | 213 | pgmlen = tvb_captured_length(tvb); |
890 | 213 | if (pgm_check_checksum && pgmlen >= reportedlen) { |
891 | 213 | vec_t cksum_vec[1]; |
892 | | |
893 | 213 | SET_CKSUM_VEC_TVB(cksum_vec[0], tvb, 0, pgmlen); |
894 | 213 | proto_tree_add_checksum(pgm_tree, tvb, ptvcursor_current_offset(cursor), hf_pgm_main_cksum_status, hf_pgm_main_cksum_status, &ei_pgm_main_cksum, |
895 | 213 | pinfo, in_cksum(&cksum_vec[0], 1), ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_IN_CKSUM); |
896 | 213 | } else { |
897 | 0 | proto_tree_add_checksum(pgm_tree, tvb, ptvcursor_current_offset(cursor), hf_pgm_main_cksum, hf_pgm_main_cksum_status, &ei_pgm_main_cksum, |
898 | 0 | pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); |
899 | 0 | } |
900 | 213 | } |
901 | 246 | ptvcursor_advance(cursor, 2); |
902 | | |
903 | 246 | gsi = tvb_bytes_to_str(pinfo->pool, tvb, 8, 6); |
904 | 246 | ptvcursor_add(cursor, hf_pgm_main_gsi, 6, ENC_NA); |
905 | 246 | proto_item_append_text(ti, ", GSI %s", gsi); |
906 | 246 | ptvcursor_add_ret_uint(cursor, hf_pgm_main_tsdulen, 2, ENC_BIG_ENDIAN, &pgmhdr_tsdulen); |
907 | 246 | sqn = tvb_get_ntohl(tvb, 16); |
908 | 246 | col_append_fstr(pinfo->cinfo, COL_INFO, |
909 | 246 | " sqn 0x%x gsi %s", sqn, gsi); |
910 | | |
911 | 246 | switch(pgmhdr_type) { |
912 | 19 | case PGM_SPM_PCKT: |
913 | 19 | type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen, |
914 | 19 | ett_pgm_spm, NULL, "%s Packet", pktname); |
915 | 19 | ptvcursor_set_tree(cursor, type_tree); |
916 | | |
917 | 19 | ptvcursor_add(cursor, hf_pgm_spm_sqn, 4, ENC_BIG_ENDIAN); |
918 | 19 | ptvcursor_add(cursor, hf_pgm_spm_trail, 4, ENC_BIG_ENDIAN); |
919 | 19 | ptvcursor_add(cursor, hf_pgm_spm_lead, 4, ENC_BIG_ENDIAN); |
920 | 19 | afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); |
921 | 19 | ti = ptvcursor_add(cursor, hf_pgm_spm_pathafi, 2, ENC_BIG_ENDIAN); |
922 | 19 | ptvcursor_add(cursor, hf_pgm_spm_res, 2, ENC_BIG_ENDIAN); |
923 | | |
924 | 19 | switch (afi) { |
925 | 2 | case AFNUM_IP: |
926 | 2 | ptvcursor_add(cursor, hf_pgm_spm_path, 4, ENC_BIG_ENDIAN); |
927 | 2 | break; |
928 | | |
929 | 1 | case AFNUM_IP6: |
930 | 1 | ptvcursor_add(cursor, hf_pgm_spm_path6, 16, ENC_NA); |
931 | 1 | break; |
932 | | |
933 | 12 | default: |
934 | 12 | expert_add_info(pinfo, ti, &ei_address_format_invalid); |
935 | 12 | ptvcursor_free(cursor); |
936 | 12 | return tvb_captured_length(tvb); |
937 | 19 | } |
938 | 1 | break; |
939 | 14 | case PGM_RDATA_PCKT: |
940 | 18 | case PGM_ODATA_PCKT: |
941 | 18 | isdata = true; |
942 | 18 | type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen, |
943 | 18 | ett_pgm_data, NULL, "%s Packet", pktname); |
944 | 18 | ptvcursor_set_tree(cursor, type_tree); |
945 | 18 | col_append_fstr(pinfo->cinfo, COL_INFO, |
946 | 18 | " tsdulen %d", pgmhdr_tsdulen); |
947 | | |
948 | 18 | ptvcursor_add(cursor, hf_pgm_spm_sqn, 4, ENC_BIG_ENDIAN); |
949 | 18 | ptvcursor_add(cursor, hf_pgm_spm_trail, 4, ENC_BIG_ENDIAN); |
950 | 18 | break; |
951 | 4 | case PGM_NAK_PCKT: |
952 | 7 | case PGM_NNAK_PCKT: |
953 | 10 | case PGM_NCF_PCKT: |
954 | 10 | type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen, |
955 | 10 | ett_pgm_nak, NULL, "%s Packet", pktname); |
956 | 10 | ptvcursor_set_tree(cursor, type_tree); |
957 | | |
958 | 10 | ptvcursor_add(cursor, hf_pgm_nak_sqn, 4, ENC_BIG_ENDIAN); |
959 | 10 | afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); |
960 | 10 | ti = ptvcursor_add(cursor, hf_pgm_nak_srcafi, 2, ENC_BIG_ENDIAN); |
961 | 10 | ptvcursor_add(cursor, hf_pgm_nak_srcres, 2, ENC_BIG_ENDIAN); |
962 | | |
963 | 10 | switch (afi) { |
964 | 1 | case AFNUM_IP: |
965 | 1 | ptvcursor_add(cursor, hf_pgm_nak_src, 4, ENC_BIG_ENDIAN); |
966 | 1 | break; |
967 | | |
968 | 1 | case AFNUM_IP6: |
969 | 1 | ptvcursor_add(cursor, hf_pgm_nak_src6, 16, ENC_NA); |
970 | 1 | break; |
971 | | |
972 | 6 | default: |
973 | 6 | expert_add_info(pinfo, ti, &ei_address_format_invalid); |
974 | 6 | break; |
975 | 10 | } |
976 | | |
977 | 8 | afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); |
978 | 8 | ti = ptvcursor_add(cursor, hf_pgm_nak_grpafi, 2, ENC_BIG_ENDIAN); |
979 | 8 | ptvcursor_add(cursor, hf_pgm_nak_grpres, 2, ENC_BIG_ENDIAN); |
980 | | |
981 | 8 | switch (afi) { |
982 | 1 | case AFNUM_IP: |
983 | 1 | ptvcursor_add(cursor, hf_pgm_nak_grp, 4, ENC_BIG_ENDIAN); |
984 | 1 | break; |
985 | | |
986 | 2 | case AFNUM_IP6: |
987 | 2 | ptvcursor_add(cursor, hf_pgm_nak_grp6, 16, ENC_NA); |
988 | 2 | break; |
989 | | |
990 | 5 | default: |
991 | 5 | expert_add_info(pinfo, ti, &ei_address_format_invalid); |
992 | 5 | ptvcursor_free(cursor); |
993 | 5 | return tvb_captured_length(tvb); |
994 | 8 | } |
995 | 2 | break; |
996 | 12 | case PGM_POLL_PCKT: { |
997 | 12 | uint32_t poll_stype; |
998 | | |
999 | 12 | type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen, |
1000 | 12 | ett_pgm_poll, NULL, "%s Packet", pktname); |
1001 | 12 | ptvcursor_set_tree(cursor, type_tree); |
1002 | | |
1003 | 12 | ptvcursor_add(cursor, hf_pgm_poll_sqn, 4, ENC_BIG_ENDIAN); |
1004 | 12 | ptvcursor_add(cursor, hf_pgm_poll_round, 2, ENC_BIG_ENDIAN); |
1005 | 12 | ptvcursor_add_ret_uint(cursor, hf_pgm_poll_subtype, 2, ENC_BIG_ENDIAN, &poll_stype); |
1006 | 12 | col_append_fstr(pinfo->cinfo, COL_INFO, |
1007 | 12 | " subtype %s", |
1008 | 12 | val_to_str(pinfo->pool, poll_stype, poll_subtype_vals, "Unknown (0x%02x)")); |
1009 | 12 | afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); |
1010 | 12 | ti = ptvcursor_add(cursor, hf_pgm_poll_pathafi, 2, ENC_BIG_ENDIAN); |
1011 | 12 | ptvcursor_add(cursor, hf_pgm_poll_res, 2, ENC_BIG_ENDIAN); |
1012 | | |
1013 | 12 | switch (afi) { |
1014 | 1 | case AFNUM_IP: |
1015 | 1 | ptvcursor_add(cursor, hf_pgm_poll_path, 4, ENC_BIG_ENDIAN); |
1016 | 1 | break; |
1017 | | |
1018 | 1 | case AFNUM_IP6: |
1019 | 1 | ptvcursor_add(cursor, hf_pgm_poll_path6, 16, ENC_NA); |
1020 | 1 | break; |
1021 | | |
1022 | 8 | default: |
1023 | 8 | expert_add_info(pinfo, ti, &ei_address_format_invalid); |
1024 | 8 | break; |
1025 | 12 | } |
1026 | | |
1027 | 10 | ptvcursor_add(cursor, hf_pgm_poll_backoff_ivl, 4, ENC_BIG_ENDIAN); |
1028 | 10 | ptvcursor_add(cursor, hf_pgm_poll_rand_str, 4, ENC_BIG_ENDIAN); |
1029 | 10 | ptvcursor_add(cursor, hf_pgm_poll_matching_bmask, 4, ENC_BIG_ENDIAN); |
1030 | 10 | break; |
1031 | 12 | } |
1032 | 8 | case PGM_POLR_PCKT: |
1033 | 8 | type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen, |
1034 | 8 | ett_pgm_polr, NULL, "%s Packet", pktname); |
1035 | 8 | ptvcursor_set_tree(cursor, type_tree); |
1036 | | |
1037 | 8 | ptvcursor_add(cursor, hf_pgm_polr_sqn, 4, ENC_BIG_ENDIAN); |
1038 | 8 | ptvcursor_add(cursor, hf_pgm_polr_round, 2, ENC_BIG_ENDIAN); |
1039 | 8 | ptvcursor_add(cursor, hf_pgm_polr_res, 2, ENC_BIG_ENDIAN); |
1040 | 8 | break; |
1041 | 2 | case PGM_ACK_PCKT: |
1042 | 4 | case PGM_ACK2_PCKT: |
1043 | 4 | type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen, |
1044 | 4 | ett_pgm_ack, NULL, "%s Packet", pktname); |
1045 | 4 | ptvcursor_set_tree(cursor, type_tree); |
1046 | | |
1047 | 4 | ptvcursor_add(cursor, hf_pgm_ack_sqn, 4, ENC_BIG_ENDIAN); |
1048 | 4 | ptvcursor_add(cursor, hf_pgm_ack_bitmap, 4, ENC_BIG_ENDIAN); |
1049 | 4 | break; |
1050 | 246 | } |
1051 | | |
1052 | 212 | if (pgmhdr_opts & PGM_OPT) |
1053 | 182 | dissect_pgmopts(cursor, pinfo, pktname); |
1054 | | |
1055 | 212 | if (isdata) |
1056 | 13 | decode_pgm_ports(tvb, ptvcursor_current_offset(cursor), pinfo, tree, pgmhdr_sport, pgmhdr_dport); |
1057 | | |
1058 | 212 | ptvcursor_free(cursor); |
1059 | 212 | return tvb_captured_length(tvb); |
1060 | 246 | } |
1061 | | |
1062 | | /* Register all the bits needed with the filtering engine */ |
1063 | | void |
1064 | | proto_register_pgm(void) |
1065 | 14 | { |
1066 | 14 | static hf_register_info hf[] = { |
1067 | 14 | { &hf_pgm_main_sport, |
1068 | 14 | { "Source Port", "pgm.hdr.sport", FT_UINT16, BASE_DEC, |
1069 | 14 | NULL, 0x0, NULL, HFILL }}, |
1070 | 14 | { &hf_pgm_main_dport, |
1071 | 14 | { "Destination Port", "pgm.hdr.dport", FT_UINT16, BASE_DEC, |
1072 | 14 | NULL, 0x0, NULL, HFILL }}, |
1073 | 14 | { &hf_pgm_port, |
1074 | 14 | { "Port", "pgm.port", FT_UINT16, BASE_DEC, |
1075 | 14 | NULL, 0x0, NULL, HFILL }}, |
1076 | 14 | { &hf_pgm_main_type, |
1077 | 14 | { "Type", "pgm.hdr.type", FT_UINT8, BASE_HEX, |
1078 | 14 | VALS(type_vals), 0x0, NULL, HFILL }}, |
1079 | 14 | { &hf_pgm_main_opts, |
1080 | 14 | { "Options", "pgm.hdr.opts", FT_UINT8, BASE_HEX, |
1081 | 14 | NULL, 0x0, NULL, HFILL }}, |
1082 | 14 | { &hf_pgm_main_opts_opt, |
1083 | 14 | { "Options", "pgm.hdr.opts.opt", FT_BOOLEAN, 8, |
1084 | 14 | TFS(&tfs_present_not_present), PGM_OPT, NULL, HFILL }}, |
1085 | 14 | { &hf_pgm_main_opts_netsig, |
1086 | 14 | { "Network Significant Options", "pgm.hdr.opts.netsig", |
1087 | 14 | FT_BOOLEAN, 8, |
1088 | 14 | TFS(&tfs_present_not_present), PGM_OPT_NETSIG, NULL, HFILL }}, |
1089 | 14 | { &hf_pgm_main_opts_varlen, |
1090 | 14 | { "Variable length Parity Packet Option", "pgm.hdr.opts.varlen", |
1091 | 14 | FT_BOOLEAN, 8, |
1092 | 14 | TFS(&tfs_present_not_present), PGM_OPT_VAR_PKTLEN, NULL, HFILL }}, |
1093 | 14 | { &hf_pgm_main_opts_parity, |
1094 | 14 | { "Parity", "pgm.hdr.opts.parity", FT_BOOLEAN, 8, |
1095 | 14 | TFS(&tfs_present_not_present), PGM_OPT_PARITY, NULL, HFILL }}, |
1096 | 14 | { &hf_pgm_main_cksum, |
1097 | 14 | { "Checksum", "pgm.hdr.cksum", FT_UINT16, BASE_HEX, |
1098 | 14 | NULL, 0x0, NULL, HFILL }}, |
1099 | 14 | { &hf_pgm_main_cksum_status, |
1100 | 14 | { "Checksum Status", "pgm.hdr.cksum.status", FT_UINT8, BASE_NONE, |
1101 | 14 | VALS(proto_checksum_vals), 0x0, NULL, HFILL }}, |
1102 | 14 | { &hf_pgm_main_gsi, |
1103 | 14 | { "Global Source Identifier", "pgm.hdr.gsi", FT_BYTES, BASE_NONE, |
1104 | 14 | NULL, 0x0, NULL, HFILL }}, |
1105 | 14 | { &hf_pgm_main_tsdulen, |
1106 | 14 | { "Transport Service Data Unit Length", "pgm.hdr.tsdulen", FT_UINT16, |
1107 | 14 | BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1108 | 14 | { &hf_pgm_spm_sqn, |
1109 | 14 | { "Sequence number", "pgm.spm.sqn", FT_UINT32, BASE_HEX, |
1110 | 14 | NULL, 0x0, NULL, HFILL }}, |
1111 | 14 | { &hf_pgm_spm_trail, |
1112 | 14 | { "Trailing Edge Sequence Number", "pgm.spm.trail", FT_UINT32, BASE_HEX, |
1113 | 14 | NULL, 0x0, NULL, HFILL }}, |
1114 | 14 | { &hf_pgm_spm_lead, |
1115 | 14 | { "Leading Edge Sequence Number", "pgm.spm.lead", FT_UINT32, BASE_HEX, |
1116 | 14 | NULL, 0x0, NULL, HFILL }}, |
1117 | 14 | { &hf_pgm_spm_pathafi, |
1118 | 14 | { "Path NLA AFI", "pgm.spm.pathafi", FT_UINT16, BASE_DEC, |
1119 | 14 | VALS(afn_vals), 0x0, NULL, HFILL }}, |
1120 | 14 | { &hf_pgm_spm_res, |
1121 | 14 | { "Reserved", "pgm.spm.res", FT_UINT16, BASE_HEX, |
1122 | 14 | NULL, 0x0, NULL, HFILL }}, |
1123 | 14 | { &hf_pgm_spm_path, |
1124 | 14 | { "Path NLA", "pgm.spm.path.ipv4", FT_IPv4, BASE_NONE, |
1125 | 14 | NULL, 0x0, NULL, HFILL }}, |
1126 | 14 | { &hf_pgm_spm_path6, |
1127 | 14 | { "Path NLA", "pgm.spm.path.ipv6", FT_IPv6, BASE_NONE, |
1128 | 14 | NULL, 0x0, NULL, HFILL }}, |
1129 | | #if 0 |
1130 | | { &hf_pgm_data_sqn, |
1131 | | { "Data Packet Sequence Number", "pgm.data.sqn", FT_UINT32, BASE_HEX, |
1132 | | NULL, 0x0, NULL, HFILL }}, |
1133 | | #endif |
1134 | | #if 0 |
1135 | | { &hf_pgm_data_trail, |
1136 | | { "Trailing Edge Sequence Number", "pgm.data.trail", FT_UINT32, BASE_HEX, |
1137 | | NULL, 0x0, NULL, HFILL }}, |
1138 | | #endif |
1139 | 14 | { &hf_pgm_nak_sqn, |
1140 | 14 | { "Requested Sequence Number", "pgm.nak.sqn", FT_UINT32, BASE_HEX, |
1141 | 14 | NULL, 0x0, NULL, HFILL }}, |
1142 | 14 | { &hf_pgm_nak_srcafi, |
1143 | 14 | { "Source NLA AFI", "pgm.nak.srcafi", FT_UINT16, BASE_DEC, |
1144 | 14 | VALS(afn_vals), 0x0, NULL, HFILL }}, |
1145 | 14 | { &hf_pgm_nak_srcres, |
1146 | 14 | { "Reserved", "pgm.nak.srcres", FT_UINT16, BASE_HEX, |
1147 | 14 | NULL, 0x0, NULL, HFILL }}, |
1148 | 14 | { &hf_pgm_nak_src, |
1149 | 14 | { "Source NLA", "pgm.nak.src.ipv4", FT_IPv4, BASE_NONE, |
1150 | 14 | NULL, 0x0, NULL, HFILL }}, |
1151 | 14 | { &hf_pgm_nak_src6, |
1152 | 14 | { "Source NLA", "pgm.nak.src.ipv6", FT_IPv6, BASE_NONE, |
1153 | 14 | NULL, 0x0, NULL, HFILL }}, |
1154 | 14 | { &hf_pgm_nak_grpafi, |
1155 | 14 | { "Multicast Group AFI", "pgm.nak.grpafi", FT_UINT16, BASE_DEC, |
1156 | 14 | VALS(afn_vals), 0x0, NULL, HFILL }}, |
1157 | 14 | { &hf_pgm_nak_grpres, |
1158 | 14 | { "Reserved", "pgm.nak.grpres", FT_UINT16, BASE_HEX, |
1159 | 14 | NULL, 0x0, NULL, HFILL }}, |
1160 | 14 | { &hf_pgm_nak_grp, |
1161 | 14 | { "Multicast Group NLA", "pgm.nak.grp.ipv4", FT_IPv4, BASE_NONE, |
1162 | 14 | NULL, 0x0, NULL, HFILL }}, |
1163 | 14 | { &hf_pgm_nak_grp6, |
1164 | 14 | { "Multicast Group NLA", "pgm.nak.grp.ipv6", FT_IPv6, BASE_NONE, |
1165 | 14 | NULL, 0x0, NULL, HFILL }}, |
1166 | 14 | { &hf_pgm_poll_sqn, |
1167 | 14 | { "Sequence Number", "pgm.poll.sqn", FT_UINT32, BASE_HEX, |
1168 | 14 | NULL, 0x0, NULL, HFILL }}, |
1169 | 14 | { &hf_pgm_poll_round, |
1170 | 14 | { "Round", "pgm.poll.round", FT_UINT16, BASE_DEC, |
1171 | 14 | NULL, 0x0, NULL, HFILL }}, |
1172 | 14 | { &hf_pgm_poll_subtype, |
1173 | 14 | { "Subtype", "pgm.poll.subtype", FT_UINT16, BASE_HEX, |
1174 | 14 | VALS(poll_subtype_vals), 0x0, NULL, HFILL }}, |
1175 | 14 | { &hf_pgm_poll_pathafi, |
1176 | 14 | { "Path NLA AFI", "pgm.poll.pathafi", FT_UINT16, BASE_DEC, |
1177 | 14 | VALS(afn_vals), 0x0, NULL, HFILL }}, |
1178 | 14 | { &hf_pgm_poll_res, |
1179 | 14 | { "Reserved", "pgm.poll.res", FT_UINT16, BASE_HEX, |
1180 | 14 | NULL, 0x0, NULL, HFILL }}, |
1181 | 14 | { &hf_pgm_poll_path, |
1182 | 14 | { "Path NLA", "pgm.poll.path.ipv4", FT_IPv4, BASE_NONE, |
1183 | 14 | NULL, 0x0, NULL, HFILL }}, |
1184 | 14 | { &hf_pgm_poll_path6, |
1185 | 14 | { "Path NLA", "pgm.poll.path.ipv6", FT_IPv6, BASE_NONE, |
1186 | 14 | NULL, 0x0, NULL, HFILL }}, |
1187 | 14 | { &hf_pgm_poll_backoff_ivl, |
1188 | 14 | { "Back-off Interval", "pgm.poll.backoff_ivl", FT_UINT32, BASE_DEC, |
1189 | 14 | NULL, 0x0, NULL, HFILL }}, |
1190 | 14 | { &hf_pgm_poll_rand_str, |
1191 | 14 | { "Random String", "pgm.poll.rand_str", FT_UINT32, BASE_HEX, |
1192 | 14 | NULL, 0x0, NULL, HFILL }}, |
1193 | 14 | { &hf_pgm_poll_matching_bmask, |
1194 | 14 | { "Matching Bitmask", "pgm.poll.matching_bmask", FT_UINT32, BASE_HEX, |
1195 | 14 | NULL, 0x0, NULL, HFILL }}, |
1196 | 14 | { &hf_pgm_polr_sqn, |
1197 | 14 | { "Sequence Number", "pgm.polr.sqn", FT_UINT32, BASE_HEX, |
1198 | 14 | NULL, 0x0, NULL, HFILL }}, |
1199 | 14 | { &hf_pgm_polr_round, |
1200 | 14 | { "Round", "pgm.polr.round", FT_UINT16, BASE_DEC, |
1201 | 14 | NULL, 0x0, NULL, HFILL }}, |
1202 | 14 | { &hf_pgm_polr_res, |
1203 | 14 | { "Reserved", "pgm.polr.res", FT_UINT16, BASE_HEX, |
1204 | 14 | NULL, 0x0, NULL, HFILL }}, |
1205 | 14 | { &hf_pgm_ack_sqn, |
1206 | 14 | { "Maximum Received Sequence Number", "pgm.ack.maxsqn", FT_UINT32, |
1207 | 14 | BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
1208 | 14 | { &hf_pgm_ack_bitmap, |
1209 | 14 | { "Packet Bitmap", "pgm.ack.bitmap", FT_UINT32, BASE_HEX, |
1210 | 14 | NULL, 0x0, NULL, HFILL }}, |
1211 | 14 | { &hf_pgm_opt_type, |
1212 | 14 | { "Type", "pgm.opts.type", FT_UINT8, BASE_HEX, |
1213 | 14 | VALS(opt_vals), 0x0, NULL, HFILL }}, |
1214 | 14 | { &hf_pgm_opt_len, |
1215 | 14 | { "Length", "pgm.opts.len", FT_UINT8, BASE_DEC, |
1216 | 14 | NULL, 0x0, NULL, HFILL }}, |
1217 | 14 | { &hf_pgm_opt_tlen, |
1218 | 14 | { "Total Length", "pgm.opts.tlen", FT_UINT16, BASE_DEC, |
1219 | 14 | NULL, 0x0, NULL, HFILL }}, |
1220 | 14 | { &hf_pgm_genopt_end, |
1221 | 14 | { "Option end", "pgm.genopts.end", FT_BOOLEAN, 8, |
1222 | 14 | TFS(&tfs_yes_no), 0x80, NULL, HFILL }}, |
1223 | 14 | { &hf_pgm_genopt_type, |
1224 | 14 | { "Type", "pgm.genopts.type", FT_UINT8, BASE_HEX, |
1225 | 14 | VALS(opt_vals), 0x7f, NULL, HFILL }}, |
1226 | 14 | { &hf_pgm_genopt_len, |
1227 | 14 | { "Length", "pgm.genopts.len", FT_UINT8, BASE_DEC, |
1228 | 14 | NULL, 0x0, NULL, HFILL }}, |
1229 | 14 | { &hf_pgm_genopt_opx, |
1230 | 14 | { "Option Extensibility Bits", "pgm.genopts.opx", FT_UINT8, BASE_HEX, |
1231 | 14 | VALS(opx_vals), 0x0, NULL, HFILL }}, |
1232 | 14 | { &hf_pgm_opt_parity_prm_po, |
1233 | 14 | { "Parity Parameters", "pgm.opts.parity_prm.op", FT_UINT8, BASE_HEX, |
1234 | 14 | NULL, 0x0, NULL, HFILL }}, |
1235 | 14 | { &hf_pgm_opt_parity_prm_prmtgsz, |
1236 | 14 | { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp", |
1237 | 14 | FT_UINT32, BASE_HEX, |
1238 | 14 | NULL, 0x0, NULL, HFILL }}, |
1239 | 14 | { &hf_pgm_opt_join_res, |
1240 | 14 | { "Reserved", "pgm.opts.join.res", FT_UINT8, BASE_HEX, |
1241 | 14 | NULL, 0x0, NULL, HFILL }}, |
1242 | 14 | { &hf_pgm_opt_join_minjoin, |
1243 | 14 | { "Minimum Sequence Number", "pgm.opts.join.min_join", |
1244 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
1245 | 14 | { &hf_pgm_opt_parity_grp_res, |
1246 | 14 | { "Reserved", "pgm.opts.parity_prm.reserved", FT_UINT8, BASE_HEX, |
1247 | 14 | NULL, 0x0, NULL, HFILL }}, |
1248 | 14 | { &hf_pgm_opt_parity_grp_prmgrp, |
1249 | 14 | { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp", |
1250 | 14 | FT_UINT32, BASE_HEX, |
1251 | 14 | NULL, 0x0, NULL, HFILL }}, |
1252 | 14 | { &hf_pgm_opt_nak_res, |
1253 | 14 | { "Reserved", "pgm.opts.nak.op", FT_UINT8, BASE_HEX, |
1254 | 14 | NULL, 0x0, NULL, HFILL }}, |
1255 | 14 | { &hf_pgm_opt_nak_list, |
1256 | 14 | { "List", "pgm.opts.nak.list", FT_BYTES, BASE_NONE, |
1257 | 14 | NULL, 0x0, NULL, HFILL }}, |
1258 | 14 | { &hf_pgm_opt_ccdata_res, |
1259 | 14 | { "Reserved", "pgm.opts.ccdata.res", FT_UINT8, BASE_DEC, |
1260 | 14 | NULL, 0x0, NULL, HFILL }}, |
1261 | 14 | { &hf_pgm_opt_ccdata_tsp, |
1262 | 14 | { "Time Stamp", "pgm.opts.ccdata.tstamp", FT_UINT16, BASE_HEX, |
1263 | 14 | NULL, 0x0, NULL, HFILL }}, |
1264 | 14 | { &hf_pgm_opt_ccdata_afi, |
1265 | 14 | { "Acker AFI", "pgm.opts.ccdata.afi", FT_UINT16, BASE_DEC, |
1266 | 14 | VALS(afn_vals), 0x0, NULL, HFILL }}, |
1267 | 14 | { &hf_pgm_opt_ccdata_res2, |
1268 | 14 | { "Reserved", "pgm.opts.ccdata.res2", FT_UINT16, BASE_DEC, |
1269 | 14 | NULL, 0x0, NULL, HFILL }}, |
1270 | 14 | { &hf_pgm_opt_ccdata_acker, |
1271 | 14 | { "Acker", "pgm.opts.ccdata.acker.ipv4", FT_IPv4, BASE_NONE, |
1272 | 14 | NULL, 0x0, NULL, HFILL }}, |
1273 | 14 | { &hf_pgm_opt_ccdata_acker6, |
1274 | 14 | { "Acker", "pgm.opts.ccdata.acker.ipv6", FT_IPv6, BASE_NONE, |
1275 | 14 | NULL, 0x0, NULL, HFILL }}, |
1276 | 14 | { &hf_pgm_opt_ccfeedbk_res, |
1277 | 14 | { "Reserved", "pgm.opts.ccdata.res", FT_UINT8, BASE_DEC, |
1278 | 14 | NULL, 0x0, NULL, HFILL }}, |
1279 | 14 | { &hf_pgm_opt_ccfeedbk_tsp, |
1280 | 14 | { "Time Stamp", "pgm.opts.ccdata.tstamp", FT_UINT16, BASE_HEX, |
1281 | 14 | NULL, 0x0, NULL, HFILL }}, |
1282 | 14 | { &hf_pgm_opt_ccfeedbk_afi, |
1283 | 14 | { "Acker AFI", "pgm.opts.ccdata.afi", FT_UINT16, BASE_DEC, |
1284 | 14 | VALS(afn_vals), 0x0, NULL, HFILL }}, |
1285 | 14 | { &hf_pgm_opt_ccfeedbk_lossrate, |
1286 | 14 | { "Loss Rate", "pgm.opts.ccdata.lossrate", FT_UINT16, BASE_HEX, |
1287 | 14 | NULL, 0x0, NULL, HFILL }}, |
1288 | 14 | { &hf_pgm_opt_ccfeedbk_acker, |
1289 | 14 | { "Acker", "pgm.opts.ccdata.acker.ipv4", FT_IPv4, BASE_NONE, |
1290 | 14 | NULL, 0x0, NULL, HFILL }}, |
1291 | 14 | { &hf_pgm_opt_ccfeedbk_acker6, |
1292 | 14 | { "Acker", "pgm.opts.ccdata.acker.ipv6", FT_IPv6, BASE_NONE, |
1293 | 14 | NULL, 0x0, NULL, HFILL }}, |
1294 | 14 | { &hf_pgm_opt_nak_bo_ivl_res, |
1295 | 14 | { "Reserved", "pgm.opts.nak_bo_ivl.res", FT_UINT8, BASE_HEX, |
1296 | 14 | NULL, 0x0, NULL, HFILL }}, |
1297 | 14 | { &hf_pgm_opt_nak_bo_ivl_bo_ivl, |
1298 | 14 | { "Back-off Interval", "pgm.opts.nak_bo_ivl.bo_ivl", FT_UINT32, BASE_DEC, |
1299 | 14 | NULL, 0x0, NULL, HFILL }}, |
1300 | 14 | { &hf_pgm_opt_nak_bo_ivl_bo_ivl_sqn, |
1301 | 14 | { "Back-off Interval Sequence Number", "pgm.opts.nak_bo_ivl.bo_ivl_sqn", FT_UINT32, BASE_HEX, |
1302 | 14 | NULL, 0x0, NULL, HFILL }}, |
1303 | 14 | { &hf_pgm_opt_nak_bo_rng_res, |
1304 | 14 | { "Reserved", "pgm.opts.nak_bo_rng.res", FT_UINT8, BASE_HEX, |
1305 | 14 | NULL, 0x0, NULL, HFILL }}, |
1306 | 14 | { &hf_pgm_opt_nak_bo_rng_min_bo_ivl, |
1307 | 14 | { "Min Back-off Interval", "pgm.opts.nak_bo_rng.min_bo_ivl", FT_UINT32, BASE_DEC, |
1308 | 14 | NULL, 0x0, NULL, HFILL }}, |
1309 | 14 | { &hf_pgm_opt_nak_bo_rng_max_bo_ivl, |
1310 | 14 | { "Max Back-off Interval", "pgm.opts.nak_bo_rng.max_bo_ivl", FT_UINT32, BASE_DEC, |
1311 | 14 | NULL, 0x0, NULL, HFILL }}, |
1312 | 14 | { &hf_pgm_opt_redirect_res, |
1313 | 14 | { "Reserved", "pgm.opts.redirect.res", FT_UINT8, BASE_DEC, |
1314 | 14 | NULL, 0x0, NULL, HFILL }}, |
1315 | 14 | { &hf_pgm_opt_redirect_afi, |
1316 | 14 | { "DLR AFI", "pgm.opts.redirect.afi", FT_UINT16, BASE_DEC, |
1317 | 14 | VALS(afn_vals), 0x0, NULL, HFILL }}, |
1318 | 14 | { &hf_pgm_opt_redirect_res2, |
1319 | 14 | { "Reserved", "pgm.opts.redirect.res2", FT_UINT16, BASE_HEX, |
1320 | 14 | NULL, 0x0, NULL, HFILL }}, |
1321 | 14 | { &hf_pgm_opt_redirect_dlr, |
1322 | 14 | { "DLR", "pgm.opts.redirect.dlr.ipv4", FT_IPv4, BASE_NONE, |
1323 | 14 | NULL, 0x0, NULL, HFILL }}, |
1324 | 14 | { &hf_pgm_opt_redirect_dlr6, |
1325 | 14 | { "DLR", "pgm.opts.redirect.dlr.ipv6", FT_IPv6, BASE_NONE, |
1326 | 14 | NULL, 0x0, NULL, HFILL }}, |
1327 | 14 | { &hf_pgm_opt_fragment_res, |
1328 | 14 | { "Reserved", "pgm.opts.fragment.res", FT_UINT8, BASE_HEX, |
1329 | 14 | NULL, 0x0, NULL, HFILL }}, |
1330 | 14 | { &hf_pgm_opt_fragment_first_sqn, |
1331 | 14 | { "First Sequence Number", "pgm.opts.fragment.first_sqn", FT_UINT32, BASE_HEX, |
1332 | 14 | NULL, 0x0, NULL, HFILL }}, |
1333 | 14 | { &hf_pgm_opt_fragment_offset, |
1334 | 14 | { "Fragment Offset", "pgm.opts.fragment.fragment_offset", FT_UINT32, BASE_DEC, |
1335 | 14 | NULL, 0x0, NULL, HFILL }}, |
1336 | 14 | { &hf_pgm_opt_fragment_total_length, |
1337 | 14 | { "Total Length", "pgm.opts.fragment.total_length", FT_UINT32, BASE_DEC, |
1338 | 14 | NULL, 0x0, NULL, HFILL }} |
1339 | 14 | }; |
1340 | 14 | static int *ett[] = { |
1341 | 14 | &ett_pgm, |
1342 | 14 | &ett_pgm_optbits, |
1343 | 14 | &ett_pgm_spm, |
1344 | 14 | &ett_pgm_data, |
1345 | 14 | &ett_pgm_nak, |
1346 | 14 | &ett_pgm_poll, |
1347 | 14 | &ett_pgm_polr, |
1348 | 14 | &ett_pgm_ack, |
1349 | 14 | &ett_pgm_opts, |
1350 | 14 | &ett_pgm_opts_join, |
1351 | 14 | &ett_pgm_opts_parityprm, |
1352 | 14 | &ett_pgm_opts_paritygrp, |
1353 | 14 | &ett_pgm_opts_naklist, |
1354 | 14 | &ett_pgm_opts_ccdata, |
1355 | 14 | &ett_pgm_opts_nak_bo_ivl, |
1356 | 14 | &ett_pgm_opts_nak_bo_rng, |
1357 | 14 | &ett_pgm_opts_redirect, |
1358 | 14 | &ett_pgm_opts_fragment |
1359 | 14 | }; |
1360 | 14 | static ei_register_info ei[] = { |
1361 | 14 | { &ei_pgm_opt_type, { "pgm.opts.type.invalid", PI_PROTOCOL, PI_WARN, "Invalid option", EXPFILL }}, |
1362 | 14 | { &ei_pgm_opt_tlen, { "pgm.opts.tlen.invalid", PI_PROTOCOL, PI_WARN, "Total Length invalid", EXPFILL }}, |
1363 | 14 | { &ei_pgm_genopt_len, { "pgm.genopts.len.invalid", PI_PROTOCOL, PI_WARN, "Option length invalid", EXPFILL }}, |
1364 | 14 | { &ei_address_format_invalid, { "pgm.address_format_invalid", PI_PROTOCOL, PI_WARN, "Can't handle this address format", EXPFILL }}, |
1365 | 14 | { &ei_pgm_main_cksum, { "pgm.bad_checksum", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }}, |
1366 | 14 | }; |
1367 | | |
1368 | 14 | module_t *pgm_module; |
1369 | 14 | expert_module_t* expert_pgm; |
1370 | | |
1371 | 14 | proto_pgm = proto_register_protocol("Pragmatic General Multicast", "PGM", "pgm"); |
1372 | | |
1373 | 14 | proto_register_field_array(proto_pgm, hf, array_length(hf)); |
1374 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
1375 | 14 | expert_pgm = expert_register_protocol(proto_pgm); |
1376 | 14 | expert_register_field_array(expert_pgm, ei, array_length(ei)); |
1377 | | |
1378 | | /* subdissector code */ |
1379 | 14 | pgm_handle = register_dissector("pgm", dissect_pgm, proto_pgm); |
1380 | 14 | subdissector_table = register_dissector_table("pgm.port", |
1381 | 14 | "PGM port", proto_pgm, FT_UINT16, BASE_DEC); |
1382 | 14 | heur_subdissector_list = register_heur_dissector_list_with_description("pgm", "PGM data fallback", proto_pgm); |
1383 | | |
1384 | | /* |
1385 | | * Register configuration preferences for UDP encapsulation |
1386 | | * (Note: Initially the ports are set to zero and the ports |
1387 | | * are not registered so the dissecting of PGM |
1388 | | * encapsulated in UDP packets is off by default; |
1389 | | * dissector_add_for_decode_as is called so that pgm |
1390 | | * is available for 'decode-as' |
1391 | | */ |
1392 | 14 | pgm_module = prefs_register_protocol(proto_pgm, NULL); |
1393 | | |
1394 | 14 | prefs_register_bool_preference(pgm_module, "check_checksum", |
1395 | 14 | "Check the validity of the PGM checksum when possible", |
1396 | 14 | "Whether to check the validity of the PGM checksum", |
1397 | 14 | &pgm_check_checksum); |
1398 | 14 | } |
1399 | | |
1400 | | /* The registration hand-off routine */ |
1401 | | /* |
1402 | | * Set up PGM Encap dissecting, which is off by default for UDP |
1403 | | */ |
1404 | | |
1405 | | void |
1406 | | proto_reg_handoff_pgm(void) |
1407 | 14 | { |
1408 | 14 | dissector_add_uint_range_with_preference("udp.port", "", pgm_handle); |
1409 | 14 | dissector_add_uint("ip.proto", IP_PROTO_PGM, pgm_handle); |
1410 | 14 | } |
1411 | | |
1412 | | /* |
1413 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
1414 | | * |
1415 | | * Local variables: |
1416 | | * c-basic-offset: 8 |
1417 | | * tab-width: 8 |
1418 | | * indent-tabs-mode: t |
1419 | | * End: |
1420 | | * |
1421 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
1422 | | * :indentSize=8:tabSize=8:noTabs=false: |
1423 | | */ |