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