xref: /netbsd-src/external/bsd/tcpdump/dist/print-pgm.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Redistribution and use in source and binary forms, with or without
30f74e101Schristos  * modification, are permitted provided that: (1) source code
40f74e101Schristos  * distributions retain the above copyright notice and this paragraph
50f74e101Schristos  * in its entirety, and (2) distributions including binary code include
60f74e101Schristos  * the above copyright notice and this paragraph in its entirety in
70f74e101Schristos  * the documentation or other materials provided with the distribution.
80f74e101Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
90f74e101Schristos  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
100f74e101Schristos  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
110f74e101Schristos  * FOR A PARTICULAR PURPOSE.
120f74e101Schristos  *
130f74e101Schristos  * Original code by Andy Heffernan (ahh@juniper.net)
140f74e101Schristos  */
150f74e101Schristos 
1611b3aaa1Schristos #include <sys/cdefs.h>
170f74e101Schristos #ifndef lint
18*26ba0b50Schristos __RCSID("$NetBSD: print-pgm.c,v 1.12 2024/09/02 16:15:32 christos Exp $");
190f74e101Schristos #endif
200f74e101Schristos 
21dc860a36Sspz /* \summary: Pragmatic General Multicast (PGM) printer */
22dc860a36Sspz 
23c74ad251Schristos #include <config.h>
240f74e101Schristos 
25c74ad251Schristos #include "netdissect-stdinc.h"
260f74e101Schristos 
27fdccd7e4Schristos #include "netdissect.h"
280f74e101Schristos #include "extract.h"
290f74e101Schristos #include "addrtoname.h"
30fdccd7e4Schristos #include "addrtostr.h"
310f74e101Schristos 
320f74e101Schristos #include "ip.h"
330f74e101Schristos #include "ip6.h"
340f74e101Schristos #include "ipproto.h"
35b3a00663Schristos #include "af.h"
360f74e101Schristos 
370f74e101Schristos /*
380f74e101Schristos  * PGM header (RFC 3208)
390f74e101Schristos  */
400f74e101Schristos struct pgm_header {
41c74ad251Schristos     nd_uint16_t	pgm_sport;
42c74ad251Schristos     nd_uint16_t	pgm_dport;
43c74ad251Schristos     nd_uint8_t	pgm_type;
44c74ad251Schristos     nd_uint8_t	pgm_options;
45c74ad251Schristos     nd_uint16_t	pgm_sum;
46c74ad251Schristos     nd_byte	pgm_gsid[6];
47c74ad251Schristos     nd_uint16_t	pgm_length;
480f74e101Schristos };
490f74e101Schristos 
500f74e101Schristos struct pgm_spm {
51c74ad251Schristos     nd_uint32_t	pgms_seq;
52c74ad251Schristos     nd_uint32_t	pgms_trailseq;
53c74ad251Schristos     nd_uint32_t	pgms_leadseq;
54c74ad251Schristos     nd_uint16_t	pgms_nla_afi;
55c74ad251Schristos     nd_uint16_t	pgms_reserved;
56b3a00663Schristos     /* ... uint8_t	pgms_nla[0]; */
570f74e101Schristos     /* ... options */
580f74e101Schristos };
590f74e101Schristos 
600f74e101Schristos struct pgm_nak {
61c74ad251Schristos     nd_uint32_t	pgmn_seq;
62c74ad251Schristos     nd_uint16_t	pgmn_source_afi;
63c74ad251Schristos     nd_uint16_t	pgmn_reserved;
64b3a00663Schristos     /* ... uint8_t	pgmn_source[0]; */
65b3a00663Schristos     /* ... uint16_t	pgmn_group_afi */
66b3a00663Schristos     /* ... uint16_t	pgmn_reserved2; */
67b3a00663Schristos     /* ... uint8_t	pgmn_group[0]; */
680f74e101Schristos     /* ... options */
690f74e101Schristos };
700f74e101Schristos 
710e9868baSchristos struct pgm_ack {
72c74ad251Schristos     nd_uint32_t	pgma_rx_max_seq;
73c74ad251Schristos     nd_uint32_t	pgma_bitmap;
740e9868baSchristos     /* ... options */
750e9868baSchristos };
760e9868baSchristos 
770f74e101Schristos struct pgm_poll {
78c74ad251Schristos     nd_uint32_t	pgmp_seq;
79c74ad251Schristos     nd_uint16_t	pgmp_round;
80c74ad251Schristos     nd_uint16_t	pgmp_subtype;
81c74ad251Schristos     nd_uint16_t	pgmp_nla_afi;
82c74ad251Schristos     nd_uint16_t	pgmp_reserved;
83b3a00663Schristos     /* ... uint8_t	pgmp_nla[0]; */
840f74e101Schristos     /* ... options */
850f74e101Schristos };
860f74e101Schristos 
87c74ad251Schristos struct pgm_polr {
88c74ad251Schristos     nd_uint32_t	pgmp_seq;
89c74ad251Schristos     nd_uint16_t	pgmp_round;
90c74ad251Schristos     nd_uint16_t	pgmp_reserved;
91c74ad251Schristos     /* ... options */
92c74ad251Schristos };
93c74ad251Schristos 
940f74e101Schristos struct pgm_data {
95c74ad251Schristos     nd_uint32_t	pgmd_seq;
96c74ad251Schristos     nd_uint32_t	pgmd_trailseq;
970f74e101Schristos     /* ... options */
980f74e101Schristos };
990f74e101Schristos 
1000f74e101Schristos typedef enum _pgm_type {
1010f74e101Schristos     PGM_SPM = 0,		/* source path message */
1020f74e101Schristos     PGM_POLL = 1,		/* POLL Request */
1030f74e101Schristos     PGM_POLR = 2,		/* POLL Response */
1040f74e101Schristos     PGM_ODATA = 4,		/* original data */
1050f74e101Schristos     PGM_RDATA = 5,		/* repair data */
1060f74e101Schristos     PGM_NAK = 8,		/* NAK */
1070f74e101Schristos     PGM_NULLNAK = 9,		/* Null NAK */
1080f74e101Schristos     PGM_NCF = 10,		/* NAK Confirmation */
1090f74e101Schristos     PGM_ACK = 11,		/* ACK for congestion control */
1100f74e101Schristos     PGM_SPMR = 12,		/* SPM request */
1110f74e101Schristos     PGM_MAX = 255
1120f74e101Schristos } pgm_type;
1130f74e101Schristos 
1140f74e101Schristos #define PGM_OPT_BIT_PRESENT	0x01
1150f74e101Schristos #define PGM_OPT_BIT_NETWORK	0x02
1160f74e101Schristos #define PGM_OPT_BIT_VAR_PKTLEN	0x40
1170f74e101Schristos #define PGM_OPT_BIT_PARITY	0x80
1180f74e101Schristos 
1190f74e101Schristos #define PGM_OPT_LENGTH		0x00
1200f74e101Schristos #define PGM_OPT_FRAGMENT        0x01
1210f74e101Schristos #define PGM_OPT_NAK_LIST        0x02
1220f74e101Schristos #define PGM_OPT_JOIN            0x03
1230f74e101Schristos #define PGM_OPT_NAK_BO_IVL	0x04
1240f74e101Schristos #define PGM_OPT_NAK_BO_RNG	0x05
1250f74e101Schristos 
1260f74e101Schristos #define PGM_OPT_REDIRECT        0x07
1270f74e101Schristos #define PGM_OPT_PARITY_PRM      0x08
1280f74e101Schristos #define PGM_OPT_PARITY_GRP      0x09
1290f74e101Schristos #define PGM_OPT_CURR_TGSIZE     0x0A
1300f74e101Schristos #define PGM_OPT_NBR_UNREACH	0x0B
1310f74e101Schristos #define PGM_OPT_PATH_NLA	0x0C
1320f74e101Schristos 
1330f74e101Schristos #define PGM_OPT_SYN             0x0D
1340f74e101Schristos #define PGM_OPT_FIN             0x0E
1350f74e101Schristos #define PGM_OPT_RST             0x0F
1360f74e101Schristos #define PGM_OPT_CR		0x10
1370f74e101Schristos #define PGM_OPT_CRQST		0x11
1380f74e101Schristos 
1390e9868baSchristos #define PGM_OPT_PGMCC_DATA	0x12
1400e9868baSchristos #define PGM_OPT_PGMCC_FEEDBACK	0x13
1410e9868baSchristos 
1420f74e101Schristos #define PGM_OPT_MASK		0x7f
1430f74e101Schristos 
1440f74e101Schristos #define PGM_OPT_END		0x80    /* end of options marker */
1450f74e101Schristos 
1460f74e101Schristos #define PGM_MIN_OPT_LEN		4
1470f74e101Schristos 
148a8e08e94Skamil UNALIGNED_OK
1490f74e101Schristos void
150b3a00663Schristos pgm_print(netdissect_options *ndo,
151c74ad251Schristos           const u_char *bp, u_int length,
152c74ad251Schristos           const u_char *bp2)
1530f74e101Schristos {
154c74ad251Schristos 	const struct pgm_header *pgm;
155c74ad251Schristos 	const struct ip *ip;
156c74ad251Schristos 	uint8_t pgm_type_val;
157b3a00663Schristos 	uint16_t sport, dport;
158fdccd7e4Schristos 	u_int nla_afnum;
1590f74e101Schristos 	char nla_buf[INET6_ADDRSTRLEN];
160c74ad251Schristos 	const struct ip6_hdr *ip6;
161b3a00663Schristos 	uint8_t opt_type, opt_len;
162b3a00663Schristos 	uint32_t seq, opts_len, len, offset;
1630f74e101Schristos 
164c74ad251Schristos 	ndo->ndo_protocol = "pgm";
165fdccd7e4Schristos 	pgm = (const struct pgm_header *)bp;
166fdccd7e4Schristos 	ip = (const struct ip *)bp2;
1670f74e101Schristos 	if (IP_V(ip) == 6)
168fdccd7e4Schristos 		ip6 = (const struct ip6_hdr *)bp2;
1690f74e101Schristos 	else
1700f74e101Schristos 		ip6 = NULL;
171c74ad251Schristos 	if (!ND_TTEST_2(pgm->pgm_dport)) {
1720f74e101Schristos 		if (ip6) {
173c74ad251Schristos 			ND_PRINT("%s > %s:",
174c74ad251Schristos 				GET_IP6ADDR_STRING(ip6->ip6_src),
175c74ad251Schristos 				GET_IP6ADDR_STRING(ip6->ip6_dst));
176fdccd7e4Schristos 		} else {
177c74ad251Schristos 			ND_PRINT("%s > %s:",
178c74ad251Schristos 				GET_IPADDR_STRING(ip->ip_src),
179c74ad251Schristos 				GET_IPADDR_STRING(ip->ip_dst));
1800f74e101Schristos 		}
181c74ad251Schristos 		nd_print_trunc(ndo);
18272c96ff3Schristos 		return;
1830f74e101Schristos 	}
1840f74e101Schristos 
185c74ad251Schristos 	sport = GET_BE_U_2(pgm->pgm_sport);
186c74ad251Schristos 	dport = GET_BE_U_2(pgm->pgm_dport);
1870f74e101Schristos 
1880f74e101Schristos 	if (ip6) {
189c74ad251Schristos 		if (GET_U_1(ip6->ip6_nxt) == IPPROTO_PGM) {
190c74ad251Schristos 			ND_PRINT("%s.%s > %s.%s: ",
191c74ad251Schristos 				GET_IP6ADDR_STRING(ip6->ip6_src),
192fdccd7e4Schristos 				tcpport_string(ndo, sport),
193c74ad251Schristos 				GET_IP6ADDR_STRING(ip6->ip6_dst),
194c74ad251Schristos 				tcpport_string(ndo, dport));
1950f74e101Schristos 		} else {
196c74ad251Schristos 			ND_PRINT("%s > %s: ",
197c74ad251Schristos 				tcpport_string(ndo, sport), tcpport_string(ndo, dport));
1980f74e101Schristos 		}
199fdccd7e4Schristos 	} else {
200c74ad251Schristos 		if (GET_U_1(ip->ip_p) == IPPROTO_PGM) {
201c74ad251Schristos 			ND_PRINT("%s.%s > %s.%s: ",
202c74ad251Schristos 				GET_IPADDR_STRING(ip->ip_src),
203fdccd7e4Schristos 				tcpport_string(ndo, sport),
204c74ad251Schristos 				GET_IPADDR_STRING(ip->ip_dst),
205c74ad251Schristos 				tcpport_string(ndo, dport));
2060f74e101Schristos 		} else {
207c74ad251Schristos 			ND_PRINT("%s > %s: ",
208c74ad251Schristos 				tcpport_string(ndo, sport), tcpport_string(ndo, dport));
2090f74e101Schristos 		}
2100f74e101Schristos 	}
2110f74e101Schristos 
212c74ad251Schristos 	ND_TCHECK_SIZE(pgm);
2130f74e101Schristos 
214c74ad251Schristos         ND_PRINT("PGM, length %u", GET_BE_U_2(pgm->pgm_length));
2150f74e101Schristos 
216b3a00663Schristos         if (!ndo->ndo_vflag)
2170f74e101Schristos             return;
2180f74e101Schristos 
219c74ad251Schristos 	pgm_type_val = GET_U_1(pgm->pgm_type);
220c74ad251Schristos 	ND_PRINT(" 0x%02x%02x%02x%02x%02x%02x ",
2210f74e101Schristos 		     pgm->pgm_gsid[0],
2220f74e101Schristos                      pgm->pgm_gsid[1],
2230f74e101Schristos                      pgm->pgm_gsid[2],
2240f74e101Schristos 		     pgm->pgm_gsid[3],
2250f74e101Schristos                      pgm->pgm_gsid[4],
226c74ad251Schristos                      pgm->pgm_gsid[5]);
227c74ad251Schristos 	switch (pgm_type_val) {
2280f74e101Schristos 	case PGM_SPM: {
229fdccd7e4Schristos 	    const struct pgm_spm *spm;
2300f74e101Schristos 
231fdccd7e4Schristos 	    spm = (const struct pgm_spm *)(pgm + 1);
232c74ad251Schristos 	    ND_TCHECK_SIZE(spm);
233fdccd7e4Schristos 	    bp = (const u_char *) (spm + 1);
2340f74e101Schristos 
235c74ad251Schristos 	    switch (GET_BE_U_2(spm->pgms_nla_afi)) {
236b3a00663Schristos 	    case AFNUM_INET:
237c74ad251Schristos 		ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
238fdccd7e4Schristos 		addrtostr(bp, nla_buf, sizeof(nla_buf));
239c74ad251Schristos 		bp += sizeof(nd_ipv4);
2400f74e101Schristos 		break;
241b3a00663Schristos 	    case AFNUM_INET6:
242c74ad251Schristos 		ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
243fdccd7e4Schristos 		addrtostr6(bp, nla_buf, sizeof(nla_buf));
244c74ad251Schristos 		bp += sizeof(nd_ipv6);
2450f74e101Schristos 		break;
2460f74e101Schristos 	    default:
2470f74e101Schristos 		goto trunc;
2480f74e101Schristos 		break;
2490f74e101Schristos 	    }
2500f74e101Schristos 
251c74ad251Schristos 	    ND_PRINT("SPM seq %u trail %u lead %u nla %s",
252c74ad251Schristos 			 GET_BE_U_4(spm->pgms_seq),
253c74ad251Schristos 			 GET_BE_U_4(spm->pgms_trailseq),
254c74ad251Schristos 			 GET_BE_U_4(spm->pgms_leadseq),
255c74ad251Schristos 			 nla_buf);
2560f74e101Schristos 	    break;
2570f74e101Schristos 	}
2580f74e101Schristos 
2590f74e101Schristos 	case PGM_POLL: {
260c74ad251Schristos 	    const struct pgm_poll *pgm_poll;
261b3a00663Schristos 	    uint32_t ivl, rnd, mask;
2620f74e101Schristos 
263c74ad251Schristos 	    pgm_poll = (const struct pgm_poll *)(pgm + 1);
264c74ad251Schristos 	    ND_TCHECK_SIZE(pgm_poll);
265c74ad251Schristos 	    bp = (const u_char *) (pgm_poll + 1);
2660f74e101Schristos 
267c74ad251Schristos 	    switch (GET_BE_U_2(pgm_poll->pgmp_nla_afi)) {
268b3a00663Schristos 	    case AFNUM_INET:
269c74ad251Schristos 		ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
270fdccd7e4Schristos 		addrtostr(bp, nla_buf, sizeof(nla_buf));
271c74ad251Schristos 		bp += sizeof(nd_ipv4);
2720f74e101Schristos 		break;
273b3a00663Schristos 	    case AFNUM_INET6:
274c74ad251Schristos 		ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
275fdccd7e4Schristos 		addrtostr6(bp, nla_buf, sizeof(nla_buf));
276c74ad251Schristos 		bp += sizeof(nd_ipv6);
2770f74e101Schristos 		break;
2780f74e101Schristos 	    default:
2790f74e101Schristos 		goto trunc;
2800f74e101Schristos 		break;
2810f74e101Schristos 	    }
2820f74e101Schristos 
283c74ad251Schristos 	    ivl = GET_BE_U_4(bp);
284b3a00663Schristos 	    bp += sizeof(uint32_t);
2850f74e101Schristos 
286c74ad251Schristos 	    rnd = GET_BE_U_4(bp);
287b3a00663Schristos 	    bp += sizeof(uint32_t);
2880f74e101Schristos 
289c74ad251Schristos 	    mask = GET_BE_U_4(bp);
290b3a00663Schristos 	    bp += sizeof(uint32_t);
2910f74e101Schristos 
292c74ad251Schristos 	    ND_PRINT("POLL seq %u round %u nla %s ivl %u rnd 0x%08x "
293c74ad251Schristos 			 "mask 0x%08x", GET_BE_U_4(pgm_poll->pgmp_seq),
294c74ad251Schristos 			 GET_BE_U_2(pgm_poll->pgmp_round), nla_buf, ivl, rnd,
295c74ad251Schristos 			 mask);
296c74ad251Schristos 	    break;
297c74ad251Schristos 	}
298c74ad251Schristos 	case PGM_POLR: {
299c74ad251Schristos 	    const struct pgm_polr *polr_msg;
300c74ad251Schristos 
301c74ad251Schristos 	    polr_msg = (const struct pgm_polr *)(pgm + 1);
302c74ad251Schristos 	    ND_TCHECK_SIZE(polr_msg);
303c74ad251Schristos 	    ND_PRINT("POLR seq %u round %u",
304c74ad251Schristos 			 GET_BE_U_4(polr_msg->pgmp_seq),
305c74ad251Schristos 			 GET_BE_U_2(polr_msg->pgmp_round));
306c74ad251Schristos 	    bp = (const u_char *) (polr_msg + 1);
3070f74e101Schristos 	    break;
3080f74e101Schristos 	}
3090f74e101Schristos 	case PGM_ODATA: {
310fdccd7e4Schristos 	    const struct pgm_data *odata;
3110f74e101Schristos 
312fdccd7e4Schristos 	    odata = (const struct pgm_data *)(pgm + 1);
313c74ad251Schristos 	    ND_TCHECK_SIZE(odata);
314c74ad251Schristos 	    ND_PRINT("ODATA trail %u seq %u",
315c74ad251Schristos 			 GET_BE_U_4(odata->pgmd_trailseq),
316c74ad251Schristos 			 GET_BE_U_4(odata->pgmd_seq));
317fdccd7e4Schristos 	    bp = (const u_char *) (odata + 1);
3180f74e101Schristos 	    break;
3190f74e101Schristos 	}
3200f74e101Schristos 
3210f74e101Schristos 	case PGM_RDATA: {
322fdccd7e4Schristos 	    const struct pgm_data *rdata;
3230f74e101Schristos 
324fdccd7e4Schristos 	    rdata = (const struct pgm_data *)(pgm + 1);
325c74ad251Schristos 	    ND_TCHECK_SIZE(rdata);
326c74ad251Schristos 	    ND_PRINT("RDATA trail %u seq %u",
327c74ad251Schristos 			 GET_BE_U_4(rdata->pgmd_trailseq),
328c74ad251Schristos 			 GET_BE_U_4(rdata->pgmd_seq));
329fdccd7e4Schristos 	    bp = (const u_char *) (rdata + 1);
3300f74e101Schristos 	    break;
3310f74e101Schristos 	}
3320f74e101Schristos 
3330f74e101Schristos 	case PGM_NAK:
3340f74e101Schristos 	case PGM_NULLNAK:
3350f74e101Schristos 	case PGM_NCF: {
336fdccd7e4Schristos 	    const struct pgm_nak *nak;
3370f74e101Schristos 	    char source_buf[INET6_ADDRSTRLEN], group_buf[INET6_ADDRSTRLEN];
3380f74e101Schristos 
339fdccd7e4Schristos 	    nak = (const struct pgm_nak *)(pgm + 1);
340c74ad251Schristos 	    ND_TCHECK_SIZE(nak);
341fdccd7e4Schristos 	    bp = (const u_char *) (nak + 1);
3420f74e101Schristos 
3430f74e101Schristos 	    /*
3440f74e101Schristos 	     * Skip past the source, saving info along the way
3450f74e101Schristos 	     * and stopping if we don't have enough.
3460f74e101Schristos 	     */
347c74ad251Schristos 	    switch (GET_BE_U_2(nak->pgmn_source_afi)) {
348b3a00663Schristos 	    case AFNUM_INET:
349c74ad251Schristos 		ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
350fdccd7e4Schristos 		addrtostr(bp, source_buf, sizeof(source_buf));
351c74ad251Schristos 		bp += sizeof(nd_ipv4);
3520f74e101Schristos 		break;
353b3a00663Schristos 	    case AFNUM_INET6:
354c74ad251Schristos 		ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
355fdccd7e4Schristos 		addrtostr6(bp, source_buf, sizeof(source_buf));
356c74ad251Schristos 		bp += sizeof(nd_ipv6);
3570f74e101Schristos 		break;
3580f74e101Schristos 	    default:
3590f74e101Schristos 		goto trunc;
3600f74e101Schristos 		break;
3610f74e101Schristos 	    }
3620f74e101Schristos 
3630f74e101Schristos 	    /*
3640f74e101Schristos 	     * Skip past the group, saving info along the way
3650f74e101Schristos 	     * and stopping if we don't have enough.
3660f74e101Schristos 	     */
367fdccd7e4Schristos 	    bp += (2 * sizeof(uint16_t));
368c74ad251Schristos 	    switch (GET_BE_U_2(bp)) {
369b3a00663Schristos 	    case AFNUM_INET:
370c74ad251Schristos 		ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
371fdccd7e4Schristos 		addrtostr(bp, group_buf, sizeof(group_buf));
372c74ad251Schristos 		bp += sizeof(nd_ipv4);
3730f74e101Schristos 		break;
374b3a00663Schristos 	    case AFNUM_INET6:
375c74ad251Schristos 		ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
376fdccd7e4Schristos 		addrtostr6(bp, group_buf, sizeof(group_buf));
377c74ad251Schristos 		bp += sizeof(nd_ipv6);
3780f74e101Schristos 		break;
3790f74e101Schristos 	    default:
3800f74e101Schristos 		goto trunc;
3810f74e101Schristos 		break;
3820f74e101Schristos 	    }
3830f74e101Schristos 
3840f74e101Schristos 	    /*
3850f74e101Schristos 	     * Options decoding can go here.
3860f74e101Schristos 	     */
387c74ad251Schristos 	    switch (pgm_type_val) {
3880f74e101Schristos 		case PGM_NAK:
389c74ad251Schristos 		    ND_PRINT("NAK ");
3900f74e101Schristos 		    break;
3910f74e101Schristos 		case PGM_NULLNAK:
392c74ad251Schristos 		    ND_PRINT("NNAK ");
3930f74e101Schristos 		    break;
3940f74e101Schristos 		case PGM_NCF:
395c74ad251Schristos 		    ND_PRINT("NCF ");
3960f74e101Schristos 		    break;
3970f74e101Schristos 		default:
3980f74e101Schristos                     break;
3990f74e101Schristos 	    }
400c74ad251Schristos 	    ND_PRINT("(%s -> %s), seq %u",
401c74ad251Schristos 			 source_buf, group_buf, GET_BE_U_4(nak->pgmn_seq));
4020f74e101Schristos 	    break;
4030f74e101Schristos 	}
4040f74e101Schristos 
4050e9868baSchristos 	case PGM_ACK: {
406fdccd7e4Schristos 	    const struct pgm_ack *ack;
4070e9868baSchristos 
408fdccd7e4Schristos 	    ack = (const struct pgm_ack *)(pgm + 1);
409c74ad251Schristos 	    ND_TCHECK_SIZE(ack);
410c74ad251Schristos 	    ND_PRINT("ACK seq %u",
411c74ad251Schristos 			 GET_BE_U_4(ack->pgma_rx_max_seq));
412fdccd7e4Schristos 	    bp = (const u_char *) (ack + 1);
4130e9868baSchristos 	    break;
4140e9868baSchristos 	}
4150e9868baSchristos 
4160f74e101Schristos 	case PGM_SPMR:
417c74ad251Schristos 	    ND_PRINT("SPMR");
4180f74e101Schristos 	    break;
4190f74e101Schristos 
4200f74e101Schristos 	default:
421c74ad251Schristos 	    ND_PRINT("UNKNOWN type 0x%02x", pgm_type_val);
4220f74e101Schristos 	    break;
4230f74e101Schristos 
4240f74e101Schristos 	}
425c74ad251Schristos 	if (GET_U_1(pgm->pgm_options) & PGM_OPT_BIT_PRESENT) {
4260f74e101Schristos 
4270f74e101Schristos 	    /*
4280f74e101Schristos 	     * make sure there's enough for the first option header
4290f74e101Schristos 	     */
430c74ad251Schristos 	    ND_TCHECK_LEN(bp, PGM_MIN_OPT_LEN);
4310f74e101Schristos 
4320f74e101Schristos 	    /*
4330f74e101Schristos 	     * That option header MUST be an OPT_LENGTH option
4340f74e101Schristos 	     * (see the first paragraph of section 9.1 in RFC 3208).
4350f74e101Schristos 	     */
436c74ad251Schristos 	    opt_type = GET_U_1(bp);
437c74ad251Schristos 	    bp++;
4380f74e101Schristos 	    if ((opt_type & PGM_OPT_MASK) != PGM_OPT_LENGTH) {
439c74ad251Schristos 		ND_PRINT("[First option bad, should be PGM_OPT_LENGTH, is %u]", opt_type & PGM_OPT_MASK);
4400f74e101Schristos 		return;
4410f74e101Schristos 	    }
442c74ad251Schristos 	    opt_len = GET_U_1(bp);
443c74ad251Schristos 	    bp++;
4440f74e101Schristos 	    if (opt_len != 4) {
445c74ad251Schristos 		ND_PRINT("[Bad OPT_LENGTH option, length %u != 4]", opt_len);
4460f74e101Schristos 		return;
4470f74e101Schristos 	    }
448c74ad251Schristos 	    opts_len = GET_BE_U_2(bp);
449b3a00663Schristos 	    bp += sizeof(uint16_t);
450c74ad251Schristos 	    if (opts_len < 4) {
451c74ad251Schristos 		ND_PRINT("[Bad total option length %u < 4]", opts_len);
452c74ad251Schristos 		return;
453c74ad251Schristos 	    }
454c74ad251Schristos 	    ND_PRINT(" OPTS LEN %u", opts_len);
4550f74e101Schristos 	    opts_len -= 4;
4560f74e101Schristos 
4570f74e101Schristos 	    while (opts_len) {
4580f74e101Schristos 		if (opts_len < PGM_MIN_OPT_LEN) {
459c74ad251Schristos 		    ND_PRINT("[Total option length leaves no room for final option]");
4600f74e101Schristos 		    return;
4610f74e101Schristos 		}
462c74ad251Schristos 		opt_type = GET_U_1(bp);
463c74ad251Schristos 		bp++;
464c74ad251Schristos 		opt_len = GET_U_1(bp);
465c74ad251Schristos 		bp++;
4660f74e101Schristos 		if (opt_len < PGM_MIN_OPT_LEN) {
467c74ad251Schristos 		    ND_PRINT("[Bad option, length %u < %u]", opt_len,
468c74ad251Schristos 		        PGM_MIN_OPT_LEN);
4690f74e101Schristos 		    break;
4700f74e101Schristos 		}
4710f74e101Schristos 		if (opts_len < opt_len) {
472c74ad251Schristos 		    ND_PRINT("[Total option length leaves no room for final option]");
4730f74e101Schristos 		    return;
4740f74e101Schristos 		}
475c74ad251Schristos 		ND_TCHECK_LEN(bp, opt_len - 2);
4760f74e101Schristos 
4770f74e101Schristos 		switch (opt_type & PGM_OPT_MASK) {
4780f74e101Schristos 		case PGM_OPT_LENGTH:
47972c96ff3Schristos #define PGM_OPT_LENGTH_LEN	(2+2)
48072c96ff3Schristos 		    if (opt_len != PGM_OPT_LENGTH_LEN) {
481c74ad251Schristos 			ND_PRINT("[Bad OPT_LENGTH option, length %u != %u]",
482c74ad251Schristos 			    opt_len, PGM_OPT_LENGTH_LEN);
4830f74e101Schristos 			return;
4840f74e101Schristos 		    }
485c74ad251Schristos 		    ND_PRINT(" OPTS LEN (extra?) %u", GET_BE_U_2(bp));
48672c96ff3Schristos 		    bp += 2;
48772c96ff3Schristos 		    opts_len -= PGM_OPT_LENGTH_LEN;
4880f74e101Schristos 		    break;
4890f74e101Schristos 
4900f74e101Schristos 		case PGM_OPT_FRAGMENT:
49172c96ff3Schristos #define PGM_OPT_FRAGMENT_LEN	(2+2+4+4+4)
49272c96ff3Schristos 		    if (opt_len != PGM_OPT_FRAGMENT_LEN) {
493c74ad251Schristos 			ND_PRINT("[Bad OPT_FRAGMENT option, length %u != %u]",
494c74ad251Schristos 			    opt_len, PGM_OPT_FRAGMENT_LEN);
4950f74e101Schristos 			return;
4960f74e101Schristos 		    }
497b3a00663Schristos 		    bp += 2;
498c74ad251Schristos 		    seq = GET_BE_U_4(bp);
49972c96ff3Schristos 		    bp += 4;
500c74ad251Schristos 		    offset = GET_BE_U_4(bp);
50172c96ff3Schristos 		    bp += 4;
502c74ad251Schristos 		    len = GET_BE_U_4(bp);
50372c96ff3Schristos 		    bp += 4;
504c74ad251Schristos 		    ND_PRINT(" FRAG seq %u off %u len %u", seq, offset, len);
50572c96ff3Schristos 		    opts_len -= PGM_OPT_FRAGMENT_LEN;
5060f74e101Schristos 		    break;
5070f74e101Schristos 
5080f74e101Schristos 		case PGM_OPT_NAK_LIST:
509b3a00663Schristos 		    bp += 2;
51072c96ff3Schristos 		    opt_len -= 4;	/* option header */
511c74ad251Schristos 		    ND_PRINT(" NAK LIST");
5120f74e101Schristos 		    while (opt_len) {
51372c96ff3Schristos 			if (opt_len < 4) {
514c74ad251Schristos 			    ND_PRINT("[Option length not a multiple of 4]");
5150f74e101Schristos 			    return;
5160f74e101Schristos 			}
517c74ad251Schristos 			ND_PRINT(" %u", GET_BE_U_4(bp));
51872c96ff3Schristos 			bp += 4;
51972c96ff3Schristos 			opt_len -= 4;
52072c96ff3Schristos 			opts_len -= 4;
5210f74e101Schristos 		    }
5220f74e101Schristos 		    break;
5230f74e101Schristos 
5240f74e101Schristos 		case PGM_OPT_JOIN:
52572c96ff3Schristos #define PGM_OPT_JOIN_LEN	(2+2+4)
52672c96ff3Schristos 		    if (opt_len != PGM_OPT_JOIN_LEN) {
527c74ad251Schristos 			ND_PRINT("[Bad OPT_JOIN option, length %u != %u]",
528c74ad251Schristos 			    opt_len, PGM_OPT_JOIN_LEN);
5290f74e101Schristos 			return;
5300f74e101Schristos 		    }
531b3a00663Schristos 		    bp += 2;
532c74ad251Schristos 		    seq = GET_BE_U_4(bp);
53372c96ff3Schristos 		    bp += 4;
534c74ad251Schristos 		    ND_PRINT(" JOIN %u", seq);
53572c96ff3Schristos 		    opts_len -= PGM_OPT_JOIN_LEN;
5360f74e101Schristos 		    break;
5370f74e101Schristos 
5380f74e101Schristos 		case PGM_OPT_NAK_BO_IVL:
53972c96ff3Schristos #define PGM_OPT_NAK_BO_IVL_LEN	(2+2+4+4)
54072c96ff3Schristos 		    if (opt_len != PGM_OPT_NAK_BO_IVL_LEN) {
541c74ad251Schristos 			ND_PRINT("[Bad OPT_NAK_BO_IVL option, length %u != %u]",
542c74ad251Schristos 			    opt_len, PGM_OPT_NAK_BO_IVL_LEN);
5430f74e101Schristos 			return;
5440f74e101Schristos 		    }
545b3a00663Schristos 		    bp += 2;
546c74ad251Schristos 		    offset = GET_BE_U_4(bp);
54772c96ff3Schristos 		    bp += 4;
548c74ad251Schristos 		    seq = GET_BE_U_4(bp);
54972c96ff3Schristos 		    bp += 4;
550c74ad251Schristos 		    ND_PRINT(" BACKOFF ivl %u ivlseq %u", offset, seq);
55172c96ff3Schristos 		    opts_len -= PGM_OPT_NAK_BO_IVL_LEN;
5520f74e101Schristos 		    break;
5530f74e101Schristos 
5540f74e101Schristos 		case PGM_OPT_NAK_BO_RNG:
55572c96ff3Schristos #define PGM_OPT_NAK_BO_RNG_LEN	(2+2+4+4)
55672c96ff3Schristos 		    if (opt_len != PGM_OPT_NAK_BO_RNG_LEN) {
557c74ad251Schristos 			ND_PRINT("[Bad OPT_NAK_BO_RNG option, length %u != %u]",
558c74ad251Schristos 			    opt_len, PGM_OPT_NAK_BO_RNG_LEN);
5590f74e101Schristos 			return;
5600f74e101Schristos 		    }
561b3a00663Schristos 		    bp += 2;
562c74ad251Schristos 		    offset = GET_BE_U_4(bp);
56372c96ff3Schristos 		    bp += 4;
564c74ad251Schristos 		    seq = GET_BE_U_4(bp);
56572c96ff3Schristos 		    bp += 4;
566c74ad251Schristos 		    ND_PRINT(" BACKOFF max %u min %u", offset, seq);
56772c96ff3Schristos 		    opts_len -= PGM_OPT_NAK_BO_RNG_LEN;
5680f74e101Schristos 		    break;
5690f74e101Schristos 
5700f74e101Schristos 		case PGM_OPT_REDIRECT:
57172c96ff3Schristos #define PGM_OPT_REDIRECT_FIXED_LEN	(2+2+2+2)
57272c96ff3Schristos 		    if (opt_len < PGM_OPT_REDIRECT_FIXED_LEN) {
573c74ad251Schristos 			ND_PRINT("[Bad OPT_REDIRECT option, length %u < %u]",
574c74ad251Schristos 			    opt_len, PGM_OPT_REDIRECT_FIXED_LEN);
57572c96ff3Schristos 			return;
57672c96ff3Schristos 		    }
577b3a00663Schristos 		    bp += 2;
578c74ad251Schristos 		    nla_afnum = GET_BE_U_2(bp);
57972c96ff3Schristos 		    bp += 2+2;
580fdccd7e4Schristos 		    switch (nla_afnum) {
581b3a00663Schristos 		    case AFNUM_INET:
582c74ad251Schristos 			if (opt_len != PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv4)) {
583c74ad251Schristos 			    ND_PRINT("[Bad OPT_REDIRECT option, length %u != %u + address size]",
584c74ad251Schristos 			        opt_len, PGM_OPT_REDIRECT_FIXED_LEN);
585fdccd7e4Schristos 			    return;
586fdccd7e4Schristos 			}
587c74ad251Schristos 			ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
588fdccd7e4Schristos 			addrtostr(bp, nla_buf, sizeof(nla_buf));
589c74ad251Schristos 			bp += sizeof(nd_ipv4);
590c74ad251Schristos 			opts_len -= PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv4);
5910f74e101Schristos 			break;
592b3a00663Schristos 		    case AFNUM_INET6:
593c74ad251Schristos 			if (opt_len != PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv6)) {
594c74ad251Schristos 			    ND_PRINT("[Bad OPT_REDIRECT option, length %u != %u + address size]",
595c74ad251Schristos 			        opt_len, PGM_OPT_REDIRECT_FIXED_LEN);
596fdccd7e4Schristos 			    return;
597fdccd7e4Schristos 			}
598c74ad251Schristos 			ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
599fdccd7e4Schristos 			addrtostr6(bp, nla_buf, sizeof(nla_buf));
600c74ad251Schristos 			bp += sizeof(nd_ipv6);
601c74ad251Schristos 			opts_len -= PGM_OPT_REDIRECT_FIXED_LEN + sizeof(nd_ipv6);
6020f74e101Schristos 			break;
6030f74e101Schristos 		    default:
6040f74e101Schristos 			goto trunc;
6050f74e101Schristos 			break;
6060f74e101Schristos 		    }
6070f74e101Schristos 
608c74ad251Schristos 		    ND_PRINT(" REDIRECT %s",  nla_buf);
6090f74e101Schristos 		    break;
6100f74e101Schristos 
6110f74e101Schristos 		case PGM_OPT_PARITY_PRM:
61272c96ff3Schristos #define PGM_OPT_PARITY_PRM_LEN	(2+2+4)
61372c96ff3Schristos 		    if (opt_len != PGM_OPT_PARITY_PRM_LEN) {
614c74ad251Schristos 			ND_PRINT("[Bad OPT_PARITY_PRM option, length %u != %u]",
615c74ad251Schristos 			    opt_len, PGM_OPT_PARITY_PRM_LEN);
6160f74e101Schristos 			return;
6170f74e101Schristos 		    }
618b3a00663Schristos 		    bp += 2;
619c74ad251Schristos 		    len = GET_BE_U_4(bp);
62072c96ff3Schristos 		    bp += 4;
621c74ad251Schristos 		    ND_PRINT(" PARITY MAXTGS %u", len);
62272c96ff3Schristos 		    opts_len -= PGM_OPT_PARITY_PRM_LEN;
6230f74e101Schristos 		    break;
6240f74e101Schristos 
6250f74e101Schristos 		case PGM_OPT_PARITY_GRP:
62672c96ff3Schristos #define PGM_OPT_PARITY_GRP_LEN	(2+2+4)
62772c96ff3Schristos 		    if (opt_len != PGM_OPT_PARITY_GRP_LEN) {
628c74ad251Schristos 			ND_PRINT("[Bad OPT_PARITY_GRP option, length %u != %u]",
629c74ad251Schristos 			    opt_len, PGM_OPT_PARITY_GRP_LEN);
6300f74e101Schristos 			return;
6310f74e101Schristos 		    }
632b3a00663Schristos 		    bp += 2;
633c74ad251Schristos 		    seq = GET_BE_U_4(bp);
63472c96ff3Schristos 		    bp += 4;
635c74ad251Schristos 		    ND_PRINT(" PARITY GROUP %u", seq);
63672c96ff3Schristos 		    opts_len -= PGM_OPT_PARITY_GRP_LEN;
6370f74e101Schristos 		    break;
6380f74e101Schristos 
6390f74e101Schristos 		case PGM_OPT_CURR_TGSIZE:
64072c96ff3Schristos #define PGM_OPT_CURR_TGSIZE_LEN	(2+2+4)
64172c96ff3Schristos 		    if (opt_len != PGM_OPT_CURR_TGSIZE_LEN) {
642c74ad251Schristos 			ND_PRINT("[Bad OPT_CURR_TGSIZE option, length %u != %u]",
643c74ad251Schristos 			    opt_len, PGM_OPT_CURR_TGSIZE_LEN);
6440f74e101Schristos 			return;
6450f74e101Schristos 		    }
646b3a00663Schristos 		    bp += 2;
647c74ad251Schristos 		    len = GET_BE_U_4(bp);
64872c96ff3Schristos 		    bp += 4;
649c74ad251Schristos 		    ND_PRINT(" PARITY ATGS %u", len);
65072c96ff3Schristos 		    opts_len -= PGM_OPT_CURR_TGSIZE_LEN;
6510f74e101Schristos 		    break;
6520f74e101Schristos 
6530f74e101Schristos 		case PGM_OPT_NBR_UNREACH:
65472c96ff3Schristos #define PGM_OPT_NBR_UNREACH_LEN	(2+2)
65572c96ff3Schristos 		    if (opt_len != PGM_OPT_NBR_UNREACH_LEN) {
656c74ad251Schristos 			ND_PRINT("[Bad OPT_NBR_UNREACH option, length %u != %u]",
657c74ad251Schristos 			    opt_len, PGM_OPT_NBR_UNREACH_LEN);
6580f74e101Schristos 			return;
6590f74e101Schristos 		    }
660b3a00663Schristos 		    bp += 2;
661c74ad251Schristos 		    ND_PRINT(" NBR_UNREACH");
66272c96ff3Schristos 		    opts_len -= PGM_OPT_NBR_UNREACH_LEN;
6630f74e101Schristos 		    break;
6640f74e101Schristos 
6650f74e101Schristos 		case PGM_OPT_PATH_NLA:
666c74ad251Schristos 		    ND_PRINT(" PATH_NLA [%u]", opt_len);
6670f74e101Schristos 		    bp += opt_len;
6680f74e101Schristos 		    opts_len -= opt_len;
6690f74e101Schristos 		    break;
6700f74e101Schristos 
6710f74e101Schristos 		case PGM_OPT_SYN:
67272c96ff3Schristos #define PGM_OPT_SYN_LEN	(2+2)
67372c96ff3Schristos 		    if (opt_len != PGM_OPT_SYN_LEN) {
674c74ad251Schristos 			ND_PRINT("[Bad OPT_SYN option, length %u != %u]",
675c74ad251Schristos 			    opt_len, PGM_OPT_SYN_LEN);
6760f74e101Schristos 			return;
6770f74e101Schristos 		    }
678b3a00663Schristos 		    bp += 2;
679c74ad251Schristos 		    ND_PRINT(" SYN");
68072c96ff3Schristos 		    opts_len -= PGM_OPT_SYN_LEN;
6810f74e101Schristos 		    break;
6820f74e101Schristos 
6830f74e101Schristos 		case PGM_OPT_FIN:
68472c96ff3Schristos #define PGM_OPT_FIN_LEN	(2+2)
68572c96ff3Schristos 		    if (opt_len != PGM_OPT_FIN_LEN) {
686c74ad251Schristos 			ND_PRINT("[Bad OPT_FIN option, length %u != %u]",
687c74ad251Schristos 			    opt_len, PGM_OPT_FIN_LEN);
6880f74e101Schristos 			return;
6890f74e101Schristos 		    }
690b3a00663Schristos 		    bp += 2;
691c74ad251Schristos 		    ND_PRINT(" FIN");
69272c96ff3Schristos 		    opts_len -= PGM_OPT_FIN_LEN;
6930f74e101Schristos 		    break;
6940f74e101Schristos 
6950f74e101Schristos 		case PGM_OPT_RST:
69672c96ff3Schristos #define PGM_OPT_RST_LEN	(2+2)
69772c96ff3Schristos 		    if (opt_len != PGM_OPT_RST_LEN) {
698c74ad251Schristos 			ND_PRINT("[Bad OPT_RST option, length %u != %u]",
699c74ad251Schristos 			    opt_len, PGM_OPT_RST_LEN);
7000f74e101Schristos 			return;
7010f74e101Schristos 		    }
702b3a00663Schristos 		    bp += 2;
703c74ad251Schristos 		    ND_PRINT(" RST");
70472c96ff3Schristos 		    opts_len -= PGM_OPT_RST_LEN;
7050f74e101Schristos 		    break;
7060f74e101Schristos 
7070f74e101Schristos 		case PGM_OPT_CR:
708c74ad251Schristos 		    ND_PRINT(" CR");
7090f74e101Schristos 		    bp += opt_len;
7100f74e101Schristos 		    opts_len -= opt_len;
7110f74e101Schristos 		    break;
7120f74e101Schristos 
7130f74e101Schristos 		case PGM_OPT_CRQST:
71472c96ff3Schristos #define PGM_OPT_CRQST_LEN	(2+2)
71572c96ff3Schristos 		    if (opt_len != PGM_OPT_CRQST_LEN) {
716c74ad251Schristos 			ND_PRINT("[Bad OPT_CRQST option, length %u != %u]",
717c74ad251Schristos 			    opt_len, PGM_OPT_CRQST_LEN);
7180f74e101Schristos 			return;
7190f74e101Schristos 		    }
720b3a00663Schristos 		    bp += 2;
721c74ad251Schristos 		    ND_PRINT(" CRQST");
72272c96ff3Schristos 		    opts_len -= PGM_OPT_CRQST_LEN;
7230f74e101Schristos 		    break;
7240f74e101Schristos 
7250e9868baSchristos 		case PGM_OPT_PGMCC_DATA:
72672c96ff3Schristos #define PGM_OPT_PGMCC_DATA_FIXED_LEN	(2+2+4+2+2)
72772c96ff3Schristos 		    if (opt_len < PGM_OPT_PGMCC_DATA_FIXED_LEN) {
728c74ad251Schristos 			ND_PRINT("[Bad OPT_PGMCC_DATA option, length %u < %u]",
729c74ad251Schristos 			    opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN);
73072c96ff3Schristos 			return;
73172c96ff3Schristos 		    }
732b3a00663Schristos 		    bp += 2;
733c74ad251Schristos 		    offset = GET_BE_U_4(bp);
73472c96ff3Schristos 		    bp += 4;
735c74ad251Schristos 		    nla_afnum = GET_BE_U_2(bp);
73672c96ff3Schristos 		    bp += 2+2;
737fdccd7e4Schristos 		    switch (nla_afnum) {
738b3a00663Schristos 		    case AFNUM_INET:
739c74ad251Schristos 			if (opt_len != PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv4)) {
740c74ad251Schristos 			    ND_PRINT("[Bad OPT_PGMCC_DATA option, length %u != %u + address size]",
741c74ad251Schristos 			        opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN);
742fdccd7e4Schristos 			    return;
743fdccd7e4Schristos 			}
744c74ad251Schristos 			ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
745fdccd7e4Schristos 			addrtostr(bp, nla_buf, sizeof(nla_buf));
746c74ad251Schristos 			bp += sizeof(nd_ipv4);
747c74ad251Schristos 			opts_len -= PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv4);
7480e9868baSchristos 			break;
749b3a00663Schristos 		    case AFNUM_INET6:
750c74ad251Schristos 			if (opt_len != PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv6)) {
751c74ad251Schristos 			    ND_PRINT("[Bad OPT_PGMCC_DATA option, length %u != %u + address size]",
752c74ad251Schristos 			        opt_len, PGM_OPT_PGMCC_DATA_FIXED_LEN);
753fdccd7e4Schristos 			    return;
754fdccd7e4Schristos 			}
755c74ad251Schristos 			ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
756fdccd7e4Schristos 			addrtostr6(bp, nla_buf, sizeof(nla_buf));
757c74ad251Schristos 			bp += sizeof(nd_ipv6);
758c74ad251Schristos 			opts_len -= PGM_OPT_PGMCC_DATA_FIXED_LEN + sizeof(nd_ipv6);
7590e9868baSchristos 			break;
7600e9868baSchristos 		    default:
7610e9868baSchristos 			goto trunc;
7620e9868baSchristos 			break;
7630e9868baSchristos 		    }
7640e9868baSchristos 
765c74ad251Schristos 		    ND_PRINT(" PGMCC DATA %u %s", offset, nla_buf);
7660e9868baSchristos 		    break;
7670e9868baSchristos 
7680e9868baSchristos 		case PGM_OPT_PGMCC_FEEDBACK:
76972c96ff3Schristos #define PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN	(2+2+4+2+2)
77072c96ff3Schristos 		    if (opt_len < PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN) {
771c74ad251Schristos 			ND_PRINT("[Bad PGM_OPT_PGMCC_FEEDBACK option, length %u < %u]",
772c74ad251Schristos 			    opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN);
77372c96ff3Schristos 			return;
77472c96ff3Schristos 		    }
775b3a00663Schristos 		    bp += 2;
776c74ad251Schristos 		    offset = GET_BE_U_4(bp);
77772c96ff3Schristos 		    bp += 4;
778c74ad251Schristos 		    nla_afnum = GET_BE_U_2(bp);
77972c96ff3Schristos 		    bp += 2+2;
780fdccd7e4Schristos 		    switch (nla_afnum) {
781b3a00663Schristos 		    case AFNUM_INET:
782c74ad251Schristos 			if (opt_len != PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv4)) {
783c74ad251Schristos 			    ND_PRINT("[Bad OPT_PGMCC_FEEDBACK option, length %u != %u + address size]",
784c74ad251Schristos 			        opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN);
785fdccd7e4Schristos 			    return;
786fdccd7e4Schristos 			}
787c74ad251Schristos 			ND_TCHECK_LEN(bp, sizeof(nd_ipv4));
788fdccd7e4Schristos 			addrtostr(bp, nla_buf, sizeof(nla_buf));
789c74ad251Schristos 			bp += sizeof(nd_ipv4);
790c74ad251Schristos 			opts_len -= PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv4);
7910e9868baSchristos 			break;
792b3a00663Schristos 		    case AFNUM_INET6:
793c74ad251Schristos 			if (opt_len != PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv6)) {
794c74ad251Schristos 			    ND_PRINT("[Bad OPT_PGMCC_FEEDBACK option, length %u != %u + address size]",
795c74ad251Schristos 			        opt_len, PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN);
796fdccd7e4Schristos 			    return;
797fdccd7e4Schristos 			}
798c74ad251Schristos 			ND_TCHECK_LEN(bp, sizeof(nd_ipv6));
799fdccd7e4Schristos 			addrtostr6(bp, nla_buf, sizeof(nla_buf));
800c74ad251Schristos 			bp += sizeof(nd_ipv6);
801c74ad251Schristos 			opts_len -= PGM_OPT_PGMCC_FEEDBACK_FIXED_LEN + sizeof(nd_ipv6);
8020e9868baSchristos 			break;
8030e9868baSchristos 		    default:
8040e9868baSchristos 			goto trunc;
8050e9868baSchristos 			break;
8060e9868baSchristos 		    }
8070e9868baSchristos 
808c74ad251Schristos 		    ND_PRINT(" PGMCC FEEDBACK %u %s", offset, nla_buf);
8090e9868baSchristos 		    break;
8100e9868baSchristos 
8110f74e101Schristos 		default:
812c74ad251Schristos 		    ND_PRINT(" OPT_%02X [%u] ", opt_type, opt_len);
8130f74e101Schristos 		    bp += opt_len;
8140f74e101Schristos 		    opts_len -= opt_len;
8150f74e101Schristos 		    break;
8160f74e101Schristos 		}
8170f74e101Schristos 
8180f74e101Schristos 		if (opt_type & PGM_OPT_END)
8190f74e101Schristos 		    break;
8200f74e101Schristos 	     }
8210f74e101Schristos 	}
8220f74e101Schristos 
823c74ad251Schristos 	ND_PRINT(" [%u]", length);
824b3a00663Schristos 	if (ndo->ndo_packettype == PT_PGM_ZMTP1 &&
825c74ad251Schristos 	    (pgm_type_val == PGM_ODATA || pgm_type_val == PGM_RDATA))
826c74ad251Schristos 		zmtp1_datagram_print(ndo, bp,
827c74ad251Schristos 				     GET_BE_U_2(pgm->pgm_length));
8280f74e101Schristos 
8290f74e101Schristos 	return;
8300f74e101Schristos 
8310f74e101Schristos trunc:
832c74ad251Schristos 	nd_print_trunc(ndo);
8330f74e101Schristos }
834