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