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