PageRenderTime 50ms CodeModel.GetById 28ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 1ms

/contrib/bsnmp/snmp_mibII/mibII_tcp.c

https://bitbucket.org/freebsd/freebsd-head/
C | 359 lines | 273 code | 51 blank | 35 comment | 44 complexity | 735a6c8c43f79e935c070a35b1d4c737 MD5 | raw file
  1/*
  2 * Copyright (c) 2001-2003
  3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
  4 *	All rights reserved.
  5 *
  6 * Author: Harti Brandt <harti@freebsd.org>
  7 * 
  8 * Redistribution and use in source and binary forms, with or without
  9 * modification, are permitted provided that the following conditions
 10 * are met:
 11 * 1. Redistributions of source code must retain the above copyright
 12 *    notice, this list of conditions and the following disclaimer.
 13 * 2. Redistributions in binary form must reproduce the above copyright
 14 *    notice, this list of conditions and the following disclaimer in the
 15 *    documentation and/or other materials provided with the distribution.
 16 * 
 17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 20 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 27 * SUCH DAMAGE.
 28 *
 29 * $Begemot: bsnmp/snmp_mibII/mibII_tcp.c,v 1.7 2005/05/23 09:03:42 brandt_h Exp $
 30 *
 31 * tcp
 32 */
 33#include "mibII.h"
 34#include "mibII_oid.h"
 35#include <sys/socketvar.h>
 36#include <netinet/in_pcb.h>
 37#include <netinet/tcp.h>
 38#include <netinet/tcp_var.h>
 39#include <netinet/tcp_timer.h>
 40#include <netinet/tcp_fsm.h>
 41
 42struct tcp_index {
 43	struct asn_oid	index;
 44	struct xtcpcb	*tp;
 45};
 46
 47static uint64_t tcp_tick;
 48static struct tcpstat tcpstat;
 49static struct xinpgen *xinpgen;
 50static size_t xinpgen_len;
 51static u_int tcp_count;
 52static u_int tcp_total;
 53
 54static u_int oidnum;
 55static struct tcp_index *tcpoids;
 56
 57static int
 58tcp_compare(const void *p1, const void *p2)
 59{
 60	const struct tcp_index *t1 = p1;
 61	const struct tcp_index *t2 = p2;
 62
 63	return (asn_compare_oid(&t1->index, &t2->index));
 64}
 65
 66static int
 67fetch_tcp(void)
 68{
 69	size_t len;
 70	struct xinpgen *ptr;
 71	struct xtcpcb *tp;
 72	struct tcp_index *oid;
 73	in_addr_t inaddr;
 74
 75	len = sizeof(tcpstat);
 76	if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, NULL, 0) == -1) {
 77		syslog(LOG_ERR, "net.inet.tcp.stats: %m");
 78		return (-1);
 79	}
 80	if (len != sizeof(tcpstat)) {
 81		syslog(LOG_ERR, "net.inet.tcp.stats: wrong size");
 82		return (-1);
 83	}
 84
 85	len = 0;
 86	if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) == -1) {
 87		syslog(LOG_ERR, "net.inet.tcp.pcblist: %m");
 88		return (-1);
 89	}
 90	if (len > xinpgen_len) {
 91		if ((ptr = realloc(xinpgen, len)) == NULL) {
 92			syslog(LOG_ERR, "%zu: %m", len);
 93			return (-1);
 94		}
 95		xinpgen = ptr;
 96		xinpgen_len = len;
 97	}
 98	if (sysctlbyname("net.inet.tcp.pcblist", xinpgen, &len, NULL, 0) == -1) {
 99		syslog(LOG_ERR, "net.inet.tcp.pcblist: %m");
100		return (-1);
101	}
102
103	tcp_tick = get_ticks();
104
105	tcp_count = 0;
106	tcp_total = 0;
107	for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len);
108	     ptr->xig_len > sizeof(struct xinpgen);
109             ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) {
110		tp = (struct xtcpcb *)ptr;
111		if (tp->xt_inp.inp_gencnt > xinpgen->xig_gen ||
112		    (tp->xt_inp.inp_vflag & (INP_IPV4|INP_IPV6)) == 0)
113			continue;
114
115		if (tp->xt_inp.inp_vflag & INP_IPV4)
116			tcp_total++;
117
118		if (tp->xt_tp.t_state == TCPS_ESTABLISHED ||
119		    tp->xt_tp.t_state == TCPS_CLOSE_WAIT)
120			tcp_count++;
121	}
122
123	if (oidnum < tcp_total) {
124		oid = realloc(tcpoids, tcp_total * sizeof(tcpoids[0]));
125		if (oid == NULL) {
126			free(tcpoids);
127			oidnum = 0;
128			return (0);
129		}
130		tcpoids = oid;
131		oidnum = tcp_total;
132	}
133
134	oid = tcpoids;
135	for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len);
136	     ptr->xig_len > sizeof(struct xinpgen);
137             ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) {
138		tp = (struct xtcpcb *)ptr;
139		if (tp->xt_inp.inp_gencnt > xinpgen->xig_gen ||
140		    (tp->xt_inp.inp_vflag & INP_IPV4) == 0)
141			continue;
142		oid->tp = tp;
143		oid->index.len = 10;
144		inaddr = ntohl(tp->xt_inp.inp_laddr.s_addr);
145		oid->index.subs[0] = (inaddr >> 24) & 0xff;
146		oid->index.subs[1] = (inaddr >> 16) & 0xff;
147		oid->index.subs[2] = (inaddr >>  8) & 0xff;
148		oid->index.subs[3] = (inaddr >>  0) & 0xff;
149		oid->index.subs[4] = ntohs(tp->xt_inp.inp_lport);
150		inaddr = ntohl(tp->xt_inp.inp_faddr.s_addr);
151		oid->index.subs[5] = (inaddr >> 24) & 0xff;
152		oid->index.subs[6] = (inaddr >> 16) & 0xff;
153		oid->index.subs[7] = (inaddr >>  8) & 0xff;
154		oid->index.subs[8] = (inaddr >>  0) & 0xff;
155		oid->index.subs[9] = ntohs(tp->xt_inp.inp_fport);
156		oid++;
157	}
158
159	qsort(tcpoids, tcp_total, sizeof(tcpoids[0]), tcp_compare);
160
161	return (0);
162}
163
164/*
165 * Scalars
166 */
167int
168op_tcp(struct snmp_context *ctx __unused, struct snmp_value *value,
169    u_int sub, u_int iidx __unused, enum snmp_op op)
170{
171	switch (op) {
172
173	  case SNMP_OP_GETNEXT:
174		abort();
175
176	  case SNMP_OP_GET:
177		break;
178
179	  case SNMP_OP_SET:
180		return (SNMP_ERR_NOT_WRITEABLE);
181
182	  case SNMP_OP_ROLLBACK:
183	  case SNMP_OP_COMMIT:
184		abort();
185	}
186
187	if (tcp_tick < this_tick)
188		if (fetch_tcp() == -1)
189			return (SNMP_ERR_GENERR);
190
191	switch (value->var.subs[sub - 1]) {
192
193	  case LEAF_tcpRtoAlgorithm:
194		value->v.integer = 4;	/* Van Jacobson */
195		break;
196
197#define hz clockinfo.hz
198
199	  case LEAF_tcpRtoMin:
200		value->v.integer = 1000 * TCPTV_MIN / hz;
201		break;
202
203	  case LEAF_tcpRtoMax:
204		value->v.integer = 1000 * TCPTV_REXMTMAX / hz;
205		break;
206#undef hz
207
208	  case LEAF_tcpMaxConn:
209		value->v.integer = -1;
210		break;
211
212	  case LEAF_tcpActiveOpens:
213		value->v.uint32 = tcpstat.tcps_connattempt;
214		break;
215
216	  case LEAF_tcpPassiveOpens:
217		value->v.uint32 = tcpstat.tcps_accepts;
218		break;
219
220	  case LEAF_tcpAttemptFails:
221		value->v.uint32 = tcpstat.tcps_conndrops;
222		break;
223
224	  case LEAF_tcpEstabResets:
225		value->v.uint32 = tcpstat.tcps_drops;
226		break;
227
228	  case LEAF_tcpCurrEstab:
229		value->v.uint32 = tcp_count;
230		break;
231
232	  case LEAF_tcpInSegs:
233		value->v.uint32 = tcpstat.tcps_rcvtotal;
234		break;
235
236	  case LEAF_tcpOutSegs:
237		value->v.uint32 = tcpstat.tcps_sndtotal -
238		    tcpstat.tcps_sndrexmitpack;
239		break;
240
241	  case LEAF_tcpRetransSegs:
242		value->v.uint32 = tcpstat.tcps_sndrexmitpack;
243		break;
244
245	  case LEAF_tcpInErrs:
246		value->v.uint32 = tcpstat.tcps_rcvbadsum +
247		    tcpstat.tcps_rcvbadoff +
248		    tcpstat.tcps_rcvshort;
249		break;
250	}
251	return (SNMP_ERR_NOERROR);
252}
253
254int
255op_tcpconn(struct snmp_context *ctx __unused, struct snmp_value *value,
256    u_int sub, u_int iidx __unused, enum snmp_op op)
257{
258	u_int i;
259
260	if (tcp_tick < this_tick)
261		if (fetch_tcp() == -1)
262			return (SNMP_ERR_GENERR);
263
264	switch (op) {
265
266	  case SNMP_OP_GETNEXT:
267		for (i = 0; i < tcp_total; i++)
268			if (index_compare(&value->var, sub, &tcpoids[i].index) < 0)
269				break;
270		if (i == tcp_total)
271			return (SNMP_ERR_NOSUCHNAME);
272		index_append(&value->var, sub, &tcpoids[i].index);
273		break;
274
275	  case SNMP_OP_GET:
276		for (i = 0; i < tcp_total; i++)
277			if (index_compare(&value->var, sub, &tcpoids[i].index) == 0)
278				break;
279		if (i == tcp_total)
280			return (SNMP_ERR_NOSUCHNAME);
281		break;
282
283	  case SNMP_OP_SET:
284		return (SNMP_ERR_NOT_WRITEABLE);
285
286	  case SNMP_OP_ROLLBACK:
287	  case SNMP_OP_COMMIT:
288	  default:
289		abort();
290	}
291
292	switch (value->var.subs[sub - 1]) {
293
294	  case LEAF_tcpConnState:
295		switch (tcpoids[i].tp->xt_tp.t_state) {
296
297		  case TCPS_CLOSED:
298			value->v.integer = 1;
299			break;
300		  case TCPS_LISTEN:
301			value->v.integer = 2;
302			break;
303		  case TCPS_SYN_SENT:
304			value->v.integer = 3;
305			break;
306		  case TCPS_SYN_RECEIVED:
307			value->v.integer = 4;
308			break;
309		  case TCPS_ESTABLISHED:
310			value->v.integer = 5;
311			break;
312		  case TCPS_CLOSE_WAIT:
313			value->v.integer = 8;
314			break;
315		  case TCPS_FIN_WAIT_1:
316			value->v.integer = 6;
317			break;
318		  case TCPS_CLOSING:
319			value->v.integer = 10;
320			break;
321		  case TCPS_LAST_ACK:
322			value->v.integer = 9;
323			break;
324		  case TCPS_FIN_WAIT_2:
325			value->v.integer = 7;
326			break;
327		  case TCPS_TIME_WAIT:
328			value->v.integer = 11;
329			break;
330		  default:
331			value->v.integer = 0;
332			break;
333		}
334		break;
335
336	  case LEAF_tcpConnLocalAddress:
337		value->v.ipaddress[0] = tcpoids[i].index.subs[0];
338		value->v.ipaddress[1] = tcpoids[i].index.subs[1];
339		value->v.ipaddress[2] = tcpoids[i].index.subs[2];
340		value->v.ipaddress[3] = tcpoids[i].index.subs[3];
341		break;
342
343	  case LEAF_tcpConnLocalPort:
344		value->v.integer = tcpoids[i].index.subs[4];
345		break;
346
347	  case LEAF_tcpConnRemAddress:
348		value->v.ipaddress[0] = tcpoids[i].index.subs[5];
349		value->v.ipaddress[1] = tcpoids[i].index.subs[6];
350		value->v.ipaddress[2] = tcpoids[i].index.subs[7];
351		value->v.ipaddress[3] = tcpoids[i].index.subs[8];
352		break;
353
354	  case LEAF_tcpConnRemPort:
355		value->v.integer = tcpoids[i].index.subs[9];
356		break;
357	}
358	return (SNMP_ERR_NOERROR);
359}