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