print-pgm.c revision 236192
11541Srgrimes/*
21541Srgrimes * Redistribution and use in source and binary forms, with or without
31541Srgrimes * modification, are permitted provided that: (1) source code
41541Srgrimes * distributions retain the above copyright notice and this paragraph
51541Srgrimes * in its entirety, and (2) distributions including binary code include
61541Srgrimes * the above copyright notice and this paragraph in its entirety in
71541Srgrimes * the documentation or other materials provided with the distribution.
81541Srgrimes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
91541Srgrimes * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
101541Srgrimes * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
111541Srgrimes * FOR A PARTICULAR PURPOSE.
121541Srgrimes *
131541Srgrimes * Original code by Andy Heffernan (ahh@juniper.net)
141541Srgrimes */
151541Srgrimes
161541Srgrimes#ifndef lint
171541Srgrimesstatic const char rcsid[] _U_ =
181541Srgrimes    "@(#) $Header: /tcpdump/master/tcpdump/print-pgm.c,v 1.5 2005-06-07 22:05:58 guy Exp $";
191541Srgrimes#endif
201541Srgrimes
211541Srgrimes#ifdef HAVE_CONFIG_H
221541Srgrimes#include "config.h"
231541Srgrimes#endif
241541Srgrimes
251541Srgrimes#include <tcpdump-stdinc.h>
261541Srgrimes
271541Srgrimes#include <stdio.h>
281541Srgrimes#include <stdlib.h>
291541Srgrimes#include <string.h>
301541Srgrimes
311541Srgrimes#include "interface.h"
321541Srgrimes#include "extract.h"
331541Srgrimes#include "addrtoname.h"
3436192Sdg
351541Srgrimes#include "ip.h"
361541Srgrimes#ifdef INET6
372169Spaul#include "ip6.h"
382169Spaul#endif
392169Spaul#include "ipproto.h"
401541Srgrimes
411541Srgrimes/*
421541Srgrimes * PGM header (RFC 3208)
431541Srgrimes */
441541Srgrimesstruct pgm_header {
451541Srgrimes    u_int16_t	pgm_sport;
4633804Sjulian    u_int16_t	pgm_dport;
471541Srgrimes    u_int8_t	pgm_type;
481541Srgrimes    u_int8_t	pgm_options;
491541Srgrimes    u_int16_t	pgm_sum;
501541Srgrimes    u_int8_t	pgm_gsid[6];
511541Srgrimes    u_int16_t	pgm_length;
529209Swollman};
531541Srgrimes
5433804Sjulianstruct pgm_spm {
551541Srgrimes    u_int32_t	pgms_seq;
5633804Sjulian    u_int32_t	pgms_trailseq;
5733804Sjulian    u_int32_t	pgms_leadseq;
5833804Sjulian    u_int16_t	pgms_nla_afi;
591541Srgrimes    u_int16_t	pgms_reserved;
6033804Sjulian    /* ... u_int8_t	pgms_nla[0]; */
6133804Sjulian    /* ... options */
6233804Sjulian};
6333804Sjulian
641541Srgrimesstruct pgm_nak {
6533804Sjulian    u_int32_t	pgmn_seq;
6633804Sjulian    u_int16_t	pgmn_source_afi;
6733804Sjulian    u_int16_t	pgmn_reserved;
6833804Sjulian    /* ... u_int8_t	pgmn_source[0]; */
691541Srgrimes    /* ... u_int16_t	pgmn_group_afi */
7033804Sjulian    /* ... u_int16_t	pgmn_reserved2; */
7133804Sjulian    /* ... u_int8_t	pgmn_group[0]; */
7233804Sjulian    /* ... options */
7333804Sjulian};
7433804Sjulian
7533804Sjulianstruct pgm_ack {
761541Srgrimes    u_int32_t	pgma_rx_max_seq;
7733804Sjulian    u_int32_t	pgma_bitmap;
7833804Sjulian    /* ... options */
7933804Sjulian};
8033804Sjulian
8133804Sjulianstruct pgm_poll {
8233804Sjulian    u_int32_t	pgmp_seq;
8333804Sjulian    u_int16_t	pgmp_round;
8433804Sjulian    u_int16_t	pgmp_reserved;
8533804Sjulian    /* ... options */
8633804Sjulian};
8733804Sjulian
8833804Sjulianstruct pgm_polr {
8933804Sjulian    u_int32_t	pgmp_seq;
9033804Sjulian    u_int16_t	pgmp_round;
9133804Sjulian    u_int16_t	pgmp_subtype;
9233804Sjulian    u_int16_t	pgmp_nla_afi;
932531Swollman    u_int16_t	pgmp_reserved;
9433804Sjulian    /* ... u_int8_t	pgmp_nla[0]; */
9533804Sjulian    /* ... options */
9633804Sjulian};
9733804Sjulian
9833804Sjulianstruct pgm_data {
9933804Sjulian    u_int32_t	pgmd_seq;
10033804Sjulian    u_int32_t	pgmd_trailseq;
10133804Sjulian    /* ... options */
10233804Sjulian};
10333804Sjulian
10433804Sjuliantypedef enum _pgm_type {
10533804Sjulian    PGM_SPM = 0,		/* source path message */
10633804Sjulian    PGM_POLL = 1,		/* POLL Request */
10733804Sjulian    PGM_POLR = 2,		/* POLL Response */
10833804Sjulian    PGM_ODATA = 4,		/* original data */
10933804Sjulian    PGM_RDATA = 5,		/* repair data */
11033804Sjulian    PGM_NAK = 8,		/* NAK */
11133804Sjulian    PGM_NULLNAK = 9,		/* Null NAK */
11233804Sjulian    PGM_NCF = 10,		/* NAK Confirmation */
11333804Sjulian    PGM_ACK = 11,		/* ACK for congestion control */
11433804Sjulian    PGM_SPMR = 12,		/* SPM request */
11533804Sjulian    PGM_MAX = 255
11633804Sjulian} pgm_type;
11733804Sjulian
11833804Sjulian#define PGM_OPT_BIT_PRESENT	0x01
11933804Sjulian#define PGM_OPT_BIT_NETWORK	0x02
12033804Sjulian#define PGM_OPT_BIT_VAR_PKTLEN	0x40
12133804Sjulian#define PGM_OPT_BIT_PARITY	0x80
1221541Srgrimes
12333804Sjulian#define PGM_OPT_LENGTH		0x00
12433804Sjulian#define PGM_OPT_FRAGMENT        0x01
12533804Sjulian#define PGM_OPT_NAK_LIST        0x02
12633804Sjulian#define PGM_OPT_JOIN            0x03
12733804Sjulian#define PGM_OPT_NAK_BO_IVL	0x04
12833804Sjulian#define PGM_OPT_NAK_BO_RNG	0x05
12933814Sjulian
13033804Sjulian#define PGM_OPT_REDIRECT        0x07
13133804Sjulian#define PGM_OPT_PARITY_PRM      0x08
13233804Sjulian#define PGM_OPT_PARITY_GRP      0x09
13333804Sjulian#define PGM_OPT_CURR_TGSIZE     0x0A
13433804Sjulian#define PGM_OPT_NBR_UNREACH	0x0B
13533804Sjulian#define PGM_OPT_PATH_NLA	0x0C
13633804Sjulian
13733804Sjulian#define PGM_OPT_SYN             0x0D
13833804Sjulian#define PGM_OPT_FIN             0x0E
13933804Sjulian#define PGM_OPT_RST             0x0F
1401541Srgrimes#define PGM_OPT_CR		0x10
14133804Sjulian#define PGM_OPT_CRQST		0x11
14233804Sjulian
14333804Sjulian#define PGM_OPT_PGMCC_DATA	0x12
14433804Sjulian#define PGM_OPT_PGMCC_FEEDBACK	0x13
14533804Sjulian
14617072Sjulian#define PGM_OPT_MASK		0x7f
1471541Srgrimes
1481541Srgrimes#define PGM_OPT_END		0x80    /* end of options marker */
1491541Srgrimes
1501541Srgrimes#define PGM_MIN_OPT_LEN		4
1511541Srgrimes
1521541Srgrimes#ifndef AFI_IP
15314195Speter#define AFI_IP		1
15414195Speter#define AFI_IP6	        2
15514195Speter#endif
15614195Speter
15714195Spetervoid
15814195Speterpgm_print(register const u_char *bp, register u_int length,
15914195Speter	  register const u_char *bp2)
16014195Speter{
16114195Speter	register const struct pgm_header *pgm;
16214195Speter	register const struct ip *ip;
16314195Speter	register char ch;
16414195Speter	u_int16_t sport, dport;
16514195Speter	int addr_size;
16614195Speter	const void *nla;
16714195Speter	int nla_af;
16814195Speter#ifdef INET6
16914195Speter	char nla_buf[INET6_ADDRSTRLEN];
17014195Speter	register const struct ip6_hdr *ip6;
17114195Speter#else
17214195Speter	char nla_buf[INET_ADDRSTRLEN];
17314195Speter#endif
17417541Speter	u_int8_t opt_type, opt_len, flags1, flags2;
17514195Speter	u_int32_t seq, opts_len, len, offset;
17614195Speter
17714195Speter	pgm = (struct pgm_header *)bp;
17814195Speter	ip = (struct ip *)bp2;
17914195Speter#ifdef INET6
18014195Speter	if (IP_V(ip) == 6)
18114195Speter		ip6 = (struct ip6_hdr *)bp2;
18214195Speter	else
18335304Sphk		ip6 = NULL;
18435304Sphk#else /* INET6 */
18535304Sphk	if (IP_V(ip) == 6) {
18635304Sphk		(void)printf("Can't handle IPv6");
18735304Sphk		return;
18835304Sphk	}
18935304Sphk#endif /* INET6 */
19035304Sphk	ch = '\0';
19135304Sphk	if (!TTEST(pgm->pgm_dport)) {
19235304Sphk#ifdef INET6
19335304Sphk		if (ip6) {
19414195Speter			(void)printf("%s > %s: [|pgm]",
19514195Speter				ip6addr_string(&ip6->ip6_src),
19614195Speter				ip6addr_string(&ip6->ip6_dst));
1971541Srgrimes			return;
19814195Speter		} else
1991541Srgrimes#endif /* INET6 */
20014195Speter		{
2011541Srgrimes			(void)printf("%s > %s: [|pgm]",
2021541Srgrimes				ipaddr_string(&ip->ip_src),
2031541Srgrimes				ipaddr_string(&ip->ip_dst));
2041541Srgrimes			return;
2051541Srgrimes		}
20614195Speter	}
20713491Speter
20835304Sphk	sport = EXTRACT_16BITS(&pgm->pgm_sport);
20935304Sphk	dport = EXTRACT_16BITS(&pgm->pgm_dport);
21013491Speter
21113491Speter#ifdef INET6
21217541Speter	if (ip6) {
21317541Speter		if (ip6->ip6_nxt == IPPROTO_PGM) {
21417541Speter			(void)printf("%s.%s > %s.%s: ",
21517541Speter				ip6addr_string(&ip6->ip6_src),
21617541Speter				tcpport_string(sport),
21717541Speter				ip6addr_string(&ip6->ip6_dst),
21817541Speter				tcpport_string(dport));
21917541Speter		} else {
2201541Srgrimes			(void)printf("%s > %s: ",
2211541Srgrimes				tcpport_string(sport), tcpport_string(dport));
2221541Srgrimes		}
22335919Sjb	} else
2241541Srgrimes#endif /*INET6*/
2251541Srgrimes	{
2261541Srgrimes		if (ip->ip_p == IPPROTO_PGM) {
2271541Srgrimes			(void)printf("%s.%s > %s.%s: ",
2281541Srgrimes				ipaddr_string(&ip->ip_src),
2291541Srgrimes				tcpport_string(sport),
2301541Srgrimes				ipaddr_string(&ip->ip_dst),
23135919Sjb				tcpport_string(dport));
2321541Srgrimes		} else {
2331541Srgrimes			(void)printf("%s > %s: ",
2341541Srgrimes				tcpport_string(sport), tcpport_string(dport));
2351541Srgrimes		}
2361541Srgrimes	}
23735919Sjb
2381541Srgrimes	TCHECK(*pgm);
2391541Srgrimes
2401541Srgrimes        (void)printf("PGM, length %u", pgm->pgm_length);
2411541Srgrimes
2421541Srgrimes        if (!vflag)
24335919Sjb            return;
2441541Srgrimes
2451541Srgrimes        if (length > pgm->pgm_length)
2461541Srgrimes            length = pgm->pgm_length;
2471541Srgrimes
24835919Sjb	(void)printf(" 0x%02x%02x%02x%02x%02x%02x ",
2491541Srgrimes		     pgm->pgm_gsid[0],
2501541Srgrimes                     pgm->pgm_gsid[1],
2511541Srgrimes                     pgm->pgm_gsid[2],
2521541Srgrimes		     pgm->pgm_gsid[3],
2531541Srgrimes                     pgm->pgm_gsid[4],
25435919Sjb                     pgm->pgm_gsid[5]);
25535919Sjb	switch (pgm->pgm_type) {
2561541Srgrimes	case PGM_SPM: {
25735919Sjb	    struct pgm_spm *spm;
25835919Sjb
25935919Sjb	    spm = (struct pgm_spm *)(pgm + 1);
2601541Srgrimes	    TCHECK(*spm);
2611541Srgrimes
2621541Srgrimes	    switch (EXTRACT_16BITS(&spm->pgms_nla_afi)) {
2631541Srgrimes	    case AFI_IP:
26435919Sjb		addr_size = sizeof(struct in_addr);
26535919Sjb		nla_af = AF_INET;
26635919Sjb		break;
26735919Sjb#ifdef INET6
2681541Srgrimes	    case AFI_IP6:
2691541Srgrimes		addr_size = sizeof(struct in6_addr);
2701541Srgrimes		nla_af = AF_INET6;
2711541Srgrimes		break;
2721541Srgrimes#endif
2731541Srgrimes	    default:
2741541Srgrimes		goto trunc;
2751541Srgrimes		break;
2761541Srgrimes	    }
2771541Srgrimes	    bp = (u_char *) (spm + 1);
2781541Srgrimes	    TCHECK2(*bp, addr_size);
2791541Srgrimes	    nla = bp;
2801541Srgrimes	    bp += addr_size;
2811541Srgrimes
2821541Srgrimes	    inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
2831541Srgrimes	    (void)printf("SPM seq %u trail %u lead %u nla %s",
2841541Srgrimes			 EXTRACT_32BITS(&spm->pgms_seq),
2851541Srgrimes                         EXTRACT_32BITS(&spm->pgms_trailseq),
2861541Srgrimes			 EXTRACT_32BITS(&spm->pgms_leadseq),
2871541Srgrimes                         nla_buf);
2881541Srgrimes	    break;
2891541Srgrimes	}
2901541Srgrimes
2911541Srgrimes	case PGM_POLL: {
2921541Srgrimes	    struct pgm_poll *poll;
2931541Srgrimes
2941541Srgrimes	    poll = (struct pgm_poll *)(pgm + 1);
2951541Srgrimes	    TCHECK(*poll);
2961541Srgrimes	    (void)printf("POLL seq %u round %u",
2971541Srgrimes			 EXTRACT_32BITS(&poll->pgmp_seq),
2981541Srgrimes                         EXTRACT_16BITS(&poll->pgmp_round));
2991541Srgrimes	    bp = (u_char *) (poll + 1);
3001541Srgrimes	    break;
3011541Srgrimes	}
3021541Srgrimes	case PGM_POLR: {
3031541Srgrimes	    struct pgm_polr *polr;
3041541Srgrimes	    u_int32_t ivl, rnd, mask;
3051541Srgrimes
3061541Srgrimes	    polr = (struct pgm_polr *)(pgm + 1);
3071541Srgrimes	    TCHECK(*polr);
3081541Srgrimes
3091541Srgrimes	    switch (EXTRACT_16BITS(&polr->pgmp_nla_afi)) {
3101541Srgrimes	    case AFI_IP:
3112531Swollman		addr_size = sizeof(struct in_addr);
3122531Swollman		nla_af = AF_INET;
3132531Swollman		break;
3149209Swollman#ifdef INET6
3159209Swollman	    case AFI_IP6:
31614195Speter		addr_size = sizeof(struct in6_addr);
31719622Sfenner		nla_af = AF_INET6;
3181541Srgrimes		break;
31917758Ssos#endif
32017758Ssos	    default:
32117758Ssos		goto trunc;
32219035Salex		break;
32317758Ssos	    }
32417758Ssos	    bp = (u_char *) (polr + 1);
32517758Ssos	    TCHECK2(*bp, addr_size);
3261541Srgrimes	    nla = bp;
3271541Srgrimes	    bp += addr_size;
3281541Srgrimes
3291541Srgrimes	    inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf));
3301541Srgrimes
3319209Swollman	    TCHECK2(*bp, sizeof(u_int32_t));
3321541Srgrimes	    ivl = EXTRACT_32BITS(bp);
3331541Srgrimes	    bp += sizeof(u_int32_t);
3341541Srgrimes
3351541Srgrimes	    TCHECK2(*bp, sizeof(u_int32_t));
3361541Srgrimes	    rnd = EXTRACT_32BITS(bp);
3371541Srgrimes	    bp += sizeof(u_int32_t);
3381541Srgrimes
3391541Srgrimes	    TCHECK2(*bp, sizeof(u_int32_t));
3401541Srgrimes	    mask = EXTRACT_32BITS(bp);
3411541Srgrimes	    bp += sizeof(u_int32_t);
34214195Speter
34314195Speter	    (void)printf("POLR seq %u round %u nla %s ivl %u rnd 0x%08x "
34414195Speter			 "mask 0x%08x", EXTRACT_32BITS(&polr->pgmp_seq),
34514195Speter			 EXTRACT_16BITS(&polr->pgmp_round), nla_buf, ivl, rnd, mask);
34614195Speter	    break;
34714195Speter	}
34814195Speter	case PGM_ODATA: {
34914195Speter	    struct pgm_data *odata;
3501541Srgrimes
3511541Srgrimes	    odata = (struct pgm_data *)(pgm + 1);
3521541Srgrimes	    TCHECK(*odata);
3531541Srgrimes	    (void)printf("ODATA trail %u seq %u",
3541541Srgrimes			 EXTRACT_32BITS(&odata->pgmd_trailseq),
3551541Srgrimes			 EXTRACT_32BITS(&odata->pgmd_seq));
3561541Srgrimes	    bp = (u_char *) (odata + 1);
3571541Srgrimes	    break;
3581541Srgrimes	}
3591541Srgrimes
3601541Srgrimes	case PGM_RDATA: {
3611541Srgrimes	    struct pgm_data *rdata;
3621541Srgrimes
3631541Srgrimes	    rdata = (struct pgm_data *)(pgm + 1);
3641541Srgrimes	    TCHECK(*rdata);
3651541Srgrimes	    (void)printf("RDATA trail %u seq %u",
3661541Srgrimes			 EXTRACT_32BITS(&rdata->pgmd_trailseq),
3671541Srgrimes			 EXTRACT_32BITS(&rdata->pgmd_seq));
3681541Srgrimes	    bp = (u_char *) (rdata + 1);
3691541Srgrimes	    break;
3701541Srgrimes	}
3711541Srgrimes
3721541Srgrimes	case PGM_NAK:
3731541Srgrimes	case PGM_NULLNAK:
3741541Srgrimes	case PGM_NCF: {
3751541Srgrimes	    struct pgm_nak *nak;
3761541Srgrimes	    const void *source, *group;
3771541Srgrimes	    int source_af, group_af;
3781541Srgrimes#ifdef INET6
3791541Srgrimes	    char source_buf[INET6_ADDRSTRLEN], group_buf[INET6_ADDRSTRLEN];
3801541Srgrimes#else
3811541Srgrimes	    char source_buf[INET_ADDRSTRLEN], group_buf[INET_ADDRSTRLEN];
3821541Srgrimes#endif
3831541Srgrimes
3841541Srgrimes	    nak = (struct pgm_nak *)(pgm + 1);
3851541Srgrimes	    TCHECK(*nak);
3861541Srgrimes
3871541Srgrimes	    /*
3881541Srgrimes	     * Skip past the source, saving info along the way
3891541Srgrimes	     * and stopping if we don't have enough.
3901541Srgrimes	     */
3911541Srgrimes	    switch (EXTRACT_16BITS(&nak->pgmn_source_afi)) {
3925109Swollman	    case AFI_IP:
3936399Swollman		addr_size = sizeof(struct in_addr);
3946399Swollman		source_af = AF_INET;
3957091Swollman		break;
3969575Speter#ifdef INET6
39712003Swollman	    case AFI_IP6:
39812003Swollman		addr_size = sizeof(struct in6_addr);
39929838Swollman		source_af = AF_INET6;
40033440Sguido		break;
40136192Sdg#endif
40236192Sdg	    default:
4031541Srgrimes		goto trunc;
4041541Srgrimes		break;
4051541Srgrimes	    }
4061541Srgrimes	    bp = (u_char *) (nak + 1);
4071541Srgrimes	    TCHECK2(*bp, addr_size);
4081541Srgrimes	    source = bp;
4091541Srgrimes	    bp += addr_size;
4105109Swollman
4116399Swollman	    /*
4126399Swollman	     * Skip past the group, saving info along the way
4137091Swollman	     * and stopping if we don't have enough.
4149575Speter	     */
41512003Swollman	    switch (EXTRACT_16BITS(bp)) {
41612003Swollman	    case AFI_IP:
41729838Swollman		addr_size = sizeof(struct in_addr);
41833440Sguido		group_af = AF_INET;
41936192Sdg		break;
4201541Srgrimes#ifdef INET6
4211541Srgrimes	    case AFI_IP6:
4221541Srgrimes		addr_size = sizeof(struct in6_addr);
4231541Srgrimes		group_af = AF_INET6;
4247088Swollman		break;
4257088Swollman#endif
4261541Srgrimes	    default:
4271541Srgrimes		goto trunc;
4281541Srgrimes		break;
4291541Srgrimes	    }
4307088Swollman	    bp += (2 * sizeof(u_int16_t));
4312169Spaul	    TCHECK2(*bp, addr_size);
43215026Sphk	    group = bp;
43315026Sphk	    bp += addr_size;
43417758Ssos
43517758Ssos	    /*
43617758Ssos	     * Options decoding can go here.
43717758Ssos	     */
43817758Ssos	    inet_ntop(source_af, source, source_buf, sizeof(source_buf));
43919035Salex	    inet_ntop(group_af, group, group_buf, sizeof(group_buf));
44019113Ssos	    switch (pgm->pgm_type) {
44117758Ssos		case PGM_NAK:
44217758Ssos		    (void)printf("NAK ");
44317758Ssos		    break;
44417758Ssos		case PGM_NULLNAK:
44517758Ssos		    (void)printf("NNAK ");
44617758Ssos		    break;
44715026Sphk		case PGM_NCF:
44815026Sphk		    (void)printf("NCF ");
4492169Spaul		    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