]> The Tcpdump Group git mirrors - tcpdump/blob - print-pgm.c
CHANGES: Add a change backported to 4.99
[tcpdump] / print-pgm.c
1 /*
2 * Redistribution and use in source and binary forms, with or without
3 * modification, are permitted provided that: (1) source code
4 * distributions retain the above copyright notice and this paragraph
5 * in its entirety, and (2) distributions including binary code include
6 * the above copyright notice and this paragraph in its entirety in
7 * the documentation or other materials provided with the distribution.
8 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
9 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
10 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
11 * FOR A PARTICULAR PURPOSE.
12 *
13 * Original code by Andy Heffernan (ahh@juniper.net)
14 */
15
16 /* \summary: Pragmatic General Multicast (PGM) printer */
17
18 /* specification: RFC 3208
19
20 Plus https://dl.acm.org/doi/pdf/10.1145/347057.347390 for PGMCC,
21 whence the ACK packet type comes; there are some I-Ds for PGMCC,
22 draft-ietf-rmt-bb-pgmcc-00 through draft-ietf-rmt-bb-pgmcc-03,
23 but none of them give any description of the packet-level
24 changes to PGM, unlike the paper in question, which merely gives
25 an *insufficient* description of said changes. In particular,
26 it doesn't indicate what the packet type code for ACK is.
27
28 Luigi Rizzo's PGMCC code for FreeBSD, at
29
30 https://web.archive.org/web/20020302084503/http://info.iet.unipi.it/~luigi/pgm-code/
31
32 uses 0x0b (11) for ACK.
33
34 A capture file attached to
35
36 https://gitlab.com/wireshark/wireshark/-/issues/4798
37
38 has packets that use 0x0d for ACK, as does the Wireshark dissector
39 for PGM, and as does OpenPGM at https://github.com/steve-o/openpgm.
40 It may be that some proprietary PGMCC implementations, such as
41 SmartPGM, do so as well.
42
43 We use *both*, treating *either one* as a PGMCC ACK, pending
44 more information, such as an answer to
45
46 https://github.com/steve-o/openpgm/issues/75.
47
48 */
49
50 #ifdef HAVE_CONFIG_H
51 #include <config.h>
52 #endif
53
54 #include "netdissect-stdinc.h"
55
56 #define ND_LONGJMP_FROM_TCHECK
57 #include "netdissect.h"
58 #include "extract.h"
59 #include "addrtoname.h"
60 #include "addrtostr.h"
61
62 #include "ip.h"
63 #include "ip6.h"
64 #include "ipproto.h"
65 #include "af.h"
66
67 /*
68 * PGM header (RFC 3208)
69 */
70 struct pgm_header {
71 nd_uint16_t pgm_sport;
72 nd_uint16_t pgm_dport;
73 nd_uint8_t pgm_type;
74 nd_uint8_t pgm_options;
75 nd_uint16_t pgm_sum;
76 nd_byte pgm_gsid[6];
77 nd_uint16_t pgm_length;
78 };
79
80 struct pgm_spm {
81 nd_uint32_t pgms_seq;
82 nd_uint32_t pgms_trailseq;
83 nd_uint32_t pgms_leadseq;
84 nd_uint16_t pgms_nla_afi;
85 nd_uint16_t pgms_reserved;
86 /* ... uint8_t pgms_nla[0]; */
87 /* ... options */
88 };
89
90 struct pgm_nak {
91 nd_uint32_t pgmn_seq;
92 nd_uint16_t pgmn_source_afi;
93 nd_uint16_t pgmn_reserved;
94 /* ... uint8_t pgmn_source[0]; */
95 /* ... uint16_t pgmn_group_afi */
96 /* ... uint16_t pgmn_reserved2; */
97 /* ... uint8_t pgmn_group[0]; */
98 /* ... options */
99 };
100
101 struct pgm_ack {
102 nd_uint32_t pgma_rx_max_seq;
103 nd_uint32_t pgma_bitmap;
104 /* ... options */
105 };
106
107 struct pgm_poll {
108 nd_uint32_t pgmp_seq;
109 nd_uint16_t pgmp_round;
110 nd_uint16_t pgmp_subtype;
111 nd_uint16_t pgmp_nla_afi;
112 nd_uint16_t pgmp_reserved;
113 /* ... uint8_t pgmp_nla[0]; */
114 /* ... options */
115 };
116
117 struct pgm_polr {
118 nd_uint32_t pgmp_seq;
119 nd_uint16_t pgmp_round;
120 nd_uint16_t pgmp_reserved;
121 /* ... options */
122 };
123
124 struct pgm_data {
125 nd_uint32_t pgmd_seq;
126 nd_uint32_t pgmd_trailseq;
127 /* ... options */
128 };
129
130 typedef enum _pgm_type {
131 PGM_SPM = 0x00, /* source path message */
132 PGM_POLL = 0x01, /* POLL Request */
133 PGM_POLR = 0x02, /* POLL Response */
134 PGM_ODATA = 0x04, /* original data */
135 PGM_RDATA = 0x05, /* repair data */
136 PGM_NAK = 0x08, /* NAK */
137 PGM_NULLNAK = 0x09, /* Null NAK */
138 PGM_NCF = 0x0a, /* NAK Confirmation */
139 PGM_ACK = 0x0b, /* ACK for congestion control? */
140 PGM_SPMR = 0x0c, /* SPM request */
141 PGM_ACK2 = 0x0d, /* Also ACK for congestion control? */
142 } pgm_type;
143
144 #define PGM_OPT_BIT_PRESENT 0x01
145 #define PGM_OPT_BIT_NETWORK 0x02
146 #define PGM_OPT_BIT_VAR_PKTLEN 0x40
147 #define PGM_OPT_BIT_PARITY 0x80
148
149 #define PGM_OPT_LENGTH 0x00
150 #define PGM_OPT_FRAGMENT 0x01
151 #define PGM_OPT_NAK_LIST 0x02
152 #define PGM_OPT_JOIN 0x03
153 #define PGM_OPT_NAK_BO_IVL 0x04
154 #define PGM_OPT_NAK_BO_RNG 0x05
155
156 #define PGM_OPT_REDIRECT 0x07
157 #define PGM_OPT_PARITY_PRM 0x08
158 #define PGM_OPT_PARITY_GRP 0x09
159 #define PGM_OPT_CURR_TGSIZE 0x0A
160 #define PGM_OPT_NBR_UNREACH 0x0B
161 #define PGM_OPT_PATH_NLA 0x0C
162
163 #define PGM_OPT_SYN 0x0D
164 #define PGM_OPT_FIN 0x0E
165 #define PGM_OPT_RST 0x0F
166 #define PGM_OPT_CR 0x10
167 #define PGM_OPT_CRQST 0x11
168
169 #define PGM_OPT_PGMCC_DATA 0x12
170 #define PGM_OPT_PGMCC_FEEDBACK 0x13
171
172 #define PGM_OPT_MASK 0x7f
173
174 #define PGM_OPT_END 0x80 /* end of options marker */
175
176 #define PGM_MIN_OPT_LEN 4
177
178 void
179 pgm_print(netdissect_options *ndo,
180 const u_char *bp, u_int length,
181 const u_char *bp2)
182 {
183 const struct pgm_header *pgm;
184 const struct ip *ip;
185 uint8_t pgm_type_val;
186 uint16_t sport, dport;
187 u_int nla_afnum;
188 char nla_buf[INET6_ADDRSTRLEN];
189 const struct ip6_hdr *ip6;
190 uint8_t opt_type, opt_len;
191 uint32_t seq, opts_len, len, offset;
192
193 ndo->ndo_protocol = "pgm";
194 pgm = (const struct pgm_header *)bp;
195 ip = (const struct ip *)bp2;
196 if (IP_V(ip) == 6)
197 ip6 = (const struct ip6_hdr *)bp2;
198 else
199 ip6 = NULL;
200 if (!ND_TTEST_2(pgm->pgm_dport)) {
201 if (ip6) {
202 ND_PRINT("%s > %s:",
203 GET_IP6ADDR_STRING(ip6->ip6_src),
204 GET_IP6ADDR_STRING(ip6->ip6_dst));
205 } else {
206 ND_PRINT("%s > %s:",
207 GET_IPADDR_STRING(ip->ip_src),
208 GET_IPADDR_STRING(ip->ip_dst));
209 }
210 nd_trunc_longjmp(ndo);
211 }
212
213 sport = GET_BE_U_2(pgm->pgm_sport);
214 dport = GET_BE_U_2(pgm->pgm_dport);
215
216 if (ip6) {
217 if (GET_U_1(ip6->ip6_nxt) == IPPROTO_PGM) {
218 ND_PRINT("%s.%s > %s.%s: ",
219 GET_IP6ADDR_STRING(ip6->ip6_src),
220 tcpport_string(ndo, sport),
221 GET_IP6ADDR_STRING(ip6->ip6_dst),
222 tcpport_string(ndo, dport));
223 } else {
224 ND_PRINT("%s > %s: ",
225 tcpport_string(ndo, sport), tcpport_string(ndo, dport));
226 }
227 } else {
228 if (GET_U_1(ip->ip_p) == IPPROTO_PGM) {
229 ND_PRINT("%s.%s > %s.%s: ",
230 GET_IPADDR_STRING(ip->ip_src),
231 tcpport_string(ndo, sport),
232 GET_IPADDR_STRING(ip->ip_dst),
233 tcpport_string(ndo, dport));
234 } else {
235 ND_PRINT("%s > %s: ",
236 tcpport_string(ndo, sport), tcpport_string(ndo, dport));
237 }
238 }
239
240 ND_TCHECK_SIZE(pgm);
241
242 ND_PRINT("PGM, length %u", GET_BE_U_2(pgm->pgm_length));
243
244 if (!ndo->ndo_vflag)
245 return;
246
247 pgm_type_val = GET_U_1(pgm->pgm_type);
248 ND_PRINT(" 0x%02x%02x%02x%02x%02x%02x ",
249 pgm->pgm_gsid[0],
250 pgm->pgm_gsid[1],
251 pgm->pgm_gsid[2],
252 pgm->pgm_gsid[3],
253 pgm->pgm_gsid[4],
254 pgm->pgm_gsid[5]);
255 bp += sizeof(struct pgm_header);
256 switch (pgm_type_val) {
257 case PGM_SPM: {
258 const struct pgm_spm *spm;
259
260 spm = (const struct pgm_spm *)bp;
261 ND_TCHECK_SIZE(spm);
262 bp += sizeof(struct pgm_spm);
263
264 switch (GET_BE_U_2(spm->pgms_nla_afi)) {
265 case AFNUM_IP:
266 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
267 addrtostr(bp, nla_buf, sizeof(nla_buf));
268 bp += sizeof(nd_ipv4);
269 break;
270 case AFNUM_IP6:
271 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
272 addrtostr6(bp, nla_buf, sizeof(nla_buf));
273 bp += sizeof(nd_ipv6);
274 break;
275 default:
276 goto invalid;
277 break;
278 }
279
280 ND_PRINT("SPM seq %u trail %u lead %u nla %s",
281 GET_BE_U_4(spm->pgms_seq),
282 GET_BE_U_4(spm->pgms_trailseq),
283 GET_BE_U_4(spm->pgms_leadseq),
284 nla_buf);
285 break;
286 }
287
288 case PGM_POLL: {
289 const struct pgm_poll *pgm_poll;
290 uint32_t ivl, rnd, mask;
291
292 pgm_poll = (const struct pgm_poll *)bp;
293 ND_TCHECK_SIZE(pgm_poll);
294 bp += sizeof(struct pgm_poll);
295
296 switch (GET_BE_U_2(pgm_poll->pgmp_nla_afi)) {
297 case AFNUM_IP:
298 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
299 addrtostr(bp, nla_buf, sizeof(nla_buf));
300 bp += sizeof(nd_ipv4);
301 break;
302 case AFNUM_IP6:
303 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
304 addrtostr6(bp, nla_buf, sizeof(nla_buf));
305 bp += sizeof(nd_ipv6);
306 break;
307 default:
308 goto invalid;
309 break;
310 }
311
312 ivl = GET_BE_U_4(bp);
313 bp += sizeof(uint32_t);
314
315 rnd = GET_BE_U_4(bp);
316 bp += sizeof(uint32_t);
317
318 mask = GET_BE_U_4(bp);
319 bp += sizeof(uint32_t);
320
321 ND_PRINT("POLL seq %u round %u nla %s ivl %u rnd 0x%08x "
322 "mask 0x%08x", GET_BE_U_4(pgm_poll->pgmp_seq),
323 GET_BE_U_2(pgm_poll->pgmp_round), nla_buf, ivl, rnd,
324 mask);
325 break;
326 }
327 case PGM_POLR: {
328 const struct pgm_polr *polr_msg;
329
330 polr_msg = (const struct pgm_polr *)bp;
331 ND_TCHECK_SIZE(polr_msg);
332 ND_PRINT("POLR seq %u round %u",
333 GET_BE_U_4(polr_msg->pgmp_seq),
334 GET_BE_U_2(polr_msg->pgmp_round));
335 bp += sizeof(struct pgm_polr);
336 break;
337 }
338 case PGM_ODATA: {
339 const struct pgm_data *odata;
340
341 odata = (const struct pgm_data *)bp;
342 ND_PRINT("ODATA trail %u seq %u",
343 GET_BE_U_4(odata->pgmd_trailseq),
344 GET_BE_U_4(odata->pgmd_seq));
345 bp += sizeof(struct pgm_data);
346 break;
347 }
348
349 case PGM_RDATA: {
350 const struct pgm_data *rdata;
351
352 rdata = (const struct pgm_data *)bp;
353 ND_PRINT("RDATA trail %u seq %u",
354 GET_BE_U_4(rdata->pgmd_trailseq),
355 GET_BE_U_4(rdata->pgmd_seq));
356 bp += sizeof(struct pgm_data);
357 break;
358 }
359
360 case PGM_NAK:
361 case PGM_NULLNAK:
362 case PGM_NCF: {
363 const struct pgm_nak *nak;
364 char source_buf[INET6_ADDRSTRLEN], group_buf[INET6_ADDRSTRLEN];
365
366 nak = (const struct pgm_nak *)bp;
367 ND_TCHECK_SIZE(nak);
368 bp += sizeof(struct pgm_nak);
369
370 /*
371 * Skip past the source, saving info along the way
372 * and stopping if we don't have enough.
373 */
374 switch (GET_BE_U_2(nak->pgmn_source_afi)) {
375 case AFNUM_IP:
376 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
377 addrtostr(bp, source_buf, sizeof(source_buf));
378 bp += sizeof(nd_ipv4);
379 break;
380 case AFNUM_IP6:
381 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
382 addrtostr6(bp, source_buf, sizeof(source_buf));
383 bp += sizeof(nd_ipv6);
384 break;
385 default:
386 goto invalid;
387 break;
388 }
389
390 /*
391 * Skip past the group, saving info along the way
392 * and stopping if we don't have enough.
393 */
394 bp += (2 * sizeof(uint16_t));
395 switch (GET_BE_U_2(bp)) {
396 case AFNUM_IP:
397 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
398 addrtostr(bp, group_buf, sizeof(group_buf));
399 bp += sizeof(nd_ipv4);
400 break;
401 case AFNUM_IP6:
402 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
403 addrtostr6(bp, group_buf, sizeof(group_buf));
404 bp += sizeof(nd_ipv6);
405 break;
406 default:
407 goto invalid;
408 break;
409 }
410
411 /*
412 * Options decoding can go here.
413 */
414 switch (pgm_type_val) {
415 case PGM_NAK:
416 ND_PRINT("NAK ");
417 break;
418 case PGM_NULLNAK:
419 ND_PRINT("NNAK ");
420 break;
421 case PGM_NCF:
422 ND_PRINT("NCF ");
423 break;
424 default:
425 break;
426 }
427 ND_PRINT("(%s -> %s), seq %u",
428 source_buf, group_buf, GET_BE_U_4(nak->pgmn_seq));
429 break;
430 }
431
432 case PGM_ACK:
433 case PGM_ACK2: {
434 const struct pgm_ack *ack;
435
436 ack = (const struct pgm_ack *)bp;
437 ND_TCHECK_SIZE(ack);
438 ND_PRINT("ACK seq %u",
439 GET_BE_U_4(ack->pgma_rx_max_seq));
440 bp += sizeof(struct pgm_ack);
441 break;
442 }
443
444 case PGM_SPMR:
445 ND_PRINT("SPMR");
446 break;
447
448 default:
449 ND_PRINT("UNKNOWN type 0x%02x", pgm_type_val);
450 break;
451
452 }
453 if (GET_U_1(pgm->pgm_options) & PGM_OPT_BIT_PRESENT) {
454
455 /*
456 * make sure there's enough for the first option header
457 */
458 ND_TCHECK_LEN(bp, PGM_MIN_OPT_LEN);
459
460 /*
461 * That option header MUST be an OPT_LENGTH option
462 * (see the first paragraph of section 9.1 in RFC 3208).
463 */
464 opt_type = GET_U_1(bp);
465 bp++;
466 if ((opt_type & PGM_OPT_MASK) != PGM_OPT_LENGTH) {
467 ND_PRINT("[First option bad, should be PGM_OPT_LENGTH, is %u]", opt_type & PGM_OPT_MASK);
468 return;
469 }
470 opt_len = GET_U_1(bp);
471 bp++;
472 if (opt_len != 4) {
473 ND_PRINT("[Bad OPT_LENGTH option, length %u != 4]", opt_len);
474 return;
475 }
476 opts_len = GET_BE_U_2(bp);
477 bp += sizeof(uint16_t);
478 if (opts_len < 4) {
479 ND_PRINT("[Bad total option length %u < 4]", opts_len);
480 return;
481 }
482 ND_PRINT(" OPTS LEN %u", opts_len);
483 opts_len -= 4;
484
485 while (opts_len) {
486 if (opts_len < PGM_MIN_OPT_LEN) {
487 ND_PRINT("[Total option length leaves no room for final option]");
488 return;
489 }
490 opt_type = GET_U_1(bp);
491 bp++;
492 opt_len = GET_U_1(bp);
493 bp++;
494 if (opt_len < PGM_MIN_OPT_LEN) {
495 ND_PRINT("[Bad option, length %u < %u]", opt_len,
496 PGM_MIN_OPT_LEN);
497 break;
498 }
499 if (opts_len < opt_len) {
500 ND_PRINT("[Total option length leaves no room for final option]");
501 return;
502 }
503 ND_TCHECK_LEN(bp, opt_len - 2);
504
505 switch (opt_type & PGM_OPT_MASK) {
506 case PGM_OPT_LENGTH:
507 #define PGM_OPT_LENGTH_LEN (2+2)
508 if (opt_len != PGM_OPT_LENGTH_LEN) {
509 ND_PRINT("[Bad OPT_LENGTH option, length %u != %u]",
510 opt_len, PGM_OPT_LENGTH_LEN);
511 return;
512 }
513 ND_PRINT(" OPTS LEN (extra?) %u", GET_BE_U_2(bp));
514 bp += 2;
515 opts_len -= PGM_OPT_LENGTH_LEN;
516 break;
517
518 case PGM_OPT_FRAGMENT:
519 #define PGM_OPT_FRAGMENT_LEN (2+2+4+4+4)
520 if (opt_len != PGM_OPT_FRAGMENT_LEN) {
521 ND_PRINT("[Bad OPT_FRAGMENT option, length %u != %u]",
522 opt_len, PGM_OPT_FRAGMENT_LEN);
523 return;
524 }
525 bp += 2;
526 seq = GET_BE_U_4(bp);
527 bp += 4;
528 offset = GET_BE_U_4(bp);
529 bp += 4;
530 len = GET_BE_U_4(bp);
531 bp += 4;
532 ND_PRINT(" FRAG seq %u off %u len %u", seq, offset, len);
533 opts_len -= PGM_OPT_FRAGMENT_LEN;
534 break;
535
536 case PGM_OPT_NAK_LIST:
537 bp += 2;
538 opt_len -= 4; /* option header */
539 ND_PRINT(" NAK LIST");
540 while (opt_len) {
541 if (opt_len < 4) {
542 ND_PRINT("[Option length not a multiple of 4]");
543 return;
544 }
545 ND_PRINT(" %u", GET_BE_U_4(bp));
546 bp += 4;
547 opt_len -= 4;
548 opts_len -= 4;
549 }
550 break;
551
552 case PGM_OPT_JOIN:
553 #define PGM_OPT_JOIN_LEN (2+2+4)
554 if (opt_len != PGM_OPT_JOIN_LEN) {
555 ND_PRINT("[Bad OPT_JOIN option, length %u != %u]",
556 opt_len, PGM_OPT_JOIN_LEN);
557 return;
558 }
559 bp += 2;
560 seq = GET_BE_U_4(bp);
561 bp += 4;
562 ND_PRINT(" JOIN %u", seq);
563 opts_len -= PGM_OPT_JOIN_LEN;
564 break;
565
566 case PGM_OPT_NAK_BO_IVL:
567 #define PGM_OPT_NAK_BO_IVL_LEN (2+2+4+4)
568 if (opt_len != PGM_OPT_NAK_BO_IVL_LEN) {
569 ND_PRINT("[Bad OPT_NAK_BO_IVL option, length %u != %u]",
570 opt_len, PGM_OPT_NAK_BO_IVL_LEN);
571 return;
572 }
573 bp += 2;
574 offset = GET_BE_U_4(bp);
575 bp += 4;
576 seq = GET_BE_U_4(bp);
577 bp += 4;
578 ND_PRINT(" BACKOFF ivl %u ivlseq %u", offset, seq);
579 opts_len -= PGM_OPT_NAK_BO_IVL_LEN;
580 break;
581
582 case PGM_OPT_NAK_BO_RNG:
583 #define PGM_OPT_NAK_BO_RNG_LEN (2+2+4+4)
584 if (opt_len != PGM_OPT_NAK_BO_RNG_LEN) {
585 ND_PRINT("[Bad OPT_NAK_BO_RNG option, length %u != %u]",
586 opt_len, PGM_OPT_NAK_BO_RNG_LEN);
587 return;
588 }
589 bp += 2;
590 offset = GET_BE_U_4(bp);
591 bp += 4;
592 seq = GET_BE_U_4(bp);
593 bp += 4;
594 ND_PRINT(" BACKOFF max %u min %u", offset, seq);
595 opts_len -= PGM_OPT_NAK_BO_RNG_LEN;
596 break;
597
598 case PGM_OPT_REDIRECT:
599 #define PGM_OPT_REDIRECT_FIXED_LEN (2+2+2+2)
600 if (opt_len < PGM_OPT_REDIRECT_FIXED_LEN) {
601 ND_PRINT("[Bad OPT_REDIRECT option, length %u < %u]",
602 opt_len, PGM_OPT_REDIRECT_FIXED_LEN);
603 return;
604 }
605 bp += 2;
606 nla_afnum = GET_BE_U_2(bp);
607 bp += 2+2;
608 switch (nla_afnum) {
609 case AFNUM_IP:
610 if (opt_len != PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv4)) {
611 ND_PRINT("[Bad OPT_REDIRECT option, length %u != %u + address size]",
612 opt_len, PGM_OPT_REDIRECT_FIXED_LEN);
613 return;
614 }
615 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
616 addrtostr(bp, nla_buf, sizeof(nla_buf));
617 bp += sizeof(nd_ipv4);
618 opts_len -= PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv4);
619 break;
620 case AFNUM_IP6:
621 if (opt_len != PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv6)) {
622 ND_PRINT("[Bad OPT_REDIRECT option, length %u != %u + address size]",
623 opt_len, PGM_OPT_REDIRECT_FIXED_LEN);
624 return;
625 }
626 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
627 addrtostr6(bp, nla_buf, sizeof(nla_buf));
628 bp += sizeof(nd_ipv6);
629 opts_len -= PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv6);
630 break;
631 default:
632 goto invalid;
633 break;
634 }
635
636 ND_PRINT(" REDIRECT %s", nla_buf);
637 break;
638
639 case PGM_OPT_PARITY_PRM:
640 #define PGM_OPT_PARITY_PRM_LEN (2+2+4)
641 if (opt_len != PGM_OPT_PARITY_PRM_LEN) {
642 ND_PRINT("[Bad OPT_PARITY_PRM option, length %u != %u]",
643 opt_len, PGM_OPT_PARITY_PRM_LEN);
644 return;
645 }
646 bp += 2;
647 len = GET_BE_U_4(bp);
648 bp += 4;
649 ND_PRINT(" PARITY MAXTGS %u", len);
650 opts_len -= PGM_OPT_PARITY_PRM_LEN;
651 break;
652
653 case PGM_OPT_PARITY_GRP:
654 #define PGM_OPT_PARITY_GRP_LEN (2+2+4)
655 if (opt_len != PGM_OPT_PARITY_GRP_LEN) {
656 ND_PRINT("[Bad OPT_PARITY_GRP option, length %u != %u]",
657 opt_len, PGM_OPT_PARITY_GRP_LEN);
658 return;
659 }
660 bp += 2;
661 seq = GET_BE_U_4(bp);
662 bp += 4;
663 ND_PRINT(" PARITY GROUP %u", seq);
664 opts_len -= PGM_OPT_PARITY_GRP_LEN;
665 break;
666
667 case PGM_OPT_CURR_TGSIZE:
668 #define PGM_OPT_CURR_TGSIZE_LEN (2+2+4)
669 if (opt_len != PGM_OPT_CURR_TGSIZE_LEN) {
670 ND_PRINT("[Bad OPT_CURR_TGSIZE option, length %u != %u]",
671 opt_len, PGM_OPT_CURR_TGSIZE_LEN);
672 return;
673 }
674 bp += 2;
675 len = GET_BE_U_4(bp);
676 bp += 4;
677 ND_PRINT(" PARITY ATGS %u", len);
678 opts_len -= PGM_OPT_CURR_TGSIZE_LEN;
679 break;
680
681 case PGM_OPT_NBR_UNREACH:
682 #define PGM_OPT_NBR_UNREACH_LEN (2+2)
683 if (opt_len != PGM_OPT_NBR_UNREACH_LEN) {
684 ND_PRINT("[Bad OPT_NBR_UNREACH option, length %u != %u]",
685 opt_len, PGM_OPT_NBR_UNREACH_LEN);
686 return;
687 }
688 bp += 2;
689 ND_PRINT(" NBR_UNREACH");
690 opts_len -= PGM_OPT_NBR_UNREACH_LEN;
691 break;
692
693 case PGM_OPT_PATH_NLA:
694 ND_PRINT(" PATH_NLA [%u]", opt_len);
695 bp += opt_len - 2;
696 opts_len -= opt_len;
697 break;
698
699 case PGM_OPT_SYN:
700 #define PGM_OPT_SYN_LEN (2+2)
701 if (opt_len != PGM_OPT_SYN_LEN) {
702 ND_PRINT("[Bad OPT_SYN option, length %u != %u]",
703 opt_len, PGM_OPT_SYN_LEN);
704 return;
705 }
706 bp += 2;
707 ND_PRINT(" SYN");
708 opts_len -= PGM_OPT_SYN_LEN;
709 break;
710
711 case PGM_OPT_FIN:
712 #define PGM_OPT_FIN_LEN (2+2)
713 if (opt_len != PGM_OPT_FIN_LEN) {
714 ND_PRINT("[Bad OPT_FIN option, length %u != %u]",
715 opt_len, PGM_OPT_FIN_LEN);
716 return;
717 }
718 bp += 2;
719 ND_PRINT(" FIN");
720 opts_len -= PGM_OPT_FIN_LEN;
721 break;
722
723 case PGM_OPT_RST:
724 #define PGM_OPT_RST_LEN (2+2)
725 if (opt_len != PGM_OPT_RST_LEN) {
726 ND_PRINT("[Bad OPT_RST option, length %u != %u]",
727 opt_len, PGM_OPT_RST_LEN);
728 return;
729 }
730 bp += 2;
731 ND_PRINT(" RST");
732 opts_len -= PGM_OPT_RST_LEN;
733 break;
734
735 case PGM_OPT_CR:
736 ND_PRINT(" CR");
737 bp += opt_len - 2;
738 opts_len -= opt_len;
739 break;
740
741 case PGM_OPT_CRQST:
742 #define PGM_OPT_CRQST_LEN (2+2)
743 if (opt_len != PGM_OPT_CRQST_LEN) {
744 ND_PRINT("[Bad OPT_CRQST option, length %u != %u]",
745 opt_len, PGM_OPT_CRQST_LEN);
746 return;
747 }
748 bp += 2;
749 ND_PRINT(" CRQST");
750 opts_len -= PGM_OPT_CRQST_LEN;
751 break;
752
753 case PGM_OPT_PGMCC_DATA:
754 #define PGM_OPT_PGMCC_DATA_FIXED_LEN (2+2+4+2+2)
755 if (opt_len < PGM_OPT_PGMCC_DATA_FIXED_LEN) {
756 ND_PRINT("[Bad OPT_PGMCC_DATA option, length %u < %u]",
757 opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN);
758 return;
759 }
760 bp += 2;
761 offset = GET_BE_U_4(bp);
762 bp += 4;
763 nla_afnum = GET_BE_U_2(bp);
764 bp += 2+2;
765 switch (nla_afnum) {
766 case AFNUM_IP:
767 if (opt_len != PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv4)) {
768 ND_PRINT("[Bad OPT_PGMCC_DATA option, length %u != %u + address size]",
769 opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN);
770 return;
771 }
772 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
773 addrtostr(bp, nla_buf, sizeof(nla_buf));
774 bp += sizeof(nd_ipv4);
775 opts_len -= PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv4);
776 break;
777 case AFNUM_IP6:
778 if (opt_len != PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv6)) {
779 ND_PRINT("[Bad OPT_PGMCC_DATA option, length %u != %u + address size]",
780 opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN);
781 return;
782 }
783 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
784 addrtostr6(bp, nla_buf, sizeof(nla_buf));
785 bp += sizeof(nd_ipv6);
786 opts_len -= PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv6);
787 break;
788 default:
789 goto invalid;
790 break;
791 }
792
793 ND_PRINT(" PGMCC DATA %u %s", offset, nla_buf);
794 break;
795
796 case PGM_OPT_PGMCC_FEEDBACK:
797 #define PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN (2+2+4+2+2)
798 if (opt_len < PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN) {
799 ND_PRINT("[Bad PGM_OPT_PGMCC_FEEDBACK option, length %u < %u]",
800 opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN);
801 return;
802 }
803 bp += 2;
804 offset = GET_BE_U_4(bp);
805 bp += 4;
806 nla_afnum = GET_BE_U_2(bp);
807 bp += 2+2;
808 switch (nla_afnum) {
809 case AFNUM_IP:
810 if (opt_len != PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv4)) {
811 ND_PRINT("[Bad OPT_PGMCC_FEEDBACK option, length %u != %u + address size]",
812 opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN);
813 return;
814 }
815 ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
816 addrtostr(bp, nla_buf, sizeof(nla_buf));
817 bp += sizeof(nd_ipv4);
818 opts_len -= PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv4);
819 break;
820 case AFNUM_IP6:
821 if (opt_len != PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv6)) {
822 ND_PRINT("[Bad OPT_PGMCC_FEEDBACK option, length %u != %u + address size]",
823 opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN);
824 return;
825 }
826 ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
827 addrtostr6(bp, nla_buf, sizeof(nla_buf));
828 bp += sizeof(nd_ipv6);
829 opts_len -= PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv6);
830 break;
831 default:
832 goto invalid;
833 break;
834 }
835
836 ND_PRINT(" PGMCC FEEDBACK %u %s", offset, nla_buf);
837 break;
838
839 default:
840 ND_PRINT(" OPT_%02X [%u] ", opt_type, opt_len);
841 bp += opt_len - 2;
842 opts_len -= opt_len;
843 break;
844 }
845
846 if (opt_type & PGM_OPT_END)
847 break;
848 }
849 }
850
851 ND_PRINT(" [%u]", length);
852 if (ndo->ndo_packettype == PT_PGM_ZMTP1 &&
853 (pgm_type_val == PGM_ODATA || pgm_type_val == PGM_RDATA))
854 zmtp1_datagram_print(ndo, bp,
855 GET_BE_U_2(pgm->pgm_length));
856
857 return;
858 invalid:
859 nd_print_invalid(ndo);
860 }