]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/bsnmp/snmp_mibII/mibII_tcp.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 struct tcpstat tcpstat;
49 static struct xinpgen *xinpgen;
50 static size_t xinpgen_len;
51 static u_int tcp_count;
52 static u_int tcp_total;
53
54 static u_int oidnum;
55 static struct tcp_index *tcpoids;
56
57 static int
58 tcp_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
66 static int
67 fetch_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  */
167 int
168 op_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
254 int
255 op_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 }