1147899Ssam/* 2147899Ssam * Redistribution and use in source and binary forms, with or without 3147899Ssam * modification, are permitted provided that: (1) source code 4147899Ssam * distributions retain the above copyright notice and this paragraph 5147899Ssam * in its entirety, and (2) distributions including binary code include 6147899Ssam * the above copyright notice and this paragraph in its entirety in 7147899Ssam * the documentation or other materials provided with the distribution. 8147899Ssam * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 9147899Ssam * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 10147899Ssam * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 11147899Ssam * FOR A PARTICULAR PURPOSE. 12147899Ssam * 13147899Ssam * Original code by Andy Heffernan (ahh@juniper.net) 14147899Ssam */ 15147899Ssam 16147899Ssam#ifndef lint 17147899Ssamstatic const char rcsid[] _U_ = 18190207Srpaulo "@(#) $Header: /tcpdump/master/tcpdump/print-pgm.c,v 1.5 2005-06-07 22:05:58 guy Exp $"; 19147899Ssam#endif 20147899Ssam 21147899Ssam#ifdef HAVE_CONFIG_H 22147899Ssam#include "config.h" 23147899Ssam#endif 24147899Ssam 25147899Ssam#include <tcpdump-stdinc.h> 26147899Ssam 27147899Ssam#include <stdio.h> 28147899Ssam#include <stdlib.h> 29147899Ssam#include <string.h> 30147899Ssam 31147899Ssam#include "interface.h" 32147899Ssam#include "extract.h" 33147899Ssam#include "addrtoname.h" 34147899Ssam 35147899Ssam#include "ip.h" 36147899Ssam#ifdef INET6 37147899Ssam#include "ip6.h" 38147899Ssam#endif 39147899Ssam#include "ipproto.h" 40147899Ssam 41147899Ssam/* 42147899Ssam * PGM header (RFC 3208) 43147899Ssam */ 44147899Ssamstruct pgm_header { 45147899Ssam u_int16_t pgm_sport; 46147899Ssam u_int16_t pgm_dport; 47147899Ssam u_int8_t pgm_type; 48147899Ssam u_int8_t pgm_options; 49147899Ssam u_int16_t pgm_sum; 50147899Ssam u_int8_t pgm_gsid[6]; 51147899Ssam u_int16_t pgm_length; 52147899Ssam}; 53147899Ssam 54147899Ssamstruct pgm_spm { 55147899Ssam u_int32_t pgms_seq; 56147899Ssam u_int32_t pgms_trailseq; 57147899Ssam u_int32_t pgms_leadseq; 58147899Ssam u_int16_t pgms_nla_afi; 59147899Ssam u_int16_t pgms_reserved; 60147899Ssam /* ... u_int8_t pgms_nla[0]; */ 61147899Ssam /* ... options */ 62147899Ssam}; 63147899Ssam 64147899Ssamstruct pgm_nak { 65147899Ssam u_int32_t pgmn_seq; 66147899Ssam u_int16_t pgmn_source_afi; 67147899Ssam u_int16_t pgmn_reserved; 68147899Ssam /* ... u_int8_t pgmn_source[0]; */ 69147899Ssam /* ... u_int16_t pgmn_group_afi */ 70147899Ssam /* ... u_int16_t pgmn_reserved2; */ 71147899Ssam /* ... u_int8_t pgmn_group[0]; */ 72147899Ssam /* ... options */ 73147899Ssam}; 74147899Ssam 75236192Sdelphijstruct pgm_ack { 76236192Sdelphij u_int32_t pgma_rx_max_seq; 77236192Sdelphij u_int32_t pgma_bitmap; 78236192Sdelphij /* ... options */ 79236192Sdelphij}; 80236192Sdelphij 81147899Ssamstruct pgm_poll { 82147899Ssam u_int32_t pgmp_seq; 83147899Ssam u_int16_t pgmp_round; 84147899Ssam u_int16_t pgmp_reserved; 85147899Ssam /* ... options */ 86147899Ssam}; 87147899Ssam 88147899Ssamstruct pgm_polr { 89147899Ssam u_int32_t pgmp_seq; 90147899Ssam u_int16_t pgmp_round; 91147899Ssam u_int16_t pgmp_subtype; 92147899Ssam u_int16_t pgmp_nla_afi; 93147899Ssam u_int16_t pgmp_reserved; 94147899Ssam /* ... u_int8_t pgmp_nla[0]; */ 95147899Ssam /* ... options */ 96147899Ssam}; 97147899Ssam 98147899Ssamstruct pgm_data { 99147899Ssam u_int32_t pgmd_seq; 100147899Ssam u_int32_t pgmd_trailseq; 101147899Ssam /* ... options */ 102147899Ssam}; 103147899Ssam 104147899Ssamtypedef enum _pgm_type { 105147899Ssam PGM_SPM = 0, /* source path message */ 106147899Ssam PGM_POLL = 1, /* POLL Request */ 107147899Ssam PGM_POLR = 2, /* POLL Response */ 108147899Ssam PGM_ODATA = 4, /* original data */ 109147899Ssam PGM_RDATA = 5, /* repair data */ 110147899Ssam PGM_NAK = 8, /* NAK */ 111147899Ssam PGM_NULLNAK = 9, /* Null NAK */ 112147899Ssam PGM_NCF = 10, /* NAK Confirmation */ 113147899Ssam PGM_ACK = 11, /* ACK for congestion control */ 114147899Ssam PGM_SPMR = 12, /* SPM request */ 115147899Ssam PGM_MAX = 255 116147899Ssam} pgm_type; 117147899Ssam 118147899Ssam#define PGM_OPT_BIT_PRESENT 0x01 119147899Ssam#define PGM_OPT_BIT_NETWORK 0x02 120147899Ssam#define PGM_OPT_BIT_VAR_PKTLEN 0x40 121147899Ssam#define PGM_OPT_BIT_PARITY 0x80 122147899Ssam 123147899Ssam#define PGM_OPT_LENGTH 0x00 124147899Ssam#define PGM_OPT_FRAGMENT 0x01 125147899Ssam#define PGM_OPT_NAK_LIST 0x02 126147899Ssam#define PGM_OPT_JOIN 0x03 127147899Ssam#define PGM_OPT_NAK_BO_IVL 0x04 128147899Ssam#define PGM_OPT_NAK_BO_RNG 0x05 129147899Ssam 130147899Ssam#define PGM_OPT_REDIRECT 0x07 131147899Ssam#define PGM_OPT_PARITY_PRM 0x08 132147899Ssam#define PGM_OPT_PARITY_GRP 0x09 133147899Ssam#define PGM_OPT_CURR_TGSIZE 0x0A 134147899Ssam#define PGM_OPT_NBR_UNREACH 0x0B 135147899Ssam#define PGM_OPT_PATH_NLA 0x0C 136147899Ssam 137147899Ssam#define PGM_OPT_SYN 0x0D 138147899Ssam#define PGM_OPT_FIN 0x0E 139147899Ssam#define PGM_OPT_RST 0x0F 140147899Ssam#define PGM_OPT_CR 0x10 141147899Ssam#define PGM_OPT_CRQST 0x11 142236192Sdelphij 143236192Sdelphij#define PGM_OPT_PGMCC_DATA 0x12 144236192Sdelphij#define PGM_OPT_PGMCC_FEEDBACK 0x13 145147899Ssam 146147899Ssam#define PGM_OPT_MASK 0x7f 147147899Ssam 148147899Ssam#define PGM_OPT_END 0x80 /* end of options marker */ 149147899Ssam 150147899Ssam#define PGM_MIN_OPT_LEN 4 151147899Ssam 152147899Ssam#ifndef AFI_IP 153147899Ssam#define AFI_IP 1 154147899Ssam#define AFI_IP6 2 155147899Ssam#endif 156147899Ssam 157147899Ssamvoid 158147899Ssampgm_print(register const u_char *bp, register u_int length, 159147899Ssam register const u_char *bp2) 160147899Ssam{ 161147899Ssam register const struct pgm_header *pgm; 162147899Ssam register const struct ip *ip; 163147899Ssam register char ch; 164147899Ssam u_int16_t sport, dport; 165147899Ssam int addr_size; 166147899Ssam const void *nla; 167147899Ssam int nla_af; 168147899Ssam#ifdef INET6 169147899Ssam char nla_buf[INET6_ADDRSTRLEN]; 170147899Ssam register const struct ip6_hdr *ip6; 171147899Ssam#else 172147899Ssam char nla_buf[INET_ADDRSTRLEN]; 173147899Ssam#endif 174147899Ssam u_int8_t opt_type, opt_len, flags1, flags2; 175147899Ssam u_int32_t seq, opts_len, len, offset; 176147899Ssam 177147899Ssam pgm = (struct pgm_header *)bp; 178147899Ssam ip = (struct ip *)bp2; 179147899Ssam#ifdef INET6 180147899Ssam if (IP_V(ip) == 6) 181147899Ssam ip6 = (struct ip6_hdr *)bp2; 182147899Ssam else 183147899Ssam ip6 = NULL; 184147899Ssam#else /* INET6 */ 185147899Ssam if (IP_V(ip) == 6) { 186147899Ssam (void)printf("Can't handle IPv6"); 187147899Ssam return; 188147899Ssam } 189147899Ssam#endif /* INET6 */ 190147899Ssam ch = '\0'; 191147899Ssam if (!TTEST(pgm->pgm_dport)) { 192147899Ssam#ifdef INET6 193147899Ssam if (ip6) { 194147899Ssam (void)printf("%s > %s: [|pgm]", 195147899Ssam ip6addr_string(&ip6->ip6_src), 196147899Ssam ip6addr_string(&ip6->ip6_dst)); 197147899Ssam return; 198147899Ssam } else 199147899Ssam#endif /* INET6 */ 200147899Ssam { 201147899Ssam (void)printf("%s > %s: [|pgm]", 202147899Ssam ipaddr_string(&ip->ip_src), 203147899Ssam ipaddr_string(&ip->ip_dst)); 204147899Ssam return; 205147899Ssam } 206147899Ssam } 207147899Ssam 208147899Ssam sport = EXTRACT_16BITS(&pgm->pgm_sport); 209147899Ssam dport = EXTRACT_16BITS(&pgm->pgm_dport); 210147899Ssam 211147899Ssam#ifdef INET6 212147899Ssam if (ip6) { 213147899Ssam if (ip6->ip6_nxt == IPPROTO_PGM) { 214147899Ssam (void)printf("%s.%s > %s.%s: ", 215147899Ssam ip6addr_string(&ip6->ip6_src), 216147899Ssam tcpport_string(sport), 217147899Ssam ip6addr_string(&ip6->ip6_dst), 218147899Ssam tcpport_string(dport)); 219147899Ssam } else { 220147899Ssam (void)printf("%s > %s: ", 221147899Ssam tcpport_string(sport), tcpport_string(dport)); 222147899Ssam } 223147899Ssam } else 224147899Ssam#endif /*INET6*/ 225147899Ssam { 226147899Ssam if (ip->ip_p == IPPROTO_PGM) { 227147899Ssam (void)printf("%s.%s > %s.%s: ", 228147899Ssam ipaddr_string(&ip->ip_src), 229147899Ssam tcpport_string(sport), 230147899Ssam ipaddr_string(&ip->ip_dst), 231147899Ssam tcpport_string(dport)); 232147899Ssam } else { 233147899Ssam (void)printf("%s > %s: ", 234147899Ssam tcpport_string(sport), tcpport_string(dport)); 235147899Ssam } 236147899Ssam } 237147899Ssam 238147899Ssam TCHECK(*pgm); 239147899Ssam 240147899Ssam (void)printf("PGM, length %u", pgm->pgm_length); 241147899Ssam 242147899Ssam if (!vflag) 243147899Ssam return; 244147899Ssam 245147899Ssam if (length > pgm->pgm_length) 246147899Ssam length = pgm->pgm_length; 247147899Ssam 248147899Ssam (void)printf(" 0x%02x%02x%02x%02x%02x%02x ", 249147899Ssam pgm->pgm_gsid[0], 250147899Ssam pgm->pgm_gsid[1], 251147899Ssam pgm->pgm_gsid[2], 252147899Ssam pgm->pgm_gsid[3], 253147899Ssam pgm->pgm_gsid[4], 254147899Ssam pgm->pgm_gsid[5]); 255147899Ssam switch (pgm->pgm_type) { 256147899Ssam case PGM_SPM: { 257147899Ssam struct pgm_spm *spm; 258147899Ssam 259147899Ssam spm = (struct pgm_spm *)(pgm + 1); 260147899Ssam TCHECK(*spm); 261147899Ssam 262147899Ssam switch (EXTRACT_16BITS(&spm->pgms_nla_afi)) { 263147899Ssam case AFI_IP: 264147899Ssam addr_size = sizeof(struct in_addr); 265147899Ssam nla_af = AF_INET; 266147899Ssam break; 267147899Ssam#ifdef INET6 268147899Ssam case AFI_IP6: 269147899Ssam addr_size = sizeof(struct in6_addr); 270147899Ssam nla_af = AF_INET6; 271147899Ssam break; 272147899Ssam#endif 273147899Ssam default: 274147899Ssam goto trunc; 275147899Ssam break; 276147899Ssam } 277147899Ssam bp = (u_char *) (spm + 1); 278147899Ssam TCHECK2(*bp, addr_size); 279147899Ssam nla = bp; 280147899Ssam bp += addr_size; 281147899Ssam 282147899Ssam inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf)); 283147899Ssam (void)printf("SPM seq %u trail %u lead %u nla %s", 284147899Ssam EXTRACT_32BITS(&spm->pgms_seq), 285147899Ssam EXTRACT_32BITS(&spm->pgms_trailseq), 286147899Ssam EXTRACT_32BITS(&spm->pgms_leadseq), 287147899Ssam nla_buf); 288147899Ssam break; 289147899Ssam } 290147899Ssam 291147899Ssam case PGM_POLL: { 292147899Ssam struct pgm_poll *poll; 293147899Ssam 294147899Ssam poll = (struct pgm_poll *)(pgm + 1); 295147899Ssam TCHECK(*poll); 296147899Ssam (void)printf("POLL seq %u round %u", 297147899Ssam EXTRACT_32BITS(&poll->pgmp_seq), 298147899Ssam EXTRACT_16BITS(&poll->pgmp_round)); 299147899Ssam bp = (u_char *) (poll + 1); 300147899Ssam break; 301147899Ssam } 302147899Ssam case PGM_POLR: { 303147899Ssam struct pgm_polr *polr; 304147899Ssam u_int32_t ivl, rnd, mask; 305147899Ssam 306147899Ssam polr = (struct pgm_polr *)(pgm + 1); 307147899Ssam TCHECK(*polr); 308147899Ssam 309147899Ssam switch (EXTRACT_16BITS(&polr->pgmp_nla_afi)) { 310147899Ssam case AFI_IP: 311147899Ssam addr_size = sizeof(struct in_addr); 312147899Ssam nla_af = AF_INET; 313147899Ssam break; 314147899Ssam#ifdef INET6 315147899Ssam case AFI_IP6: 316147899Ssam addr_size = sizeof(struct in6_addr); 317147899Ssam nla_af = AF_INET6; 318147899Ssam break; 319147899Ssam#endif 320147899Ssam default: 321147899Ssam goto trunc; 322147899Ssam break; 323147899Ssam } 324147899Ssam bp = (u_char *) (polr + 1); 325147899Ssam TCHECK2(*bp, addr_size); 326147899Ssam nla = bp; 327147899Ssam bp += addr_size; 328147899Ssam 329147899Ssam inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf)); 330147899Ssam 331147899Ssam TCHECK2(*bp, sizeof(u_int32_t)); 332147899Ssam ivl = EXTRACT_32BITS(bp); 333147899Ssam bp += sizeof(u_int32_t); 334147899Ssam 335147899Ssam TCHECK2(*bp, sizeof(u_int32_t)); 336147899Ssam rnd = EXTRACT_32BITS(bp); 337147899Ssam bp += sizeof(u_int32_t); 338147899Ssam 339147899Ssam TCHECK2(*bp, sizeof(u_int32_t)); 340147899Ssam mask = EXTRACT_32BITS(bp); 341147899Ssam bp += sizeof(u_int32_t); 342147899Ssam 343147899Ssam (void)printf("POLR seq %u round %u nla %s ivl %u rnd 0x%08x " 344147899Ssam "mask 0x%08x", EXTRACT_32BITS(&polr->pgmp_seq), 345147899Ssam EXTRACT_16BITS(&polr->pgmp_round), nla_buf, ivl, rnd, mask); 346147899Ssam break; 347147899Ssam } 348147899Ssam case PGM_ODATA: { 349147899Ssam struct pgm_data *odata; 350147899Ssam 351147899Ssam odata = (struct pgm_data *)(pgm + 1); 352147899Ssam TCHECK(*odata); 353147899Ssam (void)printf("ODATA trail %u seq %u", 354147899Ssam EXTRACT_32BITS(&odata->pgmd_trailseq), 355147899Ssam EXTRACT_32BITS(&odata->pgmd_seq)); 356147899Ssam bp = (u_char *) (odata + 1); 357147899Ssam break; 358147899Ssam } 359147899Ssam 360147899Ssam case PGM_RDATA: { 361147899Ssam struct pgm_data *rdata; 362147899Ssam 363147899Ssam rdata = (struct pgm_data *)(pgm + 1); 364147899Ssam TCHECK(*rdata); 365147899Ssam (void)printf("RDATA trail %u seq %u", 366147899Ssam EXTRACT_32BITS(&rdata->pgmd_trailseq), 367147899Ssam EXTRACT_32BITS(&rdata->pgmd_seq)); 368147899Ssam bp = (u_char *) (rdata + 1); 369147899Ssam break; 370147899Ssam } 371147899Ssam 372147899Ssam case PGM_NAK: 373147899Ssam case PGM_NULLNAK: 374147899Ssam case PGM_NCF: { 375147899Ssam struct pgm_nak *nak; 376147899Ssam const void *source, *group; 377147899Ssam int source_af, group_af; 378147899Ssam#ifdef INET6 379147899Ssam char source_buf[INET6_ADDRSTRLEN], group_buf[INET6_ADDRSTRLEN]; 380147899Ssam#else 381147899Ssam char source_buf[INET_ADDRSTRLEN], group_buf[INET_ADDRSTRLEN]; 382147899Ssam#endif 383147899Ssam 384147899Ssam nak = (struct pgm_nak *)(pgm + 1); 385147899Ssam TCHECK(*nak); 386147899Ssam 387147899Ssam /* 388147899Ssam * Skip past the source, saving info along the way 389147899Ssam * and stopping if we don't have enough. 390147899Ssam */ 391147899Ssam switch (EXTRACT_16BITS(&nak->pgmn_source_afi)) { 392147899Ssam case AFI_IP: 393147899Ssam addr_size = sizeof(struct in_addr); 394147899Ssam source_af = AF_INET; 395147899Ssam break; 396147899Ssam#ifdef INET6 397147899Ssam case AFI_IP6: 398147899Ssam addr_size = sizeof(struct in6_addr); 399147899Ssam source_af = AF_INET6; 400147899Ssam break; 401147899Ssam#endif 402147899Ssam default: 403147899Ssam goto trunc; 404147899Ssam break; 405147899Ssam } 406147899Ssam bp = (u_char *) (nak + 1); 407147899Ssam TCHECK2(*bp, addr_size); 408147899Ssam source = bp; 409147899Ssam bp += addr_size; 410147899Ssam 411147899Ssam /* 412147899Ssam * Skip past the group, saving info along the way 413147899Ssam * and stopping if we don't have enough. 414147899Ssam */ 415147899Ssam switch (EXTRACT_16BITS(bp)) { 416147899Ssam case AFI_IP: 417147899Ssam addr_size = sizeof(struct in_addr); 418147899Ssam group_af = AF_INET; 419147899Ssam break; 420147899Ssam#ifdef INET6 421147899Ssam case AFI_IP6: 422147899Ssam addr_size = sizeof(struct in6_addr); 423147899Ssam group_af = AF_INET6; 424147899Ssam break; 425147899Ssam#endif 426147899Ssam default: 427147899Ssam goto trunc; 428147899Ssam break; 429147899Ssam } 430147899Ssam bp += (2 * sizeof(u_int16_t)); 431147899Ssam TCHECK2(*bp, addr_size); 432147899Ssam group = bp; 433147899Ssam bp += addr_size; 434147899Ssam 435147899Ssam /* 436147899Ssam * Options decoding can go here. 437147899Ssam */ 438147899Ssam inet_ntop(source_af, source, source_buf, sizeof(source_buf)); 439147899Ssam inet_ntop(group_af, group, group_buf, sizeof(group_buf)); 440147899Ssam switch (pgm->pgm_type) { 441147899Ssam case PGM_NAK: 442147899Ssam (void)printf("NAK "); 443147899Ssam break; 444147899Ssam case PGM_NULLNAK: 445147899Ssam (void)printf("NNAK "); 446147899Ssam break; 447147899Ssam case PGM_NCF: 448147899Ssam (void)printf("NCF "); 449147899Ssam break; 450147899Ssam default: 451147899Ssam break; 452147899Ssam } 453147899Ssam (void)printf("(%s -> %s), seq %u", 454147899Ssam source_buf, group_buf, EXTRACT_32BITS(&nak->pgmn_seq)); 455147899Ssam break; 456147899Ssam } 457147899Ssam 458236192Sdelphij case PGM_ACK: { 459236192Sdelphij struct pgm_ack *ack; 460236192Sdelphij 461236192Sdelphij ack = (struct pgm_ack *)(pgm + 1); 462236192Sdelphij TCHECK(*ack); 463236192Sdelphij (void)printf("ACK seq %u", 464236192Sdelphij EXTRACT_32BITS(&ack->pgma_rx_max_seq)); 465236192Sdelphij bp = (u_char *) (ack + 1); 466236192Sdelphij break; 467236192Sdelphij } 468236192Sdelphij 469147899Ssam case PGM_SPMR: 470147899Ssam (void)printf("SPMR"); 471147899Ssam break; 472147899Ssam 473147899Ssam default: 474147899Ssam (void)printf("UNKNOWN type %0x02x", pgm->pgm_type); 475147899Ssam break; 476147899Ssam 477147899Ssam } 478147899Ssam if (pgm->pgm_options & PGM_OPT_BIT_PRESENT) { 479147899Ssam 480147899Ssam /* 481147899Ssam * make sure there's enough for the first option header 482147899Ssam */ 483147899Ssam if (!TTEST2(*bp, PGM_MIN_OPT_LEN)) { 484147899Ssam (void)printf("[|OPT]"); 485147899Ssam return; 486147899Ssam } 487147899Ssam 488147899Ssam /* 489147899Ssam * That option header MUST be an OPT_LENGTH option 490147899Ssam * (see the first paragraph of section 9.1 in RFC 3208). 491147899Ssam */ 492147899Ssam opt_type = *bp++; 493147899Ssam if ((opt_type & PGM_OPT_MASK) != PGM_OPT_LENGTH) { 494147899Ssam (void)printf("[First option bad, should be PGM_OPT_LENGTH, is %u]", opt_type & PGM_OPT_MASK); 495147899Ssam return; 496147899Ssam } 497147899Ssam opt_len = *bp++; 498147899Ssam if (opt_len != 4) { 499147899Ssam (void)printf("[Bad OPT_LENGTH option, length %u != 4]", opt_len); 500147899Ssam return; 501147899Ssam } 502147899Ssam opts_len = EXTRACT_16BITS(bp); 503147899Ssam if (opts_len < 4) { 504147899Ssam (void)printf("[Bad total option length %u < 4]", opts_len); 505147899Ssam return; 506147899Ssam } 507147899Ssam bp += sizeof(u_int16_t); 508147899Ssam (void)printf(" OPTS LEN %d", opts_len); 509147899Ssam opts_len -= 4; 510147899Ssam 511147899Ssam while (opts_len) { 512147899Ssam if (opts_len < PGM_MIN_OPT_LEN) { 513147899Ssam (void)printf("[Total option length leaves no room for final option]"); 514147899Ssam return; 515147899Ssam } 516147899Ssam opt_type = *bp++; 517147899Ssam opt_len = *bp++; 518147899Ssam if (opt_len < PGM_MIN_OPT_LEN) { 519147899Ssam (void)printf("[Bad option, length %u < %u]", opt_len, 520147899Ssam PGM_MIN_OPT_LEN); 521147899Ssam break; 522147899Ssam } 523147899Ssam if (opts_len < opt_len) { 524147899Ssam (void)printf("[Total option length leaves no room for final option]"); 525147899Ssam return; 526147899Ssam } 527147899Ssam if (!TTEST2(*bp, opt_len - 2)) { 528147899Ssam (void)printf(" [|OPT]"); 529147899Ssam return; 530147899Ssam } 531147899Ssam 532147899Ssam switch (opt_type & PGM_OPT_MASK) { 533147899Ssam case PGM_OPT_LENGTH: 534147899Ssam if (opt_len != 4) { 535147899Ssam (void)printf("[Bad OPT_LENGTH option, length %u != 4]", opt_len); 536147899Ssam return; 537147899Ssam } 538147899Ssam (void)printf(" OPTS LEN (extra?) %d", EXTRACT_16BITS(bp)); 539147899Ssam bp += sizeof(u_int16_t); 540147899Ssam opts_len -= 4; 541147899Ssam break; 542147899Ssam 543147899Ssam case PGM_OPT_FRAGMENT: 544147899Ssam if (opt_len != 16) { 545147899Ssam (void)printf("[Bad OPT_FRAGMENT option, length %u != 16]", opt_len); 546147899Ssam return; 547147899Ssam } 548147899Ssam flags1 = *bp++; 549147899Ssam flags2 = *bp++; 550147899Ssam seq = EXTRACT_32BITS(bp); 551147899Ssam bp += sizeof(u_int32_t); 552147899Ssam offset = EXTRACT_32BITS(bp); 553147899Ssam bp += sizeof(u_int32_t); 554147899Ssam len = EXTRACT_32BITS(bp); 555147899Ssam bp += sizeof(u_int32_t); 556147899Ssam (void)printf(" FRAG seq %u off %u len %u", seq, offset, len); 557147899Ssam opts_len -= 16; 558147899Ssam break; 559147899Ssam 560147899Ssam case PGM_OPT_NAK_LIST: 561147899Ssam flags1 = *bp++; 562147899Ssam flags2 = *bp++; 563147899Ssam opt_len -= sizeof(u_int32_t); /* option header */ 564147899Ssam (void)printf(" NAK LIST"); 565147899Ssam while (opt_len) { 566147899Ssam if (opt_len < sizeof(u_int32_t)) { 567147899Ssam (void)printf("[Option length not a multiple of 4]"); 568147899Ssam return; 569147899Ssam } 570147899Ssam TCHECK2(*bp, sizeof(u_int32_t)); 571147899Ssam (void)printf(" %u", EXTRACT_32BITS(bp)); 572147899Ssam bp += sizeof(u_int32_t); 573147899Ssam opt_len -= sizeof(u_int32_t); 574147899Ssam opts_len -= sizeof(u_int32_t); 575147899Ssam } 576147899Ssam break; 577147899Ssam 578147899Ssam case PGM_OPT_JOIN: 579147899Ssam if (opt_len != 8) { 580147899Ssam (void)printf("[Bad OPT_JOIN option, length %u != 8]", opt_len); 581147899Ssam return; 582147899Ssam } 583147899Ssam flags1 = *bp++; 584147899Ssam flags2 = *bp++; 585147899Ssam seq = EXTRACT_32BITS(bp); 586147899Ssam bp += sizeof(u_int32_t); 587147899Ssam (void)printf(" JOIN %u", seq); 588147899Ssam opts_len -= 8; 589147899Ssam break; 590147899Ssam 591147899Ssam case PGM_OPT_NAK_BO_IVL: 592147899Ssam if (opt_len != 12) { 593147899Ssam (void)printf("[Bad OPT_NAK_BO_IVL option, length %u != 12]", opt_len); 594147899Ssam return; 595147899Ssam } 596147899Ssam flags1 = *bp++; 597147899Ssam flags2 = *bp++; 598147899Ssam offset = EXTRACT_32BITS(bp); 599147899Ssam bp += sizeof(u_int32_t); 600147899Ssam seq = EXTRACT_32BITS(bp); 601147899Ssam bp += sizeof(u_int32_t); 602147899Ssam (void)printf(" BACKOFF ivl %u ivlseq %u", offset, seq); 603147899Ssam opts_len -= 12; 604147899Ssam break; 605147899Ssam 606147899Ssam case PGM_OPT_NAK_BO_RNG: 607147899Ssam if (opt_len != 12) { 608147899Ssam (void)printf("[Bad OPT_NAK_BO_RNG option, length %u != 12]", opt_len); 609147899Ssam return; 610147899Ssam } 611147899Ssam flags1 = *bp++; 612147899Ssam flags2 = *bp++; 613147899Ssam offset = EXTRACT_32BITS(bp); 614147899Ssam bp += sizeof(u_int32_t); 615147899Ssam seq = EXTRACT_32BITS(bp); 616147899Ssam bp += sizeof(u_int32_t); 617147899Ssam (void)printf(" BACKOFF max %u min %u", offset, seq); 618147899Ssam opts_len -= 12; 619147899Ssam break; 620147899Ssam 621147899Ssam case PGM_OPT_REDIRECT: 622147899Ssam flags1 = *bp++; 623147899Ssam flags2 = *bp++; 624147899Ssam switch (EXTRACT_16BITS(bp)) { 625147899Ssam case AFI_IP: 626147899Ssam addr_size = sizeof(struct in_addr); 627147899Ssam nla_af = AF_INET; 628147899Ssam break; 629147899Ssam#ifdef INET6 630147899Ssam case AFI_IP6: 631147899Ssam addr_size = sizeof(struct in6_addr); 632147899Ssam nla_af = AF_INET6; 633147899Ssam break; 634147899Ssam#endif 635147899Ssam default: 636147899Ssam goto trunc; 637147899Ssam break; 638147899Ssam } 639147899Ssam bp += (2 * sizeof(u_int16_t)); 640147899Ssam if (opt_len != 4 + addr_size) { 641147899Ssam (void)printf("[Bad OPT_REDIRECT option, length %u != 4 + address size]", opt_len); 642147899Ssam return; 643147899Ssam } 644147899Ssam TCHECK2(*bp, addr_size); 645147899Ssam nla = bp; 646147899Ssam bp += addr_size; 647147899Ssam 648147899Ssam inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf)); 649147899Ssam (void)printf(" REDIRECT %s", (char *)nla); 650147899Ssam opts_len -= 4 + addr_size; 651147899Ssam break; 652147899Ssam 653147899Ssam case PGM_OPT_PARITY_PRM: 654147899Ssam if (opt_len != 8) { 655147899Ssam (void)printf("[Bad OPT_PARITY_PRM option, length %u != 8]", opt_len); 656147899Ssam return; 657147899Ssam } 658147899Ssam flags1 = *bp++; 659147899Ssam flags2 = *bp++; 660147899Ssam len = EXTRACT_32BITS(bp); 661147899Ssam bp += sizeof(u_int32_t); 662147899Ssam (void)printf(" PARITY MAXTGS %u", len); 663147899Ssam opts_len -= 8; 664147899Ssam break; 665147899Ssam 666147899Ssam case PGM_OPT_PARITY_GRP: 667147899Ssam if (opt_len != 8) { 668147899Ssam (void)printf("[Bad OPT_PARITY_GRP option, length %u != 8]", opt_len); 669147899Ssam return; 670147899Ssam } 671147899Ssam flags1 = *bp++; 672147899Ssam flags2 = *bp++; 673147899Ssam seq = EXTRACT_32BITS(bp); 674147899Ssam bp += sizeof(u_int32_t); 675147899Ssam (void)printf(" PARITY GROUP %u", seq); 676147899Ssam opts_len -= 8; 677147899Ssam break; 678147899Ssam 679147899Ssam case PGM_OPT_CURR_TGSIZE: 680147899Ssam if (opt_len != 8) { 681147899Ssam (void)printf("[Bad OPT_CURR_TGSIZE option, length %u != 8]", opt_len); 682147899Ssam return; 683147899Ssam } 684147899Ssam flags1 = *bp++; 685147899Ssam flags2 = *bp++; 686147899Ssam len = EXTRACT_32BITS(bp); 687147899Ssam bp += sizeof(u_int32_t); 688147899Ssam (void)printf(" PARITY ATGS %u", len); 689147899Ssam opts_len -= 8; 690147899Ssam break; 691147899Ssam 692147899Ssam case PGM_OPT_NBR_UNREACH: 693147899Ssam if (opt_len != 4) { 694147899Ssam (void)printf("[Bad OPT_NBR_UNREACH option, length %u != 4]", opt_len); 695147899Ssam return; 696147899Ssam } 697147899Ssam flags1 = *bp++; 698147899Ssam flags2 = *bp++; 699147899Ssam (void)printf(" NBR_UNREACH"); 700147899Ssam opts_len -= 4; 701147899Ssam break; 702147899Ssam 703147899Ssam case PGM_OPT_PATH_NLA: 704147899Ssam (void)printf(" PATH_NLA [%d]", opt_len); 705147899Ssam bp += opt_len; 706147899Ssam opts_len -= opt_len; 707147899Ssam break; 708147899Ssam 709147899Ssam case PGM_OPT_SYN: 710147899Ssam if (opt_len != 4) { 711147899Ssam (void)printf("[Bad OPT_SYN option, length %u != 4]", opt_len); 712147899Ssam return; 713147899Ssam } 714147899Ssam flags1 = *bp++; 715147899Ssam flags2 = *bp++; 716147899Ssam (void)printf(" SYN"); 717147899Ssam opts_len -= 4; 718147899Ssam break; 719147899Ssam 720147899Ssam case PGM_OPT_FIN: 721147899Ssam if (opt_len != 4) { 722147899Ssam (void)printf("[Bad OPT_FIN option, length %u != 4]", opt_len); 723147899Ssam return; 724147899Ssam } 725147899Ssam flags1 = *bp++; 726147899Ssam flags2 = *bp++; 727147899Ssam (void)printf(" FIN"); 728147899Ssam opts_len -= 4; 729147899Ssam break; 730147899Ssam 731147899Ssam case PGM_OPT_RST: 732147899Ssam if (opt_len != 4) { 733147899Ssam (void)printf("[Bad OPT_RST option, length %u != 4]", opt_len); 734147899Ssam return; 735147899Ssam } 736147899Ssam flags1 = *bp++; 737147899Ssam flags2 = *bp++; 738147899Ssam (void)printf(" RST"); 739147899Ssam opts_len -= 4; 740147899Ssam break; 741147899Ssam 742147899Ssam case PGM_OPT_CR: 743147899Ssam (void)printf(" CR"); 744147899Ssam bp += opt_len; 745147899Ssam opts_len -= opt_len; 746147899Ssam break; 747147899Ssam 748147899Ssam case PGM_OPT_CRQST: 749147899Ssam if (opt_len != 4) { 750147899Ssam (void)printf("[Bad OPT_CRQST option, length %u != 4]", opt_len); 751147899Ssam return; 752147899Ssam } 753147899Ssam flags1 = *bp++; 754147899Ssam flags2 = *bp++; 755147899Ssam (void)printf(" CRQST"); 756147899Ssam opts_len -= 4; 757147899Ssam break; 758147899Ssam 759236192Sdelphij case PGM_OPT_PGMCC_DATA: 760236192Sdelphij flags1 = *bp++; 761236192Sdelphij flags2 = *bp++; 762236192Sdelphij offset = EXTRACT_32BITS(bp); 763236192Sdelphij bp += sizeof(u_int32_t); 764236192Sdelphij switch (EXTRACT_16BITS(bp)) { 765236192Sdelphij case AFI_IP: 766236192Sdelphij addr_size = sizeof(struct in_addr); 767236192Sdelphij nla_af = AF_INET; 768236192Sdelphij break; 769236192Sdelphij#ifdef INET6 770236192Sdelphij case AFI_IP6: 771236192Sdelphij addr_size = sizeof(struct in6_addr); 772236192Sdelphij nla_af = AF_INET6; 773236192Sdelphij break; 774236192Sdelphij#endif 775236192Sdelphij default: 776236192Sdelphij goto trunc; 777236192Sdelphij break; 778236192Sdelphij } 779236192Sdelphij bp += (2 * sizeof(u_int16_t)); 780236192Sdelphij if (opt_len != 12 + addr_size) { 781236192Sdelphij (void)printf("[Bad OPT_PGMCC_DATA option, length %u != 12 + address size]", opt_len); 782236192Sdelphij return; 783236192Sdelphij } 784236192Sdelphij TCHECK2(*bp, addr_size); 785236192Sdelphij nla = bp; 786236192Sdelphij bp += addr_size; 787236192Sdelphij 788236192Sdelphij inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf)); 789236192Sdelphij (void)printf(" PGMCC DATA %u %s", offset, (char*)nla); 790236192Sdelphij opts_len -= 16; 791236192Sdelphij break; 792236192Sdelphij 793236192Sdelphij case PGM_OPT_PGMCC_FEEDBACK: 794236192Sdelphij flags1 = *bp++; 795236192Sdelphij flags2 = *bp++; 796236192Sdelphij offset = EXTRACT_32BITS(bp); 797236192Sdelphij bp += sizeof(u_int32_t); 798236192Sdelphij switch (EXTRACT_16BITS(bp)) { 799236192Sdelphij case AFI_IP: 800236192Sdelphij addr_size = sizeof(struct in_addr); 801236192Sdelphij nla_af = AF_INET; 802236192Sdelphij break; 803236192Sdelphij#ifdef INET6 804236192Sdelphij case AFI_IP6: 805236192Sdelphij addr_size = sizeof(struct in6_addr); 806236192Sdelphij nla_af = AF_INET6; 807236192Sdelphij break; 808236192Sdelphij#endif 809236192Sdelphij default: 810236192Sdelphij goto trunc; 811236192Sdelphij break; 812236192Sdelphij } 813236192Sdelphij bp += (2 * sizeof(u_int16_t)); 814236192Sdelphij if (opt_len != 12 + addr_size) { 815236192Sdelphij (void)printf("[Bad OPT_PGMCC_FEEDBACK option, length %u != 12 + address size]", opt_len); 816236192Sdelphij return; 817236192Sdelphij } 818236192Sdelphij TCHECK2(*bp, addr_size); 819236192Sdelphij nla = bp; 820236192Sdelphij bp += addr_size; 821236192Sdelphij 822236192Sdelphij inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf)); 823236192Sdelphij (void)printf(" PGMCC FEEDBACK %u %s", offset, (char*)nla); 824236192Sdelphij opts_len -= 16; 825236192Sdelphij break; 826236192Sdelphij 827147899Ssam default: 828147899Ssam (void)printf(" OPT_%02X [%d] ", opt_type, opt_len); 829147899Ssam bp += opt_len; 830147899Ssam opts_len -= opt_len; 831147899Ssam break; 832147899Ssam } 833147899Ssam 834147899Ssam if (opt_type & PGM_OPT_END) 835147899Ssam break; 836147899Ssam } 837147899Ssam } 838147899Ssam 839147899Ssam (void)printf(" [%u]", EXTRACT_16BITS(&pgm->pgm_length)); 840147899Ssam 841147899Ssam return; 842147899Ssam 843147899Ssamtrunc: 844147899Ssam fputs("[|pgm]", stdout); 845147899Ssam if (ch != '\0') 846147899Ssam putchar('>'); 847147899Ssam} 848