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