xref: /netbsd/external/bsd/tcpdump/dist/print-pgm.c (revision 141b0ad2)
1546f56c3Schristos /*
2546f56c3Schristos  * Redistribution and use in source and binary forms, with or without
3546f56c3Schristos  * modification, are permitted provided that: (1) source code
4546f56c3Schristos  * distributions retain the above copyright notice and this paragraph
5546f56c3Schristos  * in its entirety, and (2) distributions including binary code include
6546f56c3Schristos  * the above copyright notice and this paragraph in its entirety in
7546f56c3Schristos  * the documentation or other materials provided with the distribution.
8546f56c3Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
9546f56c3Schristos  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
10546f56c3Schristos  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
11546f56c3Schristos  * FOR A PARTICULAR PURPOSE.
12546f56c3Schristos  *
13546f56c3Schristos  * Original code by Andy Heffernan (ahh@juniper.net)
14546f56c3Schristos  */
15546f56c3Schristos 
16c8632dc8Schristos #include <sys/cdefs.h>
17546f56c3Schristos #ifndef lint
18*141b0ad2Skamil __RCSID("$NetBSD: print-pgm.c,v 1.10 2020/02/24 18:39:47 kamil Exp $");
19546f56c3Schristos #endif
20546f56c3Schristos 
21c767dfb8Sspz /* \summary: Pragmatic General Multicast (PGM) printer */
22c767dfb8Sspz 
23546f56c3Schristos #ifdef HAVE_CONFIG_H
24546f56c3Schristos #include "config.h"
25546f56c3Schristos #endif
26546f56c3Schristos 
27c746cb4fSchristos #include <netdissect-stdinc.h>
28546f56c3Schristos 
29c746cb4fSchristos #include "netdissect.h"
30546f56c3Schristos #include "extract.h"
31546f56c3Schristos #include "addrtoname.h"
32c746cb4fSchristos #include "addrtostr.h"
33546f56c3Schristos 
34546f56c3Schristos #include "ip.h"
35546f56c3Schristos #include "ip6.h"
36546f56c3Schristos #include "ipproto.h"
377e4823a9Schristos #include "af.h"
38546f56c3Schristos 
39546f56c3Schristos /*
40546f56c3Schristos  * PGM header (RFC 3208)
41546f56c3Schristos  */
42546f56c3Schristos struct pgm_header {
437e4823a9Schristos     uint16_t	pgm_sport;
447e4823a9Schristos     uint16_t	pgm_dport;
457e4823a9Schristos     uint8_t	pgm_type;
467e4823a9Schristos     uint8_t	pgm_options;
477e4823a9Schristos     uint16_t	pgm_sum;
487e4823a9Schristos     uint8_t	pgm_gsid[6];
497e4823a9Schristos     uint16_t	pgm_length;
50546f56c3Schristos };
51546f56c3Schristos 
52546f56c3Schristos struct pgm_spm {
537e4823a9Schristos     uint32_t	pgms_seq;
547e4823a9Schristos     uint32_t	pgms_trailseq;
557e4823a9Schristos     uint32_t	pgms_leadseq;
567e4823a9Schristos     uint16_t	pgms_nla_afi;
577e4823a9Schristos     uint16_t	pgms_reserved;
587e4823a9Schristos     /* ... uint8_t	pgms_nla[0]; */
59546f56c3Schristos     /* ... options */
60546f56c3Schristos };
61546f56c3Schristos 
62546f56c3Schristos struct pgm_nak {
637e4823a9Schristos     uint32_t	pgmn_seq;
647e4823a9Schristos     uint16_t	pgmn_source_afi;
657e4823a9Schristos     uint16_t	pgmn_reserved;
667e4823a9Schristos     /* ... uint8_t	pgmn_source[0]; */
677e4823a9Schristos     /* ... uint16_t	pgmn_group_afi */
687e4823a9Schristos     /* ... uint16_t	pgmn_reserved2; */
697e4823a9Schristos     /* ... uint8_t	pgmn_group[0]; */
70546f56c3Schristos     /* ... options */
71546f56c3Schristos };
72546f56c3Schristos 
737becbaa8Schristos struct pgm_ack {
747e4823a9Schristos     uint32_t	pgma_rx_max_seq;
757e4823a9Schristos     uint32_t	pgma_bitmap;
767becbaa8Schristos     /* ... options */
777becbaa8Schristos };
787becbaa8Schristos 
79546f56c3Schristos struct pgm_poll {
807e4823a9Schristos     uint32_t	pgmp_seq;
817e4823a9Schristos     uint16_t	pgmp_round;
827e4823a9Schristos     uint16_t	pgmp_reserved;
83546f56c3Schristos     /* ... options */
84546f56c3Schristos };
85546f56c3Schristos 
86546f56c3Schristos struct pgm_polr {
877e4823a9Schristos     uint32_t	pgmp_seq;
887e4823a9Schristos     uint16_t	pgmp_round;
897e4823a9Schristos     uint16_t	pgmp_subtype;
907e4823a9Schristos     uint16_t	pgmp_nla_afi;
917e4823a9Schristos     uint16_t	pgmp_reserved;
927e4823a9Schristos     /* ... uint8_t	pgmp_nla[0]; */
93546f56c3Schristos     /* ... options */
94546f56c3Schristos };
95546f56c3Schristos 
96546f56c3Schristos struct pgm_data {
977e4823a9Schristos     uint32_t	pgmd_seq;
987e4823a9Schristos     uint32_t	pgmd_trailseq;
99546f56c3Schristos     /* ... options */
100546f56c3Schristos };
101546f56c3Schristos 
102546f56c3Schristos typedef enum _pgm_type {
103546f56c3Schristos     PGM_SPM = 0,		/* source path message */
104546f56c3Schristos     PGM_POLL = 1,		/* POLL Request */
105546f56c3Schristos     PGM_POLR = 2,		/* POLL Response */
106546f56c3Schristos     PGM_ODATA = 4,		/* original data */
107546f56c3Schristos     PGM_RDATA = 5,		/* repair data */
108546f56c3Schristos     PGM_NAK = 8,		/* NAK */
109546f56c3Schristos     PGM_NULLNAK = 9,		/* Null NAK */
110546f56c3Schristos     PGM_NCF = 10,		/* NAK Confirmation */
111546f56c3Schristos     PGM_ACK = 11,		/* ACK for congestion control */
112546f56c3Schristos     PGM_SPMR = 12,		/* SPM request */
113546f56c3Schristos     PGM_MAX = 255
114546f56c3Schristos } pgm_type;
115546f56c3Schristos 
116546f56c3Schristos #define PGM_OPT_BIT_PRESENT	0x01
117546f56c3Schristos #define PGM_OPT_BIT_NETWORK	0x02
118546f56c3Schristos #define PGM_OPT_BIT_VAR_PKTLEN	0x40
119546f56c3Schristos #define PGM_OPT_BIT_PARITY	0x80
120546f56c3Schristos 
121546f56c3Schristos #define PGM_OPT_LENGTH		0x00
122546f56c3Schristos #define PGM_OPT_FRAGMENT        0x01
123546f56c3Schristos #define PGM_OPT_NAK_LIST        0x02
124546f56c3Schristos #define PGM_OPT_JOIN            0x03
125546f56c3Schristos #define PGM_OPT_NAK_BO_IVL	0x04
126546f56c3Schristos #define PGM_OPT_NAK_BO_RNG	0x05
127546f56c3Schristos 
128546f56c3Schristos #define PGM_OPT_REDIRECT        0x07
129546f56c3Schristos #define PGM_OPT_PARITY_PRM      0x08
130546f56c3Schristos #define PGM_OPT_PARITY_GRP      0x09
131546f56c3Schristos #define PGM_OPT_CURR_TGSIZE     0x0A
132546f56c3Schristos #define PGM_OPT_NBR_UNREACH	0x0B
133546f56c3Schristos #define PGM_OPT_PATH_NLA	0x0C
134546f56c3Schristos 
135546f56c3Schristos #define PGM_OPT_SYN             0x0D
136546f56c3Schristos #define PGM_OPT_FIN             0x0E
137546f56c3Schristos #define PGM_OPT_RST             0x0F
138546f56c3Schristos #define PGM_OPT_CR		0x10
139546f56c3Schristos #define PGM_OPT_CRQST		0x11
140546f56c3Schristos 
1417becbaa8Schristos #define PGM_OPT_PGMCC_DATA	0x12
1427becbaa8Schristos #define PGM_OPT_PGMCC_FEEDBACK	0x13
1437becbaa8Schristos 
144546f56c3Schristos #define PGM_OPT_MASK		0x7f
145546f56c3Schristos 
146546f56c3Schristos #define PGM_OPT_END		0x80    /* end of options marker */
147546f56c3Schristos 
148546f56c3Schristos #define PGM_MIN_OPT_LEN		4
149546f56c3Schristos 
150*141b0ad2Skamil UNALIGNED_OK
151546f56c3Schristos void
pgm_print(netdissect_options * ndo,register const u_char * bp,register u_int length,register const u_char * bp2)1527e4823a9Schristos pgm_print(netdissect_options *ndo,
1537e4823a9Schristos           register const u_char *bp, register u_int length,
154546f56c3Schristos           register const u_char *bp2)
155546f56c3Schristos {
156546f56c3Schristos 	register const struct pgm_header *pgm;
157546f56c3Schristos 	register const struct ip *ip;
158546f56c3Schristos 	register char ch;
1597e4823a9Schristos 	uint16_t sport, dport;
160c746cb4fSchristos 	u_int nla_afnum;
161546f56c3Schristos 	char nla_buf[INET6_ADDRSTRLEN];
162546f56c3Schristos 	register const struct ip6_hdr *ip6;
1637e4823a9Schristos 	uint8_t opt_type, opt_len;
1647e4823a9Schristos 	uint32_t seq, opts_len, len, offset;
165546f56c3Schristos 
166c746cb4fSchristos 	pgm = (const struct pgm_header *)bp;
167c746cb4fSchristos 	ip = (const struct ip *)bp2;
168546f56c3Schristos 	if (IP_V(ip) == 6)
169c746cb4fSchristos 		ip6 = (const struct ip6_hdr *)bp2;
170546f56c3Schristos 	else
171546f56c3Schristos 		ip6 = NULL;
172546f56c3Schristos 	ch = '\0';
1737e4823a9Schristos 	if (!ND_TTEST(pgm->pgm_dport)) {
174546f56c3Schristos 		if (ip6) {
1757e4823a9Schristos 			ND_PRINT((ndo, "%s > %s: [|pgm]",
1767e4823a9Schristos 				ip6addr_string(ndo, &ip6->ip6_src),
1777e4823a9Schristos 				ip6addr_string(ndo, &ip6->ip6_dst)));
178c746cb4fSchristos 		} else {
1797e4823a9Schristos 			ND_PRINT((ndo, "%s > %s: [|pgm]",
1807e4823a9Schristos 				ipaddr_string(ndo, &ip->ip_src),
1817e4823a9Schristos 				ipaddr_string(ndo, &ip->ip_dst)));
182546f56c3Schristos 		}
1831c9cc6b1Schristos 		return;
184546f56c3Schristos 	}
185546f56c3Schristos 
186546f56c3Schristos 	sport = EXTRACT_16BITS(&pgm->pgm_sport);
187546f56c3Schristos 	dport = EXTRACT_16BITS(&pgm->pgm_dport);
188546f56c3Schristos 
189546f56c3Schristos 	if (ip6) {
190546f56c3Schristos 		if (ip6->ip6_nxt == IPPROTO_PGM) {
1917e4823a9Schristos 			ND_PRINT((ndo, "%s.%s > %s.%s: ",
1927e4823a9Schristos 				ip6addr_string(ndo, &ip6->ip6_src),
193c746cb4fSchristos 				tcpport_string(ndo, sport),
1947e4823a9Schristos 				ip6addr_string(ndo, &ip6->ip6_dst),
195c746cb4fSchristos 				tcpport_string(ndo, dport)));
196546f56c3Schristos 		} else {
1977e4823a9Schristos 			ND_PRINT((ndo, "%s > %s: ",
198c746cb4fSchristos 				tcpport_string(ndo, sport), tcpport_string(ndo, dport)));
199546f56c3Schristos 		}
200c746cb4fSchristos 	} else {
201546f56c3Schristos 		if (ip->ip_p == IPPROTO_PGM) {
2027e4823a9Schristos 			ND_PRINT((ndo, "%s.%s > %s.%s: ",
2037e4823a9Schristos 				ipaddr_string(ndo, &ip->ip_src),
204c746cb4fSchristos 				tcpport_string(ndo, sport),
2057e4823a9Schristos 				ipaddr_string(ndo, &ip->ip_dst),
206c746cb4fSchristos 				tcpport_string(ndo, dport)));
207546f56c3Schristos 		} else {
2087e4823a9Schristos 			ND_PRINT((ndo, "%s > %s: ",
209c746cb4fSchristos 				tcpport_string(ndo, sport), tcpport_string(ndo, dport)));
210546f56c3Schristos 		}
211546f56c3Schristos 	}
212546f56c3Schristos 
2137e4823a9Schristos 	ND_TCHECK(*pgm);
214546f56c3Schristos 
2157e4823a9Schristos         ND_PRINT((ndo, "PGM, length %u", EXTRACT_16BITS(&pgm->pgm_length)));
216546f56c3Schristos 
2177e4823a9Schristos         if (!ndo->ndo_vflag)
218546f56c3Schristos             return;
219546f56c3Schristos 
2207e4823a9Schristos 	ND_PRINT((ndo, " 0x%02x%02x%02x%02x%02x%02x ",
221546f56c3Schristos 		     pgm->pgm_gsid[0],
222546f56c3Schristos                      pgm->pgm_gsid[1],
223546f56c3Schristos                      pgm->pgm_gsid[2],
224546f56c3Schristos 		     pgm->pgm_gsid[3],
225546f56c3Schristos                      pgm->pgm_gsid[4],
2267e4823a9Schristos                      pgm->pgm_gsid[5]));
227546f56c3Schristos 	switch (pgm->pgm_type) {
228546f56c3Schristos 	case PGM_SPM: {
229c746cb4fSchristos 	    const struct pgm_spm *spm;
230546f56c3Schristos 
231c746cb4fSchristos 	    spm = (const struct pgm_spm *)(pgm + 1);
2327e4823a9Schristos 	    ND_TCHECK(*spm);
233c746cb4fSchristos 	    bp = (const u_char *) (spm + 1);
234546f56c3Schristos 
235546f56c3Schristos 	    switch (EXTRACT_16BITS(&spm->pgms_nla_afi)) {
2367e4823a9Schristos 	    case AFNUM_INET:
237c746cb4fSchristos 		ND_TCHECK2(*bp, sizeof(struct in_addr));
238c746cb4fSchristos 		addrtostr(bp, nla_buf, sizeof(nla_buf));
239c746cb4fSchristos 		bp += sizeof(struct in_addr);
240546f56c3Schristos 		break;
2417e4823a9Schristos 	    case AFNUM_INET6:
242c746cb4fSchristos 		ND_TCHECK2(*bp, sizeof(struct in6_addr));
243c746cb4fSchristos 		addrtostr6(bp, nla_buf, sizeof(nla_buf));
244c746cb4fSchristos 		bp += sizeof(struct in6_addr);
245546f56c3Schristos 		break;
246546f56c3Schristos 	    default:
247546f56c3Schristos 		goto trunc;
248546f56c3Schristos 		break;
249546f56c3Schristos 	    }
250546f56c3Schristos 
2517e4823a9Schristos 	    ND_PRINT((ndo, "SPM seq %u trail %u lead %u nla %s",
252546f56c3Schristos 			 EXTRACT_32BITS(&spm->pgms_seq),
253546f56c3Schristos                          EXTRACT_32BITS(&spm->pgms_trailseq),
254546f56c3Schristos 			 EXTRACT_32BITS(&spm->pgms_leadseq),
2557e4823a9Schristos                          nla_buf));
256546f56c3Schristos 	    break;
257546f56c3Schristos 	}
258546f56c3Schristos 
259546f56c3Schristos 	case PGM_POLL: {
260c746cb4fSchristos 	    const struct pgm_poll *poll_msg;
261546f56c3Schristos 
262c746cb4fSchristos 	    poll_msg = (const struct pgm_poll *)(pgm + 1);
263c746cb4fSchristos 	    ND_TCHECK(*poll_msg);
2647e4823a9Schristos 	    ND_PRINT((ndo, "POLL seq %u round %u",
265c746cb4fSchristos 			 EXTRACT_32BITS(&poll_msg->pgmp_seq),
266c746cb4fSchristos                          EXTRACT_16BITS(&poll_msg->pgmp_round)));
267c746cb4fSchristos 	    bp = (const u_char *) (poll_msg + 1);
268546f56c3Schristos 	    break;
269546f56c3Schristos 	}
270546f56c3Schristos 	case PGM_POLR: {
271c746cb4fSchristos 	    const struct pgm_polr *polr;
2727e4823a9Schristos 	    uint32_t ivl, rnd, mask;
273546f56c3Schristos 
274c746cb4fSchristos 	    polr = (const struct pgm_polr *)(pgm + 1);
2757e4823a9Schristos 	    ND_TCHECK(*polr);
276c746cb4fSchristos 	    bp = (const u_char *) (polr + 1);
277546f56c3Schristos 
278546f56c3Schristos 	    switch (EXTRACT_16BITS(&polr->pgmp_nla_afi)) {
2797e4823a9Schristos 	    case AFNUM_INET:
280c746cb4fSchristos 		ND_TCHECK2(*bp, sizeof(struct in_addr));
281c746cb4fSchristos 		addrtostr(bp, nla_buf, sizeof(nla_buf));
282c746cb4fSchristos 		bp += sizeof(struct in_addr);
283546f56c3Schristos 		break;
2847e4823a9Schristos 	    case AFNUM_INET6:
285c746cb4fSchristos 		ND_TCHECK2(*bp, sizeof(struct in6_addr));
286c746cb4fSchristos 		addrtostr6(bp, nla_buf, sizeof(nla_buf));
287c746cb4fSchristos 		bp += sizeof(struct in6_addr);
288546f56c3Schristos 		break;
289546f56c3Schristos 	    default:
290546f56c3Schristos 		goto trunc;
291546f56c3Schristos 		break;
292546f56c3Schristos 	    }
293546f56c3Schristos 
2947e4823a9Schristos 	    ND_TCHECK2(*bp, sizeof(uint32_t));
295546f56c3Schristos 	    ivl = EXTRACT_32BITS(bp);
2967e4823a9Schristos 	    bp += sizeof(uint32_t);
297546f56c3Schristos 
2987e4823a9Schristos 	    ND_TCHECK2(*bp, sizeof(uint32_t));
299546f56c3Schristos 	    rnd = EXTRACT_32BITS(bp);
3007e4823a9Schristos 	    bp += sizeof(uint32_t);
301546f56c3Schristos 
3027e4823a9Schristos 	    ND_TCHECK2(*bp, sizeof(uint32_t));
303546f56c3Schristos 	    mask = EXTRACT_32BITS(bp);
3047e4823a9Schristos 	    bp += sizeof(uint32_t);
305546f56c3Schristos 
3067e4823a9Schristos 	    ND_PRINT((ndo, "POLR seq %u round %u nla %s ivl %u rnd 0x%08x "
307546f56c3Schristos 			 "mask 0x%08x", EXTRACT_32BITS(&polr->pgmp_seq),
3087e4823a9Schristos 			 EXTRACT_16BITS(&polr->pgmp_round), nla_buf, ivl, rnd, mask));
309546f56c3Schristos 	    break;
310546f56c3Schristos 	}
311546f56c3Schristos 	case PGM_ODATA: {
312c746cb4fSchristos 	    const struct pgm_data *odata;
313546f56c3Schristos 
314c746cb4fSchristos 	    odata = (const struct pgm_data *)(pgm + 1);
3157e4823a9Schristos 	    ND_TCHECK(*odata);
3167e4823a9Schristos 	    ND_PRINT((ndo, "ODATA trail %u seq %u",
317546f56c3Schristos 			 EXTRACT_32BITS(&odata->pgmd_trailseq),
3187e4823a9Schristos 			 EXTRACT_32BITS(&odata->pgmd_seq)));
319c746cb4fSchristos 	    bp = (const u_char *) (odata + 1);
320546f56c3Schristos 	    break;
321546f56c3Schristos 	}
322546f56c3Schristos 
323546f56c3Schristos 	case PGM_RDATA: {
324c746cb4fSchristos 	    const struct pgm_data *rdata;
325546f56c3Schristos 
326c746cb4fSchristos 	    rdata = (const struct pgm_data *)(pgm + 1);
3277e4823a9Schristos 	    ND_TCHECK(*rdata);
3287e4823a9Schristos 	    ND_PRINT((ndo, "RDATA trail %u seq %u",
329546f56c3Schristos 			 EXTRACT_32BITS(&rdata->pgmd_trailseq),
3307e4823a9Schristos 			 EXTRACT_32BITS(&rdata->pgmd_seq)));
331c746cb4fSchristos 	    bp = (const u_char *) (rdata + 1);
332546f56c3Schristos 	    break;
333546f56c3Schristos 	}
334546f56c3Schristos 
335546f56c3Schristos 	case PGM_NAK:
336546f56c3Schristos 	case PGM_NULLNAK:
337546f56c3Schristos 	case PGM_NCF: {
338c746cb4fSchristos 	    const struct pgm_nak *nak;
339546f56c3Schristos 	    char source_buf[INET6_ADDRSTRLEN], group_buf[INET6_ADDRSTRLEN];
340546f56c3Schristos 
341c746cb4fSchristos 	    nak = (const struct pgm_nak *)(pgm + 1);
3427e4823a9Schristos 	    ND_TCHECK(*nak);
343c746cb4fSchristos 	    bp = (const u_char *) (nak + 1);
344546f56c3Schristos 
345546f56c3Schristos 	    /*
346546f56c3Schristos 	     * Skip past the source, saving info along the way
347546f56c3Schristos 	     * and stopping if we don't have enough.
348546f56c3Schristos 	     */
349546f56c3Schristos 	    switch (EXTRACT_16BITS(&nak->pgmn_source_afi)) {
3507e4823a9Schristos 	    case AFNUM_INET:
351c746cb4fSchristos 		ND_TCHECK2(*bp, sizeof(struct in_addr));
352c746cb4fSchristos 		addrtostr(bp, source_buf, sizeof(source_buf));
353c746cb4fSchristos 		bp += sizeof(struct in_addr);
354546f56c3Schristos 		break;
3557e4823a9Schristos 	    case AFNUM_INET6:
356c746cb4fSchristos 		ND_TCHECK2(*bp, sizeof(struct in6_addr));
357c746cb4fSchristos 		addrtostr6(bp, source_buf, sizeof(source_buf));
358c746cb4fSchristos 		bp += sizeof(struct in6_addr);
359546f56c3Schristos 		break;
360546f56c3Schristos 	    default:
361546f56c3Schristos 		goto trunc;
362546f56c3Schristos 		break;
363546f56c3Schristos 	    }
364546f56c3Schristos 
365546f56c3Schristos 	    /*
366546f56c3Schristos 	     * Skip past the group, saving info along the way
367546f56c3Schristos 	     * and stopping if we don't have enough.
368546f56c3Schristos 	     */
369c746cb4fSchristos 	    bp += (2 * sizeof(uint16_t));
3701c9cc6b1Schristos 	    ND_TCHECK_16BITS(bp);
371546f56c3Schristos 	    switch (EXTRACT_16BITS(bp)) {
3727e4823a9Schristos 	    case AFNUM_INET:
373c746cb4fSchristos 		ND_TCHECK2(*bp, sizeof(struct in_addr));
374c746cb4fSchristos 		addrtostr(bp, group_buf, sizeof(group_buf));
375c746cb4fSchristos 		bp += sizeof(struct in_addr);
376546f56c3Schristos 		break;
3777e4823a9Schristos 	    case AFNUM_INET6:
378c746cb4fSchristos 		ND_TCHECK2(*bp, sizeof(struct in6_addr));
379c746cb4fSchristos 		addrtostr6(bp, group_buf, sizeof(group_buf));
380c746cb4fSchristos 		bp += sizeof(struct in6_addr);
381546f56c3Schristos 		break;
382546f56c3Schristos 	    default:
383546f56c3Schristos 		goto trunc;
384546f56c3Schristos 		break;
385546f56c3Schristos 	    }
386546f56c3Schristos 
387546f56c3Schristos 	    /*
388546f56c3Schristos 	     * Options decoding can go here.
389546f56c3Schristos 	     */
390546f56c3Schristos 	    switch (pgm->pgm_type) {
391546f56c3Schristos 		case PGM_NAK:
3927e4823a9Schristos 		    ND_PRINT((ndo, "NAK "));
393546f56c3Schristos 		    break;
394546f56c3Schristos 		case PGM_NULLNAK:
3957e4823a9Schristos 		    ND_PRINT((ndo, "NNAK "));
396546f56c3Schristos 		    break;
397546f56c3Schristos 		case PGM_NCF:
3987e4823a9Schristos 		    ND_PRINT((ndo, "NCF "));
399546f56c3Schristos 		    break;
400546f56c3Schristos 		default:
401546f56c3Schristos                     break;
402546f56c3Schristos 	    }
4037e4823a9Schristos 	    ND_PRINT((ndo, "(%s -> %s), seq %u",
4047e4823a9Schristos 			 source_buf, group_buf, EXTRACT_32BITS(&nak->pgmn_seq)));
405546f56c3Schristos 	    break;
406546f56c3Schristos 	}
407546f56c3Schristos 
4087becbaa8Schristos 	case PGM_ACK: {
409c746cb4fSchristos 	    const struct pgm_ack *ack;
4107becbaa8Schristos 
411c746cb4fSchristos 	    ack = (const struct pgm_ack *)(pgm + 1);
4127e4823a9Schristos 	    ND_TCHECK(*ack);
4137e4823a9Schristos 	    ND_PRINT((ndo, "ACK seq %u",
4147e4823a9Schristos 			 EXTRACT_32BITS(&ack->pgma_rx_max_seq)));
415c746cb4fSchristos 	    bp = (const u_char *) (ack + 1);
4167becbaa8Schristos 	    break;
4177becbaa8Schristos 	}
4187becbaa8Schristos 
419546f56c3Schristos 	case PGM_SPMR:
4207e4823a9Schristos 	    ND_PRINT((ndo, "SPMR"));
421546f56c3Schristos 	    break;
422546f56c3Schristos 
423546f56c3Schristos 	default:
4247e4823a9Schristos 	    ND_PRINT((ndo, "UNKNOWN type 0x%02x", pgm->pgm_type));
425546f56c3Schristos 	    break;
426546f56c3Schristos 
427546f56c3Schristos 	}
428546f56c3Schristos 	if (pgm->pgm_options & PGM_OPT_BIT_PRESENT) {
429546f56c3Schristos 
430546f56c3Schristos 	    /*
431546f56c3Schristos 	     * make sure there's enough for the first option header
432546f56c3Schristos 	     */
4337e4823a9Schristos 	    if (!ND_TTEST2(*bp, PGM_MIN_OPT_LEN)) {
4347e4823a9Schristos 		ND_PRINT((ndo, "[|OPT]"));
435546f56c3Schristos 		return;
436546f56c3Schristos 	    }
437546f56c3Schristos 
438546f56c3Schristos 	    /*
439546f56c3Schristos 	     * That option header MUST be an OPT_LENGTH option
440546f56c3Schristos 	     * (see the first paragraph of section 9.1 in RFC 3208).
441546f56c3Schristos 	     */
442546f56c3Schristos 	    opt_type = *bp++;
443546f56c3Schristos 	    if ((opt_type & PGM_OPT_MASK) != PGM_OPT_LENGTH) {
4447e4823a9Schristos 		ND_PRINT((ndo, "[First option bad, should be PGM_OPT_LENGTH, is %u]", opt_type & PGM_OPT_MASK));
445546f56c3Schristos 		return;
446546f56c3Schristos 	    }
447546f56c3Schristos 	    opt_len = *bp++;
448546f56c3Schristos 	    if (opt_len != 4) {
4497e4823a9Schristos 		ND_PRINT((ndo, "[Bad OPT_LENGTH option, length %u != 4]", opt_len));
450546f56c3Schristos 		return;
451546f56c3Schristos 	    }
452546f56c3Schristos 	    opts_len = EXTRACT_16BITS(bp);
453546f56c3Schristos 	    if (opts_len < 4) {
4547e4823a9Schristos 		ND_PRINT((ndo, "[Bad total option length %u < 4]", opts_len));
455546f56c3Schristos 		return;
456546f56c3Schristos 	    }
4577e4823a9Schristos 	    bp += sizeof(uint16_t);
4587e4823a9Schristos 	    ND_PRINT((ndo, " OPTS LEN %d", opts_len));
459546f56c3Schristos 	    opts_len -= 4;
460546f56c3Schristos 
461546f56c3Schristos 	    while (opts_len) {
462546f56c3Schristos 		if (opts_len < PGM_MIN_OPT_LEN) {
4637e4823a9Schristos 		    ND_PRINT((ndo, "[Total option length leaves no room for final option]"));
464546f56c3Schristos 		    return;
465546f56c3Schristos 		}
4661c9cc6b1Schristos 		if (!ND_TTEST2(*bp, 2)) {
4671c9cc6b1Schristos 		    ND_PRINT((ndo, " [|OPT]"));
4681c9cc6b1Schristos 		    return;
4691c9cc6b1Schristos 		}
470546f56c3Schristos 		opt_type = *bp++;
471546f56c3Schristos 		opt_len = *bp++;
472546f56c3Schristos 		if (opt_len < PGM_MIN_OPT_LEN) {
4737e4823a9Schristos 		    ND_PRINT((ndo, "[Bad option, length %u < %u]", opt_len,
4747e4823a9Schristos 		        PGM_MIN_OPT_LEN));
475546f56c3Schristos 		    break;
476546f56c3Schristos 		}
477546f56c3Schristos 		if (opts_len < opt_len) {
4787e4823a9Schristos 		    ND_PRINT((ndo, "[Total option length leaves no room for final option]"));
479546f56c3Schristos 		    return;
480546f56c3Schristos 		}
4817e4823a9Schristos 		if (!ND_TTEST2(*bp, opt_len - 2)) {
4827e4823a9Schristos 		    ND_PRINT((ndo, " [|OPT]"));
483546f56c3Schristos 		    return;
484546f56c3Schristos 		}
485546f56c3Schristos 
486546f56c3Schristos 		switch (opt_type & PGM_OPT_MASK) {
487546f56c3Schristos 		case PGM_OPT_LENGTH:
4881c9cc6b1Schristos #define PGM_OPT_LENGTH_LEN	(2+2)
4891c9cc6b1Schristos 		    if (opt_len != PGM_OPT_LENGTH_LEN) {
4901c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad OPT_LENGTH option, length %u != %u]",
4911c9cc6b1Schristos 			    opt_len, PGM_OPT_LENGTH_LEN));
492546f56c3Schristos 			return;
493546f56c3Schristos 		    }
4947e4823a9Schristos 		    ND_PRINT((ndo, " OPTS LEN (extra?) %d", EXTRACT_16BITS(bp)));
4951c9cc6b1Schristos 		    bp += 2;
4961c9cc6b1Schristos 		    opts_len -= PGM_OPT_LENGTH_LEN;
497546f56c3Schristos 		    break;
498546f56c3Schristos 
499546f56c3Schristos 		case PGM_OPT_FRAGMENT:
5001c9cc6b1Schristos #define PGM_OPT_FRAGMENT_LEN	(2+2+4+4+4)
5011c9cc6b1Schristos 		    if (opt_len != PGM_OPT_FRAGMENT_LEN) {
5021c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad OPT_FRAGMENT option, length %u != %u]",
5031c9cc6b1Schristos 			    opt_len, PGM_OPT_FRAGMENT_LEN));
504546f56c3Schristos 			return;
505546f56c3Schristos 		    }
5067e4823a9Schristos 		    bp += 2;
507546f56c3Schristos 		    seq = EXTRACT_32BITS(bp);
5081c9cc6b1Schristos 		    bp += 4;
509546f56c3Schristos 		    offset = EXTRACT_32BITS(bp);
5101c9cc6b1Schristos 		    bp += 4;
511546f56c3Schristos 		    len = EXTRACT_32BITS(bp);
5121c9cc6b1Schristos 		    bp += 4;
5137e4823a9Schristos 		    ND_PRINT((ndo, " FRAG seq %u off %u len %u", seq, offset, len));
5141c9cc6b1Schristos 		    opts_len -= PGM_OPT_FRAGMENT_LEN;
515546f56c3Schristos 		    break;
516546f56c3Schristos 
517546f56c3Schristos 		case PGM_OPT_NAK_LIST:
5187e4823a9Schristos 		    bp += 2;
5191c9cc6b1Schristos 		    opt_len -= 4;	/* option header */
5207e4823a9Schristos 		    ND_PRINT((ndo, " NAK LIST"));
521546f56c3Schristos 		    while (opt_len) {
5221c9cc6b1Schristos 			if (opt_len < 4) {
5237e4823a9Schristos 			    ND_PRINT((ndo, "[Option length not a multiple of 4]"));
524546f56c3Schristos 			    return;
525546f56c3Schristos 			}
5261c9cc6b1Schristos 			ND_TCHECK2(*bp, 4);
5277e4823a9Schristos 			ND_PRINT((ndo, " %u", EXTRACT_32BITS(bp)));
5281c9cc6b1Schristos 			bp += 4;
5291c9cc6b1Schristos 			opt_len -= 4;
5301c9cc6b1Schristos 			opts_len -= 4;
531546f56c3Schristos 		    }
532546f56c3Schristos 		    break;
533546f56c3Schristos 
534546f56c3Schristos 		case PGM_OPT_JOIN:
5351c9cc6b1Schristos #define PGM_OPT_JOIN_LEN	(2+2+4)
5361c9cc6b1Schristos 		    if (opt_len != PGM_OPT_JOIN_LEN) {
5371c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad OPT_JOIN option, length %u != %u]",
5381c9cc6b1Schristos 			    opt_len, PGM_OPT_JOIN_LEN));
539546f56c3Schristos 			return;
540546f56c3Schristos 		    }
5417e4823a9Schristos 		    bp += 2;
542546f56c3Schristos 		    seq = EXTRACT_32BITS(bp);
5431c9cc6b1Schristos 		    bp += 4;
5447e4823a9Schristos 		    ND_PRINT((ndo, " JOIN %u", seq));
5451c9cc6b1Schristos 		    opts_len -= PGM_OPT_JOIN_LEN;
546546f56c3Schristos 		    break;
547546f56c3Schristos 
548546f56c3Schristos 		case PGM_OPT_NAK_BO_IVL:
5491c9cc6b1Schristos #define PGM_OPT_NAK_BO_IVL_LEN	(2+2+4+4)
5501c9cc6b1Schristos 		    if (opt_len != PGM_OPT_NAK_BO_IVL_LEN) {
5511c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad OPT_NAK_BO_IVL option, length %u != %u]",
5521c9cc6b1Schristos 			    opt_len, PGM_OPT_NAK_BO_IVL_LEN));
553546f56c3Schristos 			return;
554546f56c3Schristos 		    }
5557e4823a9Schristos 		    bp += 2;
556546f56c3Schristos 		    offset = EXTRACT_32BITS(bp);
5571c9cc6b1Schristos 		    bp += 4;
558546f56c3Schristos 		    seq = EXTRACT_32BITS(bp);
5591c9cc6b1Schristos 		    bp += 4;
5607e4823a9Schristos 		    ND_PRINT((ndo, " BACKOFF ivl %u ivlseq %u", offset, seq));
5611c9cc6b1Schristos 		    opts_len -= PGM_OPT_NAK_BO_IVL_LEN;
562546f56c3Schristos 		    break;
563546f56c3Schristos 
564546f56c3Schristos 		case PGM_OPT_NAK_BO_RNG:
5651c9cc6b1Schristos #define PGM_OPT_NAK_BO_RNG_LEN	(2+2+4+4)
5661c9cc6b1Schristos 		    if (opt_len != PGM_OPT_NAK_BO_RNG_LEN) {
5671c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad OPT_NAK_BO_RNG option, length %u != %u]",
5681c9cc6b1Schristos 			    opt_len, PGM_OPT_NAK_BO_RNG_LEN));
569546f56c3Schristos 			return;
570546f56c3Schristos 		    }
5717e4823a9Schristos 		    bp += 2;
572546f56c3Schristos 		    offset = EXTRACT_32BITS(bp);
5731c9cc6b1Schristos 		    bp += 4;
574546f56c3Schristos 		    seq = EXTRACT_32BITS(bp);
5751c9cc6b1Schristos 		    bp += 4;
5767e4823a9Schristos 		    ND_PRINT((ndo, " BACKOFF max %u min %u", offset, seq));
5771c9cc6b1Schristos 		    opts_len -= PGM_OPT_NAK_BO_RNG_LEN;
578546f56c3Schristos 		    break;
579546f56c3Schristos 
580546f56c3Schristos 		case PGM_OPT_REDIRECT:
5811c9cc6b1Schristos #define PGM_OPT_REDIRECT_FIXED_LEN	(2+2+2+2)
5821c9cc6b1Schristos 		    if (opt_len < PGM_OPT_REDIRECT_FIXED_LEN) {
5831c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad OPT_REDIRECT option, length %u < %u]",
5841c9cc6b1Schristos 			    opt_len, PGM_OPT_REDIRECT_FIXED_LEN));
5851c9cc6b1Schristos 			return;
5861c9cc6b1Schristos 		    }
5877e4823a9Schristos 		    bp += 2;
588c746cb4fSchristos 		    nla_afnum = EXTRACT_16BITS(bp);
5891c9cc6b1Schristos 		    bp += 2+2;
590c746cb4fSchristos 		    switch (nla_afnum) {
5917e4823a9Schristos 		    case AFNUM_INET:
5921c9cc6b1Schristos 			if (opt_len != PGM_OPT_REDIRECT_FIXED_LEN + sizeof(struct in_addr)) {
5931c9cc6b1Schristos 			    ND_PRINT((ndo, "[Bad OPT_REDIRECT option, length %u != %u + address size]",
5941c9cc6b1Schristos 			        opt_len, PGM_OPT_REDIRECT_FIXED_LEN));
595c746cb4fSchristos 			    return;
596c746cb4fSchristos 			}
597c746cb4fSchristos 			ND_TCHECK2(*bp, sizeof(struct in_addr));
598c746cb4fSchristos 			addrtostr(bp, nla_buf, sizeof(nla_buf));
599c746cb4fSchristos 			bp += sizeof(struct in_addr);
6001c9cc6b1Schristos 			opts_len -= PGM_OPT_REDIRECT_FIXED_LEN + sizeof(struct in_addr);
601546f56c3Schristos 			break;
6027e4823a9Schristos 		    case AFNUM_INET6:
6031c9cc6b1Schristos 			if (opt_len != PGM_OPT_REDIRECT_FIXED_LEN + sizeof(struct in6_addr)) {
6041c9cc6b1Schristos 			    ND_PRINT((ndo, "[Bad OPT_REDIRECT option, length %u != %u + address size]",
6051c9cc6b1Schristos 			        PGM_OPT_REDIRECT_FIXED_LEN, opt_len));
606c746cb4fSchristos 			    return;
607c746cb4fSchristos 			}
608c746cb4fSchristos 			ND_TCHECK2(*bp, sizeof(struct in6_addr));
609c746cb4fSchristos 			addrtostr6(bp, nla_buf, sizeof(nla_buf));
610c746cb4fSchristos 			bp += sizeof(struct in6_addr);
6111c9cc6b1Schristos 			opts_len -= PGM_OPT_REDIRECT_FIXED_LEN + sizeof(struct in6_addr);
612546f56c3Schristos 			break;
613546f56c3Schristos 		    default:
614546f56c3Schristos 			goto trunc;
615546f56c3Schristos 			break;
616546f56c3Schristos 		    }
617546f56c3Schristos 
618c746cb4fSchristos 		    ND_PRINT((ndo, " REDIRECT %s",  nla_buf));
619546f56c3Schristos 		    break;
620546f56c3Schristos 
621546f56c3Schristos 		case PGM_OPT_PARITY_PRM:
6221c9cc6b1Schristos #define PGM_OPT_PARITY_PRM_LEN	(2+2+4)
6231c9cc6b1Schristos 		    if (opt_len != PGM_OPT_PARITY_PRM_LEN) {
6241c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad OPT_PARITY_PRM option, length %u != %u]",
6251c9cc6b1Schristos 			    opt_len, PGM_OPT_PARITY_PRM_LEN));
626546f56c3Schristos 			return;
627546f56c3Schristos 		    }
6287e4823a9Schristos 		    bp += 2;
629546f56c3Schristos 		    len = EXTRACT_32BITS(bp);
6301c9cc6b1Schristos 		    bp += 4;
6317e4823a9Schristos 		    ND_PRINT((ndo, " PARITY MAXTGS %u", len));
6321c9cc6b1Schristos 		    opts_len -= PGM_OPT_PARITY_PRM_LEN;
633546f56c3Schristos 		    break;
634546f56c3Schristos 
635546f56c3Schristos 		case PGM_OPT_PARITY_GRP:
6361c9cc6b1Schristos #define PGM_OPT_PARITY_GRP_LEN	(2+2+4)
6371c9cc6b1Schristos 		    if (opt_len != PGM_OPT_PARITY_GRP_LEN) {
6381c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad OPT_PARITY_GRP option, length %u != %u]",
6391c9cc6b1Schristos 			    opt_len, PGM_OPT_PARITY_GRP_LEN));
640546f56c3Schristos 			return;
641546f56c3Schristos 		    }
6427e4823a9Schristos 		    bp += 2;
643546f56c3Schristos 		    seq = EXTRACT_32BITS(bp);
6441c9cc6b1Schristos 		    bp += 4;
6457e4823a9Schristos 		    ND_PRINT((ndo, " PARITY GROUP %u", seq));
6461c9cc6b1Schristos 		    opts_len -= PGM_OPT_PARITY_GRP_LEN;
647546f56c3Schristos 		    break;
648546f56c3Schristos 
649546f56c3Schristos 		case PGM_OPT_CURR_TGSIZE:
6501c9cc6b1Schristos #define PGM_OPT_CURR_TGSIZE_LEN	(2+2+4)
6511c9cc6b1Schristos 		    if (opt_len != PGM_OPT_CURR_TGSIZE_LEN) {
6521c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad OPT_CURR_TGSIZE option, length %u != %u]",
6531c9cc6b1Schristos 			    opt_len, PGM_OPT_CURR_TGSIZE_LEN));
654546f56c3Schristos 			return;
655546f56c3Schristos 		    }
6567e4823a9Schristos 		    bp += 2;
657546f56c3Schristos 		    len = EXTRACT_32BITS(bp);
6581c9cc6b1Schristos 		    bp += 4;
6597e4823a9Schristos 		    ND_PRINT((ndo, " PARITY ATGS %u", len));
6601c9cc6b1Schristos 		    opts_len -= PGM_OPT_CURR_TGSIZE_LEN;
661546f56c3Schristos 		    break;
662546f56c3Schristos 
663546f56c3Schristos 		case PGM_OPT_NBR_UNREACH:
6641c9cc6b1Schristos #define PGM_OPT_NBR_UNREACH_LEN	(2+2)
6651c9cc6b1Schristos 		    if (opt_len != PGM_OPT_NBR_UNREACH_LEN) {
6661c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad OPT_NBR_UNREACH option, length %u != %u]",
6671c9cc6b1Schristos 			    opt_len, PGM_OPT_NBR_UNREACH_LEN));
668546f56c3Schristos 			return;
669546f56c3Schristos 		    }
6707e4823a9Schristos 		    bp += 2;
6717e4823a9Schristos 		    ND_PRINT((ndo, " NBR_UNREACH"));
6721c9cc6b1Schristos 		    opts_len -= PGM_OPT_NBR_UNREACH_LEN;
673546f56c3Schristos 		    break;
674546f56c3Schristos 
675546f56c3Schristos 		case PGM_OPT_PATH_NLA:
6767e4823a9Schristos 		    ND_PRINT((ndo, " PATH_NLA [%d]", opt_len));
677546f56c3Schristos 		    bp += opt_len;
678546f56c3Schristos 		    opts_len -= opt_len;
679546f56c3Schristos 		    break;
680546f56c3Schristos 
681546f56c3Schristos 		case PGM_OPT_SYN:
6821c9cc6b1Schristos #define PGM_OPT_SYN_LEN	(2+2)
6831c9cc6b1Schristos 		    if (opt_len != PGM_OPT_SYN_LEN) {
6841c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad OPT_SYN option, length %u != %u]",
6851c9cc6b1Schristos 			    opt_len, PGM_OPT_SYN_LEN));
686546f56c3Schristos 			return;
687546f56c3Schristos 		    }
6887e4823a9Schristos 		    bp += 2;
6897e4823a9Schristos 		    ND_PRINT((ndo, " SYN"));
6901c9cc6b1Schristos 		    opts_len -= PGM_OPT_SYN_LEN;
691546f56c3Schristos 		    break;
692546f56c3Schristos 
693546f56c3Schristos 		case PGM_OPT_FIN:
6941c9cc6b1Schristos #define PGM_OPT_FIN_LEN	(2+2)
6951c9cc6b1Schristos 		    if (opt_len != PGM_OPT_FIN_LEN) {
6961c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad OPT_FIN option, length %u != %u]",
6971c9cc6b1Schristos 			    opt_len, PGM_OPT_FIN_LEN));
698546f56c3Schristos 			return;
699546f56c3Schristos 		    }
7007e4823a9Schristos 		    bp += 2;
7017e4823a9Schristos 		    ND_PRINT((ndo, " FIN"));
7021c9cc6b1Schristos 		    opts_len -= PGM_OPT_FIN_LEN;
703546f56c3Schristos 		    break;
704546f56c3Schristos 
705546f56c3Schristos 		case PGM_OPT_RST:
7061c9cc6b1Schristos #define PGM_OPT_RST_LEN	(2+2)
7071c9cc6b1Schristos 		    if (opt_len != PGM_OPT_RST_LEN) {
7081c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad OPT_RST option, length %u != %u]",
7091c9cc6b1Schristos 			    opt_len, PGM_OPT_RST_LEN));
710546f56c3Schristos 			return;
711546f56c3Schristos 		    }
7127e4823a9Schristos 		    bp += 2;
7137e4823a9Schristos 		    ND_PRINT((ndo, " RST"));
7141c9cc6b1Schristos 		    opts_len -= PGM_OPT_RST_LEN;
715546f56c3Schristos 		    break;
716546f56c3Schristos 
717546f56c3Schristos 		case PGM_OPT_CR:
7187e4823a9Schristos 		    ND_PRINT((ndo, " CR"));
719546f56c3Schristos 		    bp += opt_len;
720546f56c3Schristos 		    opts_len -= opt_len;
721546f56c3Schristos 		    break;
722546f56c3Schristos 
723546f56c3Schristos 		case PGM_OPT_CRQST:
7241c9cc6b1Schristos #define PGM_OPT_CRQST_LEN	(2+2)
7251c9cc6b1Schristos 		    if (opt_len != PGM_OPT_CRQST_LEN) {
7261c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad OPT_CRQST option, length %u != %u]",
7271c9cc6b1Schristos 			    opt_len, PGM_OPT_CRQST_LEN));
728546f56c3Schristos 			return;
729546f56c3Schristos 		    }
7307e4823a9Schristos 		    bp += 2;
7317e4823a9Schristos 		    ND_PRINT((ndo, " CRQST"));
7321c9cc6b1Schristos 		    opts_len -= PGM_OPT_CRQST_LEN;
733546f56c3Schristos 		    break;
734546f56c3Schristos 
7357becbaa8Schristos 		case PGM_OPT_PGMCC_DATA:
7361c9cc6b1Schristos #define PGM_OPT_PGMCC_DATA_FIXED_LEN	(2+2+4+2+2)
7371c9cc6b1Schristos 		    if (opt_len < PGM_OPT_PGMCC_DATA_FIXED_LEN) {
7381c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad OPT_PGMCC_DATA option, length %u < %u]",
7391c9cc6b1Schristos 			    opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN));
7401c9cc6b1Schristos 			return;
7411c9cc6b1Schristos 		    }
7427e4823a9Schristos 		    bp += 2;
7437becbaa8Schristos 		    offset = EXTRACT_32BITS(bp);
7441c9cc6b1Schristos 		    bp += 4;
745c746cb4fSchristos 		    nla_afnum = EXTRACT_16BITS(bp);
7461c9cc6b1Schristos 		    bp += 2+2;
747c746cb4fSchristos 		    switch (nla_afnum) {
7487e4823a9Schristos 		    case AFNUM_INET:
7491c9cc6b1Schristos 			if (opt_len != PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(struct in_addr)) {
7501c9cc6b1Schristos 			    ND_PRINT((ndo, "[Bad OPT_PGMCC_DATA option, length %u != %u + address size]",
7511c9cc6b1Schristos 			        opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN));
752c746cb4fSchristos 			    return;
753c746cb4fSchristos 			}
754c746cb4fSchristos 			ND_TCHECK2(*bp, sizeof(struct in_addr));
755c746cb4fSchristos 			addrtostr(bp, nla_buf, sizeof(nla_buf));
756c746cb4fSchristos 			bp += sizeof(struct in_addr);
7571c9cc6b1Schristos 			opts_len -= PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(struct in_addr);
7587becbaa8Schristos 			break;
7597e4823a9Schristos 		    case AFNUM_INET6:
7601c9cc6b1Schristos 			if (opt_len != PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(struct in6_addr)) {
7611c9cc6b1Schristos 			    ND_PRINT((ndo, "[Bad OPT_PGMCC_DATA option, length %u != %u + address size]",
7621c9cc6b1Schristos 			        opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN));
763c746cb4fSchristos 			    return;
764c746cb4fSchristos 			}
765c746cb4fSchristos 			ND_TCHECK2(*bp, sizeof(struct in6_addr));
766c746cb4fSchristos 			addrtostr6(bp, nla_buf, sizeof(nla_buf));
767c746cb4fSchristos 			bp += sizeof(struct in6_addr);
7681c9cc6b1Schristos 			opts_len -= PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(struct in6_addr);
7697becbaa8Schristos 			break;
7707becbaa8Schristos 		    default:
7717becbaa8Schristos 			goto trunc;
7727becbaa8Schristos 			break;
7737becbaa8Schristos 		    }
7747becbaa8Schristos 
775c746cb4fSchristos 		    ND_PRINT((ndo, " PGMCC DATA %u %s", offset, nla_buf));
7767becbaa8Schristos 		    break;
7777becbaa8Schristos 
7787becbaa8Schristos 		case PGM_OPT_PGMCC_FEEDBACK:
7791c9cc6b1Schristos #define PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN	(2+2+4+2+2)
7801c9cc6b1Schristos 		    if (opt_len < PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN) {
7811c9cc6b1Schristos 			ND_PRINT((ndo, "[Bad PGM_OPT_PGMCC_FEEDBACK option, length %u < %u]",
7821c9cc6b1Schristos 			    opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN));
7831c9cc6b1Schristos 			return;
7841c9cc6b1Schristos 		    }
7857e4823a9Schristos 		    bp += 2;
7867becbaa8Schristos 		    offset = EXTRACT_32BITS(bp);
7871c9cc6b1Schristos 		    bp += 4;
788c746cb4fSchristos 		    nla_afnum = EXTRACT_16BITS(bp);
7891c9cc6b1Schristos 		    bp += 2+2;
790c746cb4fSchristos 		    switch (nla_afnum) {
7917e4823a9Schristos 		    case AFNUM_INET:
7921c9cc6b1Schristos 			if (opt_len != PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(struct in_addr)) {
7931c9cc6b1Schristos 			    ND_PRINT((ndo, "[Bad OPT_PGMCC_FEEDBACK option, length %u != %u + address size]",
7941c9cc6b1Schristos 			        opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN));
795c746cb4fSchristos 			    return;
796c746cb4fSchristos 			}
797c746cb4fSchristos 			ND_TCHECK2(*bp, sizeof(struct in_addr));
798c746cb4fSchristos 			addrtostr(bp, nla_buf, sizeof(nla_buf));
799c746cb4fSchristos 			bp += sizeof(struct in_addr);
8001c9cc6b1Schristos 			opts_len -= PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(struct in_addr);
8017becbaa8Schristos 			break;
8027e4823a9Schristos 		    case AFNUM_INET6:
8031c9cc6b1Schristos 			if (opt_len != PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(struct in6_addr)) {
8041c9cc6b1Schristos 			    ND_PRINT((ndo, "[Bad OPT_PGMCC_FEEDBACK option, length %u != %u + address size]",
8051c9cc6b1Schristos 			        opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN));
806c746cb4fSchristos 			    return;
807c746cb4fSchristos 			}
808c746cb4fSchristos 			ND_TCHECK2(*bp, sizeof(struct in6_addr));
809c746cb4fSchristos 			addrtostr6(bp, nla_buf, sizeof(nla_buf));
810c746cb4fSchristos 			bp += sizeof(struct in6_addr);
8111c9cc6b1Schristos 			opts_len -= PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(struct in6_addr);
8127becbaa8Schristos 			break;
8137becbaa8Schristos 		    default:
8147becbaa8Schristos 			goto trunc;
8157becbaa8Schristos 			break;
8167becbaa8Schristos 		    }
8177becbaa8Schristos 
818c746cb4fSchristos 		    ND_PRINT((ndo, " PGMCC FEEDBACK %u %s", offset, nla_buf));
8197becbaa8Schristos 		    break;
8207becbaa8Schristos 
821546f56c3Schristos 		default:
8227e4823a9Schristos 		    ND_PRINT((ndo, " OPT_%02X [%d] ", opt_type, opt_len));
823546f56c3Schristos 		    bp += opt_len;
824546f56c3Schristos 		    opts_len -= opt_len;
825546f56c3Schristos 		    break;
826546f56c3Schristos 		}
827546f56c3Schristos 
828546f56c3Schristos 		if (opt_type & PGM_OPT_END)
829546f56c3Schristos 		    break;
830546f56c3Schristos 	     }
831546f56c3Schristos 	}
832546f56c3Schristos 
8337e4823a9Schristos 	ND_PRINT((ndo, " [%u]", length));
8347e4823a9Schristos 	if (ndo->ndo_packettype == PT_PGM_ZMTP1 &&
835aecd9f07Schristos 	    (pgm->pgm_type == PGM_ODATA || pgm->pgm_type == PGM_RDATA))
8367e4823a9Schristos 		zmtp1_print_datagram(ndo, bp, EXTRACT_16BITS(&pgm->pgm_length));
837546f56c3Schristos 
838546f56c3Schristos 	return;
839546f56c3Schristos 
840546f56c3Schristos trunc:
8417e4823a9Schristos 	ND_PRINT((ndo, "[|pgm]"));
842546f56c3Schristos 	if (ch != '\0')
8437e4823a9Schristos 		ND_PRINT((ndo, ">"));
844546f56c3Schristos }
845