1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate #include <stdio.h> 31*0Sstevel@tonic-gate #include <ctype.h> 32*0Sstevel@tonic-gate #include <string.h> 33*0Sstevel@tonic-gate #include <fcntl.h> 34*0Sstevel@tonic-gate #include <string.h> 35*0Sstevel@tonic-gate #include <sys/types.h> 36*0Sstevel@tonic-gate #include <sys/time.h> 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate #include <sys/stropts.h> 39*0Sstevel@tonic-gate #include <sys/socket.h> 40*0Sstevel@tonic-gate #include <sys/sockio.h> 41*0Sstevel@tonic-gate #include <net/if.h> 42*0Sstevel@tonic-gate #include <netinet/in_systm.h> 43*0Sstevel@tonic-gate #include <netinet/in.h> 44*0Sstevel@tonic-gate #include <netinet/ip.h> 45*0Sstevel@tonic-gate #include <netinet/ip6.h> 46*0Sstevel@tonic-gate #include <netinet/ip_icmp.h> 47*0Sstevel@tonic-gate #include <netinet/icmp6.h> 48*0Sstevel@tonic-gate #include <netinet/if_ether.h> 49*0Sstevel@tonic-gate #include <inet/ip6.h> 50*0Sstevel@tonic-gate #include <inet/ipsecah.h> 51*0Sstevel@tonic-gate #include <arpa/inet.h> 52*0Sstevel@tonic-gate #include <netdb.h> 53*0Sstevel@tonic-gate #include "snoop.h" 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate /* 57*0Sstevel@tonic-gate * IPv6 extension header masks. These are used by the print_ipv6_extensions() 58*0Sstevel@tonic-gate * function to return information to the caller about which extension headers 59*0Sstevel@tonic-gate * were processed. This can be useful if the caller wants to know if the 60*0Sstevel@tonic-gate * packet is an IPv6 fragment, for example. 61*0Sstevel@tonic-gate */ 62*0Sstevel@tonic-gate #define SNOOP_HOPOPTS 0x01U 63*0Sstevel@tonic-gate #define SNOOP_ROUTING 0x02U 64*0Sstevel@tonic-gate #define SNOOP_DSTOPTS 0x04U 65*0Sstevel@tonic-gate #define SNOOP_FRAGMENT 0x08U 66*0Sstevel@tonic-gate #define SNOOP_AH 0x10U 67*0Sstevel@tonic-gate #define SNOOP_ESP 0x20U 68*0Sstevel@tonic-gate #define SNOOP_IPV6 0x40U 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate extern char *dlc_header; 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate static void prt_routing_hdr(); 73*0Sstevel@tonic-gate static void prt_fragment_hdr(); 74*0Sstevel@tonic-gate static void prt_hbh_options(); 75*0Sstevel@tonic-gate static void prt_dest_options(); 76*0Sstevel@tonic-gate static void print_route(); 77*0Sstevel@tonic-gate static void print_ipoptions(); 78*0Sstevel@tonic-gate char *getproto(); 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate /* Keep track of how many nested IP headers we have. */ 81*0Sstevel@tonic-gate unsigned int encap_levels; 82*0Sstevel@tonic-gate unsigned int total_encap_levels = 1; 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate int 85*0Sstevel@tonic-gate interpret_ip(flags, ip, fraglen) 86*0Sstevel@tonic-gate int flags; 87*0Sstevel@tonic-gate struct ip *ip; 88*0Sstevel@tonic-gate int fraglen; 89*0Sstevel@tonic-gate { 90*0Sstevel@tonic-gate char *data; 91*0Sstevel@tonic-gate char buff[24]; 92*0Sstevel@tonic-gate boolean_t isfrag = B_FALSE; 93*0Sstevel@tonic-gate boolean_t morefrag; 94*0Sstevel@tonic-gate uint16_t fragoffset; 95*0Sstevel@tonic-gate int hdrlen; 96*0Sstevel@tonic-gate uint16_t iplen, uitmp; 97*0Sstevel@tonic-gate extern char *src_name, *dst_name; 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate if (ip->ip_v == IPV6_VERSION) { 100*0Sstevel@tonic-gate iplen = interpret_ipv6(flags, (ip6_t *)ip, fraglen); 101*0Sstevel@tonic-gate return (iplen); 102*0Sstevel@tonic-gate } 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate /* XXX Should this count for mix-and-match v4/v6 encapsulations? */ 105*0Sstevel@tonic-gate if (encap_levels == 0) 106*0Sstevel@tonic-gate total_encap_levels = 0; 107*0Sstevel@tonic-gate encap_levels++; 108*0Sstevel@tonic-gate total_encap_levels++; 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate hdrlen = ip->ip_hl * 4; 111*0Sstevel@tonic-gate data = ((char *)ip) + hdrlen; 112*0Sstevel@tonic-gate iplen = ntohs(ip->ip_len) - hdrlen; 113*0Sstevel@tonic-gate fraglen -= hdrlen; 114*0Sstevel@tonic-gate if (fraglen > iplen) 115*0Sstevel@tonic-gate fraglen = iplen; 116*0Sstevel@tonic-gate if (fraglen < 0) { 117*0Sstevel@tonic-gate (void) snprintf(get_sum_line(), MAXLINE, 118*0Sstevel@tonic-gate "IP truncated: header missing %d bytes", -fraglen); 119*0Sstevel@tonic-gate encap_levels--; 120*0Sstevel@tonic-gate return (fraglen + iplen); 121*0Sstevel@tonic-gate } 122*0Sstevel@tonic-gate /* 123*0Sstevel@tonic-gate * We flag this as a fragment if the more fragments bit is set, or 124*0Sstevel@tonic-gate * if the fragment offset is non-zero. 125*0Sstevel@tonic-gate */ 126*0Sstevel@tonic-gate morefrag = (ntohs(ip->ip_off) & IP_MF) == 0 ? B_FALSE : B_TRUE; 127*0Sstevel@tonic-gate fragoffset = (ntohs(ip->ip_off) & 0x1FFF) * 8; 128*0Sstevel@tonic-gate if (morefrag || fragoffset != 0) 129*0Sstevel@tonic-gate isfrag = B_TRUE; 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate if (encap_levels == 1) { 132*0Sstevel@tonic-gate src_name = addrtoname(AF_INET, &ip->ip_src); 133*0Sstevel@tonic-gate dst_name = addrtoname(AF_INET, &ip->ip_dst); 134*0Sstevel@tonic-gate } /* Else we already have the src_name and dst_name we want! */ 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate if (flags & F_SUM) { 137*0Sstevel@tonic-gate if (isfrag) { 138*0Sstevel@tonic-gate (void) snprintf(get_sum_line(), MAXLINE, 139*0Sstevel@tonic-gate "%s IP fragment ID=%d Offset=%-4d MF=%d TOS=0x%x " 140*0Sstevel@tonic-gate "TTL=%d", 141*0Sstevel@tonic-gate getproto(ip->ip_p), 142*0Sstevel@tonic-gate ntohs(ip->ip_id), 143*0Sstevel@tonic-gate fragoffset, 144*0Sstevel@tonic-gate morefrag, 145*0Sstevel@tonic-gate ip->ip_tos, 146*0Sstevel@tonic-gate ip->ip_ttl); 147*0Sstevel@tonic-gate } else { 148*0Sstevel@tonic-gate (void) strlcpy(buff, inet_ntoa(ip->ip_dst), 149*0Sstevel@tonic-gate sizeof (buff)); 150*0Sstevel@tonic-gate uitmp = ntohs(ip->ip_len); 151*0Sstevel@tonic-gate (void) snprintf(get_sum_line(), MAXLINE, 152*0Sstevel@tonic-gate "IP D=%s S=%s LEN=%u%s, ID=%d, TOS=0x%x, TTL=%d", 153*0Sstevel@tonic-gate buff, 154*0Sstevel@tonic-gate inet_ntoa(ip->ip_src), 155*0Sstevel@tonic-gate uitmp, 156*0Sstevel@tonic-gate iplen > fraglen ? "?" : "", 157*0Sstevel@tonic-gate ntohs(ip->ip_id), 158*0Sstevel@tonic-gate ip->ip_tos, 159*0Sstevel@tonic-gate ip->ip_ttl); 160*0Sstevel@tonic-gate } 161*0Sstevel@tonic-gate } 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate if (flags & F_DTAIL) { 164*0Sstevel@tonic-gate show_header("IP: ", "IP Header", iplen); 165*0Sstevel@tonic-gate show_space(); 166*0Sstevel@tonic-gate (void) snprintf(get_line((char *)ip - dlc_header, 1), 167*0Sstevel@tonic-gate get_line_remain(), "Version = %d", ip->ip_v); 168*0Sstevel@tonic-gate (void) snprintf(get_line((char *)ip - dlc_header, 1), 169*0Sstevel@tonic-gate get_line_remain(), "Header length = %d bytes", hdrlen); 170*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1), 171*0Sstevel@tonic-gate get_line_remain(), "Type of service = 0x%02x", ip->ip_tos); 172*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1), 173*0Sstevel@tonic-gate get_line_remain(), " xxx. .... = %d (precedence)", 174*0Sstevel@tonic-gate ip->ip_tos >> 5); 175*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1), 176*0Sstevel@tonic-gate get_line_remain(), " %s", 177*0Sstevel@tonic-gate getflag(ip->ip_tos, IPTOS_LOWDELAY, 178*0Sstevel@tonic-gate "low delay", "normal delay")); 179*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1), 180*0Sstevel@tonic-gate get_line_remain(), " %s", 181*0Sstevel@tonic-gate getflag(ip->ip_tos, IPTOS_THROUGHPUT, 182*0Sstevel@tonic-gate "high throughput", "normal throughput")); 183*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1), 184*0Sstevel@tonic-gate get_line_remain(), " %s", 185*0Sstevel@tonic-gate getflag(ip->ip_tos, IPTOS_RELIABILITY, 186*0Sstevel@tonic-gate "high reliability", "normal reliability")); 187*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1), 188*0Sstevel@tonic-gate get_line_remain(), " %s", 189*0Sstevel@tonic-gate getflag(ip->ip_tos, IPTOS_ECT, 190*0Sstevel@tonic-gate "ECN capable transport", "not ECN capable transport")); 191*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_tos - dlc_header, 1), 192*0Sstevel@tonic-gate get_line_remain(), " %s", 193*0Sstevel@tonic-gate getflag(ip->ip_tos, IPTOS_CE, 194*0Sstevel@tonic-gate "ECN congestion experienced", 195*0Sstevel@tonic-gate "no ECN congestion experienced")); 196*0Sstevel@tonic-gate /* warning: ip_len is signed in netinet/ip.h */ 197*0Sstevel@tonic-gate uitmp = ntohs(ip->ip_len); 198*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_len - dlc_header, 2), 199*0Sstevel@tonic-gate get_line_remain(), "Total length = %u bytes%s", uitmp, 200*0Sstevel@tonic-gate iplen > fraglen ? " -- truncated" : ""); 201*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_id - dlc_header, 2), 202*0Sstevel@tonic-gate get_line_remain(), "Identification = %d", ntohs(ip->ip_id)); 203*0Sstevel@tonic-gate /* warning: ip_off is signed in netinet/ip.h */ 204*0Sstevel@tonic-gate uitmp = ntohs(ip->ip_off); 205*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_off - dlc_header, 1), 206*0Sstevel@tonic-gate get_line_remain(), "Flags = 0x%x", uitmp >> 12); 207*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_off - dlc_header, 1), 208*0Sstevel@tonic-gate get_line_remain(), " %s", 209*0Sstevel@tonic-gate getflag(uitmp >> 8, IP_DF >> 8, 210*0Sstevel@tonic-gate "do not fragment", "may fragment")); 211*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_off - dlc_header, 1), 212*0Sstevel@tonic-gate get_line_remain(), " %s", 213*0Sstevel@tonic-gate getflag(uitmp >> 8, IP_MF >> 8, 214*0Sstevel@tonic-gate "more fragments", "last fragment")); 215*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_off - dlc_header, 2), 216*0Sstevel@tonic-gate get_line_remain(), "Fragment offset = %u bytes", 217*0Sstevel@tonic-gate fragoffset); 218*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_ttl - dlc_header, 1), 219*0Sstevel@tonic-gate get_line_remain(), "Time to live = %d seconds/hops", 220*0Sstevel@tonic-gate ip->ip_ttl); 221*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_p - dlc_header, 1), 222*0Sstevel@tonic-gate get_line_remain(), "Protocol = %d (%s)", ip->ip_p, 223*0Sstevel@tonic-gate getproto(ip->ip_p)); 224*0Sstevel@tonic-gate /* 225*0Sstevel@tonic-gate * XXX need to compute checksum and print whether it's correct 226*0Sstevel@tonic-gate */ 227*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_sum - dlc_header, 1), 228*0Sstevel@tonic-gate get_line_remain(), "Header checksum = %04x", 229*0Sstevel@tonic-gate ntohs(ip->ip_sum)); 230*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_src - dlc_header, 1), 231*0Sstevel@tonic-gate get_line_remain(), "Source address = %s, %s", 232*0Sstevel@tonic-gate inet_ntoa(ip->ip_src), addrtoname(AF_INET, &ip->ip_src)); 233*0Sstevel@tonic-gate (void) snprintf(get_line((char *)&ip->ip_dst - dlc_header, 1), 234*0Sstevel@tonic-gate get_line_remain(), "Destination address = %s, %s", 235*0Sstevel@tonic-gate inet_ntoa(ip->ip_dst), addrtoname(AF_INET, &ip->ip_dst)); 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate /* Print IP options - if any */ 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate print_ipoptions(ip + 1, hdrlen - sizeof (struct ip)); 240*0Sstevel@tonic-gate show_space(); 241*0Sstevel@tonic-gate } 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gate /* 244*0Sstevel@tonic-gate * If we are in detail mode, and this is not the first fragment of 245*0Sstevel@tonic-gate * a fragmented packet, print out a little line stating this. 246*0Sstevel@tonic-gate * Otherwise, go to the next protocol layer only if this is not a 247*0Sstevel@tonic-gate * fragment, or we are in detail mode and this is the first fragment 248*0Sstevel@tonic-gate * of a fragmented packet. 249*0Sstevel@tonic-gate */ 250*0Sstevel@tonic-gate if (flags & F_DTAIL && fragoffset != 0) { 251*0Sstevel@tonic-gate (void) snprintf(get_detail_line(data - dlc_header, iplen), 252*0Sstevel@tonic-gate MAXLINE, 253*0Sstevel@tonic-gate "%s: [%d byte(s) of data, continuation of IP ident=%d]", 254*0Sstevel@tonic-gate getproto(ip->ip_p), 255*0Sstevel@tonic-gate iplen, 256*0Sstevel@tonic-gate ntohs(ip->ip_id)); 257*0Sstevel@tonic-gate } else if (!isfrag || (flags & F_DTAIL) && isfrag && fragoffset == 0) { 258*0Sstevel@tonic-gate /* go to the next protocol layer */ 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate if (fraglen > 0) { 261*0Sstevel@tonic-gate switch (ip->ip_p) { 262*0Sstevel@tonic-gate case IPPROTO_IP: 263*0Sstevel@tonic-gate break; 264*0Sstevel@tonic-gate case IPPROTO_ENCAP: 265*0Sstevel@tonic-gate (void) interpret_ip(flags, (struct ip *)data, 266*0Sstevel@tonic-gate fraglen); 267*0Sstevel@tonic-gate break; 268*0Sstevel@tonic-gate case IPPROTO_ICMP: 269*0Sstevel@tonic-gate interpret_icmp(flags, (struct icmp *)data, 270*0Sstevel@tonic-gate iplen, fraglen); 271*0Sstevel@tonic-gate break; 272*0Sstevel@tonic-gate case IPPROTO_IGMP: 273*0Sstevel@tonic-gate interpret_igmp(flags, data, iplen, fraglen); 274*0Sstevel@tonic-gate break; 275*0Sstevel@tonic-gate case IPPROTO_GGP: 276*0Sstevel@tonic-gate break; 277*0Sstevel@tonic-gate case IPPROTO_TCP: 278*0Sstevel@tonic-gate interpret_tcp(flags, data, iplen, fraglen); 279*0Sstevel@tonic-gate break; 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate case IPPROTO_ESP: 282*0Sstevel@tonic-gate interpret_esp(flags, data, iplen, fraglen); 283*0Sstevel@tonic-gate break; 284*0Sstevel@tonic-gate case IPPROTO_AH: 285*0Sstevel@tonic-gate interpret_ah(flags, data, iplen, fraglen); 286*0Sstevel@tonic-gate break; 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate case IPPROTO_OSPF: 289*0Sstevel@tonic-gate interpret_ospf(flags, data, iplen, fraglen); 290*0Sstevel@tonic-gate break; 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate case IPPROTO_EGP: 293*0Sstevel@tonic-gate case IPPROTO_PUP: 294*0Sstevel@tonic-gate break; 295*0Sstevel@tonic-gate case IPPROTO_UDP: 296*0Sstevel@tonic-gate interpret_udp(flags, data, iplen, fraglen); 297*0Sstevel@tonic-gate break; 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate case IPPROTO_IDP: 300*0Sstevel@tonic-gate case IPPROTO_HELLO: 301*0Sstevel@tonic-gate case IPPROTO_ND: 302*0Sstevel@tonic-gate case IPPROTO_RAW: 303*0Sstevel@tonic-gate break; 304*0Sstevel@tonic-gate case IPPROTO_IPV6: /* IPV6 encap */ 305*0Sstevel@tonic-gate (void) interpret_ipv6(flags, (ip6_t *)data, 306*0Sstevel@tonic-gate iplen); 307*0Sstevel@tonic-gate break; 308*0Sstevel@tonic-gate case IPPROTO_SCTP: 309*0Sstevel@tonic-gate interpret_sctp(flags, data, iplen, fraglen); 310*0Sstevel@tonic-gate break; 311*0Sstevel@tonic-gate } 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate encap_levels--; 316*0Sstevel@tonic-gate return (iplen); 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate int 320*0Sstevel@tonic-gate interpret_ipv6(flags, ip6h, fraglen) 321*0Sstevel@tonic-gate int flags; 322*0Sstevel@tonic-gate ip6_t *ip6h; 323*0Sstevel@tonic-gate int fraglen; 324*0Sstevel@tonic-gate { 325*0Sstevel@tonic-gate uint8_t *data; 326*0Sstevel@tonic-gate int hdrlen, iplen; 327*0Sstevel@tonic-gate extern char *src_name, *dst_name; 328*0Sstevel@tonic-gate int version, flow, class; 329*0Sstevel@tonic-gate uchar_t proto; 330*0Sstevel@tonic-gate boolean_t isfrag = B_FALSE; 331*0Sstevel@tonic-gate uint8_t extmask; 332*0Sstevel@tonic-gate /* 333*0Sstevel@tonic-gate * The print_srcname and print_dstname strings are the hostname 334*0Sstevel@tonic-gate * parts of the verbose IPv6 header output, including the comma 335*0Sstevel@tonic-gate * and the space after the litteral address strings. 336*0Sstevel@tonic-gate */ 337*0Sstevel@tonic-gate char print_srcname[MAXHOSTNAMELEN + 2]; 338*0Sstevel@tonic-gate char print_dstname[MAXHOSTNAMELEN + 2]; 339*0Sstevel@tonic-gate char src_addrstr[INET6_ADDRSTRLEN]; 340*0Sstevel@tonic-gate char dst_addrstr[INET6_ADDRSTRLEN]; 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate iplen = ntohs(ip6h->ip6_plen); 343*0Sstevel@tonic-gate hdrlen = IPV6_HDR_LEN; 344*0Sstevel@tonic-gate fraglen -= hdrlen; 345*0Sstevel@tonic-gate if (fraglen < 0) 346*0Sstevel@tonic-gate return (fraglen + hdrlen); 347*0Sstevel@tonic-gate data = ((uint8_t *)ip6h) + hdrlen; 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate proto = ip6h->ip6_nxt; 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate src_name = addrtoname(AF_INET6, &ip6h->ip6_src); 352*0Sstevel@tonic-gate dst_name = addrtoname(AF_INET6, &ip6h->ip6_dst); 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate /* 355*0Sstevel@tonic-gate * Use endian-aware masks to extract traffic class and 356*0Sstevel@tonic-gate * flowinfo. Also, flowinfo is now 20 bits and class 8 357*0Sstevel@tonic-gate * rather than 24 and 4. 358*0Sstevel@tonic-gate */ 359*0Sstevel@tonic-gate class = ntohl((ip6h->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20); 360*0Sstevel@tonic-gate flow = ntohl(ip6h->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL); 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate /* 363*0Sstevel@tonic-gate * NOTE: the F_SUM and F_DTAIL flags are mutually exclusive, 364*0Sstevel@tonic-gate * so the code within the first part of the following if statement 365*0Sstevel@tonic-gate * will not affect the detailed printing of the packet. 366*0Sstevel@tonic-gate */ 367*0Sstevel@tonic-gate if (flags & F_SUM) { 368*0Sstevel@tonic-gate (void) sprintf(get_sum_line(), "IPv6 S=%s D=%s LEN=%d " 369*0Sstevel@tonic-gate "HOPS=%d CLASS=0x%x FLOW=0x%x", 370*0Sstevel@tonic-gate src_name, dst_name, iplen, ip6h->ip6_hops, class, flow); 371*0Sstevel@tonic-gate } else if (flags & F_DTAIL) { 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &ip6h->ip6_src, src_addrstr, 374*0Sstevel@tonic-gate INET6_ADDRSTRLEN); 375*0Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &ip6h->ip6_dst, dst_addrstr, 376*0Sstevel@tonic-gate INET6_ADDRSTRLEN); 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate version = ntohl(ip6h->ip6_vcf) >> 28; 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate if (strcmp(src_name, src_addrstr) == 0) 381*0Sstevel@tonic-gate print_srcname[0] = '\0'; 382*0Sstevel@tonic-gate else 383*0Sstevel@tonic-gate snprintf(print_srcname, sizeof (print_srcname), 384*0Sstevel@tonic-gate ", %s", src_name); 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate if (strcmp(dst_name, dst_addrstr) == 0) 387*0Sstevel@tonic-gate print_dstname[0] = '\0'; 388*0Sstevel@tonic-gate else 389*0Sstevel@tonic-gate snprintf(print_dstname, sizeof (print_dstname), 390*0Sstevel@tonic-gate ", %s", dst_name); 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate show_header("IPv6: ", "IPv6 Header", iplen); 393*0Sstevel@tonic-gate show_space(); 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ip6h - dlc_header, 1), 396*0Sstevel@tonic-gate "Version = %d", version); 397*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ip6h - dlc_header, 1), 398*0Sstevel@tonic-gate "Traffic Class = %d", class); 399*0Sstevel@tonic-gate (void) sprintf(get_line((char *)&ip6h->ip6_vcf - dlc_header, 4), 400*0Sstevel@tonic-gate "Flow label = 0x%x", flow); 401*0Sstevel@tonic-gate (void) sprintf(get_line((char *)&ip6h->ip6_plen - 402*0Sstevel@tonic-gate dlc_header, 2), "Payload length = %d", iplen); 403*0Sstevel@tonic-gate (void) sprintf(get_line((char *)&ip6h->ip6_nxt - 404*0Sstevel@tonic-gate dlc_header, 1), "Next Header = %d (%s)", proto, 405*0Sstevel@tonic-gate getproto(proto)); 406*0Sstevel@tonic-gate (void) sprintf(get_line((char *)&ip6h->ip6_hops - 407*0Sstevel@tonic-gate dlc_header, 1), "Hop Limit = %d", ip6h->ip6_hops); 408*0Sstevel@tonic-gate (void) sprintf(get_line((char *)&ip6h->ip6_src - dlc_header, 1), 409*0Sstevel@tonic-gate "Source address = %s%s", src_addrstr, print_srcname); 410*0Sstevel@tonic-gate (void) sprintf(get_line((char *)&ip6h->ip6_dst - dlc_header, 1), 411*0Sstevel@tonic-gate "Destination address = %s%s", dst_addrstr, print_dstname); 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate show_space(); 414*0Sstevel@tonic-gate } 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate /* 417*0Sstevel@tonic-gate * Print IPv6 Extension Headers, or skip them in the summary case. 418*0Sstevel@tonic-gate * Set isfrag to true if one of the extension headers encounterred 419*0Sstevel@tonic-gate * was a fragment header. 420*0Sstevel@tonic-gate */ 421*0Sstevel@tonic-gate if (proto == IPPROTO_HOPOPTS || proto == IPPROTO_DSTOPTS || 422*0Sstevel@tonic-gate proto == IPPROTO_ROUTING || proto == IPPROTO_FRAGMENT) { 423*0Sstevel@tonic-gate extmask = print_ipv6_extensions(flags, &data, &proto, &iplen, 424*0Sstevel@tonic-gate &fraglen); 425*0Sstevel@tonic-gate if ((extmask & SNOOP_FRAGMENT) != 0) { 426*0Sstevel@tonic-gate isfrag = B_TRUE; 427*0Sstevel@tonic-gate } 428*0Sstevel@tonic-gate } 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate /* 431*0Sstevel@tonic-gate * We only want to print upper layer information if this is not 432*0Sstevel@tonic-gate * a fragment, or if we're printing in detail. Note that the 433*0Sstevel@tonic-gate * proto variable will be set to IPPROTO_NONE if this is a fragment 434*0Sstevel@tonic-gate * with a non-zero fragment offset. 435*0Sstevel@tonic-gate */ 436*0Sstevel@tonic-gate if (!isfrag || flags & F_DTAIL) { 437*0Sstevel@tonic-gate /* go to the next protocol layer */ 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate switch (proto) { 440*0Sstevel@tonic-gate case IPPROTO_IP: 441*0Sstevel@tonic-gate break; 442*0Sstevel@tonic-gate case IPPROTO_ENCAP: 443*0Sstevel@tonic-gate (void) interpret_ip(flags, (struct ip *)data, fraglen); 444*0Sstevel@tonic-gate break; 445*0Sstevel@tonic-gate case IPPROTO_ICMPV6: 446*0Sstevel@tonic-gate interpret_icmpv6(flags, (icmp6_t *)data, iplen, 447*0Sstevel@tonic-gate fraglen); 448*0Sstevel@tonic-gate break; 449*0Sstevel@tonic-gate case IPPROTO_IGMP: 450*0Sstevel@tonic-gate interpret_igmp(flags, data, iplen, fraglen); 451*0Sstevel@tonic-gate break; 452*0Sstevel@tonic-gate case IPPROTO_GGP: 453*0Sstevel@tonic-gate break; 454*0Sstevel@tonic-gate case IPPROTO_TCP: 455*0Sstevel@tonic-gate interpret_tcp(flags, data, iplen, fraglen); 456*0Sstevel@tonic-gate break; 457*0Sstevel@tonic-gate case IPPROTO_ESP: 458*0Sstevel@tonic-gate interpret_esp(flags, data, iplen, fraglen); 459*0Sstevel@tonic-gate break; 460*0Sstevel@tonic-gate case IPPROTO_AH: 461*0Sstevel@tonic-gate interpret_ah(flags, data, iplen, fraglen); 462*0Sstevel@tonic-gate break; 463*0Sstevel@tonic-gate case IPPROTO_EGP: 464*0Sstevel@tonic-gate case IPPROTO_PUP: 465*0Sstevel@tonic-gate break; 466*0Sstevel@tonic-gate case IPPROTO_UDP: 467*0Sstevel@tonic-gate interpret_udp(flags, data, iplen, fraglen); 468*0Sstevel@tonic-gate break; 469*0Sstevel@tonic-gate case IPPROTO_IDP: 470*0Sstevel@tonic-gate case IPPROTO_HELLO: 471*0Sstevel@tonic-gate case IPPROTO_ND: 472*0Sstevel@tonic-gate case IPPROTO_RAW: 473*0Sstevel@tonic-gate break; 474*0Sstevel@tonic-gate case IPPROTO_IPV6: 475*0Sstevel@tonic-gate (void) interpret_ipv6(flags, (ip6_t *)data, iplen); 476*0Sstevel@tonic-gate break; 477*0Sstevel@tonic-gate case IPPROTO_SCTP: 478*0Sstevel@tonic-gate interpret_sctp(flags, data, iplen, fraglen); 479*0Sstevel@tonic-gate break; 480*0Sstevel@tonic-gate case IPPROTO_OSPF: 481*0Sstevel@tonic-gate interpret_ospf6(flags, data, iplen, fraglen); 482*0Sstevel@tonic-gate break; 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate return (iplen); 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate /* 490*0Sstevel@tonic-gate * ip_ext: data including the extension header. 491*0Sstevel@tonic-gate * iplen: length of the data remaining in the packet. 492*0Sstevel@tonic-gate * Returns a mask of IPv6 extension headers it processed. 493*0Sstevel@tonic-gate */ 494*0Sstevel@tonic-gate uint8_t 495*0Sstevel@tonic-gate print_ipv6_extensions(int flags, uint8_t **hdr, uint8_t *next, int *iplen, 496*0Sstevel@tonic-gate int *fraglen) 497*0Sstevel@tonic-gate { 498*0Sstevel@tonic-gate uint8_t *data_ptr; 499*0Sstevel@tonic-gate uchar_t proto = *next; 500*0Sstevel@tonic-gate boolean_t is_extension_header; 501*0Sstevel@tonic-gate struct ip6_hbh *ipv6ext_hbh; 502*0Sstevel@tonic-gate struct ip6_dest *ipv6ext_dest; 503*0Sstevel@tonic-gate struct ip6_rthdr *ipv6ext_rthdr; 504*0Sstevel@tonic-gate struct ip6_frag *ipv6ext_frag; 505*0Sstevel@tonic-gate uint32_t exthdrlen; 506*0Sstevel@tonic-gate uint8_t extmask = 0; 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate if ((hdr == NULL) || (*hdr == NULL) || (next == NULL) || (iplen == 0)) 509*0Sstevel@tonic-gate return (0); 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate data_ptr = *hdr; 512*0Sstevel@tonic-gate is_extension_header = B_TRUE; 513*0Sstevel@tonic-gate while (is_extension_header) { 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate /* 516*0Sstevel@tonic-gate * There must be at least enough data left to read the 517*0Sstevel@tonic-gate * next header and header length fields from the next 518*0Sstevel@tonic-gate * header. 519*0Sstevel@tonic-gate */ 520*0Sstevel@tonic-gate if (*fraglen < 2) { 521*0Sstevel@tonic-gate proto = IPPROTO_NONE; 522*0Sstevel@tonic-gate return (extmask); 523*0Sstevel@tonic-gate } 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate switch (proto) { 526*0Sstevel@tonic-gate case IPPROTO_HOPOPTS: 527*0Sstevel@tonic-gate ipv6ext_hbh = (struct ip6_hbh *)data_ptr; 528*0Sstevel@tonic-gate exthdrlen = 8 + ipv6ext_hbh->ip6h_len * 8; 529*0Sstevel@tonic-gate if (*fraglen <= exthdrlen) { 530*0Sstevel@tonic-gate proto = IPPROTO_NONE; 531*0Sstevel@tonic-gate return (extmask); 532*0Sstevel@tonic-gate } 533*0Sstevel@tonic-gate prt_hbh_options(flags, ipv6ext_hbh); 534*0Sstevel@tonic-gate extmask |= SNOOP_HOPOPTS; 535*0Sstevel@tonic-gate proto = ipv6ext_hbh->ip6h_nxt; 536*0Sstevel@tonic-gate break; 537*0Sstevel@tonic-gate case IPPROTO_DSTOPTS: 538*0Sstevel@tonic-gate ipv6ext_dest = (struct ip6_dest *)data_ptr; 539*0Sstevel@tonic-gate exthdrlen = 8 + ipv6ext_dest->ip6d_len * 8; 540*0Sstevel@tonic-gate if (*fraglen <= exthdrlen) { 541*0Sstevel@tonic-gate proto = IPPROTO_NONE; 542*0Sstevel@tonic-gate return (extmask); 543*0Sstevel@tonic-gate } 544*0Sstevel@tonic-gate prt_dest_options(flags, ipv6ext_dest); 545*0Sstevel@tonic-gate extmask |= SNOOP_DSTOPTS; 546*0Sstevel@tonic-gate proto = ipv6ext_dest->ip6d_nxt; 547*0Sstevel@tonic-gate break; 548*0Sstevel@tonic-gate case IPPROTO_ROUTING: 549*0Sstevel@tonic-gate ipv6ext_rthdr = (struct ip6_rthdr *)data_ptr; 550*0Sstevel@tonic-gate exthdrlen = 8 + ipv6ext_rthdr->ip6r_len * 8; 551*0Sstevel@tonic-gate if (*fraglen <= exthdrlen) { 552*0Sstevel@tonic-gate proto = IPPROTO_NONE; 553*0Sstevel@tonic-gate return (extmask); 554*0Sstevel@tonic-gate } 555*0Sstevel@tonic-gate prt_routing_hdr(flags, ipv6ext_rthdr); 556*0Sstevel@tonic-gate extmask |= SNOOP_ROUTING; 557*0Sstevel@tonic-gate proto = ipv6ext_rthdr->ip6r_nxt; 558*0Sstevel@tonic-gate break; 559*0Sstevel@tonic-gate case IPPROTO_FRAGMENT: 560*0Sstevel@tonic-gate ipv6ext_frag = (struct ip6_frag *)data_ptr; 561*0Sstevel@tonic-gate exthdrlen = sizeof (struct ip6_frag); 562*0Sstevel@tonic-gate if (*fraglen <= exthdrlen) { 563*0Sstevel@tonic-gate proto = IPPROTO_NONE; 564*0Sstevel@tonic-gate return (extmask); 565*0Sstevel@tonic-gate } 566*0Sstevel@tonic-gate prt_fragment_hdr(flags, ipv6ext_frag); 567*0Sstevel@tonic-gate extmask |= SNOOP_FRAGMENT; 568*0Sstevel@tonic-gate /* 569*0Sstevel@tonic-gate * If this is not the first fragment, forget about 570*0Sstevel@tonic-gate * the rest of the packet, snoop decoding is 571*0Sstevel@tonic-gate * stateless. 572*0Sstevel@tonic-gate */ 573*0Sstevel@tonic-gate if ((ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK) != 0) 574*0Sstevel@tonic-gate proto = IPPROTO_NONE; 575*0Sstevel@tonic-gate else 576*0Sstevel@tonic-gate proto = ipv6ext_frag->ip6f_nxt; 577*0Sstevel@tonic-gate break; 578*0Sstevel@tonic-gate default: 579*0Sstevel@tonic-gate is_extension_header = B_FALSE; 580*0Sstevel@tonic-gate break; 581*0Sstevel@tonic-gate } 582*0Sstevel@tonic-gate 583*0Sstevel@tonic-gate if (is_extension_header) { 584*0Sstevel@tonic-gate *iplen -= exthdrlen; 585*0Sstevel@tonic-gate *fraglen -= exthdrlen; 586*0Sstevel@tonic-gate data_ptr += exthdrlen; 587*0Sstevel@tonic-gate } 588*0Sstevel@tonic-gate } 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate *next = proto; 591*0Sstevel@tonic-gate *hdr = data_ptr; 592*0Sstevel@tonic-gate return (extmask); 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate static void 596*0Sstevel@tonic-gate print_ipoptions(opt, optlen) 597*0Sstevel@tonic-gate uchar_t *opt; 598*0Sstevel@tonic-gate int optlen; 599*0Sstevel@tonic-gate { 600*0Sstevel@tonic-gate int len; 601*0Sstevel@tonic-gate char *line; 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate if (optlen <= 0) { 604*0Sstevel@tonic-gate (void) sprintf(get_line((char *)&opt - dlc_header, 1), 605*0Sstevel@tonic-gate "No options"); 606*0Sstevel@tonic-gate return; 607*0Sstevel@tonic-gate } 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate (void) sprintf(get_line((char *)&opt - dlc_header, 1), 610*0Sstevel@tonic-gate "Options: (%d bytes)", optlen); 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate while (optlen > 0) { 613*0Sstevel@tonic-gate line = get_line((char *)&opt - dlc_header, 1); 614*0Sstevel@tonic-gate len = opt[1]; 615*0Sstevel@tonic-gate switch (opt[0]) { 616*0Sstevel@tonic-gate case IPOPT_EOL: 617*0Sstevel@tonic-gate (void) strcpy(line, " - End of option list"); 618*0Sstevel@tonic-gate return; 619*0Sstevel@tonic-gate case IPOPT_NOP: 620*0Sstevel@tonic-gate (void) strcpy(line, " - No op"); 621*0Sstevel@tonic-gate len = 1; 622*0Sstevel@tonic-gate break; 623*0Sstevel@tonic-gate case IPOPT_RR: 624*0Sstevel@tonic-gate (void) sprintf(line, " - Record route (%d bytes)", 625*0Sstevel@tonic-gate len); 626*0Sstevel@tonic-gate print_route(opt); 627*0Sstevel@tonic-gate break; 628*0Sstevel@tonic-gate case IPOPT_TS: 629*0Sstevel@tonic-gate (void) sprintf(line, " - Time stamp (%d bytes)", len); 630*0Sstevel@tonic-gate break; 631*0Sstevel@tonic-gate case IPOPT_SECURITY: 632*0Sstevel@tonic-gate (void) sprintf(line, " - Security (%d bytes)", len); 633*0Sstevel@tonic-gate break; 634*0Sstevel@tonic-gate case IPOPT_LSRR: 635*0Sstevel@tonic-gate (void) sprintf(line, 636*0Sstevel@tonic-gate " - Loose source route (%d bytes)", len); 637*0Sstevel@tonic-gate print_route(opt); 638*0Sstevel@tonic-gate break; 639*0Sstevel@tonic-gate case IPOPT_SATID: 640*0Sstevel@tonic-gate (void) sprintf(line, " - SATNET Stream id (%d bytes)", 641*0Sstevel@tonic-gate len); 642*0Sstevel@tonic-gate break; 643*0Sstevel@tonic-gate case IPOPT_SSRR: 644*0Sstevel@tonic-gate (void) sprintf(line, 645*0Sstevel@tonic-gate " - Strict source route, (%d bytes)", len); 646*0Sstevel@tonic-gate print_route(opt); 647*0Sstevel@tonic-gate break; 648*0Sstevel@tonic-gate default: 649*0Sstevel@tonic-gate sprintf(line, " - Option %d (unknown - %d bytes) %s", 650*0Sstevel@tonic-gate opt[0], len, tohex((char *)&opt[2], len - 2)); 651*0Sstevel@tonic-gate break; 652*0Sstevel@tonic-gate } 653*0Sstevel@tonic-gate if (len <= 0) { 654*0Sstevel@tonic-gate (void) sprintf(line, " - Incomplete option len %d", 655*0Sstevel@tonic-gate len); 656*0Sstevel@tonic-gate break; 657*0Sstevel@tonic-gate } 658*0Sstevel@tonic-gate opt += len; 659*0Sstevel@tonic-gate optlen -= len; 660*0Sstevel@tonic-gate } 661*0Sstevel@tonic-gate } 662*0Sstevel@tonic-gate 663*0Sstevel@tonic-gate static void 664*0Sstevel@tonic-gate print_route(opt) 665*0Sstevel@tonic-gate uchar_t *opt; 666*0Sstevel@tonic-gate { 667*0Sstevel@tonic-gate int len, pointer; 668*0Sstevel@tonic-gate struct in_addr addr; 669*0Sstevel@tonic-gate char *line; 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate len = opt[1]; 672*0Sstevel@tonic-gate pointer = opt[2]; 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate (void) sprintf(get_line((char *)(&opt + 2) - dlc_header, 1), 675*0Sstevel@tonic-gate " Pointer = %d", pointer); 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate pointer -= IPOPT_MINOFF; 678*0Sstevel@tonic-gate opt += (IPOPT_OFFSET + 1); 679*0Sstevel@tonic-gate len -= (IPOPT_OFFSET + 1); 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate while (len > 0) { 682*0Sstevel@tonic-gate line = get_line((char *)&(opt) - dlc_header, 4); 683*0Sstevel@tonic-gate memcpy((char *)&addr, opt, sizeof (addr)); 684*0Sstevel@tonic-gate if (addr.s_addr == INADDR_ANY) 685*0Sstevel@tonic-gate (void) strcpy(line, " -"); 686*0Sstevel@tonic-gate else 687*0Sstevel@tonic-gate (void) sprintf(line, " %s", 688*0Sstevel@tonic-gate addrtoname(AF_INET, &addr)); 689*0Sstevel@tonic-gate if (pointer == 0) 690*0Sstevel@tonic-gate (void) strcat(line, " <-- (current)"); 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate opt += sizeof (addr); 693*0Sstevel@tonic-gate len -= sizeof (addr); 694*0Sstevel@tonic-gate pointer -= sizeof (addr); 695*0Sstevel@tonic-gate } 696*0Sstevel@tonic-gate } 697*0Sstevel@tonic-gate 698*0Sstevel@tonic-gate char * 699*0Sstevel@tonic-gate getproto(p) 700*0Sstevel@tonic-gate int p; 701*0Sstevel@tonic-gate { 702*0Sstevel@tonic-gate switch (p) { 703*0Sstevel@tonic-gate case IPPROTO_HOPOPTS: return ("IPv6-HopOpts"); 704*0Sstevel@tonic-gate case IPPROTO_IPV6: return ("IPv6"); 705*0Sstevel@tonic-gate case IPPROTO_ROUTING: return ("IPv6-Route"); 706*0Sstevel@tonic-gate case IPPROTO_FRAGMENT: return ("IPv6-Frag"); 707*0Sstevel@tonic-gate case IPPROTO_RSVP: return ("RSVP"); 708*0Sstevel@tonic-gate case IPPROTO_ENCAP: return ("IP-in-IP"); 709*0Sstevel@tonic-gate case IPPROTO_AH: return ("AH"); 710*0Sstevel@tonic-gate case IPPROTO_ESP: return ("ESP"); 711*0Sstevel@tonic-gate case IPPROTO_ICMP: return ("ICMP"); 712*0Sstevel@tonic-gate case IPPROTO_ICMPV6: return ("ICMPv6"); 713*0Sstevel@tonic-gate case IPPROTO_DSTOPTS: return ("IPv6-DstOpts"); 714*0Sstevel@tonic-gate case IPPROTO_IGMP: return ("IGMP"); 715*0Sstevel@tonic-gate case IPPROTO_GGP: return ("GGP"); 716*0Sstevel@tonic-gate case IPPROTO_TCP: return ("TCP"); 717*0Sstevel@tonic-gate case IPPROTO_EGP: return ("EGP"); 718*0Sstevel@tonic-gate case IPPROTO_PUP: return ("PUP"); 719*0Sstevel@tonic-gate case IPPROTO_UDP: return ("UDP"); 720*0Sstevel@tonic-gate case IPPROTO_IDP: return ("IDP"); 721*0Sstevel@tonic-gate case IPPROTO_HELLO: return ("HELLO"); 722*0Sstevel@tonic-gate case IPPROTO_ND: return ("ND"); 723*0Sstevel@tonic-gate case IPPROTO_EON: return ("EON"); 724*0Sstevel@tonic-gate case IPPROTO_RAW: return ("RAW"); 725*0Sstevel@tonic-gate case IPPROTO_OSPF: return ("OSPF"); 726*0Sstevel@tonic-gate default: return (""); 727*0Sstevel@tonic-gate } 728*0Sstevel@tonic-gate } 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate static void 731*0Sstevel@tonic-gate prt_routing_hdr(flags, ipv6ext_rthdr) 732*0Sstevel@tonic-gate int flags; 733*0Sstevel@tonic-gate struct ip6_rthdr *ipv6ext_rthdr; 734*0Sstevel@tonic-gate { 735*0Sstevel@tonic-gate uint8_t nxt_hdr; 736*0Sstevel@tonic-gate uint8_t type; 737*0Sstevel@tonic-gate uint32_t len; 738*0Sstevel@tonic-gate uint8_t segleft; 739*0Sstevel@tonic-gate uint32_t numaddrs; 740*0Sstevel@tonic-gate int i; 741*0Sstevel@tonic-gate struct ip6_rthdr0 *ipv6ext_rthdr0; 742*0Sstevel@tonic-gate struct in6_addr *addrs; 743*0Sstevel@tonic-gate char addr[INET6_ADDRSTRLEN]; 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate /* in summary mode, we don't do anything. */ 746*0Sstevel@tonic-gate if (flags & F_SUM) { 747*0Sstevel@tonic-gate return; 748*0Sstevel@tonic-gate } 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate nxt_hdr = ipv6ext_rthdr->ip6r_nxt; 751*0Sstevel@tonic-gate type = ipv6ext_rthdr->ip6r_type; 752*0Sstevel@tonic-gate len = 8 * (ipv6ext_rthdr->ip6r_len + 1); 753*0Sstevel@tonic-gate segleft = ipv6ext_rthdr->ip6r_segleft; 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate show_header("IPv6-Route: ", "IPv6 Routing Header", 0); 756*0Sstevel@tonic-gate show_space(); 757*0Sstevel@tonic-gate 758*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_rthdr - dlc_header, 1), 759*0Sstevel@tonic-gate "Next header = %d (%s)", nxt_hdr, getproto(nxt_hdr)); 760*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_rthdr - dlc_header, 1), 761*0Sstevel@tonic-gate "Header length = %d", len); 762*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_rthdr - dlc_header, 1), 763*0Sstevel@tonic-gate "Routing type = %d", type); 764*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_rthdr - dlc_header, 1), 765*0Sstevel@tonic-gate "Segments left = %d", segleft); 766*0Sstevel@tonic-gate 767*0Sstevel@tonic-gate if (type == IPV6_RTHDR_TYPE_0) { 768*0Sstevel@tonic-gate /* 769*0Sstevel@tonic-gate * XXX This loop will print all addresses in the routing header, 770*0Sstevel@tonic-gate * XXX not just the segments left. 771*0Sstevel@tonic-gate * XXX (The header length field is twice the number of 772*0Sstevel@tonic-gate * XXX addresses) 773*0Sstevel@tonic-gate * XXX At some future time, we may want to change this 774*0Sstevel@tonic-gate * XXX to differentiate between the hops yet to do 775*0Sstevel@tonic-gate * XXX and the hops already taken. 776*0Sstevel@tonic-gate */ 777*0Sstevel@tonic-gate ipv6ext_rthdr0 = (struct ip6_rthdr0 *)ipv6ext_rthdr; 778*0Sstevel@tonic-gate numaddrs = ipv6ext_rthdr0->ip6r0_len / 2; 779*0Sstevel@tonic-gate addrs = (struct in6_addr *)(ipv6ext_rthdr0 + 1); 780*0Sstevel@tonic-gate for (i = 0; i < numaddrs; i++) { 781*0Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &addrs[i], addr, 782*0Sstevel@tonic-gate INET6_ADDRSTRLEN); 783*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_rthdr - 784*0Sstevel@tonic-gate dlc_header, 1), 785*0Sstevel@tonic-gate "address[%d]=%s", i, addr); 786*0Sstevel@tonic-gate } 787*0Sstevel@tonic-gate } 788*0Sstevel@tonic-gate 789*0Sstevel@tonic-gate show_space(); 790*0Sstevel@tonic-gate } 791*0Sstevel@tonic-gate 792*0Sstevel@tonic-gate static void 793*0Sstevel@tonic-gate prt_fragment_hdr(flags, ipv6ext_frag) 794*0Sstevel@tonic-gate int flags; 795*0Sstevel@tonic-gate struct ip6_frag *ipv6ext_frag; 796*0Sstevel@tonic-gate { 797*0Sstevel@tonic-gate boolean_t morefrag; 798*0Sstevel@tonic-gate uint16_t fragoffset; 799*0Sstevel@tonic-gate uint8_t nxt_hdr; 800*0Sstevel@tonic-gate uint32_t fragident; 801*0Sstevel@tonic-gate 802*0Sstevel@tonic-gate /* extract the various fields from the fragment header */ 803*0Sstevel@tonic-gate nxt_hdr = ipv6ext_frag->ip6f_nxt; 804*0Sstevel@tonic-gate morefrag = (ipv6ext_frag->ip6f_offlg & IP6F_MORE_FRAG) == 0 805*0Sstevel@tonic-gate ? B_FALSE : B_TRUE; 806*0Sstevel@tonic-gate fragoffset = ntohs(ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK); 807*0Sstevel@tonic-gate fragident = ntohl(ipv6ext_frag->ip6f_ident); 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate if (flags & F_SUM) { 810*0Sstevel@tonic-gate (void) sprintf(get_sum_line(), 811*0Sstevel@tonic-gate "IPv6 fragment ID=%d Offset=%-4d MF=%d", 812*0Sstevel@tonic-gate fragident, 813*0Sstevel@tonic-gate fragoffset, 814*0Sstevel@tonic-gate morefrag); 815*0Sstevel@tonic-gate } else { /* F_DTAIL */ 816*0Sstevel@tonic-gate show_header("IPv6-Frag: ", "IPv6 Fragment Header", 0); 817*0Sstevel@tonic-gate show_space(); 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_frag - dlc_header, 1), 820*0Sstevel@tonic-gate "Next Header = %d (%s)", nxt_hdr, getproto(nxt_hdr)); 821*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_frag - dlc_header, 1), 822*0Sstevel@tonic-gate "Fragment Offset = %d", fragoffset); 823*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_frag - dlc_header, 1), 824*0Sstevel@tonic-gate "More Fragments Flag = %s", morefrag ? "true" : "false"); 825*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_frag - dlc_header, 1), 826*0Sstevel@tonic-gate "Identification = %d", fragident); 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gate show_space(); 829*0Sstevel@tonic-gate } 830*0Sstevel@tonic-gate } 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate static void 833*0Sstevel@tonic-gate prt_hbh_options(flags, ipv6ext_hbh) 834*0Sstevel@tonic-gate int flags; 835*0Sstevel@tonic-gate struct ip6_hbh *ipv6ext_hbh; 836*0Sstevel@tonic-gate { 837*0Sstevel@tonic-gate uint8_t *data; 838*0Sstevel@tonic-gate uint32_t len, olen; 839*0Sstevel@tonic-gate uint8_t op_type; 840*0Sstevel@tonic-gate uint8_t op_len; 841*0Sstevel@tonic-gate uint8_t nxt_hdr; 842*0Sstevel@tonic-gate 843*0Sstevel@tonic-gate /* in summary mode, we don't do anything. */ 844*0Sstevel@tonic-gate if (flags & F_SUM) { 845*0Sstevel@tonic-gate return; 846*0Sstevel@tonic-gate } 847*0Sstevel@tonic-gate 848*0Sstevel@tonic-gate show_header("IPv6-HopOpts: ", "IPv6 Hop-by-Hop Options Header", 0); 849*0Sstevel@tonic-gate show_space(); 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate /* 852*0Sstevel@tonic-gate * Store the lengh of this ext hdr in bytes. The caller has 853*0Sstevel@tonic-gate * ensured that there is at least len bytes of data left. 854*0Sstevel@tonic-gate */ 855*0Sstevel@tonic-gate len = ipv6ext_hbh->ip6h_len * 8 + 8; 856*0Sstevel@tonic-gate 857*0Sstevel@tonic-gate data = (uint8_t *)ipv6ext_hbh + 2; 858*0Sstevel@tonic-gate len -= 2; 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate nxt_hdr = ipv6ext_hbh->ip6h_nxt; 861*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_hbh - dlc_header, 1), 862*0Sstevel@tonic-gate "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr)); 863*0Sstevel@tonic-gate 864*0Sstevel@tonic-gate while (len > 0) { 865*0Sstevel@tonic-gate GETINT8(op_type, data); 866*0Sstevel@tonic-gate olen = len; 867*0Sstevel@tonic-gate switch (op_type) { 868*0Sstevel@tonic-gate case IP6OPT_PAD1: 869*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_hbh - 870*0Sstevel@tonic-gate dlc_header, 1), 871*0Sstevel@tonic-gate "pad1 option "); 872*0Sstevel@tonic-gate len--; 873*0Sstevel@tonic-gate break; 874*0Sstevel@tonic-gate case IP6OPT_PADN: 875*0Sstevel@tonic-gate GETINT8(op_len, data); 876*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_hbh - 877*0Sstevel@tonic-gate dlc_header, 1), 878*0Sstevel@tonic-gate "padN option len = %u", op_len); 879*0Sstevel@tonic-gate data += op_len; /* skip pads */ 880*0Sstevel@tonic-gate len -= (op_len + 2); 881*0Sstevel@tonic-gate break; 882*0Sstevel@tonic-gate case IP6OPT_JUMBO: { 883*0Sstevel@tonic-gate uint32_t payload_len; 884*0Sstevel@tonic-gate 885*0Sstevel@tonic-gate GETINT8(op_len, data); 886*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_hbh - 887*0Sstevel@tonic-gate dlc_header, 1), 888*0Sstevel@tonic-gate "Jumbo Payload Option len = %u bytes", op_len); 889*0Sstevel@tonic-gate if (op_len == sizeof (uint32_t)) { 890*0Sstevel@tonic-gate GETINT32(payload_len, data); 891*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_hbh - 892*0Sstevel@tonic-gate dlc_header, 1), 893*0Sstevel@tonic-gate "Jumbo Payload Length = %u bytes", 894*0Sstevel@tonic-gate payload_len); 895*0Sstevel@tonic-gate } else { 896*0Sstevel@tonic-gate data += op_len; 897*0Sstevel@tonic-gate } 898*0Sstevel@tonic-gate len -= (op_len + 2); 899*0Sstevel@tonic-gate break; 900*0Sstevel@tonic-gate } 901*0Sstevel@tonic-gate case IP6OPT_ROUTER_ALERT: { 902*0Sstevel@tonic-gate uint16_t value; 903*0Sstevel@tonic-gate const char *label[] = {"MLD", "RSVP", "AN"}; 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate GETINT8(op_len, data); 906*0Sstevel@tonic-gate (void) snprintf(get_line((char *)ipv6ext_hbh - 907*0Sstevel@tonic-gate dlc_header, 1), get_line_remain(), 908*0Sstevel@tonic-gate "Router Alert Option len = %u bytes", op_len); 909*0Sstevel@tonic-gate if (op_len == sizeof (uint16_t)) { 910*0Sstevel@tonic-gate GETINT16(value, data); 911*0Sstevel@tonic-gate (void) snprintf(get_line((char *)ipv6ext_hbh - 912*0Sstevel@tonic-gate dlc_header, 1), get_line_remain(), 913*0Sstevel@tonic-gate "Alert Type = %d (%s)", value, 914*0Sstevel@tonic-gate value < sizeof (label) / sizeof (label[0]) ? 915*0Sstevel@tonic-gate label[value] : "???"); 916*0Sstevel@tonic-gate } else { 917*0Sstevel@tonic-gate data += op_len; 918*0Sstevel@tonic-gate } 919*0Sstevel@tonic-gate len -= (op_len + 2); 920*0Sstevel@tonic-gate break; 921*0Sstevel@tonic-gate } 922*0Sstevel@tonic-gate default: 923*0Sstevel@tonic-gate GETINT8(op_len, data); 924*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_hbh - 925*0Sstevel@tonic-gate dlc_header, 1), 926*0Sstevel@tonic-gate "Option type = %u, len = %u", op_type, op_len); 927*0Sstevel@tonic-gate data += op_len; 928*0Sstevel@tonic-gate len -= (op_len + 2); 929*0Sstevel@tonic-gate } 930*0Sstevel@tonic-gate /* check for corrupt length */ 931*0Sstevel@tonic-gate if (olen <= len) { 932*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_hbh - 933*0Sstevel@tonic-gate dlc_header, 1), 934*0Sstevel@tonic-gate "Incomplete option len = %u, len = %u", op_type, 935*0Sstevel@tonic-gate len); 936*0Sstevel@tonic-gate break; 937*0Sstevel@tonic-gate } 938*0Sstevel@tonic-gate } 939*0Sstevel@tonic-gate 940*0Sstevel@tonic-gate show_space(); 941*0Sstevel@tonic-gate } 942*0Sstevel@tonic-gate 943*0Sstevel@tonic-gate static void 944*0Sstevel@tonic-gate prt_dest_options(flags, ipv6ext_dest) 945*0Sstevel@tonic-gate int flags; 946*0Sstevel@tonic-gate struct ip6_dest *ipv6ext_dest; 947*0Sstevel@tonic-gate { 948*0Sstevel@tonic-gate uint8_t *data; 949*0Sstevel@tonic-gate uint32_t len, olen; 950*0Sstevel@tonic-gate uint8_t op_type; 951*0Sstevel@tonic-gate uint32_t op_len; 952*0Sstevel@tonic-gate uint8_t nxt_hdr; 953*0Sstevel@tonic-gate uint8_t value; 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gate /* in summary mode, we don't do anything. */ 956*0Sstevel@tonic-gate if (flags & F_SUM) { 957*0Sstevel@tonic-gate return; 958*0Sstevel@tonic-gate } 959*0Sstevel@tonic-gate 960*0Sstevel@tonic-gate show_header("IPv6-DstOpts: ", "IPv6 Destination Options Header", 0); 961*0Sstevel@tonic-gate show_space(); 962*0Sstevel@tonic-gate 963*0Sstevel@tonic-gate /* 964*0Sstevel@tonic-gate * Store the length of this ext hdr in bytes. The caller has 965*0Sstevel@tonic-gate * ensured that there is at least len bytes of data left. 966*0Sstevel@tonic-gate */ 967*0Sstevel@tonic-gate len = ipv6ext_dest->ip6d_len * 8 + 8; 968*0Sstevel@tonic-gate 969*0Sstevel@tonic-gate data = (uint8_t *)ipv6ext_dest + 2; /* skip hdr/len */ 970*0Sstevel@tonic-gate len -= 2; 971*0Sstevel@tonic-gate 972*0Sstevel@tonic-gate nxt_hdr = ipv6ext_dest->ip6d_nxt; 973*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_dest - dlc_header, 1), 974*0Sstevel@tonic-gate "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr)); 975*0Sstevel@tonic-gate 976*0Sstevel@tonic-gate while (len > 0) { 977*0Sstevel@tonic-gate GETINT8(op_type, data); 978*0Sstevel@tonic-gate olen = len; 979*0Sstevel@tonic-gate switch (op_type) { 980*0Sstevel@tonic-gate case IP6OPT_PAD1: 981*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_dest - 982*0Sstevel@tonic-gate dlc_header, 1), 983*0Sstevel@tonic-gate "pad1 option "); 984*0Sstevel@tonic-gate len--; 985*0Sstevel@tonic-gate break; 986*0Sstevel@tonic-gate case IP6OPT_PADN: 987*0Sstevel@tonic-gate GETINT8(op_len, data); 988*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_dest - 989*0Sstevel@tonic-gate dlc_header, 1), 990*0Sstevel@tonic-gate "padN option len = %u", op_len); 991*0Sstevel@tonic-gate data += op_len; 992*0Sstevel@tonic-gate len -= (op_len + 2); 993*0Sstevel@tonic-gate break; 994*0Sstevel@tonic-gate case IP6OPT_TUNNEL_LIMIT: 995*0Sstevel@tonic-gate GETINT8(op_len, data); 996*0Sstevel@tonic-gate GETINT8(value, data); 997*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_dest - 998*0Sstevel@tonic-gate dlc_header, 1), 999*0Sstevel@tonic-gate "tunnel encapsulation limit len = %d, value = %d", 1000*0Sstevel@tonic-gate op_len, value); 1001*0Sstevel@tonic-gate len -= (op_len + 2); 1002*0Sstevel@tonic-gate break; 1003*0Sstevel@tonic-gate default: 1004*0Sstevel@tonic-gate GETINT8(op_len, data); 1005*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_dest - 1006*0Sstevel@tonic-gate dlc_header, 1), 1007*0Sstevel@tonic-gate "Option type = %u, len = %u", op_type, op_len); 1008*0Sstevel@tonic-gate data += op_len; 1009*0Sstevel@tonic-gate len -= (op_len + 2); 1010*0Sstevel@tonic-gate } 1011*0Sstevel@tonic-gate /* check for corrupt length */ 1012*0Sstevel@tonic-gate if (olen <= len) { 1013*0Sstevel@tonic-gate (void) sprintf(get_line((char *)ipv6ext_dest - 1014*0Sstevel@tonic-gate dlc_header, 1), 1015*0Sstevel@tonic-gate "Incomplete option len = %u, len = %u", op_type, 1016*0Sstevel@tonic-gate len); 1017*0Sstevel@tonic-gate break; 1018*0Sstevel@tonic-gate } 1019*0Sstevel@tonic-gate } 1020*0Sstevel@tonic-gate 1021*0Sstevel@tonic-gate show_space(); 1022*0Sstevel@tonic-gate } 1023