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