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