Home | History | Annotate | Download | only in snoop
      1      0     stevel /*
      2      0     stevel  * CDDL HEADER START
      3      0     stevel  *
      4      0     stevel  * The contents of this file are subject to the terms of the
      5   1676        jpk  * Common Development and Distribution License (the "License").
      6   1676        jpk  * You may not use this file except in compliance with the License.
      7      0     stevel  *
      8      0     stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0     stevel  * or http://www.opensolaris.org/os/licensing.
     10      0     stevel  * See the License for the specific language governing permissions
     11      0     stevel  * and limitations under the License.
     12      0     stevel  *
     13      0     stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0     stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0     stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0     stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0     stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0     stevel  *
     19      0     stevel  * CDDL HEADER END
     20      0     stevel  */
     21      0     stevel /*
     22  10616  Sebastien  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0     stevel  * Use is subject to license terms.
     24      0     stevel  */
     25      0     stevel 
     26      0     stevel #include <stdio.h>
     27      0     stevel #include <string.h>
     28      0     stevel #include <fcntl.h>
     29      0     stevel #include <string.h>
     30      0     stevel #include <sys/types.h>
     31      0     stevel #include <sys/time.h>
     32      0     stevel 
     33      0     stevel #include <sys/stropts.h>
     34      0     stevel #include <sys/socket.h>
     35      0     stevel #include <net/if.h>
     36      0     stevel #include <netinet/in_systm.h>
     37      0     stevel #include <netinet/in.h>
     38      0     stevel #include <netinet/ip.h>
     39      0     stevel #include <netinet/ip6.h>
     40      0     stevel #include <netinet/ip_icmp.h>
     41      0     stevel #include <netinet/icmp6.h>
     42      0     stevel #include <netinet/if_ether.h>
     43   1676        jpk #include <inet/ip.h>
     44      0     stevel #include <inet/ip6.h>
     45      0     stevel #include <arpa/inet.h>
     46      0     stevel #include <netdb.h>
     47   1676        jpk #include <tsol/label.h>
     48   1676        jpk #include <sys/tsol/tndb.h>
     49   1676        jpk #include <sys/tsol/label_macro.h>
     50   1676        jpk 
     51      0     stevel #include "snoop.h"
     52      0     stevel 
     53      0     stevel 
     54      0     stevel /*
     55      0     stevel  * IPv6 extension header masks.  These are used by the print_ipv6_extensions()
     56      0     stevel  * function to return information to the caller about which extension headers
     57      0     stevel  * were processed.  This can be useful if the caller wants to know if the
     58      0     stevel  * packet is an IPv6 fragment, for example.
     59      0     stevel  */
     60      0     stevel #define	SNOOP_HOPOPTS	0x01U
     61      0     stevel #define	SNOOP_ROUTING	0x02U
     62      0     stevel #define	SNOOP_DSTOPTS	0x04U
     63      0     stevel #define	SNOOP_FRAGMENT	0x08U
     64      0     stevel #define	SNOOP_AH	0x10U
     65      0     stevel #define	SNOOP_ESP	0x20U
     66      0     stevel #define	SNOOP_IPV6	0x40U
     67      0     stevel 
     68   1676        jpk static void prt_routing_hdr(int, const struct ip6_rthdr *);
     69   1676        jpk static void prt_fragment_hdr(int, const struct ip6_frag *);
     70   1676        jpk static void prt_hbh_options(int, const struct ip6_hbh *);
     71   1676        jpk static void prt_dest_options(int, const struct ip6_dest *);
     72   1676        jpk static void print_route(const uchar_t *);
     73   1676        jpk static void print_ipoptions(const uchar_t *, int);
     74   1676        jpk static void print_ripso(const uchar_t *);
     75   1676        jpk static void print_cipso(const uchar_t *);
     76      0     stevel 
     77      0     stevel /* Keep track of how many nested IP headers we have. */
     78      0     stevel unsigned int encap_levels;
     79      0     stevel unsigned int total_encap_levels = 1;
     80      0     stevel 
     81      0     stevel int
     82   1676        jpk interpret_ip(int flags, const struct ip *ip, int fraglen)
     83      0     stevel {
     84   1676        jpk 	uchar_t *data;
     85      0     stevel 	char buff[24];
     86      0     stevel 	boolean_t isfrag = B_FALSE;
     87      0     stevel 	boolean_t morefrag;
     88      0     stevel 	uint16_t fragoffset;
     89      0     stevel 	int hdrlen;
     90      0     stevel 	uint16_t iplen, uitmp;
     91      0     stevel 
     92      0     stevel 	if (ip->ip_v == IPV6_VERSION) {
     93      0     stevel 		iplen = interpret_ipv6(flags, (ip6_t *)ip, fraglen);
     94      0     stevel 		return (iplen);
     95      0     stevel 	}
     96      0     stevel 
     97      0     stevel 	if (encap_levels == 0)
     98      0     stevel 		total_encap_levels = 0;
     99      0     stevel 	encap_levels++;
    100      0     stevel 	total_encap_levels++;
    101      0     stevel 
    102      0     stevel 	hdrlen = ip->ip_hl * 4;
    103   1676        jpk 	data = ((uchar_t *)ip) + hdrlen;
    104      0     stevel 	iplen = ntohs(ip->ip_len) - hdrlen;
    105      0     stevel 	fraglen -= hdrlen;
    106      0     stevel 	if (fraglen > iplen)
    107      0     stevel 		fraglen = iplen;
    108      0     stevel 	if (fraglen < 0) {
    109      0     stevel 		(void) snprintf(get_sum_line(), MAXLINE,
    110      0     stevel 		    "IP truncated: header missing %d bytes", -fraglen);
    111      0     stevel 		encap_levels--;
    112      0     stevel 		return (fraglen + iplen);
    113      0     stevel 	}
    114      0     stevel 	/*
    115      0     stevel 	 * We flag this as a fragment if the more fragments bit is set, or
    116      0     stevel 	 * if the fragment offset is non-zero.
    117      0     stevel 	 */
    118      0     stevel 	morefrag = (ntohs(ip->ip_off) & IP_MF) == 0 ? B_FALSE : B_TRUE;
    119      0     stevel 	fragoffset = (ntohs(ip->ip_off) & 0x1FFF) * 8;
    120      0     stevel 	if (morefrag || fragoffset != 0)
    121      0     stevel 		isfrag = B_TRUE;
    122      0     stevel 
    123  10616  Sebastien 	src_name = addrtoname(AF_INET, &ip->ip_src);
    124  10616  Sebastien 	dst_name = addrtoname(AF_INET, &ip->ip_dst);
    125      0     stevel 
    126      0     stevel 	if (flags & F_SUM) {
    127      0     stevel 		if (isfrag) {
    128      0     stevel 			(void) snprintf(get_sum_line(), MAXLINE,
    129      0     stevel 			    "%s IP fragment ID=%d Offset=%-4d MF=%d TOS=0x%x "
    130      0     stevel 			    "TTL=%d",
    131      0     stevel 			    getproto(ip->ip_p),
    132      0     stevel 			    ntohs(ip->ip_id),
    133      0     stevel 			    fragoffset,
    134      0     stevel 			    morefrag,
    135      0     stevel 			    ip->ip_tos,
    136      0     stevel 			    ip->ip_ttl);
    137      0     stevel 		} else {
    138      0     stevel 			(void) strlcpy(buff, inet_ntoa(ip->ip_dst),
    139      0     stevel 			    sizeof (buff));
    140      0     stevel 			uitmp = ntohs(ip->ip_len);
    141      0     stevel 			(void) snprintf(get_sum_line(), MAXLINE,
    142      0     stevel 			    "IP  D=%s S=%s LEN=%u%s, ID=%d, TOS=0x%x, TTL=%d",
    143      0     stevel 			    buff,
    144      0     stevel 			    inet_ntoa(ip->ip_src),
    145      0     stevel 			    uitmp,
    146      0     stevel 			    iplen > fraglen ? "?" : "",
    147      0     stevel 			    ntohs(ip->ip_id),
    148      0     stevel 			    ip->ip_tos,
    149      0     stevel 			    ip->ip_ttl);
    150      0     stevel 		}
    151      0     stevel 	}
    152      0     stevel 
    153      0     stevel 	if (flags & F_DTAIL) {
    154      0     stevel 		show_header("IP:   ", "IP Header", iplen);
    155      0     stevel 		show_space();
    156   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    157   1676        jpk 		    "Version = %d", ip->ip_v);
    158   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    159   1676        jpk 		    "Header length = %d bytes", hdrlen);
    160   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    161   1676        jpk 		    "Type of service = 0x%02x", ip->ip_tos);
    162   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    163   1676        jpk 		    "      xxx. .... = %d (precedence)",
    164      0     stevel 		    ip->ip_tos >> 5);
    165   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    166   1676        jpk 		    "      %s", getflag(ip->ip_tos, IPTOS_LOWDELAY,
    167      0     stevel 		    "low delay", "normal delay"));
    168   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
    169      0     stevel 		    getflag(ip->ip_tos, IPTOS_THROUGHPUT,
    170      0     stevel 		    "high throughput", "normal throughput"));
    171   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
    172      0     stevel 		    getflag(ip->ip_tos, IPTOS_RELIABILITY,
    173      0     stevel 		    "high reliability", "normal reliability"));
    174   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
    175      0     stevel 		    getflag(ip->ip_tos, IPTOS_ECT,
    176      0     stevel 		    "ECN capable transport", "not ECN capable transport"));
    177   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
    178      0     stevel 		    getflag(ip->ip_tos, IPTOS_CE,
    179      0     stevel 		    "ECN congestion experienced",
    180      0     stevel 		    "no ECN congestion experienced"));
    181      0     stevel 		/* warning: ip_len is signed in netinet/ip.h */
    182      0     stevel 		uitmp = ntohs(ip->ip_len);
    183   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    184   1676        jpk 		    "Total length = %u bytes%s", uitmp,
    185      0     stevel 		    iplen > fraglen ? " -- truncated" : "");
    186   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    187   1676        jpk 		    "Identification = %d", ntohs(ip->ip_id));
    188      0     stevel 		/* warning: ip_off is signed in netinet/ip.h */
    189      0     stevel 		uitmp = ntohs(ip->ip_off);
    190   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    191   1676        jpk 		    "Flags = 0x%x", uitmp >> 12);
    192   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
    193      0     stevel 		    getflag(uitmp >> 8, IP_DF >> 8,
    194      0     stevel 		    "do not fragment", "may fragment"));
    195   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
    196      0     stevel 		    getflag(uitmp >> 8, IP_MF >> 8,
    197      0     stevel 		    "more fragments", "last fragment"));
    198   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    199   1676        jpk 		    "Fragment offset = %u bytes",
    200      0     stevel 		    fragoffset);
    201   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    202   1676        jpk 		    "Time to live = %d seconds/hops",
    203      0     stevel 		    ip->ip_ttl);
    204   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    205   1676        jpk 		    "Protocol = %d (%s)", ip->ip_p,
    206      0     stevel 		    getproto(ip->ip_p));
    207      0     stevel 		/*
    208      0     stevel 		 * XXX need to compute checksum and print whether it's correct
    209      0     stevel 		 */
    210   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    211   1676        jpk 		    "Header checksum = %04x",
    212      0     stevel 		    ntohs(ip->ip_sum));
    213   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    214   1676        jpk 		    "Source address = %s, %s",
    215      0     stevel 		    inet_ntoa(ip->ip_src), addrtoname(AF_INET, &ip->ip_src));
    216   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    217   1676        jpk 		    "Destination address = %s, %s",
    218      0     stevel 		    inet_ntoa(ip->ip_dst), addrtoname(AF_INET, &ip->ip_dst));
    219      0     stevel 
    220      0     stevel 		/* Print IP options - if any */
    221      0     stevel 
    222   1676        jpk 		print_ipoptions((const uchar_t *)(ip + 1),
    223   1676        jpk 		    hdrlen - sizeof (struct ip));
    224      0     stevel 		show_space();
    225      0     stevel 	}
    226      0     stevel 
    227      0     stevel 	/*
    228      0     stevel 	 * If we are in detail mode, and this is not the first fragment of
    229      0     stevel 	 * a fragmented packet, print out a little line stating this.
    230      0     stevel 	 * Otherwise, go to the next protocol layer only if this is not a
    231      0     stevel 	 * fragment, or we are in detail mode and this is the first fragment
    232      0     stevel 	 * of a fragmented packet.
    233      0     stevel 	 */
    234      0     stevel 	if (flags & F_DTAIL && fragoffset != 0) {
    235   1676        jpk 		(void) snprintf(get_detail_line(0, 0), MAXLINE,
    236      0     stevel 		    "%s:  [%d byte(s) of data, continuation of IP ident=%d]",
    237      0     stevel 		    getproto(ip->ip_p),
    238      0     stevel 		    iplen,
    239      0     stevel 		    ntohs(ip->ip_id));
    240      0     stevel 	} else if (!isfrag || (flags & F_DTAIL) && isfrag && fragoffset == 0) {
    241      0     stevel 		/* go to the next protocol layer */
    242      0     stevel 
    243      0     stevel 		if (fraglen > 0) {
    244      0     stevel 			switch (ip->ip_p) {
    245      0     stevel 			case IPPROTO_IP:
    246      0     stevel 				break;
    247      0     stevel 			case IPPROTO_ENCAP:
    248   1676        jpk 				(void) interpret_ip(flags,
    249   1676        jpk 				    /* LINTED: alignment */
    250   1676        jpk 				    (const struct ip *)data, fraglen);
    251      0     stevel 				break;
    252      0     stevel 			case IPPROTO_ICMP:
    253   1676        jpk 				(void) interpret_icmp(flags,
    254   1676        jpk 				    /* LINTED: alignment */
    255   1676        jpk 				    (struct icmp *)data, iplen, fraglen);
    256      0     stevel 				break;
    257      0     stevel 			case IPPROTO_IGMP:
    258      0     stevel 				interpret_igmp(flags, data, iplen, fraglen);
    259      0     stevel 				break;
    260      0     stevel 			case IPPROTO_GGP:
    261      0     stevel 				break;
    262      0     stevel 			case IPPROTO_TCP:
    263   1676        jpk 				(void) interpret_tcp(flags,
    264   1676        jpk 				    (struct tcphdr *)data, iplen, fraglen);
    265      0     stevel 				break;
    266      0     stevel 
    267      0     stevel 			case IPPROTO_ESP:
    268   1676        jpk 				(void) interpret_esp(flags, data, iplen,
    269   1676        jpk 				    fraglen);
    270      0     stevel 				break;
    271      0     stevel 			case IPPROTO_AH:
    272   1676        jpk 				(void) interpret_ah(flags, data, iplen,
    273   1676        jpk 				    fraglen);
    274      0     stevel 				break;
    275      0     stevel 
    276      0     stevel 			case IPPROTO_OSPF:
    277      0     stevel 				interpret_ospf(flags, data, iplen, fraglen);
    278      0     stevel 				break;
    279      0     stevel 
    280      0     stevel 			case IPPROTO_EGP:
    281      0     stevel 			case IPPROTO_PUP:
    282      0     stevel 				break;
    283      0     stevel 			case IPPROTO_UDP:
    284   1676        jpk 				(void) interpret_udp(flags,
    285   1676        jpk 				    (struct udphdr *)data, iplen, fraglen);
    286      0     stevel 				break;
    287      0     stevel 
    288      0     stevel 			case IPPROTO_IDP:
    289      0     stevel 			case IPPROTO_HELLO:
    290      0     stevel 			case IPPROTO_ND:
    291      0     stevel 			case IPPROTO_RAW:
    292      0     stevel 				break;
    293      0     stevel 			case IPPROTO_IPV6:	/* IPV6 encap */
    294   1676        jpk 				/* LINTED: alignment */
    295      0     stevel 				(void) interpret_ipv6(flags, (ip6_t *)data,
    296      0     stevel 				    iplen);
    297      0     stevel 				break;
    298      0     stevel 			case IPPROTO_SCTP:
    299   1676        jpk 				(void) interpret_sctp(flags,
    300   1676        jpk 				    (struct sctp_hdr *)data, iplen, fraglen);
    301      0     stevel 				break;
    302      0     stevel 			}
    303      0     stevel 		}
    304      0     stevel 	}
    305      0     stevel 
    306      0     stevel 	encap_levels--;
    307      0     stevel 	return (iplen);
    308      0     stevel }
    309      0     stevel 
    310      0     stevel int
    311   1676        jpk interpret_ipv6(int flags, const ip6_t *ip6h, int fraglen)
    312      0     stevel {
    313      0     stevel 	uint8_t *data;
    314      0     stevel 	int hdrlen, iplen;
    315      0     stevel 	int version, flow, class;
    316      0     stevel 	uchar_t proto;
    317      0     stevel 	boolean_t isfrag = B_FALSE;
    318      0     stevel 	uint8_t extmask;
    319      0     stevel 	/*
    320      0     stevel 	 * The print_srcname and print_dstname strings are the hostname
    321      0     stevel 	 * parts of the verbose IPv6 header output, including the comma
    322      0     stevel 	 * and the space after the litteral address strings.
    323      0     stevel 	 */
    324      0     stevel 	char print_srcname[MAXHOSTNAMELEN + 2];
    325      0     stevel 	char print_dstname[MAXHOSTNAMELEN + 2];
    326      0     stevel 	char src_addrstr[INET6_ADDRSTRLEN];
    327      0     stevel 	char dst_addrstr[INET6_ADDRSTRLEN];
    328      0     stevel 
    329      0     stevel 	iplen = ntohs(ip6h->ip6_plen);
    330      0     stevel 	hdrlen = IPV6_HDR_LEN;
    331      0     stevel 	fraglen -= hdrlen;
    332      0     stevel 	if (fraglen < 0)
    333      0     stevel 		return (fraglen + hdrlen);
    334      0     stevel 	data = ((uint8_t *)ip6h) + hdrlen;
    335      0     stevel 
    336      0     stevel 	proto = ip6h->ip6_nxt;
    337      0     stevel 
    338      0     stevel 	src_name = addrtoname(AF_INET6, &ip6h->ip6_src);
    339      0     stevel 	dst_name = addrtoname(AF_INET6, &ip6h->ip6_dst);
    340      0     stevel 
    341      0     stevel 	/*
    342      0     stevel 	 * Use endian-aware masks to extract traffic class and
    343      0     stevel 	 * flowinfo.  Also, flowinfo is now 20 bits and class 8
    344      0     stevel 	 * rather than 24 and 4.
    345      0     stevel 	 */
    346      0     stevel 	class = ntohl((ip6h->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20);
    347      0     stevel 	flow = ntohl(ip6h->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL);
    348      0     stevel 
    349      0     stevel 	/*
    350      0     stevel 	 * NOTE: the F_SUM and F_DTAIL flags are mutually exclusive,
    351      0     stevel 	 * so the code within the first part of the following if statement
    352      0     stevel 	 * will not affect the detailed printing of the packet.
    353      0     stevel 	 */
    354      0     stevel 	if (flags & F_SUM) {
    355   1676        jpk 		(void) snprintf(get_sum_line(), MAXLINE,
    356   1676        jpk 		    "IPv6  S=%s D=%s LEN=%d HOPS=%d CLASS=0x%x FLOW=0x%x",
    357      0     stevel 		    src_name, dst_name, iplen, ip6h->ip6_hops, class, flow);
    358      0     stevel 	} else if (flags & F_DTAIL) {
    359      0     stevel 
    360      0     stevel 		(void) inet_ntop(AF_INET6, &ip6h->ip6_src, src_addrstr,
    361      0     stevel 		    INET6_ADDRSTRLEN);
    362      0     stevel 		(void) inet_ntop(AF_INET6, &ip6h->ip6_dst, dst_addrstr,
    363      0     stevel 		    INET6_ADDRSTRLEN);
    364      0     stevel 
    365      0     stevel 		version = ntohl(ip6h->ip6_vcf) >> 28;
    366      0     stevel 
    367  10616  Sebastien 		if (strcmp(src_name, src_addrstr) == 0) {
    368      0     stevel 			print_srcname[0] = '\0';
    369  10616  Sebastien 		} else {
    370      0     stevel 			snprintf(print_srcname, sizeof (print_srcname),
    371  10616  Sebastien 			    ", %s", src_name);
    372  10616  Sebastien 		}
    373      0     stevel 
    374  10616  Sebastien 		if (strcmp(dst_name, dst_addrstr) == 0) {
    375      0     stevel 			print_dstname[0] = '\0';
    376  10616  Sebastien 		} else {
    377      0     stevel 			snprintf(print_dstname, sizeof (print_dstname),
    378  10616  Sebastien 			    ", %s", dst_name);
    379  10616  Sebastien 		}
    380      0     stevel 
    381      0     stevel 		show_header("IPv6:   ", "IPv6 Header", iplen);
    382      0     stevel 		show_space();
    383      0     stevel 
    384   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    385      0     stevel 		    "Version = %d", version);
    386   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    387      0     stevel 		    "Traffic Class = %d", class);
    388   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    389      0     stevel 		    "Flow label = 0x%x", flow);
    390   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    391   1676        jpk 		    "Payload length = %d", iplen);
    392   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    393   1676        jpk 		    "Next Header = %d (%s)", proto,
    394      0     stevel 		    getproto(proto));
    395   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    396   1676        jpk 		    "Hop Limit = %d", ip6h->ip6_hops);
    397   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    398      0     stevel 		    "Source address = %s%s", src_addrstr, print_srcname);
    399   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    400      0     stevel 		    "Destination address = %s%s", dst_addrstr, print_dstname);
    401      0     stevel 
    402      0     stevel 		show_space();
    403      0     stevel 	}
    404      0     stevel 
    405      0     stevel 	/*
    406      0     stevel 	 * Print IPv6 Extension Headers, or skip them in the summary case.
    407      0     stevel 	 * Set isfrag to true if one of the extension headers encounterred
    408      0     stevel 	 * was a fragment header.
    409      0     stevel 	 */
    410      0     stevel 	if (proto == IPPROTO_HOPOPTS || proto == IPPROTO_DSTOPTS ||
    411      0     stevel 	    proto == IPPROTO_ROUTING || proto == IPPROTO_FRAGMENT) {
    412      0     stevel 		extmask = print_ipv6_extensions(flags, &data, &proto, &iplen,
    413      0     stevel 		    &fraglen);
    414      0     stevel 		if ((extmask & SNOOP_FRAGMENT) != 0) {
    415      0     stevel 			isfrag = B_TRUE;
    416      0     stevel 		}
    417      0     stevel 	}
    418      0     stevel 
    419      0     stevel 	/*
    420      0     stevel 	 * We only want to print upper layer information if this is not
    421      0     stevel 	 * a fragment, or if we're printing in detail.  Note that the
    422      0     stevel 	 * proto variable will be set to IPPROTO_NONE if this is a fragment
    423      0     stevel 	 * with a non-zero fragment offset.
    424      0     stevel 	 */
    425      0     stevel 	if (!isfrag || flags & F_DTAIL) {
    426      0     stevel 		/* go to the next protocol layer */
    427      0     stevel 
    428      0     stevel 		switch (proto) {
    429      0     stevel 		case IPPROTO_IP:
    430      0     stevel 			break;
    431      0     stevel 		case IPPROTO_ENCAP:
    432   1676        jpk 			/* LINTED: alignment */
    433   1676        jpk 			(void) interpret_ip(flags, (const struct ip *)data,
    434   1676        jpk 			    fraglen);
    435      0     stevel 			break;
    436      0     stevel 		case IPPROTO_ICMPV6:
    437   1676        jpk 			/* LINTED: alignment */
    438   1676        jpk 			(void) interpret_icmpv6(flags, (icmp6_t *)data, iplen,
    439      0     stevel 			    fraglen);
    440      0     stevel 			break;
    441      0     stevel 		case IPPROTO_IGMP:
    442      0     stevel 			interpret_igmp(flags, data, iplen, fraglen);
    443      0     stevel 			break;
    444      0     stevel 		case IPPROTO_GGP:
    445      0     stevel 			break;
    446      0     stevel 		case IPPROTO_TCP:
    447   1676        jpk 			(void) interpret_tcp(flags, (struct tcphdr *)data,
    448   1676        jpk 			    iplen, fraglen);
    449      0     stevel 			break;
    450      0     stevel 		case IPPROTO_ESP:
    451   1676        jpk 			(void) interpret_esp(flags, data, iplen, fraglen);
    452      0     stevel 			break;
    453      0     stevel 		case IPPROTO_AH:
    454   1676        jpk 			(void) interpret_ah(flags, data, iplen, fraglen);
    455      0     stevel 			break;
    456      0     stevel 		case IPPROTO_EGP:
    457      0     stevel 		case IPPROTO_PUP:
    458      0     stevel 			break;
    459      0     stevel 		case IPPROTO_UDP:
    460   1676        jpk 			(void) interpret_udp(flags, (struct udphdr *)data,
    461   1676        jpk 			    iplen, fraglen);
    462      0     stevel 			break;
    463      0     stevel 		case IPPROTO_IDP:
    464      0     stevel 		case IPPROTO_HELLO:
    465      0     stevel 		case IPPROTO_ND:
    466      0     stevel 		case IPPROTO_RAW:
    467      0     stevel 			break;
    468      0     stevel 		case IPPROTO_IPV6:
    469   1676        jpk 			/* LINTED: alignment */
    470   1676        jpk 			(void) interpret_ipv6(flags, (const ip6_t *)data,
    471   1676        jpk 			    iplen);
    472      0     stevel 			break;
    473      0     stevel 		case IPPROTO_SCTP:
    474   1676        jpk 			(void) interpret_sctp(flags, (struct sctp_hdr *)data,
    475   1676        jpk 			    iplen, fraglen);
    476      0     stevel 			break;
    477      0     stevel 		case IPPROTO_OSPF:
    478      0     stevel 			interpret_ospf6(flags, data, iplen, fraglen);
    479      0     stevel 			break;
    480      0     stevel 		}
    481      0     stevel 	}
    482      0     stevel 
    483      0     stevel 	return (iplen);
    484      0     stevel }
    485      0     stevel 
    486      0     stevel /*
    487      0     stevel  * ip_ext: data including the extension header.
    488      0     stevel  * iplen: length of the data remaining in the packet.
    489      0     stevel  * Returns a mask of IPv6 extension headers it processed.
    490      0     stevel  */
    491      0     stevel uint8_t
    492      0     stevel print_ipv6_extensions(int flags, uint8_t **hdr, uint8_t *next, int *iplen,
    493      0     stevel     int *fraglen)
    494      0     stevel {
    495      0     stevel 	uint8_t *data_ptr;
    496      0     stevel 	uchar_t proto = *next;
    497      0     stevel 	boolean_t is_extension_header;
    498      0     stevel 	struct ip6_hbh *ipv6ext_hbh;
    499      0     stevel 	struct ip6_dest *ipv6ext_dest;
    500      0     stevel 	struct ip6_rthdr *ipv6ext_rthdr;
    501      0     stevel 	struct ip6_frag *ipv6ext_frag;
    502      0     stevel 	uint32_t exthdrlen;
    503      0     stevel 	uint8_t extmask = 0;
    504      0     stevel 
    505      0     stevel 	if ((hdr == NULL) || (*hdr == NULL) || (next == NULL) || (iplen == 0))
    506      0     stevel 		return (0);
    507      0     stevel 
    508      0     stevel 	data_ptr = *hdr;
    509      0     stevel 	is_extension_header = B_TRUE;
    510      0     stevel 	while (is_extension_header) {
    511      0     stevel 
    512      0     stevel 		/*
    513      0     stevel 		 * There must be at least enough data left to read the
    514      0     stevel 		 * next header and header length fields from the next
    515      0     stevel 		 * header.
    516      0     stevel 		 */
    517      0     stevel 		if (*fraglen < 2) {
    518      0     stevel 			return (extmask);
    519      0     stevel 		}
    520      0     stevel 
    521      0     stevel 		switch (proto) {
    522      0     stevel 		case IPPROTO_HOPOPTS:
    523      0     stevel 			ipv6ext_hbh = (struct ip6_hbh *)data_ptr;
    524      0     stevel 			exthdrlen = 8 + ipv6ext_hbh->ip6h_len * 8;
    525      0     stevel 			if (*fraglen <= exthdrlen) {
    526      0     stevel 				return (extmask);
    527      0     stevel 			}
    528      0     stevel 			prt_hbh_options(flags, ipv6ext_hbh);
    529      0     stevel 			extmask |= SNOOP_HOPOPTS;
    530      0     stevel 			proto = ipv6ext_hbh->ip6h_nxt;
    531      0     stevel 			break;
    532      0     stevel 		case IPPROTO_DSTOPTS:
    533      0     stevel 			ipv6ext_dest = (struct ip6_dest *)data_ptr;
    534      0     stevel 			exthdrlen = 8 + ipv6ext_dest->ip6d_len * 8;
    535      0     stevel 			if (*fraglen <= exthdrlen) {
    536      0     stevel 				return (extmask);
    537      0     stevel 			}
    538      0     stevel 			prt_dest_options(flags, ipv6ext_dest);
    539      0     stevel 			extmask |= SNOOP_DSTOPTS;
    540      0     stevel 			proto = ipv6ext_dest->ip6d_nxt;
    541      0     stevel 			break;
    542      0     stevel 		case IPPROTO_ROUTING:
    543      0     stevel 			ipv6ext_rthdr = (struct ip6_rthdr *)data_ptr;
    544      0     stevel 			exthdrlen = 8 + ipv6ext_rthdr->ip6r_len * 8;
    545      0     stevel 			if (*fraglen <= exthdrlen) {
    546      0     stevel 				return (extmask);
    547      0     stevel 			}
    548      0     stevel 			prt_routing_hdr(flags, ipv6ext_rthdr);
    549      0     stevel 			extmask |= SNOOP_ROUTING;
    550      0     stevel 			proto = ipv6ext_rthdr->ip6r_nxt;
    551      0     stevel 			break;
    552      0     stevel 		case IPPROTO_FRAGMENT:
    553   1676        jpk 			/* LINTED: alignment */
    554      0     stevel 			ipv6ext_frag = (struct ip6_frag *)data_ptr;
    555      0     stevel 			exthdrlen = sizeof (struct ip6_frag);
    556      0     stevel 			if (*fraglen <= exthdrlen) {
    557      0     stevel 				return (extmask);
    558      0     stevel 			}
    559      0     stevel 			prt_fragment_hdr(flags, ipv6ext_frag);
    560      0     stevel 			extmask |= SNOOP_FRAGMENT;
    561      0     stevel 			/*
    562      0     stevel 			 * If this is not the first fragment, forget about
    563      0     stevel 			 * the rest of the packet, snoop decoding is
    564      0     stevel 			 * stateless.
    565      0     stevel 			 */
    566      0     stevel 			if ((ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK) != 0)
    567      0     stevel 				proto = IPPROTO_NONE;
    568      0     stevel 			else
    569      0     stevel 				proto = ipv6ext_frag->ip6f_nxt;
    570      0     stevel 			break;
    571      0     stevel 		default:
    572      0     stevel 			is_extension_header = B_FALSE;
    573      0     stevel 			break;
    574      0     stevel 		}
    575      0     stevel 
    576      0     stevel 		if (is_extension_header) {
    577      0     stevel 			*iplen -= exthdrlen;
    578      0     stevel 			*fraglen -= exthdrlen;
    579      0     stevel 			data_ptr += exthdrlen;
    580      0     stevel 		}
    581      0     stevel 	}
    582      0     stevel 
    583      0     stevel 	*next = proto;
    584      0     stevel 	*hdr = data_ptr;
    585      0     stevel 	return (extmask);
    586      0     stevel }
    587      0     stevel 
    588      0     stevel static void
    589   1676        jpk print_ipoptions(const uchar_t *opt, int optlen)
    590      0     stevel {
    591      0     stevel 	int len;
    592   1676        jpk 	int remain;
    593      0     stevel 	char *line;
    594   1676        jpk 	const char *truncstr;
    595      0     stevel 
    596      0     stevel 	if (optlen <= 0) {
    597   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    598      0     stevel 		    "No options");
    599      0     stevel 		return;
    600      0     stevel 	}
    601      0     stevel 
    602   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
    603      0     stevel 	    "Options: (%d bytes)", optlen);
    604      0     stevel 
    605      0     stevel 	while (optlen > 0) {
    606   1676        jpk 		line = get_line(0, 0);
    607   1676        jpk 		remain = get_line_remain();
    608      0     stevel 		len = opt[1];
    609   1676        jpk 		truncstr = len > optlen ? "?" : "";
    610      0     stevel 		switch (opt[0]) {
    611      0     stevel 		case IPOPT_EOL:
    612   1676        jpk 			(void) strlcpy(line, "  - End of option list", remain);
    613      0     stevel 			return;
    614      0     stevel 		case IPOPT_NOP:
    615   1676        jpk 			(void) strlcpy(line, "  - No op", remain);
    616      0     stevel 			len = 1;
    617      0     stevel 			break;
    618      0     stevel 		case IPOPT_RR:
    619   1676        jpk 			(void) snprintf(line, remain,
    620   1676        jpk 			    "  - Record route (%d bytes%s)", len, truncstr);
    621      0     stevel 			print_route(opt);
    622      0     stevel 			break;
    623      0     stevel 		case IPOPT_TS:
    624   1676        jpk 			(void) snprintf(line, remain,
    625   1676        jpk 			    "  - Time stamp (%d bytes%s)", len, truncstr);
    626      0     stevel 			break;
    627      0     stevel 		case IPOPT_SECURITY:
    628   1676        jpk 			(void) snprintf(line, remain, "  - RIPSO (%d bytes%s)",
    629   1676        jpk 			    len, truncstr);
    630   1676        jpk 			print_ripso(opt);
    631   1676        jpk 			break;
    632   1676        jpk 		case IPOPT_COMSEC:
    633   1676        jpk 			(void) snprintf(line, remain, "  - CIPSO (%d bytes%s)",
    634   1676        jpk 			    len, truncstr);
    635   1676        jpk 			print_cipso(opt);
    636      0     stevel 			break;
    637      0     stevel 		case IPOPT_LSRR:
    638   1676        jpk 			(void) snprintf(line, remain,
    639   1676        jpk 			    "  - Loose source route (%d bytes%s)", len,
    640   1676        jpk 			    truncstr);
    641      0     stevel 			print_route(opt);
    642      0     stevel 			break;
    643      0     stevel 		case IPOPT_SATID:
    644   1676        jpk 			(void) snprintf(line, remain,
    645   1676        jpk 			    "  - SATNET Stream id (%d bytes%s)",
    646   1676        jpk 			    len, truncstr);
    647      0     stevel 			break;
    648      0     stevel 		case IPOPT_SSRR:
    649   1676        jpk 			(void) snprintf(line, remain,
    650   1676        jpk 			    "  - Strict source route, (%d bytes%s)", len,
    651   1676        jpk 			    truncstr);
    652      0     stevel 			print_route(opt);
    653      0     stevel 			break;
    654      0     stevel 		default:
    655   1676        jpk 			(void) snprintf(line, remain,
    656   1676        jpk 			    "  - Option %d (unknown - %d bytes%s) %s",
    657   1676        jpk 			    opt[0], len, truncstr,
    658   1676        jpk 			    tohex((char *)&opt[2], len - 2));
    659      0     stevel 			break;
    660      0     stevel 		}
    661      0     stevel 		if (len <= 0) {
    662   1676        jpk 			(void) snprintf(line, remain,
    663   1676        jpk 			    "  - Incomplete option len %d", len);
    664      0     stevel 			break;
    665      0     stevel 		}
    666      0     stevel 		opt += len;
    667      0     stevel 		optlen -= len;
    668      0     stevel 	}
    669      0     stevel }
    670      0     stevel 
    671      0     stevel static void
    672   1676        jpk print_route(const uchar_t *opt)
    673      0     stevel {
    674   1676        jpk 	int len, pointer, remain;
    675      0     stevel 	struct in_addr addr;
    676      0     stevel 	char *line;
    677      0     stevel 
    678      0     stevel 	len = opt[1];
    679      0     stevel 	pointer = opt[2];
    680      0     stevel 
    681   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
    682      0     stevel 	    "    Pointer = %d", pointer);
    683      0     stevel 
    684      0     stevel 	pointer -= IPOPT_MINOFF;
    685      0     stevel 	opt += (IPOPT_OFFSET + 1);
    686      0     stevel 	len -= (IPOPT_OFFSET + 1);
    687      0     stevel 
    688      0     stevel 	while (len > 0) {
    689   1676        jpk 		line = get_line(0, 0);
    690   1676        jpk 		remain = get_line_remain();
    691      0     stevel 		memcpy((char *)&addr, opt, sizeof (addr));
    692      0     stevel 		if (addr.s_addr == INADDR_ANY)
    693   1676        jpk 			(void) strlcpy(line, "      -", remain);
    694      0     stevel 		else
    695   1676        jpk 			(void) snprintf(line, remain, "      %s",
    696      0     stevel 			    addrtoname(AF_INET, &addr));
    697      0     stevel 		if (pointer == 0)
    698   1676        jpk 			(void) strlcat(line, "  <-- (current)", remain);
    699      0     stevel 
    700      0     stevel 		opt += sizeof (addr);
    701      0     stevel 		len -= sizeof (addr);
    702      0     stevel 		pointer -= sizeof (addr);
    703      0     stevel 	}
    704      0     stevel }
    705      0     stevel 
    706      0     stevel char *
    707   1676        jpk getproto(int p)
    708      0     stevel {
    709      0     stevel 	switch (p) {
    710      0     stevel 	case IPPROTO_HOPOPTS:	return ("IPv6-HopOpts");
    711      0     stevel 	case IPPROTO_IPV6:	return ("IPv6");
    712      0     stevel 	case IPPROTO_ROUTING:	return ("IPv6-Route");
    713      0     stevel 	case IPPROTO_FRAGMENT:	return ("IPv6-Frag");
    714      0     stevel 	case IPPROTO_RSVP:	return ("RSVP");
    715      0     stevel 	case IPPROTO_ENCAP:	return ("IP-in-IP");
    716      0     stevel 	case IPPROTO_AH:	return ("AH");
    717      0     stevel 	case IPPROTO_ESP:	return ("ESP");
    718      0     stevel 	case IPPROTO_ICMP:	return ("ICMP");
    719      0     stevel 	case IPPROTO_ICMPV6:	return ("ICMPv6");
    720      0     stevel 	case IPPROTO_DSTOPTS:	return ("IPv6-DstOpts");
    721      0     stevel 	case IPPROTO_IGMP:	return ("IGMP");
    722      0     stevel 	case IPPROTO_GGP:	return ("GGP");
    723      0     stevel 	case IPPROTO_TCP:	return ("TCP");
    724      0     stevel 	case IPPROTO_EGP:	return ("EGP");
    725      0     stevel 	case IPPROTO_PUP:	return ("PUP");
    726      0     stevel 	case IPPROTO_UDP:	return ("UDP");
    727      0     stevel 	case IPPROTO_IDP:	return ("IDP");
    728      0     stevel 	case IPPROTO_HELLO:	return ("HELLO");
    729      0     stevel 	case IPPROTO_ND:	return ("ND");
    730      0     stevel 	case IPPROTO_EON:	return ("EON");
    731      0     stevel 	case IPPROTO_RAW:	return ("RAW");
    732      0     stevel 	case IPPROTO_OSPF:	return ("OSPF");
    733      0     stevel 	default:		return ("");
    734      0     stevel 	}
    735      0     stevel }
    736      0     stevel 
    737      0     stevel static void
    738   1676        jpk prt_routing_hdr(int flags, const struct ip6_rthdr *ipv6ext_rthdr)
    739      0     stevel {
    740      0     stevel 	uint8_t nxt_hdr;
    741      0     stevel 	uint8_t type;
    742      0     stevel 	uint32_t len;
    743      0     stevel 	uint8_t segleft;
    744      0     stevel 	uint32_t numaddrs;
    745      0     stevel 	int i;
    746      0     stevel 	struct ip6_rthdr0 *ipv6ext_rthdr0;
    747      0     stevel 	struct in6_addr *addrs;
    748      0     stevel 	char addr[INET6_ADDRSTRLEN];
    749      0     stevel 
    750      0     stevel 	/* in summary mode, we don't do anything. */
    751      0     stevel 	if (flags & F_SUM) {
    752      0     stevel 		return;
    753      0     stevel 	}
    754      0     stevel 
    755      0     stevel 	nxt_hdr = ipv6ext_rthdr->ip6r_nxt;
    756      0     stevel 	type = ipv6ext_rthdr->ip6r_type;
    757      0     stevel 	len = 8 * (ipv6ext_rthdr->ip6r_len + 1);
    758      0     stevel 	segleft = ipv6ext_rthdr->ip6r_segleft;
    759      0     stevel 
    760      0     stevel 	show_header("IPv6-Route:  ", "IPv6 Routing Header", 0);
    761      0     stevel 	show_space();
    762      0     stevel 
    763   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
    764      0     stevel 	    "Next header = %d (%s)", nxt_hdr, getproto(nxt_hdr));
    765   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
    766      0     stevel 	    "Header length = %d", len);
    767   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
    768      0     stevel 	    "Routing type = %d", type);
    769   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
    770      0     stevel 	    "Segments left = %d", segleft);
    771      0     stevel 
    772      0     stevel 	if (type == IPV6_RTHDR_TYPE_0) {
    773      0     stevel 		/*
    774      0     stevel 		 * XXX This loop will print all addresses in the routing header,
    775      0     stevel 		 * XXX not just the segments left.
    776      0     stevel 		 * XXX (The header length field is twice the number of
    777      0     stevel 		 * XXX addresses)
    778      0     stevel 		 * XXX At some future time, we may want to change this
    779      0     stevel 		 * XXX to differentiate between the hops yet to do
    780      0     stevel 		 * XXX and the hops already taken.
    781      0     stevel 		 */
    782   1676        jpk 		/* LINTED: alignment */
    783      0     stevel 		ipv6ext_rthdr0 = (struct ip6_rthdr0 *)ipv6ext_rthdr;
    784      0     stevel 		numaddrs = ipv6ext_rthdr0->ip6r0_len / 2;
    785      0     stevel 		addrs = (struct in6_addr *)(ipv6ext_rthdr0 + 1);
    786      0     stevel 		for (i = 0; i < numaddrs; i++) {
    787      0     stevel 			(void) inet_ntop(AF_INET6, &addrs[i], addr,
    788      0     stevel 			    INET6_ADDRSTRLEN);
    789   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
    790      0     stevel 			    "address[%d]=%s", i, addr);
    791      0     stevel 		}
    792      0     stevel 	}
    793      0     stevel 
    794      0     stevel 	show_space();
    795      0     stevel }
    796      0     stevel 
    797      0     stevel static void
    798   1676        jpk prt_fragment_hdr(int flags, const struct ip6_frag *ipv6ext_frag)
    799      0     stevel {
    800      0     stevel 	boolean_t morefrag;
    801      0     stevel 	uint16_t fragoffset;
    802      0     stevel 	uint8_t nxt_hdr;
    803      0     stevel 	uint32_t fragident;
    804      0     stevel 
    805      0     stevel 	/* extract the various fields from the fragment header */
    806      0     stevel 	nxt_hdr = ipv6ext_frag->ip6f_nxt;
    807      0     stevel 	morefrag = (ipv6ext_frag->ip6f_offlg & IP6F_MORE_FRAG) == 0
    808      0     stevel 	    ? B_FALSE : B_TRUE;
    809      0     stevel 	fragoffset = ntohs(ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK);
    810      0     stevel 	fragident = ntohl(ipv6ext_frag->ip6f_ident);
    811      0     stevel 
    812      0     stevel 	if (flags & F_SUM) {
    813   1676        jpk 		(void) snprintf(get_sum_line(), MAXLINE,
    814      0     stevel 		    "IPv6 fragment ID=%d Offset=%-4d MF=%d",
    815      0     stevel 		    fragident,
    816      0     stevel 		    fragoffset,
    817      0     stevel 		    morefrag);
    818      0     stevel 	} else { /* F_DTAIL */
    819      0     stevel 		show_header("IPv6-Frag:  ", "IPv6 Fragment Header", 0);
    820      0     stevel 		show_space();
    821      0     stevel 
    822   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    823      0     stevel 		    "Next Header = %d (%s)", nxt_hdr, getproto(nxt_hdr));
    824   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    825      0     stevel 		    "Fragment Offset = %d", fragoffset);
    826   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    827      0     stevel 		    "More Fragments Flag = %s", morefrag ? "true" : "false");
    828   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
    829      0     stevel 		    "Identification = %d", fragident);
    830      0     stevel 
    831      0     stevel 		show_space();
    832      0     stevel 	}
    833      0     stevel }
    834      0     stevel 
    835      0     stevel static void
    836   1676        jpk print_ip6opt_ls(const uchar_t *data, unsigned int op_len)
    837      0     stevel {
    838   1676        jpk 	uint32_t doi;
    839   1676        jpk 	uint8_t sotype, solen;
    840   1676        jpk 	uint16_t value, value2;
    841   1676        jpk 	char *cp;
    842   1676        jpk 	int remlen;
    843   1676        jpk 	boolean_t printed;
    844   1676        jpk 
    845   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
    846   1676        jpk 	    "Labeled Security Option len = %u bytes%s", op_len,
    847   1676        jpk 	    op_len < sizeof (uint32_t) || (op_len & 1) != 0 ? "?" : "");
    848   1676        jpk 	if (op_len < sizeof (uint32_t))
    849   1676        jpk 		return;
    850   1676        jpk 	GETINT32(doi, data);
    851   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
    852   1676        jpk 	    "    DOI = %d (%s)", doi, doi == IP6LS_DOI_V4 ? "IPv4" : "???");
    853   1676        jpk 	op_len -= sizeof (uint32_t);
    854   1676        jpk 	while (op_len > 0) {
    855   1676        jpk 		GETINT8(sotype, data);
    856   1676        jpk 		if (op_len < 2) {
    857   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
    858   1676        jpk 			    "    truncated %u suboption (no len)", sotype);
    859   1676        jpk 			break;
    860   1676        jpk 		}
    861   1676        jpk 		GETINT8(solen, data);
    862   1676        jpk 		if (solen < 2 || solen > op_len) {
    863   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
    864   1676        jpk 			    "    bad %u suboption (len 2 <= %u <= %u)",
    865   1676        jpk 			    sotype, solen, op_len);
    866   1676        jpk 			if (solen < 2)
    867   1676        jpk 				solen = 2;
    868   1676        jpk 			if (solen > op_len)
    869   1676        jpk 				solen = op_len;
    870   1676        jpk 		}
    871   1676        jpk 		op_len -= solen;
    872   1676        jpk 		solen -= 2;
    873   1676        jpk 		cp = get_line(0, 0);
    874   1676        jpk 		remlen = get_line_remain();
    875   1676        jpk 		(void) strlcpy(cp, "    ", remlen);
    876   1676        jpk 		cp += 4;
    877   1676        jpk 		remlen -= 4;
    878   1676        jpk 		printed = B_TRUE;
    879   1676        jpk 		switch (sotype) {
    880   1676        jpk 		case IP6LS_TT_LEVEL:
    881   1676        jpk 			if (solen != 2) {
    882   1676        jpk 				printed = B_FALSE;
    883   1676        jpk 				break;
    884   1676        jpk 			}
    885   1676        jpk 			GETINT16(value, data);
    886   1676        jpk 			(void) snprintf(cp, remlen, "Level %u", value);
    887   1676        jpk 			solen = 0;
    888   1676        jpk 			break;
    889   1676        jpk 		case IP6LS_TT_VECTOR:
    890   1676        jpk 			(void) strlcpy(cp, "Bit-Vector: ", remlen);
    891   1676        jpk 			remlen -= strlen(cp);
    892   1676        jpk 			cp += strlen(cp);
    893   1676        jpk 			while (solen > 1) {
    894   1676        jpk 				GETINT16(value, data);
    895   1676        jpk 				solen -= 2;
    896   1676        jpk 				(void) snprintf(cp, remlen, "%04x", value);
    897   1676        jpk 				remlen -= strlen(cp);
    898   1676        jpk 				cp += strlen(cp);
    899   1676        jpk 			}
    900   1676        jpk 			break;
    901   1676        jpk 		case IP6LS_TT_ENUM:
    902   1676        jpk 			(void) strlcpy(cp, "Enumeration:", remlen);
    903   1676        jpk 			remlen -= strlen(cp);
    904   1676        jpk 			cp += strlen(cp);
    905   1676        jpk 			while (solen > 1) {
    906   1676        jpk 				GETINT16(value, data);
    907   1676        jpk 				solen -= 2;
    908   1676        jpk 				(void) snprintf(cp, remlen, " %u", value);
    909   1676        jpk 				remlen -= strlen(cp);
    910   1676        jpk 				cp += strlen(cp);
    911   1676        jpk 			}
    912   1676        jpk 			break;
    913   1676        jpk 		case IP6LS_TT_RANGES:
    914   1676        jpk 			(void) strlcpy(cp, "Ranges:", remlen);
    915   1676        jpk 			remlen -= strlen(cp);
    916   1676        jpk 			cp += strlen(cp);
    917   1676        jpk 			while (solen > 3) {
    918   1676        jpk 				GETINT16(value, data);
    919   1676        jpk 				GETINT16(value2, data);
    920   1676        jpk 				solen -= 4;
    921   1676        jpk 				(void) snprintf(cp, remlen, " %u-%u", value,
    922   1676        jpk 				    value2);
    923   1676        jpk 				remlen -= strlen(cp);
    924   1676        jpk 				cp += strlen(cp);
    925   1676        jpk 			}
    926   1676        jpk 			break;
    927   1676        jpk 		case IP6LS_TT_V4:
    928   1676        jpk 			(void) strlcpy(cp, "IPv4 Option", remlen);
    929   1676        jpk 			print_ipoptions(data, solen);
    930   1676        jpk 			solen = 0;
    931   1676        jpk 			break;
    932   1676        jpk 		case IP6LS_TT_DEST:
    933   1676        jpk 			(void) snprintf(cp, remlen,
    934   1676        jpk 			    "Destination-Only Data length %u", solen);
    935   1676        jpk 			solen = 0;
    936   1676        jpk 			break;
    937   1676        jpk 		default:
    938   1676        jpk 			(void) snprintf(cp, remlen,
    939   1676        jpk 			    "    unknown %u suboption (len %u)", sotype, solen);
    940   1676        jpk 			solen = 0;
    941   1676        jpk 			break;
    942   1676        jpk 		}
    943   1676        jpk 		if (solen != 0) {
    944   1676        jpk 			if (printed) {
    945   1676        jpk 				cp = get_line(0, 0);
    946   1676        jpk 				remlen = get_line_remain();
    947   1676        jpk 			}
    948   1676        jpk 			(void) snprintf(cp, remlen,
    949   1676        jpk 			    "    malformed %u suboption (remaining %u)",
    950   1676        jpk 			    sotype, solen);
    951   1676        jpk 			data += solen;
    952   1676        jpk 		}
    953   1676        jpk 	}
    954   1676        jpk }
    955   1676        jpk 
    956   1676        jpk static void
    957   1676        jpk prt_hbh_options(int flags, const struct ip6_hbh *ipv6ext_hbh)
    958   1676        jpk {
    959   1676        jpk 	const uint8_t *data, *ndata;
    960   1676        jpk 	uint32_t len;
    961      0     stevel 	uint8_t op_type;
    962      0     stevel 	uint8_t op_len;
    963      0     stevel 	uint8_t nxt_hdr;
    964      0     stevel 
    965      0     stevel 	/* in summary mode, we don't do anything. */
    966      0     stevel 	if (flags & F_SUM) {
    967      0     stevel 		return;
    968      0     stevel 	}
    969      0     stevel 
    970      0     stevel 	show_header("IPv6-HopOpts:  ", "IPv6 Hop-by-Hop Options Header", 0);
    971      0     stevel 	show_space();
    972      0     stevel 
    973      0     stevel 	/*
    974      0     stevel 	 * Store the lengh of this ext hdr in bytes.  The caller has
    975      0     stevel 	 * ensured that there is at least len bytes of data left.
    976      0     stevel 	 */
    977      0     stevel 	len = ipv6ext_hbh->ip6h_len * 8 + 8;
    978      0     stevel 
    979   1676        jpk 	ndata = (const uint8_t *)ipv6ext_hbh + 2;
    980      0     stevel 	len -= 2;
    981      0     stevel 
    982      0     stevel 	nxt_hdr = ipv6ext_hbh->ip6h_nxt;
    983   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
    984      0     stevel 	    "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr));
    985      0     stevel 
    986      0     stevel 	while (len > 0) {
    987   1676        jpk 		data = ndata;
    988      0     stevel 		GETINT8(op_type, data);
    989   1676        jpk 		/* This is the only one-octet IPv6 option */
    990   1676        jpk 		if (op_type == IP6OPT_PAD1) {
    991   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
    992      0     stevel 			    "pad1 option ");
    993      0     stevel 			len--;
    994   1676        jpk 			ndata = data;
    995   1676        jpk 			continue;
    996   1676        jpk 		}
    997   1676        jpk 		GETINT8(op_len, data);
    998   1676        jpk 		if (len < 2 || op_len + 2 > len) {
    999   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1000   1676        jpk 			    "Error: option %u truncated (%u + 2 > %u)",
   1001   1676        jpk 			    op_type, op_len, len);
   1002   1676        jpk 			op_len = len - 2;
   1003   1676        jpk 			/*
   1004   1676        jpk 			 * Continue processing the malformed option so that we
   1005   1676        jpk 			 * can display as much as possible.
   1006   1676        jpk 			 */
   1007   1676        jpk 		}
   1008   1676        jpk 
   1009   1676        jpk 		/* advance pointers to the next option */
   1010   1676        jpk 		len -= op_len + 2;
   1011   1676        jpk 		ndata = data + op_len;
   1012   1676        jpk 
   1013   1676        jpk 		/* process this option */
   1014   1676        jpk 		switch (op_type) {
   1015      0     stevel 		case IP6OPT_PADN:
   1016   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1017      0     stevel 			    "padN option len = %u", op_len);
   1018      0     stevel 			break;
   1019      0     stevel 		case IP6OPT_JUMBO: {
   1020      0     stevel 			uint32_t payload_len;
   1021      0     stevel 
   1022   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1023   1676        jpk 			    "Jumbo Payload Option len = %u bytes%s", op_len,
   1024   1676        jpk 			    op_len == sizeof (uint32_t) ? "" : "?");
   1025      0     stevel 			if (op_len == sizeof (uint32_t)) {
   1026      0     stevel 				GETINT32(payload_len, data);
   1027   1676        jpk 				(void) snprintf(get_line(0, 0),
   1028   1676        jpk 				    get_line_remain(),
   1029      0     stevel 				    "Jumbo Payload Length = %u bytes",
   1030      0     stevel 				    payload_len);
   1031      0     stevel 			}
   1032      0     stevel 			break;
   1033      0     stevel 		}
   1034      0     stevel 		case IP6OPT_ROUTER_ALERT: {
   1035      0     stevel 			uint16_t value;
   1036      0     stevel 			const char *label[] = {"MLD", "RSVP", "AN"};
   1037      0     stevel 
   1038   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1039   1676        jpk 			    "Router Alert Option len = %u bytes%s", op_len,
   1040   1676        jpk 			    op_len == sizeof (uint16_t) ? "" : "?");
   1041      0     stevel 			if (op_len == sizeof (uint16_t)) {
   1042      0     stevel 				GETINT16(value, data);
   1043   1676        jpk 				(void) snprintf(get_line(0, 0),
   1044   1676        jpk 				    get_line_remain(),
   1045      0     stevel 				    "Alert Type = %d (%s)", value,
   1046      0     stevel 				    value < sizeof (label) / sizeof (label[0]) ?
   1047      0     stevel 				    label[value] : "???");
   1048      0     stevel 			}
   1049      0     stevel 			break;
   1050      0     stevel 		}
   1051   1676        jpk 		case IP6OPT_LS:
   1052   1676        jpk 			print_ip6opt_ls(data, op_len);
   1053   1676        jpk 			break;
   1054      0     stevel 		default:
   1055   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1056      0     stevel 			    "Option type = %u, len = %u", op_type, op_len);
   1057      0     stevel 			break;
   1058      0     stevel 		}
   1059      0     stevel 	}
   1060      0     stevel 
   1061      0     stevel 	show_space();
   1062      0     stevel }
   1063      0     stevel 
   1064      0     stevel static void
   1065   1676        jpk prt_dest_options(int flags, const struct ip6_dest *ipv6ext_dest)
   1066      0     stevel {
   1067   1676        jpk 	const uint8_t *data, *ndata;
   1068   1676        jpk 	uint32_t len;
   1069      0     stevel 	uint8_t op_type;
   1070      0     stevel 	uint32_t op_len;
   1071      0     stevel 	uint8_t nxt_hdr;
   1072      0     stevel 	uint8_t value;
   1073      0     stevel 
   1074      0     stevel 	/* in summary mode, we don't do anything. */
   1075      0     stevel 	if (flags & F_SUM) {
   1076      0     stevel 		return;
   1077      0     stevel 	}
   1078      0     stevel 
   1079      0     stevel 	show_header("IPv6-DstOpts:  ", "IPv6 Destination Options Header", 0);
   1080      0     stevel 	show_space();
   1081      0     stevel 
   1082      0     stevel 	/*
   1083      0     stevel 	 * Store the length of this ext hdr in bytes.  The caller has
   1084      0     stevel 	 * ensured that there is at least len bytes of data left.
   1085      0     stevel 	 */
   1086      0     stevel 	len = ipv6ext_dest->ip6d_len * 8 + 8;
   1087      0     stevel 
   1088   1676        jpk 	ndata = (const uint8_t *)ipv6ext_dest + 2; /* skip hdr/len */
   1089      0     stevel 	len -= 2;
   1090      0     stevel 
   1091      0     stevel 	nxt_hdr = ipv6ext_dest->ip6d_nxt;
   1092   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
   1093      0     stevel 	    "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr));
   1094      0     stevel 
   1095      0     stevel 	while (len > 0) {
   1096   1676        jpk 		data = ndata;
   1097      0     stevel 		GETINT8(op_type, data);
   1098   1676        jpk 		if (op_type == IP6OPT_PAD1) {
   1099   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1100      0     stevel 			    "pad1 option ");
   1101      0     stevel 			len--;
   1102   1676        jpk 			ndata = data;
   1103   1676        jpk 			continue;
   1104   1676        jpk 		}
   1105   1676        jpk 		GETINT8(op_len, data);
   1106   1676        jpk 		if (len < 2 || op_len + 2 > len) {
   1107   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1108   1676        jpk 			    "Error: option %u truncated (%u + 2 > %u)",
   1109   1676        jpk 			    op_type, op_len, len);
   1110   1676        jpk 			op_len = len - 2;
   1111   1676        jpk 			/*
   1112   1676        jpk 			 * Continue processing the malformed option so that we
   1113   1676        jpk 			 * can display as much as possible.
   1114   1676        jpk 			 */
   1115   1676        jpk 		}
   1116   1676        jpk 
   1117   1676        jpk 		/* advance pointers to the next option */
   1118   1676        jpk 		len -= op_len + 2;
   1119   1676        jpk 		ndata = data + op_len;
   1120   1676        jpk 
   1121   1676        jpk 		/* process this option */
   1122   1676        jpk 		switch (op_type) {
   1123      0     stevel 		case IP6OPT_PADN:
   1124   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1125      0     stevel 			    "padN option len = %u", op_len);
   1126      0     stevel 			break;
   1127      0     stevel 		case IP6OPT_TUNNEL_LIMIT:
   1128      0     stevel 			GETINT8(value, data);
   1129   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1130      0     stevel 			    "tunnel encapsulation limit len = %d, value = %d",
   1131      0     stevel 			    op_len, value);
   1132   1676        jpk 			break;
   1133   1676        jpk 		case IP6OPT_LS:
   1134   1676        jpk 			print_ip6opt_ls(data, op_len);
   1135      0     stevel 			break;
   1136      0     stevel 		default:
   1137   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1138      0     stevel 			    "Option type = %u, len = %u", op_type, op_len);
   1139      0     stevel 			break;
   1140      0     stevel 		}
   1141      0     stevel 	}
   1142      0     stevel 
   1143      0     stevel 	show_space();
   1144      0     stevel }
   1145   1676        jpk 
   1146   1676        jpk #define	ALABEL_MAXLEN	256
   1147   1676        jpk 
   1148   1676        jpk static char ascii_label[ALABEL_MAXLEN];
   1149   1676        jpk static char *plabel = ascii_label;
   1150   1676        jpk 
   1151   1676        jpk struct snoop_pair {
   1152   1676        jpk 	int val;
   1153   1676        jpk 	const char *name;
   1154   1676        jpk };
   1155   1676        jpk 
   1156   1676        jpk static struct snoop_pair ripso_class_tbl[] = {
   1157   1676        jpk 	TSOL_CL_TOP_SECRET,	"TOP SECRET",
   1158   1676        jpk 	TSOL_CL_SECRET,		"SECRET",
   1159   1676        jpk 	TSOL_CL_CONFIDENTIAL,	"CONFIDENTIAL",
   1160   1676        jpk 	TSOL_CL_UNCLASSIFIED,	"UNCLASSIFIED",
   1161   1676        jpk 	-1,			NULL
   1162   1676        jpk };
   1163   1676        jpk 
   1164   1676        jpk static struct snoop_pair ripso_prot_tbl[] = {
   1165   1676        jpk 	TSOL_PA_GENSER,		"GENSER",
   1166   1676        jpk 	TSOL_PA_SIOP_ESI,	"SIOP-ESI",
   1167   1676        jpk 	TSOL_PA_SCI,		"SCI",
   1168   1676        jpk 	TSOL_PA_NSA,		"NSA",
   1169   1676        jpk 	TSOL_PA_DOE,		"DOE",
   1170   1676        jpk 	0x04,			"UNASSIGNED",
   1171   1676        jpk 	0x02,			"UNASSIGNED",
   1172   1676        jpk 	-1,			NULL
   1173   1676        jpk };
   1174   1676        jpk 
   1175   1676        jpk static struct snoop_pair *
   1176   1676        jpk get_pair_byval(struct snoop_pair pairlist[], int val)
   1177   1676        jpk {
   1178   1676        jpk 	int i;
   1179   1676        jpk 
   1180   1676        jpk 	for (i = 0; pairlist[i].name != NULL; i++)
   1181   1676        jpk 		if (pairlist[i].val == val)
   1182   1676        jpk 			return (&pairlist[i]);
   1183   1676        jpk 	return (NULL);
   1184   1676        jpk }
   1185   1676        jpk 
   1186   1676        jpk static void
   1187   1676        jpk print_ripso(const uchar_t *opt)
   1188   1676        jpk {
   1189   1676        jpk 	struct snoop_pair *ripso_class;
   1190   1676        jpk 	int i, index, prot_len;
   1191   1676        jpk 	boolean_t first_prot;
   1192   1676        jpk 	char line[100], *ptr;
   1193   1676        jpk 
   1194   1676        jpk 	prot_len = opt[1] - 3;
   1195   1676        jpk 	if (prot_len < 0)
   1196   1676        jpk 		return;
   1197   1676        jpk 
   1198   1676        jpk 	show_header("RIPSO:  ", "Revised IP Security Option", 0);
   1199   1676        jpk 	show_space();
   1200   1676        jpk 
   1201   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
   1202   1676        jpk 	    "Type = Basic Security Option (%d), Length = %d", opt[0], opt[1]);
   1203   1676        jpk 
   1204   1676        jpk 	/*
   1205   1676        jpk 	 * Display Classification Level
   1206   1676        jpk 	 */
   1207   1676        jpk 	ripso_class = get_pair_byval(ripso_class_tbl, (int)opt[2]);
   1208   1676        jpk 	if (ripso_class != NULL)
   1209   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
   1210   1676        jpk 		    "Classification = Unknown (0x%02x)", opt[2]);
   1211   1676        jpk 	else
   1212   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
   1213   1676        jpk 		    "Classification = %s (0x%02x)",
   1214   1676        jpk 		    ripso_class->name, ripso_class->val);
   1215   1676        jpk 
   1216   1676        jpk 	/*
   1217   1676        jpk 	 * Display Protection Authority Flags
   1218   1676        jpk 	 */
   1219   1676        jpk 	(void) snprintf(line, sizeof (line), "Protection Authority = ");
   1220   1676        jpk 	ptr = line;
   1221   1676        jpk 	first_prot = B_TRUE;
   1222   1676        jpk 	for (i = 0; i < prot_len; i++) {
   1223   1676        jpk 		index = 0;
   1224   1676        jpk 		while (ripso_prot_tbl[index].name != NULL) {
   1225   1676        jpk 			if (opt[3 + i] & ripso_prot_tbl[index].val) {
   1226   1676        jpk 				ptr = strchr(ptr, 0);
   1227   1676        jpk 				if (!first_prot) {
   1228   1676        jpk 					(void) strlcpy(ptr, ", ",
   1229   1676        jpk 					    sizeof (line) - (ptr - line));
   1230   1676        jpk 					ptr = strchr(ptr, 0);
   1231   1676        jpk 				}
   1232   1676        jpk 				(void) snprintf(ptr,
   1233   1676        jpk 				    sizeof (line) - (ptr - line),
   1234   1676        jpk 				    "%s (0x%02x)",
   1235   1676        jpk 				    ripso_prot_tbl[index].name,
   1236   1676        jpk 				    ripso_prot_tbl[index].val);
   1237   1676        jpk 			}
   1238   1676        jpk 			index++;
   1239   1676        jpk 		}
   1240   1676        jpk 		if ((opt[3 + i] & 1) == 0)
   1241   1676        jpk 			break;
   1242   1676        jpk 	}
   1243   1676        jpk 	if (!first_prot)
   1244   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(), "%s", line);
   1245   1676        jpk 	else
   1246   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(), "%sNone",
   1247   1676        jpk 		    line);
   1248   1676        jpk }
   1249   1676        jpk 
   1250   1676        jpk #define	CIPSO_GENERIC_ARRAY_LEN	200
   1251   1676        jpk 
   1252   1676        jpk /*
   1253   1676        jpk  * Return 1 if CIPSO SL and Categories are all 1's; 0 otherwise.
   1254   1676        jpk  *
   1255   1676        jpk  * Note: opt starts with "Tag Type":
   1256   1676        jpk  *
   1257   1676        jpk  * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)|
   1258   1676        jpk  *
   1259   1676        jpk  */
   1260   1676        jpk static boolean_t
   1261   1676        jpk cipso_high(const uchar_t *opt)
   1262   1676        jpk {
   1263   1676        jpk 	int i;
   1264   1676        jpk 
   1265   1676        jpk 	if (((int)opt[1] + 6) < IP_MAX_OPT_LENGTH)
   1266   1676        jpk 		return (B_FALSE);
   1267   1676        jpk 	for (i = 0; i < ((int)opt[1] - 3); i++)
   1268   1676        jpk 		if (opt[3 + i] != 0xff)
   1269   1676        jpk 			return (B_FALSE);
   1270   1676        jpk 	return (B_TRUE);
   1271   1676        jpk }
   1272   1676        jpk 
   1273   1676        jpk /*
   1274   1676        jpk  * Converts CIPSO label to SL.
   1275   1676        jpk  *
   1276   1676        jpk  * Note: opt starts with "Tag Type":
   1277   1676        jpk  *
   1278   1676        jpk  * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)|
   1279   1676        jpk  *
   1280   1676        jpk  */
   1281   1676        jpk static void
   1282   1676        jpk cipso2sl(const uchar_t *opt, bslabel_t *sl, int *high)
   1283   1676        jpk {
   1284   1676        jpk 	int i, taglen;
   1285   1676        jpk 	uchar_t *q = (uchar_t *)&((_bslabel_impl_t *)sl)->compartments;
   1286   1676        jpk 
   1287   1676        jpk 	*high = 0;
   1288   1676        jpk 	taglen = opt[1];
   1289   1676        jpk 	memset((caddr_t)sl, 0, sizeof (bslabel_t));
   1290   1676        jpk 
   1291   1676        jpk 	if (cipso_high(opt)) {
   1292   1676        jpk 		BSLHIGH(sl);
   1293   1676        jpk 		*high = 1;
   1294   1676        jpk 	} else {
   1295   1676        jpk 		LCLASS_SET((_bslabel_impl_t *)sl, opt[3]);
   1296   1676        jpk 		for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++)
   1297   1676        jpk 			q[i] = opt[TSOL_TT1_MIN_LENGTH + i];
   1298   1676        jpk 	}
   1299   1676        jpk 	SETBLTYPE(sl, SUN_SL_ID);
   1300   1676        jpk }
   1301   1676        jpk 
   1302   1676        jpk static int
   1303   1676        jpk interpret_cipso_tagtype1(const uchar_t *opt)
   1304   1676        jpk {
   1305   1676        jpk 	int i, taglen, ishigh;
   1306   1676        jpk 	bslabel_t sl;
   1307   1676        jpk 	char line[CIPSO_GENERIC_ARRAY_LEN], *ptr;
   1308   1676        jpk 
   1309   1676        jpk 	taglen = opt[1];
   1310   1676        jpk 	if (taglen < TSOL_TT1_MIN_LENGTH ||
   1311   1676        jpk 	    taglen > TSOL_TT1_MAX_LENGTH)
   1312   1676        jpk 		return (taglen);
   1313   1676        jpk 
   1314   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
   1315   1676        jpk 	    "Tag Type = %d, Tag Length = %d", opt[0], opt[1]);
   1316   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
   1317   1676        jpk 	    "Sensitivity Level = 0x%02x", opt[3]);
   1318   1676        jpk 	ptr = line;
   1319   1676        jpk 	for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++) {
   1320   1676        jpk 		(void) snprintf(ptr, sizeof (line) - (ptr - line), "%02x",
   1321   1676        jpk 		    opt[TSOL_TT1_MIN_LENGTH + i]);
   1322   1676        jpk 		ptr = strchr(ptr, 0);
   1323   1676        jpk 	}
   1324   1676        jpk 	if (i != 0) {
   1325   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
   1326   1676        jpk 		    "Categories = ");
   1327   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(), "\t%s",
   1328   1676        jpk 		    line);
   1329   1676        jpk 	} else {
   1330   1676        jpk 		(void) snprintf(get_line(0, 0), get_line_remain(),
   1331   1676        jpk 		    "Categories = None");
   1332   1676        jpk 	}
   1333   1676        jpk 	cipso2sl(opt, &sl, &ishigh);
   1334   1688       rica 	if (is_system_labeled()) {
   1335   1676        jpk 		if (bsltos(&sl, &plabel, ALABEL_MAXLEN,
   1336   1676        jpk 		    LONG_CLASSIFICATION|LONG_WORDS|VIEW_INTERNAL) < 0) {
   1337   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1338   1676        jpk 			    "The Sensitivity Level and Categories can't be "
   1339   1676        jpk 			    "mapped to a valid SL");
   1340   1676        jpk 		} else {
   1341   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1342   1676        jpk 			    "The Sensitivity Level and Categories are mapped "
   1343   1676        jpk 			    "to the SL:");
   1344   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1345   1676        jpk 			    "\t%s", ascii_label);
   1346   1676        jpk 		}
   1347   1676        jpk 	}
   1348   1676        jpk 	return (taglen);
   1349   1676        jpk }
   1350   1676        jpk 
   1351   1676        jpk /*
   1352   1676        jpk  * The following struct definition #define's are copied from TS1.x. They are
   1353   1676        jpk  * not used here (except TTYPE_3_MAX_TOKENS), but included as a reference for
   1354   1676        jpk  * the tag type 3 packet format.
   1355   1676        jpk  */
   1356   1676        jpk #define	TTYPE_3_MAX_TOKENS	7
   1357   1676        jpk 
   1358   1676        jpk /*
   1359   1676        jpk  * Display CIPSO tag type 3 which is defined by MAXSIX.
   1360   1676        jpk  */
   1361   1676        jpk static int
   1362   1676        jpk interpret_cipso_tagtype3(const uchar_t *opt)
   1363   1676        jpk {
   1364   1676        jpk 	uchar_t tagtype;
   1365   1676        jpk 	int index, numtokens, taglen;
   1366   1676        jpk 	uint16_t mask;
   1367   1676        jpk 	uint32_t token;
   1368   1676        jpk 	static const char *name[] = {
   1369   1676        jpk 		"SL",
   1370   1676        jpk 		"NCAV",
   1371   1676        jpk 		"INTEG",
   1372   1676        jpk 		"SID",
   1373   1676        jpk 		"undefined",
   1374   1676        jpk 		"undefined",
   1375   1676        jpk 		"IL",
   1376   1676        jpk 		"PRIVS",
   1377   1676        jpk 		"LUID",
   1378   1676        jpk 		"PID",
   1379   1676        jpk 		"IDS",
   1380   1676        jpk 		"ACL"
   1381   1676        jpk 	};
   1382   1676        jpk 
   1383   1676        jpk 	tagtype = *opt++;
   1384   1676        jpk 	(void) memcpy(&mask, opt + 3, sizeof (mask));
   1385   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
   1386   1676        jpk 	    "Tag Type = %d (MAXSIX)", tagtype);
   1387   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
   1388   1676        jpk 	    "Generation = 0x%02x%02x%02x, Mask = 0x%04x", opt[0], opt[1],
   1389   1676        jpk 	    opt[2], mask);
   1390   1676        jpk 	opt += 3 + sizeof (mask);
   1391   1676        jpk 
   1392   1676        jpk 	/*
   1393   1676        jpk 	 * Display tokens
   1394   1676        jpk 	 */
   1395   1676        jpk 	numtokens = 0;
   1396   1676        jpk 	index = 0;
   1397   1676        jpk 	while (mask != 0 && numtokens < TTYPE_3_MAX_TOKENS) {
   1398   1676        jpk 		if (mask & 0x0001) {
   1399   1676        jpk 			(void) memcpy(&token, opt, sizeof (token));
   1400   1676        jpk 			opt += sizeof (token);
   1401   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1402   1676        jpk 			    "Attribute = %s, Token = 0x%08x",
   1403   1676        jpk 			    index < sizeof (name) / sizeof (*name) ?
   1404   1676        jpk 			    name[index] : "unknown", token);
   1405   1676        jpk 			numtokens++;
   1406   1676        jpk 		}
   1407   1676        jpk 		mask = mask >> 1;
   1408   1676        jpk 		index++;
   1409   1676        jpk 	}
   1410   1676        jpk 
   1411   1676        jpk 	taglen = 6 + numtokens * 4;
   1412   1676        jpk 	return (taglen);
   1413   1676        jpk }
   1414   1676        jpk 
   1415   1676        jpk static void
   1416   1676        jpk print_cipso(const uchar_t *opt)
   1417   1676        jpk {
   1418   1676        jpk 	int optlen, taglen, tagnum;
   1419   1676        jpk 	uint32_t doi;
   1420   1676        jpk 	char line[CIPSO_GENERIC_ARRAY_LEN];
   1421   1676        jpk 	char *oldnest;
   1422   1676        jpk 
   1423   1676        jpk 	optlen = opt[1];
   1424   1676        jpk 	if (optlen < TSOL_CIPSO_MIN_LENGTH || optlen > TSOL_CIPSO_MAX_LENGTH)
   1425   1676        jpk 		return;
   1426   1676        jpk 
   1427   1676        jpk 	oldnest = prot_nest_prefix;
   1428   1676        jpk 	prot_nest_prefix = prot_prefix;
   1429   1676        jpk 	show_header("CIPSO:  ", "Common IP Security Option", 0);
   1430   1676        jpk 	show_space();
   1431   1676        jpk 
   1432   1676        jpk 	/*
   1433   1676        jpk 	 * Display CIPSO Header
   1434   1676        jpk 	 */
   1435   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
   1436   1676        jpk 	    "Type = CIPSO (%d), Length = %d", opt[0], opt[1]);
   1437   1676        jpk 	(void) memcpy(&doi, opt + 2, sizeof (doi));
   1438   1676        jpk 	(void) snprintf(get_line(0, 0), get_line_remain(),
   1439   1676        jpk 	    "Domain of Interpretation = %u", (unsigned)ntohl(doi));
   1440   1676        jpk 
   1441   1676        jpk 	if (opt[1] == TSOL_CIPSO_MIN_LENGTH) {	/* no tags */
   1442   1676        jpk 		show_space();
   1443   1676        jpk 		prot_prefix = prot_nest_prefix;
   1444   1676        jpk 		prot_nest_prefix = oldnest;
   1445   1676        jpk 		return;
   1446   1676        jpk 	}
   1447   1676        jpk 	optlen -= TSOL_CIPSO_MIN_LENGTH;
   1448   1676        jpk 	opt += TSOL_CIPSO_MIN_LENGTH;
   1449   1676        jpk 
   1450   1676        jpk 	/*
   1451   1676        jpk 	 * Display Each Tag
   1452   1676        jpk 	 */
   1453   1676        jpk 	tagnum = 1;
   1454   1676        jpk 	while (optlen >= TSOL_TT1_MIN_LENGTH) {
   1455   1676        jpk 		(void) snprintf(line, sizeof (line), "Tag# %d", tagnum);
   1456   1676        jpk 		show_header("CIPSO:  ", line, 0);
   1457   1676        jpk 		/*
   1458   1676        jpk 		 * We handle tag type 1 and 3 only. Note, tag type 3
   1459   1676        jpk 		 * is MAXSIX defined.
   1460   1676        jpk 		 */
   1461   1676        jpk 		switch (opt[0]) {
   1462   1676        jpk 		case 1:
   1463   1676        jpk 			taglen = interpret_cipso_tagtype1(opt);
   1464   1676        jpk 			break;
   1465   1676        jpk 		case 3:
   1466   1676        jpk 			taglen = interpret_cipso_tagtype3(opt);
   1467   1676        jpk 			break;
   1468   1676        jpk 		default:
   1469   1676        jpk 			(void) snprintf(get_line(0, 0), get_line_remain(),
   1470   1676        jpk 			    "Unknown Tag Type %d", opt[0]);
   1471   1676        jpk 			show_space();
   1472   1676        jpk 			prot_prefix = prot_nest_prefix;
   1473   1676        jpk 			prot_nest_prefix = oldnest;
   1474   1676        jpk 			return;
   1475   1676        jpk 		}
   1476   1676        jpk 
   1477   1676        jpk 		/*
   1478   1676        jpk 		 * Move to the next tag
   1479   1676        jpk 		 */
   1480   1676        jpk 		if (taglen <= 0)
   1481   1676        jpk 			break;
   1482   1676        jpk 		optlen -= taglen;
   1483   1676        jpk 		opt += taglen;
   1484   1676        jpk 		tagnum++;
   1485   1676        jpk 	}
   1486   1676        jpk 	show_space();
   1487   1676        jpk 	prot_prefix = prot_nest_prefix;
   1488   1676        jpk 	prot_nest_prefix = oldnest;
   1489   1676        jpk }
   1490