1122394Sharti/*
2122394Sharti * Copyright (c) 2001-2003
3122394Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4122394Sharti *	All rights reserved.
5122394Sharti *
6122394Sharti * Author: Harti Brandt <harti@freebsd.org>
7133211Sharti *
8133211Sharti * Redistribution and use in source and binary forms, with or without
9133211Sharti * modification, are permitted provided that the following conditions
10133211Sharti * are met:
11133211Sharti * 1. Redistributions of source code must retain the above copyright
12133211Sharti *    notice, this list of conditions and the following disclaimer.
13122394Sharti * 2. Redistributions in binary form must reproduce the above copyright
14122394Sharti *    notice, this list of conditions and the following disclaimer in the
15122394Sharti *    documentation and/or other materials provided with the distribution.
16133211Sharti *
17133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20133211Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27133211Sharti * SUCH DAMAGE.
28122394Sharti *
29146525Sharti * $Begemot: bsnmp/snmp_mibII/mibII_tcp.c,v 1.7 2005/05/23 09:03:42 brandt_h Exp $
30122394Sharti *
31122394Sharti * tcp
32122394Sharti */
33122394Sharti#include "mibII.h"
34122394Sharti#include "mibII_oid.h"
35122394Sharti#include <sys/socketvar.h>
36122394Sharti#include <netinet/in_pcb.h>
37122394Sharti#include <netinet/tcp.h>
38122394Sharti#include <netinet/tcp_var.h>
39122394Sharti#include <netinet/tcp_timer.h>
40122394Sharti#include <netinet/tcp_fsm.h>
41122394Sharti
42122394Shartistruct tcp_index {
43122394Sharti	struct asn_oid	index;
44122394Sharti	struct xtcpcb	*tp;
45122394Sharti};
46122394Sharti
47146525Shartistatic uint64_t tcp_tick;
48122394Shartistatic struct tcpstat tcpstat;
49122394Shartistatic struct xinpgen *xinpgen;
50122394Shartistatic size_t xinpgen_len;
51122394Shartistatic u_int tcp_count;
52122394Shartistatic u_int tcp_total;
53122394Sharti
54122394Shartistatic u_int oidnum;
55122394Shartistatic struct tcp_index *tcpoids;
56122394Sharti
57122394Shartistatic int
58122394Shartitcp_compare(const void *p1, const void *p2)
59122394Sharti{
60122394Sharti	const struct tcp_index *t1 = p1;
61122394Sharti	const struct tcp_index *t2 = p2;
62122394Sharti
63122394Sharti	return (asn_compare_oid(&t1->index, &t2->index));
64122394Sharti}
65122394Sharti
66122394Shartistatic int
67122394Shartifetch_tcp(void)
68122394Sharti{
69122394Sharti	size_t len;
70122394Sharti	struct xinpgen *ptr;
71122394Sharti	struct xtcpcb *tp;
72122394Sharti	struct tcp_index *oid;
73122394Sharti	in_addr_t inaddr;
74122394Sharti
75122394Sharti	len = sizeof(tcpstat);
76122394Sharti	if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, NULL, 0) == -1) {
77122394Sharti		syslog(LOG_ERR, "net.inet.tcp.stats: %m");
78122394Sharti		return (-1);
79122394Sharti	}
80122394Sharti	if (len != sizeof(tcpstat)) {
81122394Sharti		syslog(LOG_ERR, "net.inet.tcp.stats: wrong size");
82122394Sharti		return (-1);
83122394Sharti	}
84122394Sharti
85122394Sharti	len = 0;
86122394Sharti	if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) == -1) {
87122394Sharti		syslog(LOG_ERR, "net.inet.tcp.pcblist: %m");
88122394Sharti		return (-1);
89122394Sharti	}
90122394Sharti	if (len > xinpgen_len) {
91122394Sharti		if ((ptr = realloc(xinpgen, len)) == NULL) {
92122394Sharti			syslog(LOG_ERR, "%zu: %m", len);
93122394Sharti			return (-1);
94122394Sharti		}
95122394Sharti		xinpgen = ptr;
96122394Sharti		xinpgen_len = len;
97122394Sharti	}
98122394Sharti	if (sysctlbyname("net.inet.tcp.pcblist", xinpgen, &len, NULL, 0) == -1) {
99122394Sharti		syslog(LOG_ERR, "net.inet.tcp.pcblist: %m");
100122394Sharti		return (-1);
101122394Sharti	}
102122394Sharti
103122394Sharti	tcp_tick = get_ticks();
104122394Sharti
105122394Sharti	tcp_count = 0;
106122394Sharti	tcp_total = 0;
107122394Sharti	for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len);
108122394Sharti	     ptr->xig_len > sizeof(struct xinpgen);
109122394Sharti             ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) {
110122394Sharti		tp = (struct xtcpcb *)ptr;
111122394Sharti		if (tp->xt_inp.inp_gencnt > xinpgen->xig_gen ||
112236693Semax		    (tp->xt_inp.inp_vflag & (INP_IPV4|INP_IPV6)) == 0)
113122394Sharti			continue;
114122394Sharti
115236693Semax		if (tp->xt_inp.inp_vflag & INP_IPV4)
116236693Semax			tcp_total++;
117236693Semax
118122394Sharti		if (tp->xt_tp.t_state == TCPS_ESTABLISHED ||
119122394Sharti		    tp->xt_tp.t_state == TCPS_CLOSE_WAIT)
120122394Sharti			tcp_count++;
121122394Sharti	}
122122394Sharti
123122394Sharti	if (oidnum < tcp_total) {
124122394Sharti		oid = realloc(tcpoids, tcp_total * sizeof(tcpoids[0]));
125122394Sharti		if (oid == NULL) {
126122394Sharti			free(tcpoids);
127122394Sharti			oidnum = 0;
128122394Sharti			return (0);
129122394Sharti		}
130122394Sharti		tcpoids = oid;
131122394Sharti		oidnum = tcp_total;
132122394Sharti	}
133122394Sharti
134122394Sharti	oid = tcpoids;
135122394Sharti	for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len);
136122394Sharti	     ptr->xig_len > sizeof(struct xinpgen);
137122394Sharti             ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) {
138122394Sharti		tp = (struct xtcpcb *)ptr;
139122394Sharti		if (tp->xt_inp.inp_gencnt > xinpgen->xig_gen ||
140122394Sharti		    (tp->xt_inp.inp_vflag & INP_IPV4) == 0)
141122394Sharti			continue;
142122394Sharti		oid->tp = tp;
143122394Sharti		oid->index.len = 10;
144122394Sharti		inaddr = ntohl(tp->xt_inp.inp_laddr.s_addr);
145122394Sharti		oid->index.subs[0] = (inaddr >> 24) & 0xff;
146122394Sharti		oid->index.subs[1] = (inaddr >> 16) & 0xff;
147122394Sharti		oid->index.subs[2] = (inaddr >>  8) & 0xff;
148122394Sharti		oid->index.subs[3] = (inaddr >>  0) & 0xff;
149122394Sharti		oid->index.subs[4] = ntohs(tp->xt_inp.inp_lport);
150122394Sharti		inaddr = ntohl(tp->xt_inp.inp_faddr.s_addr);
151122394Sharti		oid->index.subs[5] = (inaddr >> 24) & 0xff;
152122394Sharti		oid->index.subs[6] = (inaddr >> 16) & 0xff;
153122394Sharti		oid->index.subs[7] = (inaddr >>  8) & 0xff;
154122394Sharti		oid->index.subs[8] = (inaddr >>  0) & 0xff;
155122394Sharti		oid->index.subs[9] = ntohs(tp->xt_inp.inp_fport);
156122394Sharti		oid++;
157122394Sharti	}
158122394Sharti
159122394Sharti	qsort(tcpoids, tcp_total, sizeof(tcpoids[0]), tcp_compare);
160122394Sharti
161122394Sharti	return (0);
162122394Sharti}
163122394Sharti
164122394Sharti/*
165122394Sharti * Scalars
166122394Sharti */
167122394Shartiint
168122394Shartiop_tcp(struct snmp_context *ctx __unused, struct snmp_value *value,
169122394Sharti    u_int sub, u_int iidx __unused, enum snmp_op op)
170122394Sharti{
171122394Sharti	switch (op) {
172122394Sharti
173122394Sharti	  case SNMP_OP_GETNEXT:
174122394Sharti		abort();
175122394Sharti
176122394Sharti	  case SNMP_OP_GET:
177122394Sharti		break;
178122394Sharti
179122394Sharti	  case SNMP_OP_SET:
180122394Sharti		return (SNMP_ERR_NOT_WRITEABLE);
181122394Sharti
182122394Sharti	  case SNMP_OP_ROLLBACK:
183122394Sharti	  case SNMP_OP_COMMIT:
184122394Sharti		abort();
185122394Sharti	}
186122394Sharti
187122394Sharti	if (tcp_tick < this_tick)
188122394Sharti		if (fetch_tcp() == -1)
189122394Sharti			return (SNMP_ERR_GENERR);
190122394Sharti
191122394Sharti	switch (value->var.subs[sub - 1]) {
192122394Sharti
193122394Sharti	  case LEAF_tcpRtoAlgorithm:
194122394Sharti		value->v.integer = 4;	/* Van Jacobson */
195122394Sharti		break;
196122394Sharti
197122394Sharti#define hz clockinfo.hz
198122394Sharti
199122394Sharti	  case LEAF_tcpRtoMin:
200122394Sharti		value->v.integer = 1000 * TCPTV_MIN / hz;
201122394Sharti		break;
202122394Sharti
203122394Sharti	  case LEAF_tcpRtoMax:
204122394Sharti		value->v.integer = 1000 * TCPTV_REXMTMAX / hz;
205122394Sharti		break;
206122394Sharti#undef hz
207122394Sharti
208122394Sharti	  case LEAF_tcpMaxConn:
209122394Sharti		value->v.integer = -1;
210122394Sharti		break;
211122394Sharti
212122394Sharti	  case LEAF_tcpActiveOpens:
213122394Sharti		value->v.uint32 = tcpstat.tcps_connattempt;
214122394Sharti		break;
215122394Sharti
216122394Sharti	  case LEAF_tcpPassiveOpens:
217122394Sharti		value->v.uint32 = tcpstat.tcps_accepts;
218122394Sharti		break;
219122394Sharti
220122394Sharti	  case LEAF_tcpAttemptFails:
221122394Sharti		value->v.uint32 = tcpstat.tcps_conndrops;
222122394Sharti		break;
223122394Sharti
224122394Sharti	  case LEAF_tcpEstabResets:
225122394Sharti		value->v.uint32 = tcpstat.tcps_drops;
226122394Sharti		break;
227122394Sharti
228122394Sharti	  case LEAF_tcpCurrEstab:
229122394Sharti		value->v.uint32 = tcp_count;
230122394Sharti		break;
231122394Sharti
232122394Sharti	  case LEAF_tcpInSegs:
233122394Sharti		value->v.uint32 = tcpstat.tcps_rcvtotal;
234122394Sharti		break;
235122394Sharti
236122394Sharti	  case LEAF_tcpOutSegs:
237122394Sharti		value->v.uint32 = tcpstat.tcps_sndtotal -
238122394Sharti		    tcpstat.tcps_sndrexmitpack;
239122394Sharti		break;
240122394Sharti
241122394Sharti	  case LEAF_tcpRetransSegs:
242122394Sharti		value->v.uint32 = tcpstat.tcps_sndrexmitpack;
243122394Sharti		break;
244122394Sharti
245122394Sharti	  case LEAF_tcpInErrs:
246122394Sharti		value->v.uint32 = tcpstat.tcps_rcvbadsum +
247122394Sharti		    tcpstat.tcps_rcvbadoff +
248122394Sharti		    tcpstat.tcps_rcvshort;
249122394Sharti		break;
250122394Sharti	}
251122394Sharti	return (SNMP_ERR_NOERROR);
252122394Sharti}
253122394Sharti
254122394Shartiint
255122394Shartiop_tcpconn(struct snmp_context *ctx __unused, struct snmp_value *value,
256122394Sharti    u_int sub, u_int iidx __unused, enum snmp_op op)
257122394Sharti{
258122394Sharti	u_int i;
259122394Sharti
260122394Sharti	if (tcp_tick < this_tick)
261122394Sharti		if (fetch_tcp() == -1)
262122394Sharti			return (SNMP_ERR_GENERR);
263122394Sharti
264122394Sharti	switch (op) {
265122394Sharti
266122394Sharti	  case SNMP_OP_GETNEXT:
267122394Sharti		for (i = 0; i < tcp_total; i++)
268122394Sharti			if (index_compare(&value->var, sub, &tcpoids[i].index) < 0)
269122394Sharti				break;
270122394Sharti		if (i == tcp_total)
271122394Sharti			return (SNMP_ERR_NOSUCHNAME);
272122394Sharti		index_append(&value->var, sub, &tcpoids[i].index);
273122394Sharti		break;
274122394Sharti
275122394Sharti	  case SNMP_OP_GET:
276122394Sharti		for (i = 0; i < tcp_total; i++)
277122394Sharti			if (index_compare(&value->var, sub, &tcpoids[i].index) == 0)
278122394Sharti				break;
279122394Sharti		if (i == tcp_total)
280122394Sharti			return (SNMP_ERR_NOSUCHNAME);
281122394Sharti		break;
282122394Sharti
283122394Sharti	  case SNMP_OP_SET:
284122394Sharti		return (SNMP_ERR_NOT_WRITEABLE);
285122394Sharti
286122394Sharti	  case SNMP_OP_ROLLBACK:
287122394Sharti	  case SNMP_OP_COMMIT:
288122394Sharti	  default:
289122394Sharti		abort();
290122394Sharti	}
291122394Sharti
292122394Sharti	switch (value->var.subs[sub - 1]) {
293122394Sharti
294122394Sharti	  case LEAF_tcpConnState:
295122394Sharti		switch (tcpoids[i].tp->xt_tp.t_state) {
296122394Sharti
297122394Sharti		  case TCPS_CLOSED:
298122394Sharti			value->v.integer = 1;
299122394Sharti			break;
300122394Sharti		  case TCPS_LISTEN:
301122394Sharti			value->v.integer = 2;
302122394Sharti			break;
303122394Sharti		  case TCPS_SYN_SENT:
304122394Sharti			value->v.integer = 3;
305122394Sharti			break;
306122394Sharti		  case TCPS_SYN_RECEIVED:
307122394Sharti			value->v.integer = 4;
308122394Sharti			break;
309122394Sharti		  case TCPS_ESTABLISHED:
310122394Sharti			value->v.integer = 5;
311122394Sharti			break;
312122394Sharti		  case TCPS_CLOSE_WAIT:
313122394Sharti			value->v.integer = 8;
314122394Sharti			break;
315122394Sharti		  case TCPS_FIN_WAIT_1:
316122394Sharti			value->v.integer = 6;
317122394Sharti			break;
318122394Sharti		  case TCPS_CLOSING:
319122394Sharti			value->v.integer = 10;
320122394Sharti			break;
321122394Sharti		  case TCPS_LAST_ACK:
322122394Sharti			value->v.integer = 9;
323122394Sharti			break;
324122394Sharti		  case TCPS_FIN_WAIT_2:
325122394Sharti			value->v.integer = 7;
326122394Sharti			break;
327122394Sharti		  case TCPS_TIME_WAIT:
328122394Sharti			value->v.integer = 11;
329122394Sharti			break;
330122394Sharti		  default:
331122394Sharti			value->v.integer = 0;
332122394Sharti			break;
333122394Sharti		}
334122394Sharti		break;
335122394Sharti
336122394Sharti	  case LEAF_tcpConnLocalAddress:
337122394Sharti		value->v.ipaddress[0] = tcpoids[i].index.subs[0];
338122394Sharti		value->v.ipaddress[1] = tcpoids[i].index.subs[1];
339122394Sharti		value->v.ipaddress[2] = tcpoids[i].index.subs[2];
340122394Sharti		value->v.ipaddress[3] = tcpoids[i].index.subs[3];
341122394Sharti		break;
342122394Sharti
343122394Sharti	  case LEAF_tcpConnLocalPort:
344122394Sharti		value->v.integer = tcpoids[i].index.subs[4];
345122394Sharti		break;
346122394Sharti
347122394Sharti	  case LEAF_tcpConnRemAddress:
348122394Sharti		value->v.ipaddress[0] = tcpoids[i].index.subs[5];
349122394Sharti		value->v.ipaddress[1] = tcpoids[i].index.subs[6];
350122394Sharti		value->v.ipaddress[2] = tcpoids[i].index.subs[7];
351122394Sharti		value->v.ipaddress[3] = tcpoids[i].index.subs[8];
352122394Sharti		break;
353122394Sharti
354122394Sharti	  case LEAF_tcpConnRemPort:
355122394Sharti		value->v.integer = tcpoids[i].index.subs[9];
356122394Sharti		break;
357122394Sharti	}
358122394Sharti	return (SNMP_ERR_NOERROR);
359122394Sharti}
360