17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*2e3b6467Skcpoon * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <stdio.h> 317c478bd9Sstevel@tonic-gate #include <string.h> 327c478bd9Sstevel@tonic-gate #include <fcntl.h> 337c478bd9Sstevel@tonic-gate #include <string.h> 347c478bd9Sstevel@tonic-gate #include <sys/types.h> 357c478bd9Sstevel@tonic-gate #include <sys/time.h> 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include <sys/socket.h> 387c478bd9Sstevel@tonic-gate #include <net/if.h> 397c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 407c478bd9Sstevel@tonic-gate #include <netinet/in.h> 417c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 427c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h> 437c478bd9Sstevel@tonic-gate #include <netinet/tcp.h> 447c478bd9Sstevel@tonic-gate #include "snoop.h" 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate extern char *dlc_header; 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #define TCPOPT_HEADER_LEN 2 497c478bd9Sstevel@tonic-gate #define TCPOPT_TSTAMP_LEN 10 507c478bd9Sstevel@tonic-gate #define TCPOPT_SACK_LEN 8 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate /* 537c478bd9Sstevel@tonic-gate * Convert a network byte order 32 bit integer to a host order integer. 547c478bd9Sstevel@tonic-gate * ntohl() cannot be used because option values may not be aligned properly. 557c478bd9Sstevel@tonic-gate */ 567c478bd9Sstevel@tonic-gate #define GET_UINT32(opt) (((uint_t)*((uchar_t *)(opt) + 0) << 24) | \ 577c478bd9Sstevel@tonic-gate ((uint_t)*((uchar_t *)(opt) + 1) << 16) | \ 587c478bd9Sstevel@tonic-gate ((uint_t)*((uchar_t *)(opt) + 2) << 8) | \ 597c478bd9Sstevel@tonic-gate ((uint_t)*((uchar_t *)(opt) + 3))) 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate static void print_tcpoptions_summary(uchar_t *, int, char *); 627c478bd9Sstevel@tonic-gate static void print_tcpoptions(uchar_t *, int); 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate static const struct { 657c478bd9Sstevel@tonic-gate unsigned int tf_flag; 667c478bd9Sstevel@tonic-gate const char *tf_name; 677c478bd9Sstevel@tonic-gate } tcp_flags[] = { 687c478bd9Sstevel@tonic-gate { TH_SYN, "Syn" }, 697c478bd9Sstevel@tonic-gate { TH_FIN, "Fin" }, 707c478bd9Sstevel@tonic-gate { TH_RST, "Rst" }, 717c478bd9Sstevel@tonic-gate { TH_PUSH, "Push" }, 727c478bd9Sstevel@tonic-gate { TH_ECE, "ECE" }, 737c478bd9Sstevel@tonic-gate { TH_CWR, "CWR" }, 747c478bd9Sstevel@tonic-gate { 0, NULL } 757c478bd9Sstevel@tonic-gate }; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate int 787c478bd9Sstevel@tonic-gate interpret_tcp(int flags, struct tcphdr *tcp, int iplen, int fraglen) 797c478bd9Sstevel@tonic-gate { 807c478bd9Sstevel@tonic-gate char *data; 817c478bd9Sstevel@tonic-gate int hdrlen, tcplen; 827c478bd9Sstevel@tonic-gate int sunrpc = 0; 837c478bd9Sstevel@tonic-gate char *pname; 847c478bd9Sstevel@tonic-gate char buff[32]; 857c478bd9Sstevel@tonic-gate char *line, *endline; 867c478bd9Sstevel@tonic-gate unsigned int i; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate hdrlen = tcp->th_off * 4; 897c478bd9Sstevel@tonic-gate data = (char *)tcp + hdrlen; 907c478bd9Sstevel@tonic-gate tcplen = iplen - hdrlen; 917c478bd9Sstevel@tonic-gate fraglen -= hdrlen; 927c478bd9Sstevel@tonic-gate if (fraglen < 0) 93*2e3b6467Skcpoon return (fraglen + hdrlen); /* incomplete header */ 947c478bd9Sstevel@tonic-gate if (fraglen > tcplen) 957c478bd9Sstevel@tonic-gate fraglen = tcplen; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate if (flags & F_SUM) { 987c478bd9Sstevel@tonic-gate line = get_sum_line(); 997c478bd9Sstevel@tonic-gate endline = line + MAXLINE; 1007c478bd9Sstevel@tonic-gate (void) snprintf(line, endline - line, "TCP D=%d S=%d", 1017c478bd9Sstevel@tonic-gate ntohs(tcp->th_dport), ntohs(tcp->th_sport)); 1027c478bd9Sstevel@tonic-gate line += strlen(line); 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate for (i = 0; tcp_flags[i].tf_name != NULL; i++) { 1057c478bd9Sstevel@tonic-gate if (tcp->th_flags & tcp_flags[i].tf_flag) { 1067c478bd9Sstevel@tonic-gate (void) snprintf(line, endline - line, " %s", 1077c478bd9Sstevel@tonic-gate tcp_flags[i].tf_name); 1087c478bd9Sstevel@tonic-gate line += strlen(line); 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_URG) { 1137c478bd9Sstevel@tonic-gate (void) snprintf(line, endline - line, " Urg=%u", 1147c478bd9Sstevel@tonic-gate ntohs(tcp->th_urp)); 1157c478bd9Sstevel@tonic-gate line += strlen(line); 1167c478bd9Sstevel@tonic-gate } 1177c478bd9Sstevel@tonic-gate if (tcp->th_flags & TH_ACK) { 1187c478bd9Sstevel@tonic-gate (void) snprintf(line, endline - line, " Ack=%u", 1197c478bd9Sstevel@tonic-gate ntohl(tcp->th_ack)); 1207c478bd9Sstevel@tonic-gate line += strlen(line); 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate if (ntohl(tcp->th_seq)) { 1237c478bd9Sstevel@tonic-gate (void) snprintf(line, endline - line, " Seq=%u Len=%d", 1247c478bd9Sstevel@tonic-gate ntohl(tcp->th_seq), tcplen); 1257c478bd9Sstevel@tonic-gate line += strlen(line); 1267c478bd9Sstevel@tonic-gate } 1277c478bd9Sstevel@tonic-gate (void) snprintf(line, endline - line, " Win=%d", 1287c478bd9Sstevel@tonic-gate ntohs(tcp->th_win)); 1297c478bd9Sstevel@tonic-gate print_tcpoptions_summary((uchar_t *)(tcp + 1), 1307c478bd9Sstevel@tonic-gate (int)(tcp->th_off * 4 - sizeof (struct tcphdr)), line); 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate sunrpc = !reservedport(IPPROTO_TCP, ntohs(tcp->th_dport)) && 1347c478bd9Sstevel@tonic-gate !reservedport(IPPROTO_TCP, ntohs(tcp->th_sport)) && 1357c478bd9Sstevel@tonic-gate valid_rpc(data + 4, fraglen - 4); 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate if (flags & F_DTAIL) { 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate show_header("TCP: ", "TCP Header", tcplen); 1407c478bd9Sstevel@tonic-gate show_space(); 141*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)tcp->th_sport - 142*2e3b6467Skcpoon dlc_header, 2), "Source port = %d", ntohs(tcp->th_sport)); 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate if (sunrpc) { 1457c478bd9Sstevel@tonic-gate pname = "(Sun RPC)"; 1467c478bd9Sstevel@tonic-gate } else { 1477c478bd9Sstevel@tonic-gate pname = getportname(IPPROTO_TCP, ntohs(tcp->th_dport)); 1487c478bd9Sstevel@tonic-gate if (pname == NULL) { 1497c478bd9Sstevel@tonic-gate pname = ""; 1507c478bd9Sstevel@tonic-gate } else { 1517c478bd9Sstevel@tonic-gate (void) sprintf(buff, "(%s)", pname); 1527c478bd9Sstevel@tonic-gate pname = buff; 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate } 155*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)tcp->th_dport - 156*2e3b6467Skcpoon dlc_header, 2), "Destination port = %d %s", 1577c478bd9Sstevel@tonic-gate ntohs(tcp->th_dport), pname); 158*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)tcp->th_seq - 159*2e3b6467Skcpoon dlc_header, 4), "Sequence number = %u", 1607c478bd9Sstevel@tonic-gate ntohl(tcp->th_seq)); 161*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)tcp->th_ack - dlc_header, 4), 1627c478bd9Sstevel@tonic-gate "Acknowledgement number = %u", 1637c478bd9Sstevel@tonic-gate ntohl(tcp->th_ack)); 164*2e3b6467Skcpoon (void) sprintf(get_line(((char *)(uintptr_t)tcp->th_ack - dlc_header) + 165*2e3b6467Skcpoon 4, 1), "Data offset = %d bytes", tcp->th_off * 4); 166*2e3b6467Skcpoon (void) sprintf(get_line(((char *)(uintptr_t)tcp->th_flags - 167*2e3b6467Skcpoon dlc_header) + 4, 1), "Flags = 0x%02x", tcp->th_flags); 168*2e3b6467Skcpoon (void) sprintf(get_line(((char *)(uintptr_t)tcp->th_flags - 169*2e3b6467Skcpoon dlc_header) + 4, 1), " %s", getflag(tcp->th_flags, TH_CWR, 1707c478bd9Sstevel@tonic-gate "ECN congestion window reduced", 1717c478bd9Sstevel@tonic-gate "No ECN congestion window reduced")); 172*2e3b6467Skcpoon (void) sprintf(get_line(((char *)(uintptr_t)tcp->th_flags - 173*2e3b6467Skcpoon dlc_header) + 4, 1), " %s", getflag(tcp->th_flags, TH_ECE, 1747c478bd9Sstevel@tonic-gate "ECN echo", "No ECN echo")); 175*2e3b6467Skcpoon (void) sprintf(get_line(((char *)(uintptr_t)tcp->th_flags - 176*2e3b6467Skcpoon dlc_header) + 4, 1), " %s", 1777c478bd9Sstevel@tonic-gate getflag(tcp->th_flags, TH_URG, 1787c478bd9Sstevel@tonic-gate "Urgent pointer", "No urgent pointer")); 179*2e3b6467Skcpoon (void) sprintf(get_line(((char *)(uintptr_t)tcp->th_flags - 180*2e3b6467Skcpoon dlc_header) + 4, 1), " %s", getflag(tcp->th_flags, TH_ACK, 1817c478bd9Sstevel@tonic-gate "Acknowledgement", "No acknowledgement")); 182*2e3b6467Skcpoon (void) sprintf(get_line(((char *)(uintptr_t)tcp->th_flags - 183*2e3b6467Skcpoon dlc_header) + 4, 1), " %s", getflag(tcp->th_flags, TH_PUSH, 1847c478bd9Sstevel@tonic-gate "Push", "No push")); 185*2e3b6467Skcpoon (void) sprintf(get_line(((char *)(uintptr_t)tcp->th_flags - 186*2e3b6467Skcpoon dlc_header) + 4, 1), " %s", getflag(tcp->th_flags, TH_RST, 1877c478bd9Sstevel@tonic-gate "Reset", "No reset")); 188*2e3b6467Skcpoon (void) sprintf(get_line(((char *)(uintptr_t)tcp->th_flags - 189*2e3b6467Skcpoon dlc_header) + 4, 1), " %s", getflag(tcp->th_flags, TH_SYN, 1907c478bd9Sstevel@tonic-gate "Syn", "No Syn")); 191*2e3b6467Skcpoon (void) sprintf(get_line(((char *)(uintptr_t)tcp->th_flags - 192*2e3b6467Skcpoon dlc_header) + 4, 1), " %s", getflag(tcp->th_flags, TH_FIN, 1937c478bd9Sstevel@tonic-gate "Fin", "No Fin")); 194*2e3b6467Skcpoon (void) sprintf(get_line(((char *)(uintptr_t)tcp->th_win - dlc_header) + 195*2e3b6467Skcpoon 4, 1), "Window = %d", ntohs(tcp->th_win)); 1967c478bd9Sstevel@tonic-gate /* XXX need to compute checksum and print whether correct */ 197*2e3b6467Skcpoon (void) sprintf(get_line(((char *)(uintptr_t)tcp->th_sum - dlc_header) + 198*2e3b6467Skcpoon 4, 1), "Checksum = 0x%04x", ntohs(tcp->th_sum)); 199*2e3b6467Skcpoon (void) sprintf(get_line(((char *)(uintptr_t)tcp->th_urp - dlc_header) + 200*2e3b6467Skcpoon 4, 1), "Urgent pointer = %d", ntohs(tcp->th_urp)); 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate /* Print TCP options - if any */ 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate print_tcpoptions((uchar_t *)(tcp + 1), 2057c478bd9Sstevel@tonic-gate tcp->th_off * 4 - sizeof (struct tcphdr)); 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate show_space(); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate /* go to the next protocol layer */ 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate if (!interpret_reserved(flags, IPPROTO_TCP, 2137c478bd9Sstevel@tonic-gate ntohs(tcp->th_sport), 2147c478bd9Sstevel@tonic-gate ntohs(tcp->th_dport), 2157c478bd9Sstevel@tonic-gate data, fraglen)) { 2167c478bd9Sstevel@tonic-gate if (sunrpc && fraglen > 0) 2177c478bd9Sstevel@tonic-gate interpret_rpc(flags, data, fraglen, IPPROTO_TCP); 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate return (tcplen); 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate static void 2247c478bd9Sstevel@tonic-gate print_tcpoptions(opt, optlen) 2257c478bd9Sstevel@tonic-gate uchar_t *opt; 2267c478bd9Sstevel@tonic-gate int optlen; 2277c478bd9Sstevel@tonic-gate { 2287c478bd9Sstevel@tonic-gate int len; 2297c478bd9Sstevel@tonic-gate char *line; 2307c478bd9Sstevel@tonic-gate uchar_t *sack_opt; 2317c478bd9Sstevel@tonic-gate uchar_t *end_opt; 2327c478bd9Sstevel@tonic-gate int sack_len; 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate if (optlen <= 0) { 2357c478bd9Sstevel@tonic-gate (void) sprintf(get_line((char *)&opt - dlc_header, 1), 2367c478bd9Sstevel@tonic-gate "No options"); 2377c478bd9Sstevel@tonic-gate return; 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate (void) sprintf(get_line((char *)&opt - dlc_header, 1), 2417c478bd9Sstevel@tonic-gate "Options: (%d bytes)", optlen); 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate while (optlen > 0) { 2447c478bd9Sstevel@tonic-gate line = get_line((char *)&opt - dlc_header, 1); 2457c478bd9Sstevel@tonic-gate len = opt[1]; 2467c478bd9Sstevel@tonic-gate switch (opt[0]) { 2477c478bd9Sstevel@tonic-gate case TCPOPT_EOL: 2487c478bd9Sstevel@tonic-gate (void) strcpy(line, " - End of option list"); 2497c478bd9Sstevel@tonic-gate return; 2507c478bd9Sstevel@tonic-gate case TCPOPT_NOP: 2517c478bd9Sstevel@tonic-gate (void) strcpy(line, " - No operation"); 2527c478bd9Sstevel@tonic-gate len = 1; 2537c478bd9Sstevel@tonic-gate break; 2547c478bd9Sstevel@tonic-gate case TCPOPT_MAXSEG: 2557c478bd9Sstevel@tonic-gate (void) sprintf(line, 2567c478bd9Sstevel@tonic-gate " - Maximum segment size = %d bytes", 2577c478bd9Sstevel@tonic-gate (opt[2] << 8) + opt[3]); 2587c478bd9Sstevel@tonic-gate break; 2597c478bd9Sstevel@tonic-gate case TCPOPT_WSCALE: 2607c478bd9Sstevel@tonic-gate (void) sprintf(line, " - Window scale = %d", opt[2]); 2617c478bd9Sstevel@tonic-gate break; 2627c478bd9Sstevel@tonic-gate case TCPOPT_TSTAMP: 2637c478bd9Sstevel@tonic-gate /* Sanity check. */ 2647c478bd9Sstevel@tonic-gate if (optlen < TCPOPT_TSTAMP_LEN) { 2657c478bd9Sstevel@tonic-gate (void) sprintf(line, 2667c478bd9Sstevel@tonic-gate " - Incomplete TS option"); 2677c478bd9Sstevel@tonic-gate } else { 2687c478bd9Sstevel@tonic-gate (void) sprintf(line, 2697c478bd9Sstevel@tonic-gate " - TS Val = %u, TS Echo = %u", 2707c478bd9Sstevel@tonic-gate GET_UINT32(opt + 2), 2717c478bd9Sstevel@tonic-gate GET_UINT32(opt + 6)); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate break; 2747c478bd9Sstevel@tonic-gate case TCPOPT_SACK_PERMITTED: 2757c478bd9Sstevel@tonic-gate (void) sprintf(line, " - SACK permitted option"); 2767c478bd9Sstevel@tonic-gate break; 2777c478bd9Sstevel@tonic-gate case TCPOPT_SACK: 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * Sanity check. Total length should be greater 2807c478bd9Sstevel@tonic-gate * than just the option header length. 2817c478bd9Sstevel@tonic-gate */ 2827c478bd9Sstevel@tonic-gate if (len <= TCPOPT_HEADER_LEN || 2837c478bd9Sstevel@tonic-gate opt[1] <= TCPOPT_HEADER_LEN || len < opt[1]) { 2847c478bd9Sstevel@tonic-gate (void) sprintf(line, 2857c478bd9Sstevel@tonic-gate " - Incomplete SACK option"); 2867c478bd9Sstevel@tonic-gate break; 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate sack_len = opt[1] - TCPOPT_HEADER_LEN; 2897c478bd9Sstevel@tonic-gate sack_opt = opt + TCPOPT_HEADER_LEN; 2907c478bd9Sstevel@tonic-gate end_opt = opt + optlen; 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate (void) sprintf(line, " - SACK blocks:"); 2937c478bd9Sstevel@tonic-gate line = get_line((char *)&opt - dlc_header, 1); 2947c478bd9Sstevel@tonic-gate (void) sprintf(line, " "); 2957c478bd9Sstevel@tonic-gate while (sack_len > 0) { 2967c478bd9Sstevel@tonic-gate char sack_blk[MAXLINE + 1]; 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate /* 2997c478bd9Sstevel@tonic-gate * sack_len may not tell us the truth about 3007c478bd9Sstevel@tonic-gate * the real length... Need to be careful 3017c478bd9Sstevel@tonic-gate * not to step beyond the option buffer. 3027c478bd9Sstevel@tonic-gate */ 3037c478bd9Sstevel@tonic-gate if (sack_opt + TCPOPT_SACK_LEN > end_opt) { 3047c478bd9Sstevel@tonic-gate (void) strcat(line, 3057c478bd9Sstevel@tonic-gate "...incomplete SACK block"); 3067c478bd9Sstevel@tonic-gate break; 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate (void) sprintf(sack_blk, "(%u-%u) ", 3097c478bd9Sstevel@tonic-gate GET_UINT32(sack_opt), 3107c478bd9Sstevel@tonic-gate GET_UINT32(sack_opt + 4)); 3117c478bd9Sstevel@tonic-gate (void) strcat(line, sack_blk); 3127c478bd9Sstevel@tonic-gate sack_opt += TCPOPT_SACK_LEN; 3137c478bd9Sstevel@tonic-gate sack_len -= TCPOPT_SACK_LEN; 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate break; 3167c478bd9Sstevel@tonic-gate default: 3177c478bd9Sstevel@tonic-gate (void) sprintf(line, 3187c478bd9Sstevel@tonic-gate " - Option %d (unknown - %d bytes) %s", 3197c478bd9Sstevel@tonic-gate opt[0], 3207c478bd9Sstevel@tonic-gate len - 2, 3217c478bd9Sstevel@tonic-gate tohex((char *)&opt[2], len - 2)); 3227c478bd9Sstevel@tonic-gate break; 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate if (len <= 0) { 3257c478bd9Sstevel@tonic-gate (void) sprintf(line, " - Incomplete option len %d", 3267c478bd9Sstevel@tonic-gate len); 3277c478bd9Sstevel@tonic-gate break; 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate opt += len; 3307c478bd9Sstevel@tonic-gate optlen -= len; 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate /* 3357c478bd9Sstevel@tonic-gate * This function is basically the same as print_tcpoptions() except that 3367c478bd9Sstevel@tonic-gate * all options are printed on the same line. 3377c478bd9Sstevel@tonic-gate */ 3387c478bd9Sstevel@tonic-gate static void 3397c478bd9Sstevel@tonic-gate print_tcpoptions_summary(uchar_t *opt, int optlen, char *line) 3407c478bd9Sstevel@tonic-gate { 3417c478bd9Sstevel@tonic-gate int len; 3427c478bd9Sstevel@tonic-gate uchar_t *sack_opt; 3437c478bd9Sstevel@tonic-gate uchar_t *end_opt; 3447c478bd9Sstevel@tonic-gate int sack_len; 3457c478bd9Sstevel@tonic-gate char options[MAXLINE + 1]; 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate if (optlen <= 0) { 3487c478bd9Sstevel@tonic-gate return; 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate (void) strcat(line, " Options=<"); 3527c478bd9Sstevel@tonic-gate while (optlen > 0) { 3537c478bd9Sstevel@tonic-gate len = opt[1]; 3547c478bd9Sstevel@tonic-gate switch (opt[0]) { 3557c478bd9Sstevel@tonic-gate case TCPOPT_EOL: 3567c478bd9Sstevel@tonic-gate (void) strcat(line, "eol>"); 3577c478bd9Sstevel@tonic-gate return; 3587c478bd9Sstevel@tonic-gate case TCPOPT_NOP: 3597c478bd9Sstevel@tonic-gate (void) strcat(line, "nop"); 3607c478bd9Sstevel@tonic-gate len = 1; 3617c478bd9Sstevel@tonic-gate break; 3627c478bd9Sstevel@tonic-gate case TCPOPT_MAXSEG: 3637c478bd9Sstevel@tonic-gate (void) sprintf(options, "mss %d", 3647c478bd9Sstevel@tonic-gate (opt[2] << 8) + opt[3]); 3657c478bd9Sstevel@tonic-gate (void) strcat(line, options); 3667c478bd9Sstevel@tonic-gate break; 3677c478bd9Sstevel@tonic-gate case TCPOPT_WSCALE: 3687c478bd9Sstevel@tonic-gate (void) sprintf(options, "wscale %d", opt[2]); 3697c478bd9Sstevel@tonic-gate (void) strcat(line, options); 3707c478bd9Sstevel@tonic-gate break; 3717c478bd9Sstevel@tonic-gate case TCPOPT_TSTAMP: 3727c478bd9Sstevel@tonic-gate /* Sanity check. */ 3737c478bd9Sstevel@tonic-gate if (optlen < TCPOPT_TSTAMP_LEN) { 3747c478bd9Sstevel@tonic-gate (void) strcat(line, "tstamp|"); 3757c478bd9Sstevel@tonic-gate } else { 3767c478bd9Sstevel@tonic-gate (void) sprintf(options, 3777c478bd9Sstevel@tonic-gate "tstamp %u %u", GET_UINT32(opt + 2), 3787c478bd9Sstevel@tonic-gate GET_UINT32(opt + 6)); 3797c478bd9Sstevel@tonic-gate (void) strcat(line, options); 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate break; 3827c478bd9Sstevel@tonic-gate case TCPOPT_SACK_PERMITTED: 3837c478bd9Sstevel@tonic-gate (void) strcat(line, "sackOK"); 3847c478bd9Sstevel@tonic-gate break; 3857c478bd9Sstevel@tonic-gate case TCPOPT_SACK: 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * Sanity check. Total length should be greater 3887c478bd9Sstevel@tonic-gate * than just the option header length. 3897c478bd9Sstevel@tonic-gate */ 3907c478bd9Sstevel@tonic-gate if (len <= TCPOPT_HEADER_LEN || 3917c478bd9Sstevel@tonic-gate opt[1] <= TCPOPT_HEADER_LEN || len < opt[1]) { 3927c478bd9Sstevel@tonic-gate (void) strcat(line, "sack|"); 3937c478bd9Sstevel@tonic-gate break; 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate sack_len = opt[1] - TCPOPT_HEADER_LEN; 3967c478bd9Sstevel@tonic-gate sack_opt = opt + TCPOPT_HEADER_LEN; 3977c478bd9Sstevel@tonic-gate end_opt = opt + optlen; 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate (void) strcat(line, "sack"); 4007c478bd9Sstevel@tonic-gate while (sack_len > 0) { 4017c478bd9Sstevel@tonic-gate /* 4027c478bd9Sstevel@tonic-gate * sack_len may not tell us the truth about 4037c478bd9Sstevel@tonic-gate * the real length... Need to be careful 4047c478bd9Sstevel@tonic-gate * not to step beyond the option buffer. 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate if (sack_opt + TCPOPT_SACK_LEN > end_opt) { 4077c478bd9Sstevel@tonic-gate (void) strcat(line, "|"); 4087c478bd9Sstevel@tonic-gate break; 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate (void) sprintf(options, " %u-%u", 4117c478bd9Sstevel@tonic-gate GET_UINT32(sack_opt), 4127c478bd9Sstevel@tonic-gate GET_UINT32(sack_opt + 4)); 4137c478bd9Sstevel@tonic-gate (void) strcat(line, options); 4147c478bd9Sstevel@tonic-gate sack_opt += TCPOPT_SACK_LEN; 4157c478bd9Sstevel@tonic-gate sack_len -= TCPOPT_SACK_LEN; 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate break; 4187c478bd9Sstevel@tonic-gate default: 4197c478bd9Sstevel@tonic-gate (void) sprintf(options, "unknown %d", opt[0]); 4207c478bd9Sstevel@tonic-gate (void) strcat(line, options); 4217c478bd9Sstevel@tonic-gate break; 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate if (len <= 0) { 4247c478bd9Sstevel@tonic-gate (void) sprintf(options, "optlen %d", len); 4257c478bd9Sstevel@tonic-gate (void) strcat(line, options); 4267c478bd9Sstevel@tonic-gate break; 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate opt += len; 4297c478bd9Sstevel@tonic-gate optlen -= len; 4307c478bd9Sstevel@tonic-gate if (optlen > 0) { 4317c478bd9Sstevel@tonic-gate (void) strcat(line, ","); 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate (void) strcat(line, ">"); 4357c478bd9Sstevel@tonic-gate } 436