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