1*a2f04351SSebastien Roy /*
2*a2f04351SSebastien Roy  * CDDL HEADER START
3*a2f04351SSebastien Roy  *
4*a2f04351SSebastien Roy  * This file and its contents are supplied under the terms of the
5*a2f04351SSebastien Roy  * Common Development and Distribution License ("CDDL"), version 1.0.
6*a2f04351SSebastien Roy  * You may only use this file in accordance with the terms of version
7*a2f04351SSebastien Roy  * 1.0 of the CDDL.
8*a2f04351SSebastien Roy  *
9*a2f04351SSebastien Roy  * A full copy of the text of the CDDL should have accompanied this
10*a2f04351SSebastien Roy  * source.  A copy of the CDDL is also available via the Internet at
11*a2f04351SSebastien Roy  * http://www.illumos.org/license/CDDL.
12*a2f04351SSebastien Roy  *
13*a2f04351SSebastien Roy  * CDDL HEADER END
14*a2f04351SSebastien Roy  */
15*a2f04351SSebastien Roy /*
16*a2f04351SSebastien Roy  * Copyright (c) 2015, 2016 by Delphix. All rights reserved.
17*a2f04351SSebastien Roy  */
18*a2f04351SSebastien Roy 
19*a2f04351SSebastien Roy #include <stdio.h>
20*a2f04351SSebastien Roy #include <string.h>
21*a2f04351SSebastien Roy #include <stdlib.h>
22*a2f04351SSebastien Roy #include <inet/mib2.h>
23*a2f04351SSebastien Roy #include <sys/debug.h>
24*a2f04351SSebastien Roy #include <sys/stropts.h>
25*a2f04351SSebastien Roy #include <sys/types.h>
26*a2f04351SSebastien Roy #include <sys/socket.h>
27*a2f04351SSebastien Roy #include <netinet/in.h>
28*a2f04351SSebastien Roy #include <inet/tcp.h>
29*a2f04351SSebastien Roy #include <arpa/inet.h>
30*a2f04351SSebastien Roy #include <ofmt.h>
31*a2f04351SSebastien Roy #include <sys/time.h>
32*a2f04351SSebastien Roy #include "connstat_mib.h"
33*a2f04351SSebastien Roy #include "connstat_tcp.h"
34*a2f04351SSebastien Roy 
35*a2f04351SSebastien Roy /*
36*a2f04351SSebastien Roy  * The byte order of some of the fields in this code can be a bit confusing.
37*a2f04351SSebastien Roy  * When using sockaddr_in(6) structs, the address and ports are always in
38*a2f04351SSebastien Roy  * Network Byte Order (Big Endian), as required by sockaddr(3SOCKET).
39*a2f04351SSebastien Roy  *
40*a2f04351SSebastien Roy  * When using the structs mib2_tcpConnEntry_t and mib2_tcp6ConnEntry_t, the
41*a2f04351SSebastien Roy  * address fields (tcp(6)ConnLocalAddress and tcp(6)ConnRemAdddress) are in
42*a2f04351SSebastien Roy  * Network Byte Order. Note, however, that the port fields ARE NOT, but are
43*a2f04351SSebastien Roy  * instead in Host Byte Order. This isn't a problem though, since the ports
44*a2f04351SSebastien Roy  * we filter on from the command-line (ca_lport and ca_rport) are kept in
45*a2f04351SSebastien Roy  * Host Byte Order after parsing.
46*a2f04351SSebastien Roy  *
47*a2f04351SSebastien Roy  * Since the t_lport and t_rport fields come from the MIB structs, they are
48*a2f04351SSebastien Roy  * likewise stored in Host Byte Order (and need to be for printing). The
49*a2f04351SSebastien Roy  * t_laddr and t_raddr fields are string representations of the addresses,
50*a2f04351SSebastien Roy  * so they don't require any special attention.
51*a2f04351SSebastien Roy  *
52*a2f04351SSebastien Roy  * All of the statistics (such as bytes read and written, current window
53*a2f04351SSebastien Roy  * sizes, etc.) are in Host Byte Order.
54*a2f04351SSebastien Roy  */
55*a2f04351SSebastien Roy 
56*a2f04351SSebastien Roy typedef struct tcp_fields_buf_s {
57*a2f04351SSebastien Roy 	char t_laddr[INET6_ADDRSTRLEN];
58*a2f04351SSebastien Roy 	char t_raddr[INET6_ADDRSTRLEN];
59*a2f04351SSebastien Roy 	uint16_t t_lport;
60*a2f04351SSebastien Roy 	uint16_t t_rport;
61*a2f04351SSebastien Roy 	uint64_t t_inbytes;
62*a2f04351SSebastien Roy 	uint64_t t_insegs;
63*a2f04351SSebastien Roy 	uint64_t t_inunorderbytes;
64*a2f04351SSebastien Roy 	uint64_t t_inunordersegs;
65*a2f04351SSebastien Roy 	uint64_t t_outbytes;
66*a2f04351SSebastien Roy 	uint64_t t_outsegs;
67*a2f04351SSebastien Roy 	uint64_t t_retransbytes;
68*a2f04351SSebastien Roy 	uint64_t t_retranssegs;
69*a2f04351SSebastien Roy 	uint32_t t_suna;
70*a2f04351SSebastien Roy 	uint32_t t_unsent;
71*a2f04351SSebastien Roy 	uint32_t t_swnd;
72*a2f04351SSebastien Roy 	uint32_t t_cwnd;
73*a2f04351SSebastien Roy 	uint32_t t_rwnd;
74*a2f04351SSebastien Roy 	uint32_t t_mss;
75*a2f04351SSebastien Roy 	uint32_t t_rto;
76*a2f04351SSebastien Roy 	uint32_t t_rtt_cnt;
77*a2f04351SSebastien Roy 	uint64_t t_rtt_sum;
78*a2f04351SSebastien Roy 	int t_state;
79*a2f04351SSebastien Roy 	uint64_t t_rtt;
80*a2f04351SSebastien Roy } tcp_fields_buf_t;
81*a2f04351SSebastien Roy 
82*a2f04351SSebastien Roy static boolean_t print_tcp_state(ofmt_arg_t *, char *, uint_t);
83*a2f04351SSebastien Roy 
84*a2f04351SSebastien Roy static ofmt_field_t tcp_fields[] = {
85*a2f04351SSebastien Roy 	{ "LADDR",	26,
86*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_laddr),	print_string },
87*a2f04351SSebastien Roy 	{ "RADDR",	26,
88*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_raddr),	print_string },
89*a2f04351SSebastien Roy 	{ "LPORT",	6,
90*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_lport),	print_uint16 },
91*a2f04351SSebastien Roy 	{ "RPORT",	6,
92*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_rport),	print_uint16 },
93*a2f04351SSebastien Roy 	{ "INBYTES",	11,
94*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_inbytes),	print_uint64 },
95*a2f04351SSebastien Roy 	{ "INSEGS",	11,
96*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_insegs),	print_uint64 },
97*a2f04351SSebastien Roy 	{ "INUNORDERBYTES",	15,
98*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_inunorderbytes),	print_uint64 },
99*a2f04351SSebastien Roy 	{ "INUNORDERSEGS",	14,
100*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_inunordersegs),	print_uint64 },
101*a2f04351SSebastien Roy 	{ "OUTBYTES",	11,
102*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_outbytes),	print_uint64 },
103*a2f04351SSebastien Roy 	{ "OUTSEGS",	11,
104*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_outsegs),	print_uint64 },
105*a2f04351SSebastien Roy 	{ "RETRANSBYTES",	13,
106*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_retransbytes),	print_uint64 },
107*a2f04351SSebastien Roy 	{ "RETRANSSEGS",	12,
108*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_retranssegs),	print_uint64 },
109*a2f04351SSebastien Roy 	{ "SUNA",	11,
110*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_suna),	print_uint32 },
111*a2f04351SSebastien Roy 	{ "UNSENT",	11,
112*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_unsent),	print_uint32 },
113*a2f04351SSebastien Roy 	{ "SWND",	11,
114*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_swnd),	print_uint32 },
115*a2f04351SSebastien Roy 	{ "CWND",	11,
116*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_cwnd),	print_uint32 },
117*a2f04351SSebastien Roy 	{ "RWND",	11,
118*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_rwnd),	print_uint32 },
119*a2f04351SSebastien Roy 	{ "MSS",	6,
120*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_mss),	print_uint32 },
121*a2f04351SSebastien Roy 	{ "RTO",	8,
122*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_rto),	print_uint32 },
123*a2f04351SSebastien Roy 	{ "RTT",	8,
124*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_rtt),	print_uint64 },
125*a2f04351SSebastien Roy 	{ "RTTS",	8,
126*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_rtt_sum),	print_uint64 },
127*a2f04351SSebastien Roy 	{ "RTTC",	11,
128*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_rtt_cnt),	print_uint32 },
129*a2f04351SSebastien Roy 	{ "STATE",	12,
130*a2f04351SSebastien Roy 		offsetof(tcp_fields_buf_t, t_state),	print_tcp_state },
131*a2f04351SSebastien Roy 	{ NULL, 0, 0, NULL}
132*a2f04351SSebastien Roy };
133*a2f04351SSebastien Roy 
134*a2f04351SSebastien Roy static tcp_fields_buf_t fields_buf;
135*a2f04351SSebastien Roy 
136*a2f04351SSebastien Roy 
137*a2f04351SSebastien Roy typedef struct tcp_state_info_s {
138*a2f04351SSebastien Roy 	int tsi_state;
139*a2f04351SSebastien Roy 	const char *tsi_string;
140*a2f04351SSebastien Roy } tcp_state_info_t;
141*a2f04351SSebastien Roy 
142*a2f04351SSebastien Roy tcp_state_info_t tcp_state_info[] = {
143*a2f04351SSebastien Roy 	{ TCPS_CLOSED, "CLOSED" },
144*a2f04351SSebastien Roy 	{ TCPS_IDLE, "IDLE" },
145*a2f04351SSebastien Roy 	{ TCPS_BOUND, "BOUND" },
146*a2f04351SSebastien Roy 	{ TCPS_LISTEN, "LISTEN" },
147*a2f04351SSebastien Roy 	{ TCPS_SYN_SENT, "SYN_SENT" },
148*a2f04351SSebastien Roy 	{ TCPS_SYN_RCVD, "SYN_RCVD" },
149*a2f04351SSebastien Roy 	{ TCPS_ESTABLISHED, "ESTABLISHED" },
150*a2f04351SSebastien Roy 	{ TCPS_CLOSE_WAIT, "CLOSE_WAIT" },
151*a2f04351SSebastien Roy 	{ TCPS_FIN_WAIT_1, "FIN_WAIT_1" },
152*a2f04351SSebastien Roy 	{ TCPS_CLOSING, "CLOSING" },
153*a2f04351SSebastien Roy 	{ TCPS_LAST_ACK, "LAST_ACK" },
154*a2f04351SSebastien Roy 	{ TCPS_FIN_WAIT_2, "FIN_WAIT_2" },
155*a2f04351SSebastien Roy 	{ TCPS_TIME_WAIT, "TIME_WAIT" },
156*a2f04351SSebastien Roy 	{ TCPS_CLOSED - 1, NULL }
157*a2f04351SSebastien Roy };
158*a2f04351SSebastien Roy 
159*a2f04351SSebastien Roy ofmt_field_t *
tcp_get_fields(void)160*a2f04351SSebastien Roy tcp_get_fields(void)
161*a2f04351SSebastien Roy {
162*a2f04351SSebastien Roy 	return (tcp_fields);
163*a2f04351SSebastien Roy }
164*a2f04351SSebastien Roy 
165*a2f04351SSebastien Roy /*
166*a2f04351SSebastien Roy  * Extract information from the connection info structure into the global
167*a2f04351SSebastien Roy  * output buffer.
168*a2f04351SSebastien Roy  */
169*a2f04351SSebastien Roy static void
tcp_ci2buf(struct tcpConnEntryInfo_s * ci)170*a2f04351SSebastien Roy tcp_ci2buf(struct tcpConnEntryInfo_s *ci)
171*a2f04351SSebastien Roy {
172*a2f04351SSebastien Roy 	fields_buf.t_inbytes =
173*a2f04351SSebastien Roy 	    ci->ce_in_data_inorder_bytes + ci->ce_in_data_unorder_bytes;
174*a2f04351SSebastien Roy 	fields_buf.t_insegs =
175*a2f04351SSebastien Roy 	    ci->ce_in_data_inorder_segs + ci->ce_in_data_unorder_segs;
176*a2f04351SSebastien Roy 	fields_buf.t_inunorderbytes = ci->ce_in_data_unorder_bytes;
177*a2f04351SSebastien Roy 	fields_buf.t_inunordersegs = ci->ce_in_data_unorder_segs;
178*a2f04351SSebastien Roy 	fields_buf.t_outbytes = ci->ce_out_data_bytes;
179*a2f04351SSebastien Roy 	fields_buf.t_outsegs = ci->ce_out_data_segs;
180*a2f04351SSebastien Roy 	fields_buf.t_retransbytes = ci->ce_out_retrans_bytes;
181*a2f04351SSebastien Roy 	fields_buf.t_retranssegs = ci->ce_out_retrans_segs;
182*a2f04351SSebastien Roy 	fields_buf.t_suna = ci->ce_snxt - ci->ce_suna;
183*a2f04351SSebastien Roy 	fields_buf.t_unsent = ci->ce_unsent;
184*a2f04351SSebastien Roy 	fields_buf.t_swnd = ci->ce_swnd;
185*a2f04351SSebastien Roy 	fields_buf.t_cwnd = ci->ce_cwnd;
186*a2f04351SSebastien Roy 	fields_buf.t_rwnd = ci->ce_rwnd;
187*a2f04351SSebastien Roy 	fields_buf.t_mss = ci->ce_mss;
188*a2f04351SSebastien Roy 	fields_buf.t_rto = ci->ce_rto;
189*a2f04351SSebastien Roy 	fields_buf.t_rtt = (ci->ce_out_data_segs == 0 ? 0 : ci->ce_rtt_sa);
190*a2f04351SSebastien Roy 	fields_buf.t_rtt_sum = ci->ce_rtt_sum;
191*a2f04351SSebastien Roy 	fields_buf.t_rtt_cnt = ci->ce_rtt_cnt;
192*a2f04351SSebastien Roy 	fields_buf.t_state = ci->ce_state;
193*a2f04351SSebastien Roy }
194*a2f04351SSebastien Roy 
195*a2f04351SSebastien Roy /*
196*a2f04351SSebastien Roy  * Extract information from the connection entry into the global output
197*a2f04351SSebastien Roy  * buffer.
198*a2f04351SSebastien Roy  */
199*a2f04351SSebastien Roy static void
tcp_ipv4_ce2buf(mib2_tcpConnEntry_t * ce)200*a2f04351SSebastien Roy tcp_ipv4_ce2buf(mib2_tcpConnEntry_t *ce)
201*a2f04351SSebastien Roy {
202*a2f04351SSebastien Roy 	VERIFY3P(inet_ntop(AF_INET, (void *)&ce->tcpConnLocalAddress,
203*a2f04351SSebastien Roy 	    fields_buf.t_laddr, sizeof (fields_buf.t_laddr)), !=, NULL);
204*a2f04351SSebastien Roy 	VERIFY3P(inet_ntop(AF_INET, (void *)&ce->tcpConnRemAddress,
205*a2f04351SSebastien Roy 	    fields_buf.t_raddr, sizeof (fields_buf.t_raddr)), !=, NULL);
206*a2f04351SSebastien Roy 
207*a2f04351SSebastien Roy 	fields_buf.t_lport = ce->tcpConnLocalPort;
208*a2f04351SSebastien Roy 	fields_buf.t_rport = ce->tcpConnRemPort;
209*a2f04351SSebastien Roy 
210*a2f04351SSebastien Roy 	tcp_ci2buf(&ce->tcpConnEntryInfo);
211*a2f04351SSebastien Roy }
212*a2f04351SSebastien Roy 
213*a2f04351SSebastien Roy static void
tcp_ipv6_ce2buf(mib2_tcp6ConnEntry_t * ce)214*a2f04351SSebastien Roy tcp_ipv6_ce2buf(mib2_tcp6ConnEntry_t *ce)
215*a2f04351SSebastien Roy {
216*a2f04351SSebastien Roy 	VERIFY3P(inet_ntop(AF_INET6, (void *)&ce->tcp6ConnLocalAddress,
217*a2f04351SSebastien Roy 	    fields_buf.t_laddr, sizeof (fields_buf.t_laddr)), !=, NULL);
218*a2f04351SSebastien Roy 	VERIFY3P(inet_ntop(AF_INET6, (void *)&ce->tcp6ConnRemAddress,
219*a2f04351SSebastien Roy 	    fields_buf.t_raddr, sizeof (fields_buf.t_raddr)), !=, NULL);
220*a2f04351SSebastien Roy 
221*a2f04351SSebastien Roy 	fields_buf.t_lport = ce->tcp6ConnLocalPort;
222*a2f04351SSebastien Roy 	fields_buf.t_rport = ce->tcp6ConnRemPort;
223*a2f04351SSebastien Roy 
224*a2f04351SSebastien Roy 	tcp_ci2buf(&ce->tcp6ConnEntryInfo);
225*a2f04351SSebastien Roy }
226*a2f04351SSebastien Roy 
227*a2f04351SSebastien Roy /*
228*a2f04351SSebastien Roy  * Print a single IPv4 connection entry, taking into account possible
229*a2f04351SSebastien Roy  * filters that have been set in state.
230*a2f04351SSebastien Roy  */
231*a2f04351SSebastien Roy static void
tcp_ipv4_print(mib2_tcpConnEntry_t * ce,conn_walk_state_t * state)232*a2f04351SSebastien Roy tcp_ipv4_print(mib2_tcpConnEntry_t *ce, conn_walk_state_t *state)
233*a2f04351SSebastien Roy {
234*a2f04351SSebastien Roy 	if (!(state->cws_flags & CS_LOOPBACK) &&
235*a2f04351SSebastien Roy 	    ntohl(ce->tcpConnLocalAddress) == INADDR_LOOPBACK) {
236*a2f04351SSebastien Roy 		return;
237*a2f04351SSebastien Roy 	}
238*a2f04351SSebastien Roy 
239*a2f04351SSebastien Roy 	if (state->cws_flags & CS_LADDR) {
240*a2f04351SSebastien Roy 		struct sockaddr_in *sin =
241*a2f04351SSebastien Roy 		    (struct sockaddr_in *)&state->cws_filter.ca_laddr;
242*a2f04351SSebastien Roy 		if (ce->tcpConnLocalAddress != sin->sin_addr.s_addr) {
243*a2f04351SSebastien Roy 			return;
244*a2f04351SSebastien Roy 		}
245*a2f04351SSebastien Roy 	}
246*a2f04351SSebastien Roy 	if (state->cws_flags & CS_RADDR) {
247*a2f04351SSebastien Roy 		struct sockaddr_in *sin =
248*a2f04351SSebastien Roy 		    (struct sockaddr_in *)&state->cws_filter.ca_raddr;
249*a2f04351SSebastien Roy 		if (ce->tcpConnRemAddress != sin->sin_addr.s_addr) {
250*a2f04351SSebastien Roy 			return;
251*a2f04351SSebastien Roy 		}
252*a2f04351SSebastien Roy 	}
253*a2f04351SSebastien Roy 	if (state->cws_flags & CS_LPORT) {
254*a2f04351SSebastien Roy 		if (ce->tcpConnLocalPort != state->cws_filter.ca_lport) {
255*a2f04351SSebastien Roy 			return;
256*a2f04351SSebastien Roy 		}
257*a2f04351SSebastien Roy 	}
258*a2f04351SSebastien Roy 	if (state->cws_flags & CS_RPORT) {
259*a2f04351SSebastien Roy 		if (ce->tcpConnRemPort != state->cws_filter.ca_rport) {
260*a2f04351SSebastien Roy 			return;
261*a2f04351SSebastien Roy 		}
262*a2f04351SSebastien Roy 	}
263*a2f04351SSebastien Roy 
264*a2f04351SSebastien Roy 	if ((state->cws_flags & CS_STATE) &&
265*a2f04351SSebastien Roy 	    ce->tcpConnEntryInfo.ce_state != state->cws_filter.ca_state) {
266*a2f04351SSebastien Roy 		return;
267*a2f04351SSebastien Roy 	}
268*a2f04351SSebastien Roy 
269*a2f04351SSebastien Roy 	tcp_ipv4_ce2buf(ce);
270*a2f04351SSebastien Roy 	ofmt_print(state->cws_ofmt, &fields_buf);
271*a2f04351SSebastien Roy }
272*a2f04351SSebastien Roy 
273*a2f04351SSebastien Roy /*
274*a2f04351SSebastien Roy  * Print a single IPv6 connection entry, taking into account possible
275*a2f04351SSebastien Roy  * filters that have been set in state.
276*a2f04351SSebastien Roy  */
277*a2f04351SSebastien Roy static void
tcp_ipv6_print(mib2_tcp6ConnEntry_t * ce,conn_walk_state_t * state)278*a2f04351SSebastien Roy tcp_ipv6_print(mib2_tcp6ConnEntry_t *ce, conn_walk_state_t *state)
279*a2f04351SSebastien Roy {
280*a2f04351SSebastien Roy 	if (!(state->cws_flags & CS_LOOPBACK) &&
281*a2f04351SSebastien Roy 	    IN6_IS_ADDR_LOOPBACK(
282*a2f04351SSebastien Roy 	    (struct in6_addr *)&ce->tcp6ConnLocalAddress)) {
283*a2f04351SSebastien Roy 		return;
284*a2f04351SSebastien Roy 	}
285*a2f04351SSebastien Roy 
286*a2f04351SSebastien Roy 	if (state->cws_flags & CS_LADDR) {
287*a2f04351SSebastien Roy 		struct sockaddr_in6 *sin6 =
288*a2f04351SSebastien Roy 		    (struct sockaddr_in6 *)&state->cws_filter.ca_laddr;
289*a2f04351SSebastien Roy 		if (!IN6_ARE_ADDR_EQUAL(
290*a2f04351SSebastien Roy 		    (struct in6_addr *)&ce->tcp6ConnLocalAddress,
291*a2f04351SSebastien Roy 		    &sin6->sin6_addr)) {
292*a2f04351SSebastien Roy 			return;
293*a2f04351SSebastien Roy 		}
294*a2f04351SSebastien Roy 	}
295*a2f04351SSebastien Roy 	if (state->cws_flags & CS_RADDR) {
296*a2f04351SSebastien Roy 		struct sockaddr_in6 *sin6 =
297*a2f04351SSebastien Roy 		    (struct sockaddr_in6 *)&state->cws_filter.ca_raddr;
298*a2f04351SSebastien Roy 		if (!IN6_ARE_ADDR_EQUAL(
299*a2f04351SSebastien Roy 		    (struct in6_addr *)&ce->tcp6ConnRemAddress,
300*a2f04351SSebastien Roy 		    &sin6->sin6_addr)) {
301*a2f04351SSebastien Roy 			return;
302*a2f04351SSebastien Roy 		}
303*a2f04351SSebastien Roy 	}
304*a2f04351SSebastien Roy 	if (state->cws_flags & CS_LPORT) {
305*a2f04351SSebastien Roy 		if (ce->tcp6ConnLocalPort != state->cws_filter.ca_lport) {
306*a2f04351SSebastien Roy 			return;
307*a2f04351SSebastien Roy 		}
308*a2f04351SSebastien Roy 	}
309*a2f04351SSebastien Roy 	if (state->cws_flags & CS_RPORT) {
310*a2f04351SSebastien Roy 		if (ce->tcp6ConnRemPort != state->cws_filter.ca_rport) {
311*a2f04351SSebastien Roy 			return;
312*a2f04351SSebastien Roy 		}
313*a2f04351SSebastien Roy 	}
314*a2f04351SSebastien Roy 
315*a2f04351SSebastien Roy 	if ((state->cws_flags & CS_STATE) &&
316*a2f04351SSebastien Roy 	    ce->tcp6ConnEntryInfo.ce_state != state->cws_filter.ca_state) {
317*a2f04351SSebastien Roy 		return;
318*a2f04351SSebastien Roy 	}
319*a2f04351SSebastien Roy 
320*a2f04351SSebastien Roy 	tcp_ipv6_ce2buf(ce);
321*a2f04351SSebastien Roy 	ofmt_print(state->cws_ofmt, &fields_buf);
322*a2f04351SSebastien Roy }
323*a2f04351SSebastien Roy 
324*a2f04351SSebastien Roy void
tcp_walk_ipv4(struct strbuf * dbuf,conn_walk_state_t * state)325*a2f04351SSebastien Roy tcp_walk_ipv4(struct strbuf *dbuf, conn_walk_state_t *state)
326*a2f04351SSebastien Roy {
327*a2f04351SSebastien Roy 	uint_t nconns = (dbuf->len / sizeof (mib2_tcpConnEntry_t));
328*a2f04351SSebastien Roy 	/* LINTED E_BAD_PTR_CAST_ALIGN */
329*a2f04351SSebastien Roy 	mib2_tcpConnEntry_t *ce = (mib2_tcpConnEntry_t *)dbuf->buf;
330*a2f04351SSebastien Roy 
331*a2f04351SSebastien Roy 	for (; nconns > 0; ce++, nconns--) {
332*a2f04351SSebastien Roy 		tcp_ipv4_print(ce, state);
333*a2f04351SSebastien Roy 	}
334*a2f04351SSebastien Roy }
335*a2f04351SSebastien Roy 
336*a2f04351SSebastien Roy void
tcp_walk_ipv6(struct strbuf * dbuf,conn_walk_state_t * state)337*a2f04351SSebastien Roy tcp_walk_ipv6(struct strbuf *dbuf, conn_walk_state_t *state)
338*a2f04351SSebastien Roy {
339*a2f04351SSebastien Roy 	uint_t nconns = (dbuf->len / sizeof (mib2_tcp6ConnEntry_t));
340*a2f04351SSebastien Roy 	/* LINTED E_BAD_PTR_CAST_ALIGN */
341*a2f04351SSebastien Roy 	mib2_tcp6ConnEntry_t *ce = (mib2_tcp6ConnEntry_t *)dbuf->buf;
342*a2f04351SSebastien Roy 
343*a2f04351SSebastien Roy 	for (; nconns > 0; ce++, nconns--) {
344*a2f04351SSebastien Roy 		tcp_ipv6_print(ce, state);
345*a2f04351SSebastien Roy 	}
346*a2f04351SSebastien Roy }
347*a2f04351SSebastien Roy 
348*a2f04351SSebastien Roy static tcp_state_info_t *
tcp_stateinfobystate(int state)349*a2f04351SSebastien Roy tcp_stateinfobystate(int state)
350*a2f04351SSebastien Roy {
351*a2f04351SSebastien Roy 	tcp_state_info_t *sip;
352*a2f04351SSebastien Roy 
353*a2f04351SSebastien Roy 	for (sip = tcp_state_info; sip->tsi_string != NULL; sip++) {
354*a2f04351SSebastien Roy 		if (sip->tsi_state == state) {
355*a2f04351SSebastien Roy 			return (sip);
356*a2f04351SSebastien Roy 		}
357*a2f04351SSebastien Roy 	}
358*a2f04351SSebastien Roy 	return (NULL);
359*a2f04351SSebastien Roy }
360*a2f04351SSebastien Roy 
361*a2f04351SSebastien Roy static tcp_state_info_t *
tcp_stateinfobystr(const char * statestr)362*a2f04351SSebastien Roy tcp_stateinfobystr(const char *statestr)
363*a2f04351SSebastien Roy {
364*a2f04351SSebastien Roy 	tcp_state_info_t *sip;
365*a2f04351SSebastien Roy 
366*a2f04351SSebastien Roy 	for (sip = tcp_state_info; sip->tsi_string != NULL; sip++) {
367*a2f04351SSebastien Roy 		if (strncasecmp(statestr, sip->tsi_string,
368*a2f04351SSebastien Roy 		    strlen(sip->tsi_string)) == 0) {
369*a2f04351SSebastien Roy 			return (sip);
370*a2f04351SSebastien Roy 		}
371*a2f04351SSebastien Roy 	}
372*a2f04351SSebastien Roy 	return (NULL);
373*a2f04351SSebastien Roy }
374*a2f04351SSebastien Roy 
375*a2f04351SSebastien Roy int
tcp_str2state(const char * statestr)376*a2f04351SSebastien Roy tcp_str2state(const char *statestr)
377*a2f04351SSebastien Roy {
378*a2f04351SSebastien Roy 	tcp_state_info_t *sip = tcp_stateinfobystr(statestr);
379*a2f04351SSebastien Roy 	return (sip == NULL ? TCPS_CLOSED - 1 : sip->tsi_state);
380*a2f04351SSebastien Roy }
381*a2f04351SSebastien Roy 
382*a2f04351SSebastien Roy static const char *
tcp_state2str(int state)383*a2f04351SSebastien Roy tcp_state2str(int state)
384*a2f04351SSebastien Roy {
385*a2f04351SSebastien Roy 	tcp_state_info_t *sip = tcp_stateinfobystate(state);
386*a2f04351SSebastien Roy 	return (sip == NULL ? NULL : sip->tsi_string);
387*a2f04351SSebastien Roy }
388*a2f04351SSebastien Roy 
389*a2f04351SSebastien Roy static boolean_t
print_tcp_state(ofmt_arg_t * ofarg,char * buf,uint_t bufsize)390*a2f04351SSebastien Roy print_tcp_state(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
391*a2f04351SSebastien Roy {
392*a2f04351SSebastien Roy 	/* LINTED E_BAD_PTR_CAST_ALIGN */
393*a2f04351SSebastien Roy 	int state = *(int *)((char *)ofarg->ofmt_cbarg + ofarg->ofmt_id);
394*a2f04351SSebastien Roy 	const char *statestr = tcp_state2str(state);
395*a2f04351SSebastien Roy 
396*a2f04351SSebastien Roy 	if (statestr != NULL) {
397*a2f04351SSebastien Roy 		(void) strlcpy(buf, statestr, bufsize);
398*a2f04351SSebastien Roy 	} else {
399*a2f04351SSebastien Roy 		(void) snprintf(buf, bufsize, "UNKNOWN(%d)", state);
400*a2f04351SSebastien Roy 	}
401*a2f04351SSebastien Roy 
402*a2f04351SSebastien Roy 	return (B_TRUE);
403*a2f04351SSebastien Roy }
404