4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 #pragma ident "%Z%%M% %I% %E% SMI"
34 #include <sys/types.h>
37 #include <sys/socket.h>
39 #include <netinet/in_systm.h>
40 #include <netinet/in.h>
41 #include <netinet/ip.h>
42 #include <netinet/if_ether.h>
43 #include <netinet/tcp.h>
46 extern char *dlc_header
;
48 #define TCPOPT_HEADER_LEN 2
49 #define TCPOPT_TSTAMP_LEN 10
50 #define TCPOPT_SACK_LEN 8
53 * Convert a network byte order 32 bit integer to a host order integer.
54 * ntohl() cannot be used because option values may not be aligned properly.
56 #define GET_UINT32(opt) (((uint_t)*((uchar_t *)(opt) + 0) << 24) | \
57 ((uint_t)*((uchar_t *)(opt) + 1) << 16) | \
58 ((uint_t)*((uchar_t *)(opt) + 2) << 8) | \
59 ((uint_t)*((uchar_t *)(opt) + 3)))
61 static void print_tcpoptions_summary(uchar_t
*, int, char *);
62 static void print_tcpoptions(uchar_t
*, int);
78 interpret_tcp(int flags
, struct tcphdr
*tcp
, int iplen
, int fraglen
)
88 hdrlen
= tcp
->th_off
* 4;
89 data
= (char *)tcp
+ hdrlen
;
90 tcplen
= iplen
- hdrlen
;
93 return (fraglen
+ hdrlen
); /* incomplete header */
98 line
= get_sum_line();
99 endline
= line
+ MAXLINE
;
100 (void) snprintf(line
, endline
- line
, "TCP D=%d S=%d",
101 ntohs(tcp
->th_dport
), ntohs(tcp
->th_sport
));
102 line
+= strlen(line
);
104 for (i
= 0; tcp_flags
[i
].tf_name
!= NULL
; i
++) {
105 if (tcp
->th_flags
& tcp_flags
[i
].tf_flag
) {
106 (void) snprintf(line
, endline
- line
, " %s",
107 tcp_flags
[i
].tf_name
);
108 line
+= strlen(line
);
112 if (tcp
->th_flags
& TH_URG
) {
113 (void) snprintf(line
, endline
- line
, " Urg=%u",
115 line
+= strlen(line
);
117 if (tcp
->th_flags
& TH_ACK
) {
118 (void) snprintf(line
, endline
- line
, " Ack=%u",
120 line
+= strlen(line
);
122 if (ntohl(tcp
->th_seq
)) {
123 (void) snprintf(line
, endline
- line
, " Seq=%u Len=%d",
124 ntohl(tcp
->th_seq
), tcplen
);
125 line
+= strlen(line
);
127 (void) snprintf(line
, endline
- line
, " Win=%d",
129 print_tcpoptions_summary((uchar_t
*)(tcp
+ 1),
130 (int)(tcp
->th_off
* 4 - sizeof (struct tcphdr
)), line
);
133 sunrpc
= !reservedport(IPPROTO_TCP
, ntohs(tcp
->th_dport
)) &&
134 !reservedport(IPPROTO_TCP
, ntohs(tcp
->th_sport
)) &&
135 valid_rpc(data
+ 4, fraglen
- 4);
137 if (flags
& F_DTAIL
) {
139 show_header("TCP: ", "TCP Header", tcplen
);
141 (void) sprintf(get_line((char *)(uintptr_t)tcp
->th_sport
-
142 dlc_header
, 2), "Source port = %d", ntohs(tcp
->th_sport
));
147 pname
= getportname(IPPROTO_TCP
, ntohs(tcp
->th_dport
));
151 (void) sprintf(buff
, "(%s)", pname
);
155 (void) sprintf(get_line((char *)(uintptr_t)tcp
->th_dport
-
156 dlc_header
, 2), "Destination port = %d %s",
157 ntohs(tcp
->th_dport
), pname
);
158 (void) sprintf(get_line((char *)(uintptr_t)tcp
->th_seq
-
159 dlc_header
, 4), "Sequence number = %u",
161 (void) sprintf(get_line((char *)(uintptr_t)tcp
->th_ack
- dlc_header
, 4),
162 "Acknowledgement number = %u",
164 (void) sprintf(get_line(((char *)(uintptr_t)tcp
->th_ack
- dlc_header
) +
165 4, 1), "Data offset = %d bytes", tcp
->th_off
* 4);
166 (void) sprintf(get_line(((char *)(uintptr_t)tcp
->th_flags
-
167 dlc_header
) + 4, 1), "Flags = 0x%02x", tcp
->th_flags
);
168 (void) sprintf(get_line(((char *)(uintptr_t)tcp
->th_flags
-
169 dlc_header
) + 4, 1), " %s", getflag(tcp
->th_flags
, TH_CWR
,
170 "ECN congestion window reduced",
171 "No ECN congestion window reduced"));
172 (void) sprintf(get_line(((char *)(uintptr_t)tcp
->th_flags
-
173 dlc_header
) + 4, 1), " %s", getflag(tcp
->th_flags
, TH_ECE
,
174 "ECN echo", "No ECN echo"));
175 (void) sprintf(get_line(((char *)(uintptr_t)tcp
->th_flags
-
176 dlc_header
) + 4, 1), " %s",
177 getflag(tcp
->th_flags
, TH_URG
,
178 "Urgent pointer", "No urgent pointer"));
179 (void) sprintf(get_line(((char *)(uintptr_t)tcp
->th_flags
-
180 dlc_header
) + 4, 1), " %s", getflag(tcp
->th_flags
, TH_ACK
,
181 "Acknowledgement", "No acknowledgement"));
182 (void) sprintf(get_line(((char *)(uintptr_t)tcp
->th_flags
-
183 dlc_header
) + 4, 1), " %s", getflag(tcp
->th_flags
, TH_PUSH
,
185 (void) sprintf(get_line(((char *)(uintptr_t)tcp
->th_flags
-
186 dlc_header
) + 4, 1), " %s", getflag(tcp
->th_flags
, TH_RST
,
187 "Reset", "No reset"));
188 (void) sprintf(get_line(((char *)(uintptr_t)tcp
->th_flags
-
189 dlc_header
) + 4, 1), " %s", getflag(tcp
->th_flags
, TH_SYN
,
191 (void) sprintf(get_line(((char *)(uintptr_t)tcp
->th_flags
-
192 dlc_header
) + 4, 1), " %s", getflag(tcp
->th_flags
, TH_FIN
,
194 (void) sprintf(get_line(((char *)(uintptr_t)tcp
->th_win
- dlc_header
) +
195 4, 1), "Window = %d", ntohs(tcp
->th_win
));
196 /* XXX need to compute checksum and print whether correct */
197 (void) sprintf(get_line(((char *)(uintptr_t)tcp
->th_sum
- dlc_header
) +
198 4, 1), "Checksum = 0x%04x", ntohs(tcp
->th_sum
));
199 (void) sprintf(get_line(((char *)(uintptr_t)tcp
->th_urp
- dlc_header
) +
200 4, 1), "Urgent pointer = %d", ntohs(tcp
->th_urp
));
202 /* Print TCP options - if any */
204 print_tcpoptions((uchar_t
*)(tcp
+ 1),
205 tcp
->th_off
* 4 - sizeof (struct tcphdr
));
210 /* go to the next protocol layer */
212 if (!interpret_reserved(flags
, IPPROTO_TCP
,
213 ntohs(tcp
->th_sport
),
214 ntohs(tcp
->th_dport
),
216 if (sunrpc
&& fraglen
> 0)
217 interpret_rpc(flags
, data
, fraglen
, IPPROTO_TCP
);
224 print_tcpoptions(opt
, optlen
)
235 (void) sprintf(get_line((char *)&opt
- dlc_header
, 1),
240 (void) sprintf(get_line((char *)&opt
- dlc_header
, 1),
241 "Options: (%d bytes)", optlen
);
244 line
= get_line((char *)&opt
- dlc_header
, 1);
248 (void) strcpy(line
, " - End of option list");
251 (void) strcpy(line
, " - No operation");
256 " - Maximum segment size = %d bytes",
257 (opt
[2] << 8) + opt
[3]);
260 (void) sprintf(line
, " - Window scale = %d", opt
[2]);
264 if (optlen
< TCPOPT_TSTAMP_LEN
) {
266 " - Incomplete TS option");
269 " - TS Val = %u, TS Echo = %u",
271 GET_UINT32(opt
+ 6));
274 case TCPOPT_SACK_PERMITTED
:
275 (void) sprintf(line
, " - SACK permitted option");
279 * Sanity check. Total length should be greater
280 * than just the option header length.
282 if (len
<= TCPOPT_HEADER_LEN
||
283 opt
[1] <= TCPOPT_HEADER_LEN
|| len
< opt
[1]) {
285 " - Incomplete SACK option");
288 sack_len
= opt
[1] - TCPOPT_HEADER_LEN
;
289 sack_opt
= opt
+ TCPOPT_HEADER_LEN
;
290 end_opt
= opt
+ optlen
;
292 (void) sprintf(line
, " - SACK blocks:");
293 line
= get_line((char *)&opt
- dlc_header
, 1);
294 (void) sprintf(line
, " ");
295 while (sack_len
> 0) {
296 char sack_blk
[MAXLINE
+ 1];
299 * sack_len may not tell us the truth about
300 * the real length... Need to be careful
301 * not to step beyond the option buffer.
303 if (sack_opt
+ TCPOPT_SACK_LEN
> end_opt
) {
305 "...incomplete SACK block");
308 (void) sprintf(sack_blk
, "(%u-%u) ",
309 GET_UINT32(sack_opt
),
310 GET_UINT32(sack_opt
+ 4));
311 (void) strcat(line
, sack_blk
);
312 sack_opt
+= TCPOPT_SACK_LEN
;
313 sack_len
-= TCPOPT_SACK_LEN
;
318 " - Option %d (unknown - %d bytes) %s",
321 tohex((char *)&opt
[2], len
- 2));
325 (void) sprintf(line
, " - Incomplete option len %d",
335 * This function is basically the same as print_tcpoptions() except that
336 * all options are printed on the same line.
339 print_tcpoptions_summary(uchar_t
*opt
, int optlen
, char *line
)
345 char options
[MAXLINE
+ 1];
351 (void) strcat(line
, " Options=<");
356 (void) strcat(line
, "eol>");
359 (void) strcat(line
, "nop");
363 (void) sprintf(options
, "mss %d",
364 (opt
[2] << 8) + opt
[3]);
365 (void) strcat(line
, options
);
368 (void) sprintf(options
, "wscale %d", opt
[2]);
369 (void) strcat(line
, options
);
373 if (optlen
< TCPOPT_TSTAMP_LEN
) {
374 (void) strcat(line
, "tstamp|");
376 (void) sprintf(options
,
377 "tstamp %u %u", GET_UINT32(opt
+ 2),
378 GET_UINT32(opt
+ 6));
379 (void) strcat(line
, options
);
382 case TCPOPT_SACK_PERMITTED
:
383 (void) strcat(line
, "sackOK");
387 * Sanity check. Total length should be greater
388 * than just the option header length.
390 if (len
<= TCPOPT_HEADER_LEN
||
391 opt
[1] <= TCPOPT_HEADER_LEN
|| len
< opt
[1]) {
392 (void) strcat(line
, "sack|");
395 sack_len
= opt
[1] - TCPOPT_HEADER_LEN
;
396 sack_opt
= opt
+ TCPOPT_HEADER_LEN
;
397 end_opt
= opt
+ optlen
;
399 (void) strcat(line
, "sack");
400 while (sack_len
> 0) {
402 * sack_len may not tell us the truth about
403 * the real length... Need to be careful
404 * not to step beyond the option buffer.
406 if (sack_opt
+ TCPOPT_SACK_LEN
> end_opt
) {
407 (void) strcat(line
, "|");
410 (void) sprintf(options
, " %u-%u",
411 GET_UINT32(sack_opt
),
412 GET_UINT32(sack_opt
+ 4));
413 (void) strcat(line
, options
);
414 sack_opt
+= TCPOPT_SACK_LEN
;
415 sack_len
-= TCPOPT_SACK_LEN
;
419 (void) sprintf(options
, "unknown %d", opt
[0]);
420 (void) strcat(line
, options
);
424 (void) sprintf(options
, "optlen %d", len
);
425 (void) strcat(line
, options
);
431 (void) strcat(line
, ",");
434 (void) strcat(line
, ">");