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, flags1, flags2;
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", pgm->pgm_length);
241
242        if (!vflag)
243            return;
244
245        if (length > pgm->pgm_length)
246            length = pgm->pgm_length;
247
248	(void)printf(" 0x%02x%02x%02x%02x%02x%02x ",
249		     pgm->pgm_gsid[0],
250                     pgm->pgm_gsid[1],
251                     pgm->pgm_gsid[2],
252		     pgm->pgm_gsid[3],
253                     pgm->pgm_gsid[4],
254                     pgm->pgm_gsid[5]);
255	switch (pgm->pgm_type) {
256	case PGM_SPM: {
257	    struct pgm_spm *spm;
258
259	    spm = (struct pgm_spm *)(pgm + 1);
260	    TCHECK(*spm);
261
262	    switch (EXTRACT_16BITS(&spm->pgms_nla_afi)) {
263	    case AFI_IP:
264		addr_size = sizeof(struct in_addr);
265		nla_af = AF_INET;
266		break;
267#ifdef INET6
268	    case AFI_IP6:
269		addr_size = sizeof(struct in6_addr);
270		nla_af = AF_INET6;
271		break;
272#endif
273	    default:
274		goto trunc;
275		break;
276	    }
277	    bp = (u_char *) (spm + 1);
278	    TCHECK2(*bp, addr_size);
279	    nla = bp;
280	    bp += addr_size;
281
282	    inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
283	    (void)printf("SPM seq %u trail %u lead %u nla %s",
284			 EXTRACT_32BITS(&spm->pgms_seq),
285                         EXTRACT_32BITS(&spm->pgms_trailseq),
286			 EXTRACT_32BITS(&spm->pgms_leadseq),
287                         nla_buf);
288	    break;
289	}
290
291	case PGM_POLL: {
292	    struct pgm_poll *poll;
293
294	    poll = (struct pgm_poll *)(pgm + 1);
295	    TCHECK(*poll);
296	    (void)printf("POLL seq %u round %u",
297			 EXTRACT_32BITS(&poll->pgmp_seq),
298                         EXTRACT_16BITS(&poll->pgmp_round));
299	    bp = (u_char *) (poll + 1);
300	    break;
301	}
302	case PGM_POLR: {
303	    struct pgm_polr *polr;
304	    u_int32_t ivl, rnd, mask;
305
306	    polr = (struct pgm_polr *)(pgm + 1);
307	    TCHECK(*polr);
308
309	    switch (EXTRACT_16BITS(&polr->pgmp_nla_afi)) {
310	    case AFI_IP:
311		addr_size = sizeof(struct in_addr);
312		nla_af = AF_INET;
313		break;
314#ifdef INET6
315	    case AFI_IP6:
316		addr_size = sizeof(struct in6_addr);
317		nla_af = AF_INET6;
318		break;
319#endif
320	    default:
321		goto trunc;
322		break;
323	    }
324	    bp = (u_char *) (polr + 1);
325	    TCHECK2(*bp, addr_size);
326	    nla = bp;
327	    bp += addr_size;
328
329	    inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
330
331	    TCHECK2(*bp, sizeof(u_int32_t));
332	    ivl = EXTRACT_32BITS(bp);
333	    bp += sizeof(u_int32_t);
334
335	    TCHECK2(*bp, sizeof(u_int32_t));
336	    rnd = EXTRACT_32BITS(bp);
337	    bp += sizeof(u_int32_t);
338
339	    TCHECK2(*bp, sizeof(u_int32_t));
340	    mask = EXTRACT_32BITS(bp);
341	    bp += sizeof(u_int32_t);
342
343	    (void)printf("POLR seq %u round %u nla %s ivl %u rnd 0x%08x "
344			 "mask 0x%08x", EXTRACT_32BITS(&polr->pgmp_seq),
345			 EXTRACT_16BITS(&polr->pgmp_round), nla_buf, ivl, rnd, mask);
346	    break;
347	}
348	case PGM_ODATA: {
349	    struct pgm_data *odata;
350
351	    odata = (struct pgm_data *)(pgm + 1);
352	    TCHECK(*odata);
353	    (void)printf("ODATA trail %u seq %u",
354			 EXTRACT_32BITS(&odata->pgmd_trailseq),
355			 EXTRACT_32BITS(&odata->pgmd_seq));
356	    bp = (u_char *) (odata + 1);
357	    break;
358	}
359
360	case PGM_RDATA: {
361	    struct pgm_data *rdata;
362
363	    rdata = (struct pgm_data *)(pgm + 1);
364	    TCHECK(*rdata);
365	    (void)printf("RDATA trail %u seq %u",
366			 EXTRACT_32BITS(&rdata->pgmd_trailseq),
367			 EXTRACT_32BITS(&rdata->pgmd_seq));
368	    bp = (u_char *) (rdata + 1);
369	    break;
370	}
371
372	case PGM_NAK:
373	case PGM_NULLNAK:
374	case PGM_NCF: {
375	    struct pgm_nak *nak;
376	    const void *source, *group;
377	    int source_af, group_af;
378#ifdef INET6
379	    char source_buf[INET6_ADDRSTRLEN], group_buf[INET6_ADDRSTRLEN];
380#else
381	    char source_buf[INET_ADDRSTRLEN], group_buf[INET_ADDRSTRLEN];
382#endif
383
384	    nak = (struct pgm_nak *)(pgm + 1);
385	    TCHECK(*nak);
386
387	    /*
388	     * Skip past the source, saving info along the way
389	     * and stopping if we don't have enough.
390	     */
391	    switch (EXTRACT_16BITS(&nak->pgmn_source_afi)) {
392	    case AFI_IP:
393		addr_size = sizeof(struct in_addr);
394		source_af = AF_INET;
395		break;
396#ifdef INET6
397	    case AFI_IP6:
398		addr_size = sizeof(struct in6_addr);
399		source_af = AF_INET6;
400		break;
401#endif
402	    default:
403		goto trunc;
404		break;
405	    }
406	    bp = (u_char *) (nak + 1);
407	    TCHECK2(*bp, addr_size);
408	    source = bp;
409	    bp += addr_size;
410
411	    /*
412	     * Skip past the group, saving info along the way
413	     * and stopping if we don't have enough.
414	     */
415	    switch (EXTRACT_16BITS(bp)) {
416	    case AFI_IP:
417		addr_size = sizeof(struct in_addr);
418		group_af = AF_INET;
419		break;
420#ifdef INET6
421	    case AFI_IP6:
422		addr_size = sizeof(struct in6_addr);
423		group_af = AF_INET6;
424		break;
425#endif
426	    default:
427		goto trunc;
428		break;
429	    }
430	    bp += (2 * sizeof(u_int16_t));
431	    TCHECK2(*bp, addr_size);
432	    group = bp;
433	    bp += addr_size;
434
435	    /*
436	     * Options decoding can go here.
437	     */
438	    inet_ntop(source_af, source, source_buf, sizeof(source_buf));
439	    inet_ntop(group_af, group, group_buf, sizeof(group_buf));
440	    switch (pgm->pgm_type) {
441		case PGM_NAK:
442		    (void)printf("NAK ");
443		    break;
444		case PGM_NULLNAK:
445		    (void)printf("NNAK ");
446		    break;
447		case PGM_NCF:
448		    (void)printf("NCF ");
449		    break;
450		default:
451                    break;
452	    }
453	    (void)printf("(%s -> %s), seq %u",
454			 source_buf, group_buf, EXTRACT_32BITS(&nak->pgmn_seq));
455	    break;
456	}
457
458	case PGM_ACK: {
459	    struct pgm_ack *ack;
460
461	    ack = (struct pgm_ack *)(pgm + 1);
462	    TCHECK(*ack);
463	    (void)printf("ACK seq %u",
464			 EXTRACT_32BITS(&ack->pgma_rx_max_seq));
465	    bp = (u_char *) (ack + 1);
466	    break;
467	}
468
469	case PGM_SPMR:
470	    (void)printf("SPMR");
471	    break;
472
473	default:
474	    (void)printf("UNKNOWN type %0x02x", pgm->pgm_type);
475	    break;
476
477	}
478	if (pgm->pgm_options & PGM_OPT_BIT_PRESENT) {
479
480	    /*
481	     * make sure there's enough for the first option header
482	     */
483	    if (!TTEST2(*bp, PGM_MIN_OPT_LEN)) {
484		(void)printf("[|OPT]");
485		return;
486	    }
487
488	    /*
489	     * That option header MUST be an OPT_LENGTH option
490	     * (see the first paragraph of section 9.1 in RFC 3208).
491	     */
492	    opt_type = *bp++;
493	    if ((opt_type & PGM_OPT_MASK) != PGM_OPT_LENGTH) {
494		(void)printf("[First option bad, should be PGM_OPT_LENGTH, is %u]", opt_type & PGM_OPT_MASK);
495		return;
496	    }
497	    opt_len = *bp++;
498	    if (opt_len != 4) {
499		(void)printf("[Bad OPT_LENGTH option, length %u != 4]", opt_len);
500		return;
501	    }
502	    opts_len = EXTRACT_16BITS(bp);
503	    if (opts_len < 4) {
504		(void)printf("[Bad total option length %u < 4]", opts_len);
505		return;
506	    }
507	    bp += sizeof(u_int16_t);
508	    (void)printf(" OPTS LEN %d", opts_len);
509	    opts_len -= 4;
510
511	    while (opts_len) {
512		if (opts_len < PGM_MIN_OPT_LEN) {
513		    (void)printf("[Total option length leaves no room for final option]");
514		    return;
515		}
516		opt_type = *bp++;
517		opt_len = *bp++;
518		if (opt_len < PGM_MIN_OPT_LEN) {
519		    (void)printf("[Bad option, length %u < %u]", opt_len,
520		        PGM_MIN_OPT_LEN);
521		    break;
522		}
523		if (opts_len < opt_len) {
524		    (void)printf("[Total option length leaves no room for final option]");
525		    return;
526		}
527		if (!TTEST2(*bp, opt_len - 2)) {
528		    (void)printf(" [|OPT]");
529		    return;
530		}
531
532		switch (opt_type & PGM_OPT_MASK) {
533		case PGM_OPT_LENGTH:
534		    if (opt_len != 4) {
535			(void)printf("[Bad OPT_LENGTH option, length %u != 4]", opt_len);
536			return;
537		    }
538		    (void)printf(" OPTS LEN (extra?) %d", EXTRACT_16BITS(bp));
539		    bp += sizeof(u_int16_t);
540		    opts_len -= 4;
541		    break;
542
543		case PGM_OPT_FRAGMENT:
544		    if (opt_len != 16) {
545			(void)printf("[Bad OPT_FRAGMENT option, length %u != 16]", opt_len);
546			return;
547		    }
548		    flags1 = *bp++;
549		    flags2 = *bp++;
550		    seq = EXTRACT_32BITS(bp);
551		    bp += sizeof(u_int32_t);
552		    offset = EXTRACT_32BITS(bp);
553		    bp += sizeof(u_int32_t);
554		    len = EXTRACT_32BITS(bp);
555		    bp += sizeof(u_int32_t);
556		    (void)printf(" FRAG seq %u off %u len %u", seq, offset, len);
557		    opts_len -= 16;
558		    break;
559
560		case PGM_OPT_NAK_LIST:
561		    flags1 = *bp++;
562		    flags2 = *bp++;
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		    flags1 = *bp++;
584		    flags2 = *bp++;
585		    seq = EXTRACT_32BITS(bp);
586		    bp += sizeof(u_int32_t);
587		    (void)printf(" JOIN %u", seq);
588		    opts_len -= 8;
589		    break;
590
591		case PGM_OPT_NAK_BO_IVL:
592		    if (opt_len != 12) {
593			(void)printf("[Bad OPT_NAK_BO_IVL option, length %u != 12]", opt_len);
594			return;
595		    }
596		    flags1 = *bp++;
597		    flags2 = *bp++;
598		    offset = EXTRACT_32BITS(bp);
599		    bp += sizeof(u_int32_t);
600		    seq = EXTRACT_32BITS(bp);
601		    bp += sizeof(u_int32_t);
602		    (void)printf(" BACKOFF ivl %u ivlseq %u", offset, seq);
603		    opts_len -= 12;
604		    break;
605
606		case PGM_OPT_NAK_BO_RNG:
607		    if (opt_len != 12) {
608			(void)printf("[Bad OPT_NAK_BO_RNG option, length %u != 12]", opt_len);
609			return;
610		    }
611		    flags1 = *bp++;
612		    flags2 = *bp++;
613		    offset = EXTRACT_32BITS(bp);
614		    bp += sizeof(u_int32_t);
615		    seq = EXTRACT_32BITS(bp);
616		    bp += sizeof(u_int32_t);
617		    (void)printf(" BACKOFF max %u min %u", offset, seq);
618		    opts_len -= 12;
619		    break;
620
621		case PGM_OPT_REDIRECT:
622		    flags1 = *bp++;
623		    flags2 = *bp++;
624		    switch (EXTRACT_16BITS(bp)) {
625		    case AFI_IP:
626			addr_size = sizeof(struct in_addr);
627			nla_af = AF_INET;
628			break;
629#ifdef INET6
630		    case AFI_IP6:
631			addr_size = sizeof(struct in6_addr);
632			nla_af = AF_INET6;
633			break;
634#endif
635		    default:
636			goto trunc;
637			break;
638		    }
639		    bp += (2 * sizeof(u_int16_t));
640		    if (opt_len != 4 + addr_size) {
641			(void)printf("[Bad OPT_REDIRECT option, length %u != 4 + address size]", opt_len);
642			return;
643		    }
644		    TCHECK2(*bp, addr_size);
645		    nla = bp;
646		    bp += addr_size;
647
648		    inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
649		    (void)printf(" REDIRECT %s",  (char *)nla);
650		    opts_len -= 4 + addr_size;
651		    break;
652
653		case PGM_OPT_PARITY_PRM:
654		    if (opt_len != 8) {
655			(void)printf("[Bad OPT_PARITY_PRM option, length %u != 8]", opt_len);
656			return;
657		    }
658		    flags1 = *bp++;
659		    flags2 = *bp++;
660		    len = EXTRACT_32BITS(bp);
661		    bp += sizeof(u_int32_t);
662		    (void)printf(" PARITY MAXTGS %u", len);
663		    opts_len -= 8;
664		    break;
665
666		case PGM_OPT_PARITY_GRP:
667		    if (opt_len != 8) {
668			(void)printf("[Bad OPT_PARITY_GRP option, length %u != 8]", opt_len);
669			return;
670		    }
671		    flags1 = *bp++;
672		    flags2 = *bp++;
673		    seq = EXTRACT_32BITS(bp);
674		    bp += sizeof(u_int32_t);
675		    (void)printf(" PARITY GROUP %u", seq);
676		    opts_len -= 8;
677		    break;
678
679		case PGM_OPT_CURR_TGSIZE:
680		    if (opt_len != 8) {
681			(void)printf("[Bad OPT_CURR_TGSIZE option, length %u != 8]", opt_len);
682			return;
683		    }
684		    flags1 = *bp++;
685		    flags2 = *bp++;
686		    len = EXTRACT_32BITS(bp);
687		    bp += sizeof(u_int32_t);
688		    (void)printf(" PARITY ATGS %u", len);
689		    opts_len -= 8;
690		    break;
691
692		case PGM_OPT_NBR_UNREACH:
693		    if (opt_len != 4) {
694			(void)printf("[Bad OPT_NBR_UNREACH option, length %u != 4]", opt_len);
695			return;
696		    }
697		    flags1 = *bp++;
698		    flags2 = *bp++;
699		    (void)printf(" NBR_UNREACH");
700		    opts_len -= 4;
701		    break;
702
703		case PGM_OPT_PATH_NLA:
704		    (void)printf(" PATH_NLA [%d]", opt_len);
705		    bp += opt_len;
706		    opts_len -= opt_len;
707		    break;
708
709		case PGM_OPT_SYN:
710		    if (opt_len != 4) {
711			(void)printf("[Bad OPT_SYN option, length %u != 4]", opt_len);
712			return;
713		    }
714		    flags1 = *bp++;
715		    flags2 = *bp++;
716		    (void)printf(" SYN");
717		    opts_len -= 4;
718		    break;
719
720		case PGM_OPT_FIN:
721		    if (opt_len != 4) {
722			(void)printf("[Bad OPT_FIN option, length %u != 4]", opt_len);
723			return;
724		    }
725		    flags1 = *bp++;
726		    flags2 = *bp++;
727		    (void)printf(" FIN");
728		    opts_len -= 4;
729		    break;
730
731		case PGM_OPT_RST:
732		    if (opt_len != 4) {
733			(void)printf("[Bad OPT_RST option, length %u != 4]", opt_len);
734			return;
735		    }
736		    flags1 = *bp++;
737		    flags2 = *bp++;
738		    (void)printf(" RST");
739		    opts_len -= 4;
740		    break;
741
742		case PGM_OPT_CR:
743		    (void)printf(" CR");
744		    bp += opt_len;
745		    opts_len -= opt_len;
746		    break;
747
748		case PGM_OPT_CRQST:
749		    if (opt_len != 4) {
750			(void)printf("[Bad OPT_CRQST option, length %u != 4]", opt_len);
751			return;
752		    }
753		    flags1 = *bp++;
754		    flags2 = *bp++;
755		    (void)printf(" CRQST");
756		    opts_len -= 4;
757		    break;
758
759		case PGM_OPT_PGMCC_DATA:
760		    flags1 = *bp++;
761		    flags2 = *bp++;
762		    offset = EXTRACT_32BITS(bp);
763		    bp += sizeof(u_int32_t);
764		    switch (EXTRACT_16BITS(bp)) {
765		    case AFI_IP:
766			addr_size = sizeof(struct in_addr);
767			nla_af = AF_INET;
768			break;
769#ifdef INET6
770		    case AFI_IP6:
771			addr_size = sizeof(struct in6_addr);
772			nla_af = AF_INET6;
773			break;
774#endif
775		    default:
776			goto trunc;
777			break;
778		    }
779		    bp += (2 * sizeof(u_int16_t));
780		    if (opt_len != 12 + addr_size) {
781			(void)printf("[Bad OPT_PGMCC_DATA option, length %u != 12 + address size]", opt_len);
782			return;
783		    }
784		    TCHECK2(*bp, addr_size);
785		    nla = bp;
786		    bp += addr_size;
787
788		    inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
789		    (void)printf(" PGMCC DATA %u %s", offset, (char*)nla);
790		    opts_len -= 16;
791		    break;
792
793		case PGM_OPT_PGMCC_FEEDBACK:
794		    flags1 = *bp++;
795		    flags2 = *bp++;
796		    offset = EXTRACT_32BITS(bp);
797		    bp += sizeof(u_int32_t);
798		    switch (EXTRACT_16BITS(bp)) {
799		    case AFI_IP:
800			addr_size = sizeof(struct in_addr);
801			nla_af = AF_INET;
802			break;
803#ifdef INET6
804		    case AFI_IP6:
805			addr_size = sizeof(struct in6_addr);
806			nla_af = AF_INET6;
807			break;
808#endif
809		    default:
810			goto trunc;
811			break;
812		    }
813		    bp += (2 * sizeof(u_int16_t));
814		    if (opt_len != 12 + addr_size) {
815			(void)printf("[Bad OPT_PGMCC_FEEDBACK option, length %u != 12 + address size]", opt_len);
816			return;
817		    }
818		    TCHECK2(*bp, addr_size);
819		    nla = bp;
820		    bp += addr_size;
821
822		    inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
823		    (void)printf(" PGMCC FEEDBACK %u %s", offset, (char*)nla);
824		    opts_len -= 16;
825		    break;
826
827		default:
828		    (void)printf(" OPT_%02X [%d] ", opt_type, opt_len);
829		    bp += opt_len;
830		    opts_len -= opt_len;
831		    break;
832		}
833
834		if (opt_type & PGM_OPT_END)
835		    break;
836	     }
837	}
838
839	(void)printf(" [%u]", EXTRACT_16BITS(&pgm->pgm_length));
840
841	return;
842
843trunc:
844	fputs("[|pgm]", stdout);
845	if (ch != '\0')
846		putchar('>');
847}
848