]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bsnmp/snmp_mibII/mibII_tcp.c
Merge openmp trunk r366426, resolve conflicts, and add FREEBSD-Xlist.
[FreeBSD/FreeBSD.git] / contrib / bsnmp / snmp_mibII / mibII_tcp.c
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
42 struct tcp_index {
43         struct asn_oid  index;
44         struct xtcpcb   *tp;
45 };
46
47 static uint64_t tcp_tick;
48 static uint64_t tcp_stats_tick;
49 static struct tcpstat tcpstat;
50 static uint64_t tcps_states[TCP_NSTATES];
51 static struct xinpgen *xinpgen;
52 static size_t xinpgen_len;
53 static u_int tcp_total;
54
55 static u_int oidnum;
56 static struct tcp_index *tcpoids;
57
58 static int
59 tcp_compare(const void *p1, const void *p2)
60 {
61         const struct tcp_index *t1 = p1;
62         const struct tcp_index *t2 = p2;
63
64         return (asn_compare_oid(&t1->index, &t2->index));
65 }
66
67 static int
68 fetch_tcp_stats(void)
69 {
70         size_t len;
71
72         len = sizeof(tcpstat);
73         if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, NULL, 0) == -1) {
74                 syslog(LOG_ERR, "net.inet.tcp.stats: %m");
75                 return (-1);
76         }
77         if (len != sizeof(tcpstat)) {
78                 syslog(LOG_ERR, "net.inet.tcp.stats: wrong size");
79                 return (-1);
80         }
81
82         len = sizeof(tcps_states);
83         if (sysctlbyname("net.inet.tcp.states", &tcps_states, &len, NULL,
84             0) == -1) {
85                 syslog(LOG_ERR, "net.inet.tcp.states: %m");
86                 return (-1);
87         }
88         if (len != sizeof(tcps_states)) {
89                 syslog(LOG_ERR, "net.inet.tcp.states: wrong size");
90                 return (-1);
91         }
92
93         tcp_stats_tick = get_ticks();
94
95         return (0);
96 }
97
98 static int
99 fetch_tcp(void)
100 {
101         size_t len;
102         struct xinpgen *ptr;
103         struct xtcpcb *tp;
104         struct tcp_index *oid;
105         in_addr_t inaddr;
106
107         len = 0;
108         if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) == -1) {
109                 syslog(LOG_ERR, "net.inet.tcp.pcblist: %m");
110                 return (-1);
111         }
112         if (len > xinpgen_len) {
113                 if ((ptr = realloc(xinpgen, len)) == NULL) {
114                         syslog(LOG_ERR, "%zu: %m", len);
115                         return (-1);
116                 }
117                 xinpgen = ptr;
118                 xinpgen_len = len;
119         }
120         if (sysctlbyname("net.inet.tcp.pcblist", xinpgen, &len, NULL, 0) == -1) {
121                 syslog(LOG_ERR, "net.inet.tcp.pcblist: %m");
122                 return (-1);
123         }
124
125         tcp_tick = get_ticks();
126
127         tcp_total = 0;
128         for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len);
129              ptr->xig_len > sizeof(struct xinpgen);
130              ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) {
131                 tp = (struct xtcpcb *)ptr;
132                 if (tp->xt_inp.inp_gencnt > xinpgen->xig_gen ||
133                     (tp->xt_inp.inp_vflag & (INP_IPV4|INP_IPV6)) == 0)
134                         continue;
135
136                 if (tp->xt_inp.inp_vflag & INP_IPV4)
137                         tcp_total++;
138         }
139
140         if (oidnum < tcp_total) {
141                 oid = realloc(tcpoids, tcp_total * sizeof(tcpoids[0]));
142                 if (oid == NULL) {
143                         free(tcpoids);
144                         oidnum = 0;
145                         return (0);
146                 }
147                 tcpoids = oid;
148                 oidnum = tcp_total;
149         }
150
151         oid = tcpoids;
152         for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len);
153              ptr->xig_len > sizeof(struct xinpgen);
154              ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) {
155                 tp = (struct xtcpcb *)ptr;
156                 if (tp->xt_inp.inp_gencnt > xinpgen->xig_gen ||
157                     (tp->xt_inp.inp_vflag & INP_IPV4) == 0)
158                         continue;
159                 oid->tp = tp;
160                 oid->index.len = 10;
161                 inaddr = ntohl(tp->xt_inp.inp_laddr.s_addr);
162                 oid->index.subs[0] = (inaddr >> 24) & 0xff;
163                 oid->index.subs[1] = (inaddr >> 16) & 0xff;
164                 oid->index.subs[2] = (inaddr >>  8) & 0xff;
165                 oid->index.subs[3] = (inaddr >>  0) & 0xff;
166                 oid->index.subs[4] = ntohs(tp->xt_inp.inp_lport);
167                 inaddr = ntohl(tp->xt_inp.inp_faddr.s_addr);
168                 oid->index.subs[5] = (inaddr >> 24) & 0xff;
169                 oid->index.subs[6] = (inaddr >> 16) & 0xff;
170                 oid->index.subs[7] = (inaddr >>  8) & 0xff;
171                 oid->index.subs[8] = (inaddr >>  0) & 0xff;
172                 oid->index.subs[9] = ntohs(tp->xt_inp.inp_fport);
173                 oid++;
174         }
175
176         qsort(tcpoids, tcp_total, sizeof(tcpoids[0]), tcp_compare);
177
178         return (0);
179 }
180
181 /*
182  * Scalars
183  */
184 int
185 op_tcp(struct snmp_context *ctx __unused, struct snmp_value *value,
186     u_int sub, u_int iidx __unused, enum snmp_op op)
187 {
188         switch (op) {
189
190           case SNMP_OP_GETNEXT:
191                 abort();
192
193           case SNMP_OP_GET:
194                 break;
195
196           case SNMP_OP_SET:
197                 return (SNMP_ERR_NOT_WRITEABLE);
198
199           case SNMP_OP_ROLLBACK:
200           case SNMP_OP_COMMIT:
201                 abort();
202         }
203
204         if (tcp_stats_tick < this_tick)
205                 if (fetch_tcp_stats() == -1)
206                         return (SNMP_ERR_GENERR);
207
208         switch (value->var.subs[sub - 1]) {
209
210           case LEAF_tcpRtoAlgorithm:
211                 value->v.integer = 4;   /* Van Jacobson */
212                 break;
213
214 #define hz clockinfo.hz
215
216           case LEAF_tcpRtoMin:
217                 value->v.integer = 1000 * TCPTV_MIN / hz;
218                 break;
219
220           case LEAF_tcpRtoMax:
221                 value->v.integer = 1000 * TCPTV_REXMTMAX / hz;
222                 break;
223 #undef hz
224
225           case LEAF_tcpMaxConn:
226                 value->v.integer = -1;
227                 break;
228
229           case LEAF_tcpActiveOpens:
230                 value->v.uint32 = tcpstat.tcps_connattempt;
231                 break;
232
233           case LEAF_tcpPassiveOpens:
234                 value->v.uint32 = tcpstat.tcps_accepts;
235                 break;
236
237           case LEAF_tcpAttemptFails:
238                 value->v.uint32 = tcpstat.tcps_conndrops;
239                 break;
240
241           case LEAF_tcpEstabResets:
242                 value->v.uint32 = tcpstat.tcps_drops;
243                 break;
244
245           case LEAF_tcpCurrEstab:
246                 value->v.uint32 = tcps_states[TCPS_ESTABLISHED] +
247                     tcps_states[TCPS_CLOSE_WAIT];
248                 break;
249
250           case LEAF_tcpInSegs:
251                 value->v.uint32 = tcpstat.tcps_rcvtotal;
252                 break;
253
254           case LEAF_tcpOutSegs:
255                 value->v.uint32 = tcpstat.tcps_sndtotal -
256                     tcpstat.tcps_sndrexmitpack;
257                 break;
258
259           case LEAF_tcpRetransSegs:
260                 value->v.uint32 = tcpstat.tcps_sndrexmitpack;
261                 break;
262
263           case LEAF_tcpInErrs:
264                 value->v.uint32 = tcpstat.tcps_rcvbadsum +
265                     tcpstat.tcps_rcvbadoff +
266                     tcpstat.tcps_rcvshort;
267                 break;
268         }
269         return (SNMP_ERR_NOERROR);
270 }
271
272 int
273 op_tcpconn(struct snmp_context *ctx __unused, struct snmp_value *value,
274     u_int sub, u_int iidx __unused, enum snmp_op op)
275 {
276         u_int i;
277
278         if (tcp_tick < this_tick)
279                 if (fetch_tcp() == -1)
280                         return (SNMP_ERR_GENERR);
281
282         switch (op) {
283
284           case SNMP_OP_GETNEXT:
285                 for (i = 0; i < tcp_total; i++)
286                         if (index_compare(&value->var, sub, &tcpoids[i].index) < 0)
287                                 break;
288                 if (i == tcp_total)
289                         return (SNMP_ERR_NOSUCHNAME);
290                 index_append(&value->var, sub, &tcpoids[i].index);
291                 break;
292
293           case SNMP_OP_GET:
294                 for (i = 0; i < tcp_total; i++)
295                         if (index_compare(&value->var, sub, &tcpoids[i].index) == 0)
296                                 break;
297                 if (i == tcp_total)
298                         return (SNMP_ERR_NOSUCHNAME);
299                 break;
300
301           case SNMP_OP_SET:
302                 return (SNMP_ERR_NOT_WRITEABLE);
303
304           case SNMP_OP_ROLLBACK:
305           case SNMP_OP_COMMIT:
306           default:
307                 abort();
308         }
309
310         switch (value->var.subs[sub - 1]) {
311
312           case LEAF_tcpConnState:
313                 switch (tcpoids[i].tp->t_state) {
314
315                   case TCPS_CLOSED:
316                         value->v.integer = 1;
317                         break;
318                   case TCPS_LISTEN:
319                         value->v.integer = 2;
320                         break;
321                   case TCPS_SYN_SENT:
322                         value->v.integer = 3;
323                         break;
324                   case TCPS_SYN_RECEIVED:
325                         value->v.integer = 4;
326                         break;
327                   case TCPS_ESTABLISHED:
328                         value->v.integer = 5;
329                         break;
330                   case TCPS_CLOSE_WAIT:
331                         value->v.integer = 8;
332                         break;
333                   case TCPS_FIN_WAIT_1:
334                         value->v.integer = 6;
335                         break;
336                   case TCPS_CLOSING:
337                         value->v.integer = 10;
338                         break;
339                   case TCPS_LAST_ACK:
340                         value->v.integer = 9;
341                         break;
342                   case TCPS_FIN_WAIT_2:
343                         value->v.integer = 7;
344                         break;
345                   case TCPS_TIME_WAIT:
346                         value->v.integer = 11;
347                         break;
348                   default:
349                         value->v.integer = 0;
350                         break;
351                 }
352                 break;
353
354           case LEAF_tcpConnLocalAddress:
355                 value->v.ipaddress[0] = tcpoids[i].index.subs[0];
356                 value->v.ipaddress[1] = tcpoids[i].index.subs[1];
357                 value->v.ipaddress[2] = tcpoids[i].index.subs[2];
358                 value->v.ipaddress[3] = tcpoids[i].index.subs[3];
359                 break;
360
361           case LEAF_tcpConnLocalPort:
362                 value->v.integer = tcpoids[i].index.subs[4];
363                 break;
364
365           case LEAF_tcpConnRemAddress:
366                 value->v.ipaddress[0] = tcpoids[i].index.subs[5];
367                 value->v.ipaddress[1] = tcpoids[i].index.subs[6];
368                 value->v.ipaddress[2] = tcpoids[i].index.subs[7];
369                 value->v.ipaddress[3] = tcpoids[i].index.subs[8];
370                 break;
371
372           case LEAF_tcpConnRemPort:
373                 value->v.integer = tcpoids[i].index.subs[9];
374                 break;
375         }
376         return (SNMP_ERR_NOERROR);
377 }