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