3
* TCP MIB group implementation - tcp.c
7
#include <net-snmp/net-snmp-config.h>
8
#include "mibII_common.h"
10
#if HAVE_SYS_PROTOSW_H
11
#include <sys/protosw.h>
14
#include <arpa/inet.h>
17
#if defined(osf4) || defined(osf5) || defined(aix4) || defined(hpux10)
19
* these are undefed to remove a stupid warning on osf compilers
20
* because they get redefined with a slightly different notation of the
26
#if HAVE_NETINET_TCP_H
27
#include <netinet/tcp.h>
29
#if HAVE_NETINET_TCPIP_H
30
#include <netinet/tcpip.h>
32
#if HAVE_NETINET_TCP_TIMER_H
33
#include <netinet/tcp_timer.h>
35
#if HAVE_NETINET_TCP_VAR_H
36
#include <netinet/tcp_var.h>
38
#if HAVE_NETINET_TCP_FSM_H
39
#include <netinet/tcp_fsm.h>
42
#include <net-snmp/net-snmp-includes.h>
43
#include <net-snmp/agent/net-snmp-agent-includes.h>
44
#include <net-snmp/agent/auto_nlist.h>
46
#include "util_funcs.h"
49
#include "sysORTable.h"
51
#ifndef MIB_STATS_CACHE_TIMEOUT
52
#define MIB_STATS_CACHE_TIMEOUT 5
54
#ifndef TCP_STATS_CACHE_TIMEOUT
55
#define TCP_STATS_CACHE_TIMEOUT MIB_STATS_CACHE_TIMEOUT
58
/*********************
60
* Kernel & interface information,
61
* and internal forward declarations
63
*********************/
66
* FreeBSD4 *does* need an explicit variable 'hz'
67
* since this appears in a system header file.
68
* But only define it under FreeBSD, since it
69
* breaks other systems (notable AIX)
75
/*********************
77
* Initialisation & common implementation functions
79
*********************/
83
* Define the OID pointer to the top of the mib tree that we're
84
* registering underneath, and the OID for the MIB module
86
oid tcp_oid[] = { SNMP_OID_MIB2, 6 };
87
oid tcp_module_oid[] = { SNMP_OID_MIB2, 49 };
92
netsnmp_handler_registration *reginfo;
95
* register ourselves with the agent as a group of scalars...
97
DEBUGMSGTL(("mibII/tcpScalar", "Initialising TCP scalar group\n"));
98
reginfo = netsnmp_create_handler_registration("tcp", tcp_handler,
99
tcp_oid, OID_LENGTH(tcp_oid), HANDLER_CAN_RONLY);
100
netsnmp_register_scalar_group(reginfo, TCPRTOALGORITHM, TCPOUTRSTS);
103
* .... with a local cache
104
* (except for HP-UX 11, which extracts objects individually)
107
netsnmp_inject_handler( reginfo,
108
netsnmp_get_cache_handler(TCP_STATS_CACHE_TIMEOUT,
110
tcp_oid, OID_LENGTH(tcp_oid)));
113
REGISTER_SYSOR_ENTRY(tcp_module_oid,
114
"The MIB module for managing TCP implementations");
116
#ifdef TCPSTAT_SYMBOL
117
auto_nlist(TCPSTAT_SYMBOL, 0, 0);
120
auto_nlist(TCP_SYMBOL, 0, 0);
123
hz = sysconf(_SC_CLK_TCK); /* get ticks/s from system */
126
init_kernel_sunos5();
130
/*********************
132
* System specific implementation functions
134
*********************/
137
#define TCP_STAT_STRUCTURE int
141
#define TCP_STAT_STRUCTURE struct tcp_mib
142
#define USES_SNMP_DESIGNED_TCPSTAT
143
#undef TCPSTAT_SYMBOL
147
#define TCP_STAT_STRUCTURE mib2_tcp_t
148
#define USES_SNMP_DESIGNED_TCPSTAT
152
#include <iphlpapi.h>
153
#define TCP_STAT_STRUCTURE MIB_TCPSTATS
156
#ifdef HAVE_SYS_TCPIPSTATS_H
157
#define TCP_STAT_STRUCTURE struct kna
158
#define USES_TRADITIONAL_TCPSTAT
161
#if !defined(TCP_STAT_STRUCTURE)
162
#define TCP_STAT_STRUCTURE struct tcpstat
163
#define USES_TRADITIONAL_TCPSTAT
166
TCP_STAT_STRUCTURE tcpstat;
170
/*********************
172
* System independent handler (mostly)
174
*********************/
179
tcp_handler(netsnmp_mib_handler *handler,
180
netsnmp_handler_registration *reginfo,
181
netsnmp_agent_request_info *reqinfo,
182
netsnmp_request_info *requests)
184
netsnmp_request_info *request;
185
netsnmp_variable_list *requestvb;
188
int type = ASN_COUNTER;
191
* The cached data should already have been loaded by the
192
* cache handler, higher up the handler chain.
193
* But just to be safe, check this and load it manually if necessary
196
if (!netsnmp_is_cache_valid(reqinfo)) {
197
tcp_load( NULL, NULL ); /* XXX - check for failure */
206
DEBUGMSGTL(("mibII/tcpScalar", "Handler - mode %s\n",
207
se_find_label_in_slist("agent_mode", reqinfo->mode)));
208
switch (reqinfo->mode) {
210
for (request=requests; request; request=request->next) {
211
requestvb = request->requestvb;
212
subid = requestvb->name[OID_LENGTH(tcp_oid)]; /* XXX */
214
DEBUGMSGTL(( "mibII/tcpScalar", "oid: "));
215
DEBUGMSGOID(("mibII/tcpScalar", requestvb->name,
216
requestvb->name_length));
217
DEBUGMSG(( "mibII/tcpScalar", "\n"));
219
#ifdef USES_SNMP_DESIGNED_TCPSTAT
220
case TCPRTOALGORITHM:
221
ret_value = tcpstat.tcpRtoAlgorithm;
225
ret_value = tcpstat.tcpRtoMin;
229
ret_value = tcpstat.tcpRtoMax;
233
ret_value = tcpstat.tcpMaxConn;
237
ret_value = tcpstat.tcpActiveOpens;
239
case TCPPASSIVEOPENS:
240
ret_value = tcpstat.tcpPassiveOpens;
242
case TCPATTEMPTFAILS:
243
ret_value = tcpstat.tcpAttemptFails;
246
ret_value = tcpstat.tcpEstabResets;
249
ret_value = tcpstat.tcpCurrEstab;
253
ret_value = tcpstat.tcpInSegs;
256
ret_value = tcpstat.tcpOutSegs;
259
ret_value = tcpstat.tcpRetransSegs;
263
ret_value = tcp_load(NULL, (void *)TCPINERRS);
264
if (ret_value == -1) {
265
netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
271
if (tcpstat.tcpInErrsValid) {
272
ret_value = tcpstat.tcpInErrs;
275
netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
279
netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
282
#endif /* solaris2 */
285
if (tcpstat.tcpOutRstsValid) {
286
ret_value = tcpstat.tcpOutRsts;
290
netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
292
#else /* USES_SNMP_DESIGNED_TCPSTAT */
294
#ifdef USES_TRADITIONAL_TCPSTAT
295
#ifdef HAVE_SYS_TCPIPSTATS_H
297
* This actually reads statistics for *all* the groups together,
298
* so we need to isolate the TCP-specific bits.
300
#define tcpstat tcpstat.tcpstat
302
case TCPRTOALGORITHM: /* Assume Van Jacobsen's algorithm */
307
#ifdef TCPTV_NEEDS_HZ
308
ret_value = TCPTV_MIN;
310
ret_value = TCPTV_MIN / PR_SLOWHZ * 1000;
315
#ifdef TCPTV_NEEDS_HZ
316
ret_value = TCPTV_REXMTMAX;
318
ret_value = TCPTV_REXMTMAX / PR_SLOWHZ * 1000;
323
ret_value = -1; /* Dynamic maximum */
327
ret_value = tcpstat.tcps_connattempt;
329
case TCPPASSIVEOPENS:
330
ret_value = tcpstat.tcps_accepts;
333
* NB: tcps_drops is actually the sum of the two MIB
334
* counters tcpAttemptFails and tcpEstabResets.
336
case TCPATTEMPTFAILS:
337
ret_value = tcpstat.tcps_conndrops;
340
ret_value = tcpstat.tcps_drops;
343
#ifdef USING_MIBII_TCPTABLE_MODULE
344
ret_value = TCP_Count_Connections();
351
ret_value = tcpstat.tcps_rcvtotal;
355
* RFC 1213 defines this as the number of segments sent
356
* "excluding those containing only retransmitted octets"
358
ret_value = tcpstat.tcps_sndtotal - tcpstat.tcps_sndrexmitpack;
361
ret_value = tcpstat.tcps_sndrexmitpack;
364
ret_value = tcpstat.tcps_rcvbadsum + tcpstat.tcps_rcvbadoff
365
#ifdef STRUCT_TCPSTAT_HAS_TCPS_RCVMEMDROP
366
+ tcpstat.tcps_rcvmemdrop
368
+ tcpstat.tcps_rcvshort;
371
ret_value = tcpstat.tcps_sndctrl - tcpstat.tcps_closed;
373
#ifdef HAVE_SYS_TCPIPSTATS_H
376
#else /* USES_TRADITIONAL_TCPSTAT */
379
case TCPRTOALGORITHM:
384
if (subid == TCPCURRESTAB)
389
case TCPPASSIVEOPENS:
390
case TCPATTEMPTFAILS:
398
* This is a bit of a hack, to shoehorn the HP-UX 11
399
* single-object retrieval approach into the caching
402
if (tcp_load(NULL, (void*)subid) == -1 ) {
403
netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
411
case TCPRTOALGORITHM:
412
ret_value = tcpstat.dwRtoAlgorithm;
416
ret_value = tcpstat.dwRtoMin;
420
ret_value = tcpstat.dwRtoMax;
424
ret_value = tcpstat.dwMaxConn;
428
ret_value = tcpstat.dwActiveOpens;
430
case TCPPASSIVEOPENS:
431
ret_value = tcpstat.dwPassiveOpens;
433
case TCPATTEMPTFAILS:
434
ret_value = tcpstat.dwAttemptFails;
437
ret_value = tcpstat.dwEstabResets;
440
ret_value = tcpstat.dwCurrEstab;
444
ret_value = tcpstat.dwInSegs;
447
ret_value = tcpstat.dwOutSegs;
450
ret_value = tcpstat.dwRetransSegs;
453
ret_value = tcpstat.dwInErrs;
456
ret_value = tcpstat.dwOutRsts;
460
#endif /* USES_TRADITIONAL_TCPSTAT */
461
#endif /* USES_SNMP_DESIGNED_TCPSTAT */
465
* This is not actually a valid scalar object.
466
* The table registration should take precedence,
467
* so skip this subtree, regardless of architecture.
469
netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
473
snmp_set_var_typed_value(request->requestvb, (u_char)type,
474
(u_char *)&ret_value, sizeof(ret_value));
480
case MODE_SET_RESERVE1:
481
case MODE_SET_RESERVE2:
482
case MODE_SET_ACTION:
483
case MODE_SET_COMMIT:
486
snmp_log(LOG_WARNING, "mibII/tcp: Unsupported mode (%d)\n",
490
snmp_log(LOG_WARNING, "mibII/tcp: Unrecognised mode (%d)\n",
495
return SNMP_ERR_NOERROR;
500
/*********************
502
* Internal implementation functions
504
*********************/
508
tcp_load(netsnmp_cache *cache, void *vmagic)
514
int magic = (int) vmagic;
516
if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) < 0) {
517
DEBUGMSGTL(("mibII/tcpScalar", "Failed to load TCP object %d (hpux11)\n", magic));
518
return (-1); /* error */
522
case TCPRTOALGORITHM:
523
p.objid = ID_tcpRtoAlgorithm;
526
p.objid = ID_tcpRtoMin;
529
p.objid = ID_tcpRtoMax;
532
p.objid = ID_tcpMaxConn;
535
p.objid = ID_tcpActiveOpens;
537
case TCPPASSIVEOPENS:
538
p.objid = ID_tcpPassiveOpens;
540
case TCPATTEMPTFAILS:
541
p.objid = ID_tcpAttemptFails;
544
p.objid = ID_tcpEstabResets;
547
p.objid = ID_tcpCurrEstab;
550
p.objid = ID_tcpInSegs;
553
p.objid = ID_tcpOutSegs;
556
p.objid = ID_tcpRetransSegs;
559
p.objid = ID_tcpInErrs;
562
p.objid = ID_tcpOutRsts;
570
p.buffer = (void *)&tcpstat;
571
ulen = sizeof(TCP_STAT_STRUCTURE);
573
ret = get_mib_info(fd, &p);
576
DEBUGMSGTL(("mibII/tcpScalar", "%s TCP object %d (hpux11)\n",
577
(ret < 0 ? "Failed to load" : "Loaded"), magic));
578
return (ret); /* 0: ok, < 0: error */
583
tcp_load(netsnmp_cache *cache, void *vmagic)
587
ret_value = linux_read_tcp_stat(&tcpstat);
589
if ( ret_value < 0 ) {
590
DEBUGMSGTL(("mibII/tcpScalar", "Failed to load TCP scalar Group (linux)\n"));
592
DEBUGMSGTL(("mibII/tcpScalar", "Loaded TCP scalar Group (linux)\n"));
599
tcp_load(netsnmp_cache *cache, void *vmagic)
602
int magic = (int)vmagic;
606
* tcpInErrs is actually implemented as part of the MIB_IP group
607
* so we need to retrieve this independently
609
if (magic == TCPINERRS) {
611
(MIB_IP, &ipstat, sizeof(mib2_ip_t), GET_FIRST,
612
&Get_everything, NULL) < 0) {
613
DEBUGMSGTL(("mibII/tcpScalar", "Failed to load TCP object %d (solaris)\n", magic));
616
DEBUGMSGTL(("mibII/tcpScalar", "Loaded TCP object %d (solaris)\n", magic));
617
return ipstat.tcpInErrs;
622
* Otherwise, retrieve the whole of the MIB_TCP group (and cache it)
624
ret_value = getMibstat(MIB_TCP, &tcpstat, sizeof(mib2_tcp_t),
625
GET_FIRST, &Get_everything, NULL);
627
if ( ret_value < 0 ) {
628
DEBUGMSGTL(("mibII/tcpScalar", "Failed to load TCP scalar Group (solaris)\n"));
630
DEBUGMSGTL(("mibII/tcpScalar", "Loaded TCP scalar Group (solaris)\n"));
637
tcp_load(netsnmp_cache *cache, void *vmagic)
641
ret_value = GetTcpStatistics(&tcpstat);
643
if ( ret_value < 0 ) {
644
DEBUGMSGTL(("mibII/tcpScalar", "Failed to load TCP scalar Group (win32)\n"));
646
DEBUGMSGTL(("mibII/tcpScalar", "Loaded TCP scalar Group (win32)\n"));
651
#if (defined(CAN_USE_SYSCTL) && defined(TCPCTL_STATS))
653
tcp_load(netsnmp_cache *cache, void *vmagic)
655
int sname[4] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS };
656
size_t len = sizeof(tcpstat);
659
ret_value = sysctl(sname, 4, &tcpstat, &len, 0, 0);
661
if ( ret_value < 0 ) {
662
DEBUGMSGTL(("mibII/tcpScalar", "Failed to load TCP scalar Group (sysctl)\n"));
664
DEBUGMSGTL(("mibII/tcpScalar", "Loaded TCP scalar Group (sysctl)\n"));
668
#else /* (defined(CAN_USE_SYSCTL) && defined(TCPCTL_STATS)) */
669
#ifdef HAVE_SYS_TCPIPSTATS_H
671
tcp_load(netsnmp_cache *cache, void *vmagic)
675
ret_value = sysmp(MP_SAGET, MPSA_TCPIPSTATS, &tcpstat, sizeof(tcpstat));
677
if ( ret_value < 0 ) {
678
DEBUGMSGTL(("mibII/tcpScalar", "Failed to load TCP scalar Group (tcpipstats)\n"));
680
DEBUGMSGTL(("mibII/tcpScalar", "Loaded TCP scalar Group (tcpipstats)\n"));
684
#else /* HAVE_SYS_TCPIPSTATS_H */
685
#ifdef TCPSTAT_SYMBOL
687
tcp_load(netsnmp_cache *cache, void *vmagic)
691
if (auto_nlist(TCPSTAT_SYMBOL, (char *)&tcpstat, sizeof(tcpstat)))
694
if ( ret_value < 0 ) {
695
DEBUGMSGTL(("mibII/tcpScalar", "Failed to load TCP scalar Group (tcpstat)\n"));
697
DEBUGMSGTL(("mibII/tcpScalar", "Loaded TCP scalar Group (tcpstat)\n"));
701
#else /* TCPSTAT_SYMBOL */
703
tcp_load(netsnmp_cache *cache, void *vmagic)
707
DEBUGMSGTL(("mibII/tcpScalar", "Failed to load TCP scalar Group (null)\n"));
710
#endif /* TCPSTAT_SYMBOL */
711
#endif /* HAVE_SYS_TCPIPSTATS_H */
712
#endif /* (defined(CAN_USE_SYSCTL) && defined(TCPCTL_STATS)) */
715
#endif /* solaris2 */
720
tcp_free(netsnmp_cache *cache, void *magic)
722
memset(&tcpstat, 0, sizeof(tcpstat));