print-pgm.c revision 236192
11541Srgrimes/* 21541Srgrimes * Redistribution and use in source and binary forms, with or without 31541Srgrimes * modification, are permitted provided that: (1) source code 41541Srgrimes * distributions retain the above copyright notice and this paragraph 51541Srgrimes * in its entirety, and (2) distributions including binary code include 61541Srgrimes * the above copyright notice and this paragraph in its entirety in 71541Srgrimes * the documentation or other materials provided with the distribution. 81541Srgrimes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 91541Srgrimes * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 101541Srgrimes * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 111541Srgrimes * FOR A PARTICULAR PURPOSE. 121541Srgrimes * 131541Srgrimes * Original code by Andy Heffernan (ahh@juniper.net) 141541Srgrimes */ 151541Srgrimes 161541Srgrimes#ifndef lint 171541Srgrimesstatic const char rcsid[] _U_ = 181541Srgrimes "@(#) $Header: /tcpdump/master/tcpdump/print-pgm.c,v 1.5 2005-06-07 22:05:58 guy Exp $"; 191541Srgrimes#endif 201541Srgrimes 211541Srgrimes#ifdef HAVE_CONFIG_H 221541Srgrimes#include "config.h" 231541Srgrimes#endif 241541Srgrimes 251541Srgrimes#include <tcpdump-stdinc.h> 261541Srgrimes 271541Srgrimes#include <stdio.h> 281541Srgrimes#include <stdlib.h> 291541Srgrimes#include <string.h> 301541Srgrimes 311541Srgrimes#include "interface.h" 321541Srgrimes#include "extract.h" 331541Srgrimes#include "addrtoname.h" 3436192Sdg 351541Srgrimes#include "ip.h" 361541Srgrimes#ifdef INET6 372169Spaul#include "ip6.h" 382169Spaul#endif 392169Spaul#include "ipproto.h" 401541Srgrimes 411541Srgrimes/* 421541Srgrimes * PGM header (RFC 3208) 431541Srgrimes */ 441541Srgrimesstruct pgm_header { 451541Srgrimes u_int16_t pgm_sport; 4633804Sjulian u_int16_t pgm_dport; 471541Srgrimes u_int8_t pgm_type; 481541Srgrimes u_int8_t pgm_options; 491541Srgrimes u_int16_t pgm_sum; 501541Srgrimes u_int8_t pgm_gsid[6]; 511541Srgrimes u_int16_t pgm_length; 529209Swollman}; 531541Srgrimes 5433804Sjulianstruct pgm_spm { 551541Srgrimes u_int32_t pgms_seq; 5633804Sjulian u_int32_t pgms_trailseq; 5733804Sjulian u_int32_t pgms_leadseq; 5833804Sjulian u_int16_t pgms_nla_afi; 591541Srgrimes u_int16_t pgms_reserved; 6033804Sjulian /* ... u_int8_t pgms_nla[0]; */ 6133804Sjulian /* ... options */ 6233804Sjulian}; 6333804Sjulian 641541Srgrimesstruct pgm_nak { 6533804Sjulian u_int32_t pgmn_seq; 6633804Sjulian u_int16_t pgmn_source_afi; 6733804Sjulian u_int16_t pgmn_reserved; 6833804Sjulian /* ... u_int8_t pgmn_source[0]; */ 691541Srgrimes /* ... u_int16_t pgmn_group_afi */ 7033804Sjulian /* ... u_int16_t pgmn_reserved2; */ 7133804Sjulian /* ... u_int8_t pgmn_group[0]; */ 7233804Sjulian /* ... options */ 7333804Sjulian}; 7433804Sjulian 7533804Sjulianstruct pgm_ack { 761541Srgrimes u_int32_t pgma_rx_max_seq; 7733804Sjulian u_int32_t pgma_bitmap; 7833804Sjulian /* ... options */ 7933804Sjulian}; 8033804Sjulian 8133804Sjulianstruct pgm_poll { 8233804Sjulian u_int32_t pgmp_seq; 8333804Sjulian u_int16_t pgmp_round; 8433804Sjulian u_int16_t pgmp_reserved; 8533804Sjulian /* ... options */ 8633804Sjulian}; 8733804Sjulian 8833804Sjulianstruct pgm_polr { 8933804Sjulian u_int32_t pgmp_seq; 9033804Sjulian u_int16_t pgmp_round; 9133804Sjulian u_int16_t pgmp_subtype; 9233804Sjulian u_int16_t pgmp_nla_afi; 932531Swollman u_int16_t pgmp_reserved; 9433804Sjulian /* ... u_int8_t pgmp_nla[0]; */ 9533804Sjulian /* ... options */ 9633804Sjulian}; 9733804Sjulian 9833804Sjulianstruct pgm_data { 9933804Sjulian u_int32_t pgmd_seq; 10033804Sjulian u_int32_t pgmd_trailseq; 10133804Sjulian /* ... options */ 10233804Sjulian}; 10333804Sjulian 10433804Sjuliantypedef enum _pgm_type { 10533804Sjulian PGM_SPM = 0, /* source path message */ 10633804Sjulian PGM_POLL = 1, /* POLL Request */ 10733804Sjulian PGM_POLR = 2, /* POLL Response */ 10833804Sjulian PGM_ODATA = 4, /* original data */ 10933804Sjulian PGM_RDATA = 5, /* repair data */ 11033804Sjulian PGM_NAK = 8, /* NAK */ 11133804Sjulian PGM_NULLNAK = 9, /* Null NAK */ 11233804Sjulian PGM_NCF = 10, /* NAK Confirmation */ 11333804Sjulian PGM_ACK = 11, /* ACK for congestion control */ 11433804Sjulian PGM_SPMR = 12, /* SPM request */ 11533804Sjulian PGM_MAX = 255 11633804Sjulian} pgm_type; 11733804Sjulian 11833804Sjulian#define PGM_OPT_BIT_PRESENT 0x01 11933804Sjulian#define PGM_OPT_BIT_NETWORK 0x02 12033804Sjulian#define PGM_OPT_BIT_VAR_PKTLEN 0x40 12133804Sjulian#define PGM_OPT_BIT_PARITY 0x80 1221541Srgrimes 12333804Sjulian#define PGM_OPT_LENGTH 0x00 12433804Sjulian#define PGM_OPT_FRAGMENT 0x01 12533804Sjulian#define PGM_OPT_NAK_LIST 0x02 12633804Sjulian#define PGM_OPT_JOIN 0x03 12733804Sjulian#define PGM_OPT_NAK_BO_IVL 0x04 12833804Sjulian#define PGM_OPT_NAK_BO_RNG 0x05 12933814Sjulian 13033804Sjulian#define PGM_OPT_REDIRECT 0x07 13133804Sjulian#define PGM_OPT_PARITY_PRM 0x08 13233804Sjulian#define PGM_OPT_PARITY_GRP 0x09 13333804Sjulian#define PGM_OPT_CURR_TGSIZE 0x0A 13433804Sjulian#define PGM_OPT_NBR_UNREACH 0x0B 13533804Sjulian#define PGM_OPT_PATH_NLA 0x0C 13633804Sjulian 13733804Sjulian#define PGM_OPT_SYN 0x0D 13833804Sjulian#define PGM_OPT_FIN 0x0E 13933804Sjulian#define PGM_OPT_RST 0x0F 1401541Srgrimes#define PGM_OPT_CR 0x10 14133804Sjulian#define PGM_OPT_CRQST 0x11 14233804Sjulian 14333804Sjulian#define PGM_OPT_PGMCC_DATA 0x12 14433804Sjulian#define PGM_OPT_PGMCC_FEEDBACK 0x13 14533804Sjulian 14617072Sjulian#define PGM_OPT_MASK 0x7f 1471541Srgrimes 1481541Srgrimes#define PGM_OPT_END 0x80 /* end of options marker */ 1491541Srgrimes 1501541Srgrimes#define PGM_MIN_OPT_LEN 4 1511541Srgrimes 1521541Srgrimes#ifndef AFI_IP 15314195Speter#define AFI_IP 1 15414195Speter#define AFI_IP6 2 15514195Speter#endif 15614195Speter 15714195Spetervoid 15814195Speterpgm_print(register const u_char *bp, register u_int length, 15914195Speter register const u_char *bp2) 16014195Speter{ 16114195Speter register const struct pgm_header *pgm; 16214195Speter register const struct ip *ip; 16314195Speter register char ch; 16414195Speter u_int16_t sport, dport; 16514195Speter int addr_size; 16614195Speter const void *nla; 16714195Speter int nla_af; 16814195Speter#ifdef INET6 16914195Speter char nla_buf[INET6_ADDRSTRLEN]; 17014195Speter register const struct ip6_hdr *ip6; 17114195Speter#else 17214195Speter char nla_buf[INET_ADDRSTRLEN]; 17314195Speter#endif 17417541Speter u_int8_t opt_type, opt_len, flags1, flags2; 17514195Speter u_int32_t seq, opts_len, len, offset; 17614195Speter 17714195Speter pgm = (struct pgm_header *)bp; 17814195Speter ip = (struct ip *)bp2; 17914195Speter#ifdef INET6 18014195Speter if (IP_V(ip) == 6) 18114195Speter ip6 = (struct ip6_hdr *)bp2; 18214195Speter else 18335304Sphk ip6 = NULL; 18435304Sphk#else /* INET6 */ 18535304Sphk if (IP_V(ip) == 6) { 18635304Sphk (void)printf("Can't handle IPv6"); 18735304Sphk return; 18835304Sphk } 18935304Sphk#endif /* INET6 */ 19035304Sphk ch = '\0'; 19135304Sphk if (!TTEST(pgm->pgm_dport)) { 19235304Sphk#ifdef INET6 19335304Sphk if (ip6) { 19414195Speter (void)printf("%s > %s: [|pgm]", 19514195Speter ip6addr_string(&ip6->ip6_src), 19614195Speter ip6addr_string(&ip6->ip6_dst)); 1971541Srgrimes return; 19814195Speter } else 1991541Srgrimes#endif /* INET6 */ 20014195Speter { 2011541Srgrimes (void)printf("%s > %s: [|pgm]", 2021541Srgrimes ipaddr_string(&ip->ip_src), 2031541Srgrimes ipaddr_string(&ip->ip_dst)); 2041541Srgrimes return; 2051541Srgrimes } 20614195Speter } 20713491Speter 20835304Sphk sport = EXTRACT_16BITS(&pgm->pgm_sport); 20935304Sphk dport = EXTRACT_16BITS(&pgm->pgm_dport); 21013491Speter 21113491Speter#ifdef INET6 21217541Speter if (ip6) { 21317541Speter if (ip6->ip6_nxt == IPPROTO_PGM) { 21417541Speter (void)printf("%s.%s > %s.%s: ", 21517541Speter ip6addr_string(&ip6->ip6_src), 21617541Speter tcpport_string(sport), 21717541Speter ip6addr_string(&ip6->ip6_dst), 21817541Speter tcpport_string(dport)); 21917541Speter } else { 2201541Srgrimes (void)printf("%s > %s: ", 2211541Srgrimes tcpport_string(sport), tcpport_string(dport)); 2221541Srgrimes } 22335919Sjb } else 2241541Srgrimes#endif /*INET6*/ 2251541Srgrimes { 2261541Srgrimes if (ip->ip_p == IPPROTO_PGM) { 2271541Srgrimes (void)printf("%s.%s > %s.%s: ", 2281541Srgrimes ipaddr_string(&ip->ip_src), 2291541Srgrimes tcpport_string(sport), 2301541Srgrimes ipaddr_string(&ip->ip_dst), 23135919Sjb tcpport_string(dport)); 2321541Srgrimes } else { 2331541Srgrimes (void)printf("%s > %s: ", 2341541Srgrimes tcpport_string(sport), tcpport_string(dport)); 2351541Srgrimes } 2361541Srgrimes } 23735919Sjb 2381541Srgrimes TCHECK(*pgm); 2391541Srgrimes 2401541Srgrimes (void)printf("PGM, length %u", pgm->pgm_length); 2411541Srgrimes 2421541Srgrimes if (!vflag) 24335919Sjb return; 2441541Srgrimes 2451541Srgrimes if (length > pgm->pgm_length) 2461541Srgrimes length = pgm->pgm_length; 2471541Srgrimes 24835919Sjb (void)printf(" 0x%02x%02x%02x%02x%02x%02x ", 2491541Srgrimes pgm->pgm_gsid[0], 2501541Srgrimes pgm->pgm_gsid[1], 2511541Srgrimes pgm->pgm_gsid[2], 2521541Srgrimes pgm->pgm_gsid[3], 2531541Srgrimes pgm->pgm_gsid[4], 25435919Sjb pgm->pgm_gsid[5]); 25535919Sjb switch (pgm->pgm_type) { 2561541Srgrimes case PGM_SPM: { 25735919Sjb struct pgm_spm *spm; 25835919Sjb 25935919Sjb spm = (struct pgm_spm *)(pgm + 1); 2601541Srgrimes TCHECK(*spm); 2611541Srgrimes 2621541Srgrimes switch (EXTRACT_16BITS(&spm->pgms_nla_afi)) { 2631541Srgrimes case AFI_IP: 26435919Sjb addr_size = sizeof(struct in_addr); 26535919Sjb nla_af = AF_INET; 26635919Sjb break; 26735919Sjb#ifdef INET6 2681541Srgrimes case AFI_IP6: 2691541Srgrimes addr_size = sizeof(struct in6_addr); 2701541Srgrimes nla_af = AF_INET6; 2711541Srgrimes break; 2721541Srgrimes#endif 2731541Srgrimes default: 2741541Srgrimes goto trunc; 2751541Srgrimes break; 2761541Srgrimes } 2771541Srgrimes bp = (u_char *) (spm + 1); 2781541Srgrimes TCHECK2(*bp, addr_size); 2791541Srgrimes nla = bp; 2801541Srgrimes bp += addr_size; 2811541Srgrimes 2821541Srgrimes inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf)); 2831541Srgrimes (void)printf("SPM seq %u trail %u lead %u nla %s", 2841541Srgrimes EXTRACT_32BITS(&spm->pgms_seq), 2851541Srgrimes EXTRACT_32BITS(&spm->pgms_trailseq), 2861541Srgrimes EXTRACT_32BITS(&spm->pgms_leadseq), 2871541Srgrimes nla_buf); 2881541Srgrimes break; 2891541Srgrimes } 2901541Srgrimes 2911541Srgrimes case PGM_POLL: { 2921541Srgrimes struct pgm_poll *poll; 2931541Srgrimes 2941541Srgrimes poll = (struct pgm_poll *)(pgm + 1); 2951541Srgrimes TCHECK(*poll); 2961541Srgrimes (void)printf("POLL seq %u round %u", 2971541Srgrimes EXTRACT_32BITS(&poll->pgmp_seq), 2981541Srgrimes EXTRACT_16BITS(&poll->pgmp_round)); 2991541Srgrimes bp = (u_char *) (poll + 1); 3001541Srgrimes break; 3011541Srgrimes } 3021541Srgrimes case PGM_POLR: { 3031541Srgrimes struct pgm_polr *polr; 3041541Srgrimes u_int32_t ivl, rnd, mask; 3051541Srgrimes 3061541Srgrimes polr = (struct pgm_polr *)(pgm + 1); 3071541Srgrimes TCHECK(*polr); 3081541Srgrimes 3091541Srgrimes switch (EXTRACT_16BITS(&polr->pgmp_nla_afi)) { 3101541Srgrimes case AFI_IP: 3112531Swollman addr_size = sizeof(struct in_addr); 3122531Swollman nla_af = AF_INET; 3132531Swollman break; 3149209Swollman#ifdef INET6 3159209Swollman case AFI_IP6: 31614195Speter addr_size = sizeof(struct in6_addr); 31719622Sfenner nla_af = AF_INET6; 3181541Srgrimes break; 31917758Ssos#endif 32017758Ssos default: 32117758Ssos goto trunc; 32219035Salex break; 32317758Ssos } 32417758Ssos bp = (u_char *) (polr + 1); 32517758Ssos TCHECK2(*bp, addr_size); 3261541Srgrimes nla = bp; 3271541Srgrimes bp += addr_size; 3281541Srgrimes 3291541Srgrimes inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf)); 3301541Srgrimes 3319209Swollman TCHECK2(*bp, sizeof(u_int32_t)); 3321541Srgrimes ivl = EXTRACT_32BITS(bp); 3331541Srgrimes bp += sizeof(u_int32_t); 3341541Srgrimes 3351541Srgrimes TCHECK2(*bp, sizeof(u_int32_t)); 3361541Srgrimes rnd = EXTRACT_32BITS(bp); 3371541Srgrimes bp += sizeof(u_int32_t); 3381541Srgrimes 3391541Srgrimes TCHECK2(*bp, sizeof(u_int32_t)); 3401541Srgrimes mask = EXTRACT_32BITS(bp); 3411541Srgrimes bp += sizeof(u_int32_t); 34214195Speter 34314195Speter (void)printf("POLR seq %u round %u nla %s ivl %u rnd 0x%08x " 34414195Speter "mask 0x%08x", EXTRACT_32BITS(&polr->pgmp_seq), 34514195Speter EXTRACT_16BITS(&polr->pgmp_round), nla_buf, ivl, rnd, mask); 34614195Speter break; 34714195Speter } 34814195Speter case PGM_ODATA: { 34914195Speter struct pgm_data *odata; 3501541Srgrimes 3511541Srgrimes odata = (struct pgm_data *)(pgm + 1); 3521541Srgrimes TCHECK(*odata); 3531541Srgrimes (void)printf("ODATA trail %u seq %u", 3541541Srgrimes EXTRACT_32BITS(&odata->pgmd_trailseq), 3551541Srgrimes EXTRACT_32BITS(&odata->pgmd_seq)); 3561541Srgrimes bp = (u_char *) (odata + 1); 3571541Srgrimes break; 3581541Srgrimes } 3591541Srgrimes 3601541Srgrimes case PGM_RDATA: { 3611541Srgrimes struct pgm_data *rdata; 3621541Srgrimes 3631541Srgrimes rdata = (struct pgm_data *)(pgm + 1); 3641541Srgrimes TCHECK(*rdata); 3651541Srgrimes (void)printf("RDATA trail %u seq %u", 3661541Srgrimes EXTRACT_32BITS(&rdata->pgmd_trailseq), 3671541Srgrimes EXTRACT_32BITS(&rdata->pgmd_seq)); 3681541Srgrimes bp = (u_char *) (rdata + 1); 3691541Srgrimes break; 3701541Srgrimes } 3711541Srgrimes 3721541Srgrimes case PGM_NAK: 3731541Srgrimes case PGM_NULLNAK: 3741541Srgrimes case PGM_NCF: { 3751541Srgrimes struct pgm_nak *nak; 3761541Srgrimes const void *source, *group; 3771541Srgrimes int source_af, group_af; 3781541Srgrimes#ifdef INET6 3791541Srgrimes char source_buf[INET6_ADDRSTRLEN], group_buf[INET6_ADDRSTRLEN]; 3801541Srgrimes#else 3811541Srgrimes char source_buf[INET_ADDRSTRLEN], group_buf[INET_ADDRSTRLEN]; 3821541Srgrimes#endif 3831541Srgrimes 3841541Srgrimes nak = (struct pgm_nak *)(pgm + 1); 3851541Srgrimes TCHECK(*nak); 3861541Srgrimes 3871541Srgrimes /* 3881541Srgrimes * Skip past the source, saving info along the way 3891541Srgrimes * and stopping if we don't have enough. 3901541Srgrimes */ 3911541Srgrimes switch (EXTRACT_16BITS(&nak->pgmn_source_afi)) { 3925109Swollman case AFI_IP: 3936399Swollman addr_size = sizeof(struct in_addr); 3946399Swollman source_af = AF_INET; 3957091Swollman break; 3969575Speter#ifdef INET6 39712003Swollman case AFI_IP6: 39812003Swollman addr_size = sizeof(struct in6_addr); 39929838Swollman source_af = AF_INET6; 40033440Sguido break; 40136192Sdg#endif 40236192Sdg default: 4031541Srgrimes goto trunc; 4041541Srgrimes break; 4051541Srgrimes } 4061541Srgrimes bp = (u_char *) (nak + 1); 4071541Srgrimes TCHECK2(*bp, addr_size); 4081541Srgrimes source = bp; 4091541Srgrimes bp += addr_size; 4105109Swollman 4116399Swollman /* 4126399Swollman * Skip past the group, saving info along the way 4137091Swollman * and stopping if we don't have enough. 4149575Speter */ 41512003Swollman switch (EXTRACT_16BITS(bp)) { 41612003Swollman case AFI_IP: 41729838Swollman addr_size = sizeof(struct in_addr); 41833440Sguido group_af = AF_INET; 41936192Sdg break; 4201541Srgrimes#ifdef INET6 4211541Srgrimes case AFI_IP6: 4221541Srgrimes addr_size = sizeof(struct in6_addr); 4231541Srgrimes group_af = AF_INET6; 4247088Swollman break; 4257088Swollman#endif 4261541Srgrimes default: 4271541Srgrimes goto trunc; 4281541Srgrimes break; 4291541Srgrimes } 4307088Swollman bp += (2 * sizeof(u_int16_t)); 4312169Spaul TCHECK2(*bp, addr_size); 43215026Sphk group = bp; 43315026Sphk bp += addr_size; 43417758Ssos 43517758Ssos /* 43617758Ssos * Options decoding can go here. 43717758Ssos */ 43817758Ssos inet_ntop(source_af, source, source_buf, sizeof(source_buf)); 43919035Salex inet_ntop(group_af, group, group_buf, sizeof(group_buf)); 44019113Ssos switch (pgm->pgm_type) { 44117758Ssos case PGM_NAK: 44217758Ssos (void)printf("NAK "); 44317758Ssos break; 44417758Ssos case PGM_NULLNAK: 44517758Ssos (void)printf("NNAK "); 44617758Ssos break; 44715026Sphk case PGM_NCF: 44815026Sphk (void)printf("NCF "); 4492169Spaul break; 450 default: 451 break; 452 } 453 (void)printf("(%s -> %s), seq %u", 454 source_buf, group_buf, EXTRACT_32BITS(&nak->pgmn_seq)); 455 break; 456 } 457 458 case PGM_ACK: { 459 struct pgm_ack *ack; 460 461 ack = (struct pgm_ack *)(pgm + 1); 462 TCHECK(*ack); 463 (void)printf("ACK seq %u", 464 EXTRACT_32BITS(&ack->pgma_rx_max_seq)); 465 bp = (u_char *) (ack + 1); 466 break; 467 } 468 469 case PGM_SPMR: 470 (void)printf("SPMR"); 471 break; 472 473 default: 474 (void)printf("UNKNOWN type %0x02x", pgm->pgm_type); 475 break; 476 477 } 478 if (pgm->pgm_options & PGM_OPT_BIT_PRESENT) { 479 480 /* 481 * make sure there's enough for the first option header 482 */ 483 if (!TTEST2(*bp, PGM_MIN_OPT_LEN)) { 484 (void)printf("[|OPT]"); 485 return; 486 } 487 488 /* 489 * That option header MUST be an OPT_LENGTH option 490 * (see the first paragraph of section 9.1 in RFC 3208). 491 */ 492 opt_type = *bp++; 493 if ((opt_type & PGM_OPT_MASK) != PGM_OPT_LENGTH) { 494 (void)printf("[First option bad, should be PGM_OPT_LENGTH, is %u]", opt_type & PGM_OPT_MASK); 495 return; 496 } 497 opt_len = *bp++; 498 if (opt_len != 4) { 499 (void)printf("[Bad OPT_LENGTH option, length %u != 4]", opt_len); 500 return; 501 } 502 opts_len = EXTRACT_16BITS(bp); 503 if (opts_len < 4) { 504 (void)printf("[Bad total option length %u < 4]", opts_len); 505 return; 506 } 507 bp += sizeof(u_int16_t); 508 (void)printf(" OPTS LEN %d", opts_len); 509 opts_len -= 4; 510 511 while (opts_len) { 512 if (opts_len < PGM_MIN_OPT_LEN) { 513 (void)printf("[Total option length leaves no room for final option]"); 514 return; 515 } 516 opt_type = *bp++; 517 opt_len = *bp++; 518 if (opt_len < PGM_MIN_OPT_LEN) { 519 (void)printf("[Bad option, length %u < %u]", opt_len, 520 PGM_MIN_OPT_LEN); 521 break; 522 } 523 if (opts_len < opt_len) { 524 (void)printf("[Total option length leaves no room for final option]"); 525 return; 526 } 527 if (!TTEST2(*bp, opt_len - 2)) { 528 (void)printf(" [|OPT]"); 529 return; 530 } 531 532 switch (opt_type & PGM_OPT_MASK) { 533 case PGM_OPT_LENGTH: 534 if (opt_len != 4) { 535 (void)printf("[Bad OPT_LENGTH option, length %u != 4]", opt_len); 536 return; 537 } 538 (void)printf(" OPTS LEN (extra?) %d", EXTRACT_16BITS(bp)); 539 bp += sizeof(u_int16_t); 540 opts_len -= 4; 541 break; 542 543 case PGM_OPT_FRAGMENT: 544 if (opt_len != 16) { 545 (void)printf("[Bad OPT_FRAGMENT option, length %u != 16]", opt_len); 546 return; 547 } 548 flags1 = *bp++; 549 flags2 = *bp++; 550 seq = EXTRACT_32BITS(bp); 551 bp += sizeof(u_int32_t); 552 offset = EXTRACT_32BITS(bp); 553 bp += sizeof(u_int32_t); 554 len = EXTRACT_32BITS(bp); 555 bp += sizeof(u_int32_t); 556 (void)printf(" FRAG seq %u off %u len %u", seq, offset, len); 557 opts_len -= 16; 558 break; 559 560 case PGM_OPT_NAK_LIST: 561 flags1 = *bp++; 562 flags2 = *bp++; 563 opt_len -= sizeof(u_int32_t); /* option header */ 564 (void)printf(" NAK LIST"); 565 while (opt_len) { 566 if (opt_len < sizeof(u_int32_t)) { 567 (void)printf("[Option length not a multiple of 4]"); 568 return; 569 } 570 TCHECK2(*bp, sizeof(u_int32_t)); 571 (void)printf(" %u", EXTRACT_32BITS(bp)); 572 bp += sizeof(u_int32_t); 573 opt_len -= sizeof(u_int32_t); 574 opts_len -= sizeof(u_int32_t); 575 } 576 break; 577 578 case PGM_OPT_JOIN: 579 if (opt_len != 8) { 580 (void)printf("[Bad OPT_JOIN option, length %u != 8]", opt_len); 581 return; 582 } 583 flags1 = *bp++; 584 flags2 = *bp++; 585 seq = EXTRACT_32BITS(bp); 586 bp += sizeof(u_int32_t); 587 (void)printf(" JOIN %u", seq); 588 opts_len -= 8; 589 break; 590 591 case PGM_OPT_NAK_BO_IVL: 592 if (opt_len != 12) { 593 (void)printf("[Bad OPT_NAK_BO_IVL option, length %u != 12]", opt_len); 594 return; 595 } 596 flags1 = *bp++; 597 flags2 = *bp++; 598 offset = EXTRACT_32BITS(bp); 599 bp += sizeof(u_int32_t); 600 seq = EXTRACT_32BITS(bp); 601 bp += sizeof(u_int32_t); 602 (void)printf(" BACKOFF ivl %u ivlseq %u", offset, seq); 603 opts_len -= 12; 604 break; 605 606 case PGM_OPT_NAK_BO_RNG: 607 if (opt_len != 12) { 608 (void)printf("[Bad OPT_NAK_BO_RNG option, length %u != 12]", opt_len); 609 return; 610 } 611 flags1 = *bp++; 612 flags2 = *bp++; 613 offset = EXTRACT_32BITS(bp); 614 bp += sizeof(u_int32_t); 615 seq = EXTRACT_32BITS(bp); 616 bp += sizeof(u_int32_t); 617 (void)printf(" BACKOFF max %u min %u", offset, seq); 618 opts_len -= 12; 619 break; 620 621 case PGM_OPT_REDIRECT: 622 flags1 = *bp++; 623 flags2 = *bp++; 624 switch (EXTRACT_16BITS(bp)) { 625 case AFI_IP: 626 addr_size = sizeof(struct in_addr); 627 nla_af = AF_INET; 628 break; 629#ifdef INET6 630 case AFI_IP6: 631 addr_size = sizeof(struct in6_addr); 632 nla_af = AF_INET6; 633 break; 634#endif 635 default: 636 goto trunc; 637 break; 638 } 639 bp += (2 * sizeof(u_int16_t)); 640 if (opt_len != 4 + addr_size) { 641 (void)printf("[Bad OPT_REDIRECT option, length %u != 4 + address size]", opt_len); 642 return; 643 } 644 TCHECK2(*bp, addr_size); 645 nla = bp; 646 bp += addr_size; 647 648 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf)); 649 (void)printf(" REDIRECT %s", (char *)nla); 650 opts_len -= 4 + addr_size; 651 break; 652 653 case PGM_OPT_PARITY_PRM: 654 if (opt_len != 8) { 655 (void)printf("[Bad OPT_PARITY_PRM option, length %u != 8]", opt_len); 656 return; 657 } 658 flags1 = *bp++; 659 flags2 = *bp++; 660 len = EXTRACT_32BITS(bp); 661 bp += sizeof(u_int32_t); 662 (void)printf(" PARITY MAXTGS %u", len); 663 opts_len -= 8; 664 break; 665 666 case PGM_OPT_PARITY_GRP: 667 if (opt_len != 8) { 668 (void)printf("[Bad OPT_PARITY_GRP option, length %u != 8]", opt_len); 669 return; 670 } 671 flags1 = *bp++; 672 flags2 = *bp++; 673 seq = EXTRACT_32BITS(bp); 674 bp += sizeof(u_int32_t); 675 (void)printf(" PARITY GROUP %u", seq); 676 opts_len -= 8; 677 break; 678 679 case PGM_OPT_CURR_TGSIZE: 680 if (opt_len != 8) { 681 (void)printf("[Bad OPT_CURR_TGSIZE option, length %u != 8]", opt_len); 682 return; 683 } 684 flags1 = *bp++; 685 flags2 = *bp++; 686 len = EXTRACT_32BITS(bp); 687 bp += sizeof(u_int32_t); 688 (void)printf(" PARITY ATGS %u", len); 689 opts_len -= 8; 690 break; 691 692 case PGM_OPT_NBR_UNREACH: 693 if (opt_len != 4) { 694 (void)printf("[Bad OPT_NBR_UNREACH option, length %u != 4]", opt_len); 695 return; 696 } 697 flags1 = *bp++; 698 flags2 = *bp++; 699 (void)printf(" NBR_UNREACH"); 700 opts_len -= 4; 701 break; 702 703 case PGM_OPT_PATH_NLA: 704 (void)printf(" PATH_NLA [%d]", opt_len); 705 bp += opt_len; 706 opts_len -= opt_len; 707 break; 708 709 case PGM_OPT_SYN: 710 if (opt_len != 4) { 711 (void)printf("[Bad OPT_SYN option, length %u != 4]", opt_len); 712 return; 713 } 714 flags1 = *bp++; 715 flags2 = *bp++; 716 (void)printf(" SYN"); 717 opts_len -= 4; 718 break; 719 720 case PGM_OPT_FIN: 721 if (opt_len != 4) { 722 (void)printf("[Bad OPT_FIN option, length %u != 4]", opt_len); 723 return; 724 } 725 flags1 = *bp++; 726 flags2 = *bp++; 727 (void)printf(" FIN"); 728 opts_len -= 4; 729 break; 730 731 case PGM_OPT_RST: 732 if (opt_len != 4) { 733 (void)printf("[Bad OPT_RST option, length %u != 4]", opt_len); 734 return; 735 } 736 flags1 = *bp++; 737 flags2 = *bp++; 738 (void)printf(" RST"); 739 opts_len -= 4; 740 break; 741 742 case PGM_OPT_CR: 743 (void)printf(" CR"); 744 bp += opt_len; 745 opts_len -= opt_len; 746 break; 747 748 case PGM_OPT_CRQST: 749 if (opt_len != 4) { 750 (void)printf("[Bad OPT_CRQST option, length %u != 4]", opt_len); 751 return; 752 } 753 flags1 = *bp++; 754 flags2 = *bp++; 755 (void)printf(" CRQST"); 756 opts_len -= 4; 757 break; 758 759 case PGM_OPT_PGMCC_DATA: 760 flags1 = *bp++; 761 flags2 = *bp++; 762 offset = EXTRACT_32BITS(bp); 763 bp += sizeof(u_int32_t); 764 switch (EXTRACT_16BITS(bp)) { 765 case AFI_IP: 766 addr_size = sizeof(struct in_addr); 767 nla_af = AF_INET; 768 break; 769#ifdef INET6 770 case AFI_IP6: 771 addr_size = sizeof(struct in6_addr); 772 nla_af = AF_INET6; 773 break; 774#endif 775 default: 776 goto trunc; 777 break; 778 } 779 bp += (2 * sizeof(u_int16_t)); 780 if (opt_len != 12 + addr_size) { 781 (void)printf("[Bad OPT_PGMCC_DATA option, length %u != 12 + address size]", opt_len); 782 return; 783 } 784 TCHECK2(*bp, addr_size); 785 nla = bp; 786 bp += addr_size; 787 788 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf)); 789 (void)printf(" PGMCC DATA %u %s", offset, (char*)nla); 790 opts_len -= 16; 791 break; 792 793 case PGM_OPT_PGMCC_FEEDBACK: 794 flags1 = *bp++; 795 flags2 = *bp++; 796 offset = EXTRACT_32BITS(bp); 797 bp += sizeof(u_int32_t); 798 switch (EXTRACT_16BITS(bp)) { 799 case AFI_IP: 800 addr_size = sizeof(struct in_addr); 801 nla_af = AF_INET; 802 break; 803#ifdef INET6 804 case AFI_IP6: 805 addr_size = sizeof(struct in6_addr); 806 nla_af = AF_INET6; 807 break; 808#endif 809 default: 810 goto trunc; 811 break; 812 } 813 bp += (2 * sizeof(u_int16_t)); 814 if (opt_len != 12 + addr_size) { 815 (void)printf("[Bad OPT_PGMCC_FEEDBACK option, length %u != 12 + address size]", opt_len); 816 return; 817 } 818 TCHECK2(*bp, addr_size); 819 nla = bp; 820 bp += addr_size; 821 822 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf)); 823 (void)printf(" PGMCC FEEDBACK %u %s", offset, (char*)nla); 824 opts_len -= 16; 825 break; 826 827 default: 828 (void)printf(" OPT_%02X [%d] ", opt_type, opt_len); 829 bp += opt_len; 830 opts_len -= opt_len; 831 break; 832 } 833 834 if (opt_type & PGM_OPT_END) 835 break; 836 } 837 } 838 839 (void)printf(" [%u]", EXTRACT_16BITS(&pgm->pgm_length)); 840 841 return; 842 843trunc: 844 fputs("[|pgm]", stdout); 845 if (ch != '\0') 846 putchar('>'); 847} 848