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