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