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