www.usr.com/support/gpl/USR9113_release1.0.tar.gz
[bcm963xx.git] / userapps / opensource / net-snmp / agent / mibgroup / mibII / tcp.c
1 #ifdef SNMP_TCP_MIB
2 /*
3  *  TCP MIB group implementation - tcp.c
4  *
5  */
6
7 #include <net-snmp/net-snmp-config.h>
8
9 #if HAVE_STRING_H
10 #include <string.h>
11 #endif
12 #if HAVE_STDLIB_H
13 #include <stdlib.h>
14 #endif
15 #if HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif
18
19 #if HAVE_SYS_PARAM_H
20 #include <sys/param.h>
21 #endif
22 #if HAVE_SYS_PROTOSW_H
23 #include <sys/protosw.h>
24 #endif
25
26 #if HAVE_SYS_SYSMP_H
27 #include <sys/sysmp.h>
28 #endif
29 #if defined(IFNET_NEEDS_KERNEL) && !defined(_KERNEL)
30 #define _KERNEL 1
31 #define _I_DEFINED_KERNEL
32 #endif
33 #if HAVE_SYS_SOCKET_H
34 #include <sys/socket.h>
35 #endif
36 #if HAVE_WINSOCK_H
37 #include <winsock.h>
38 #endif
39 #if HAVE_NETINET_IN_H
40 #include <netinet/in.h>
41 #endif
42 #if HAVE_NET_IF_H
43 #include <net/if.h>
44 #endif
45 #if HAVE_NET_IF_VAR_H
46 #include <net/if_var.h>
47 #endif
48 #ifdef _I_DEFINED_KERNEL
49 #undef _KERNEL
50 #endif
51 #if HAVE_SYS_STREAM_H
52 #include <sys/stream.h>
53 #endif
54 #if HAVE_NET_ROUTE_H
55 #include <net/route.h>
56 #endif
57 #if HAVE_NETINET_IN_SYSTM_H
58 #include <netinet/in_systm.h>
59 #endif
60 #if HAVE_NETINET_IP_H
61 #include <netinet/ip.h>
62 #endif
63 #if HAVE_SYS_QUEUE_H
64 #include <sys/queue.h>
65 #endif
66 #if HAVE_NETINET_IP_VAR_H
67 #include <netinet/ip_var.h>
68 #endif
69 #ifdef INET6
70 #if HAVE_NETINET6_IP6_VAR_H
71 #include <netinet6/ip6_var.h>
72 #endif
73 #endif
74 #if HAVE_SYS_SOCKETVAR_H
75 #include <sys/socketvar.h>
76 #endif
77 #if HAVE_NETINET_IN_PCB_H
78 #include <netinet/in_pcb.h>
79 #endif
80 #if HAVE_INET_MIB2_H
81 #include <inet/mib2.h>
82 #endif
83
84 #if HAVE_SYS_SYSCTL_H
85 #include <sys/sysctl.h>
86 #endif
87 #if HAVE_ARPA_INET_H
88 #include <arpa/inet.h>
89 #endif
90
91 #if defined(osf4) || defined(aix4) || defined(hpux10)
92 /*
93  * these are undefed to remove a stupid warning on osf compilers
94  * because they get redefined with a slightly different notation of the
95  * same value.  -- Wes 
96  */
97 #undef TCP_NODELAY
98 #undef TCP_MAXSEG
99 #endif
100 #if HAVE_NETINET_TCP_H
101 #include <netinet/tcp.h>
102 #endif
103 #if HAVE_NETINET_TCPIP_H
104 #include <netinet/tcpip.h>
105 #endif
106 #if HAVE_NETINET_TCP_TIMER_H
107 #include <netinet/tcp_timer.h>
108 #endif
109 #if HAVE_NETINET_TCP_VAR_H
110 #include <netinet/tcp_var.h>
111 #endif
112 #if HAVE_NETINET_TCP_FSM_H
113 #include <netinet/tcp_fsm.h>
114 #endif
115 #if HAVE_SYS_TCPIPSTATS_H
116 #include <sys/tcpipstats.h>
117 #endif
118
119 #if HAVE_DMALLOC_H
120 #include <dmalloc.h>
121 #endif
122
123 #include <net-snmp/net-snmp-includes.h>
124 #include <net-snmp/agent/net-snmp-agent-includes.h>
125 #include <net-snmp/agent/auto_nlist.h>
126
127 #ifdef solaris2
128 #include "kernel_sunos5.h"
129 #else
130 #include "kernel.h"
131 #endif
132 #ifdef linux
133 #include "kernel_linux.h"
134 #endif
135 #include "util_funcs.h"
136
137 #ifdef hpux
138 #include <sys/mib.h>
139 #include <netinet/mib_kern.h>
140 #endif                          /* hpux */
141
142 #ifdef cygwin
143 #define WIN32
144 #include <windows.h>
145 #endif
146
147 #include "tcp.h"
148 #include "tcpTable.h"
149 #ifdef SNMP_SYSOR_MIB
150 #include "sysORTable.h"
151 #endif /* SNMP_SYSOR_MIB */
152
153 #ifndef MIB_STATS_CACHE_TIMEOUT
154 #define MIB_STATS_CACHE_TIMEOUT 5
155 #endif
156 #ifndef TCP_STATS_CACHE_TIMEOUT
157 #define TCP_STATS_CACHE_TIMEOUT MIB_STATS_CACHE_TIMEOUT
158 #endif
159 marker_t        tcp_stats_cache_marker = NULL;
160
161         /*********************
162          *
163          *  Kernel & interface information,
164          *   and internal forward declarations
165          *
166          *********************/
167
168 #ifdef freebsd4
169 static unsigned int hz;
170 #endif
171
172         /*********************
173          *
174          *  Initialisation & common implementation functions
175          *
176          *********************/
177
178 struct variable3 tcp_variables[] = {
179     {TCPRTOALGORITHM, ASN_INTEGER, RONLY, var_tcp, 1, {1}},
180     {TCPRTOMIN, ASN_INTEGER, RONLY, var_tcp, 1, {2}},
181 #ifndef sunV3
182     {TCPRTOMAX, ASN_INTEGER, RONLY, var_tcp, 1, {3}},
183 #endif
184     {TCPMAXCONN, ASN_INTEGER, RONLY, var_tcp, 1, {4}},
185 #ifndef sunV3
186     {TCPACTIVEOPENS, ASN_COUNTER, RONLY, var_tcp, 1, {5}},
187     {TCPPASSIVEOPENS, ASN_COUNTER, RONLY, var_tcp, 1, {6}},
188     {TCPATTEMPTFAILS, ASN_COUNTER, RONLY, var_tcp, 1, {7}},
189     {TCPESTABRESETS, ASN_COUNTER, RONLY, var_tcp, 1, {8}},
190 #endif
191     {TCPCURRESTAB, ASN_GAUGE, RONLY, var_tcp, 1, {9}},
192 #ifndef sunV3
193     {TCPINSEGS, ASN_COUNTER, RONLY, var_tcp, 1, {10}},
194     {TCPOUTSEGS, ASN_COUNTER, RONLY, var_tcp, 1, {11}},
195     {TCPRETRANSSEGS, ASN_COUNTER, RONLY, var_tcp, 1, {12}},
196 #endif
197 #ifdef WIN32
198     {TCPCONNSTATE, ASN_INTEGER, RWRITE, var_tcpEntry, 3, {13, 1, 1}},
199 #else
200     {TCPCONNSTATE, ASN_INTEGER, RONLY, var_tcpEntry, 3, {13, 1, 1}},
201 #endif
202     {TCPCONNLOCALADDRESS, ASN_IPADDRESS, RONLY, var_tcpEntry, 3,
203      {13, 1, 2}},
204     {TCPCONNLOCALPORT, ASN_INTEGER, RONLY, var_tcpEntry, 3, {13, 1, 3}},
205     {TCPCONNREMADDRESS, ASN_IPADDRESS, RONLY, var_tcpEntry, 3, {13, 1, 4}},
206     {TCPCONNREMPORT, ASN_INTEGER, RONLY, var_tcpEntry, 3, {13, 1, 5}},
207     {TCPINERRS, ASN_COUNTER, RONLY, var_tcp, 1, {14}},
208     {TCPOUTRSTS, ASN_COUNTER, RONLY, var_tcp, 1, {15}}
209 };
210
211 /*
212  * Define the OID pointer to the top of the mib tree that we're
213  * registering underneath, and the OID for the MIB module 
214  */
215 oid             tcp_variables_oid[] = { SNMP_OID_MIB2, 6 };
216 oid             tcp_module_oid[] = { SNMP_OID_MIB2, 49 };
217
218 void
219 init_tcp(void)
220 {
221     /*
222      * register ourselves with the agent to handle our mib tree 
223      */
224     REGISTER_MIB("mibII/tcp", tcp_variables, variable3,
225                  tcp_variables_oid);
226 #ifdef SNMP_SYSOR_MIB
227     REGISTER_SYSOR_ENTRY(tcp_module_oid,
228                          "The MIB module for managing TCP implementations");
229 #endif /* SNMP_SYSOR_MIB */
230 #ifdef TCPSTAT_SYMBOL
231     auto_nlist(TCPSTAT_SYMBOL, 0, 0);
232 #endif
233 #ifdef TCP_SYMBOL
234     auto_nlist(TCP_SYMBOL, 0, 0);
235 #endif
236 #if freebsd4
237     hz = sysconf(_SC_CLK_TCK);  /* get ticks/s from system */
238 #endif
239 #ifdef solaris2
240     init_kernel_sunos5();
241 #endif
242 }
243
244
245         /*********************
246          *
247          *  System specific implementation functions
248          *
249          *********************/
250
251 #ifdef linux
252 #define TCP_STAT_STRUCTURE      struct tcp_mib
253 #define USES_SNMP_DESIGNED_TCPSTAT
254 #undef TCPSTAT_SYMBOL
255 #endif
256
257 #ifdef solaris2
258 #define TCP_STAT_STRUCTURE      mib2_tcp_t
259 #define USES_SNMP_DESIGNED_TCPSTAT
260 #endif
261
262 #ifdef hpux11
263 #define TCP_STAT_STRUCTURE      int
264 #endif
265
266 #ifdef WIN32
267 #include <iphlpapi.h>
268 #define TCP_STAT_STRUCTURE     MIB_TCPSTATS
269 #endif
270
271 #ifdef HAVE_SYS_TCPIPSTATS_H
272 #define TCP_STAT_STRUCTURE      struct kna
273 #define USES_TRADITIONAL_TCPSTAT
274 #endif
275
276 #if !defined(TCP_STAT_STRUCTURE)
277 #define TCP_STAT_STRUCTURE      struct tcpstat
278 #define USES_TRADITIONAL_TCPSTAT
279 #endif
280
281 long            read_tcp_stat(TCP_STAT_STRUCTURE *, int);
282
283
284 u_char         *
285 var_tcp(struct variable *vp,
286         oid * name,
287         size_t * length,
288         int exact, size_t * var_len, WriteMethod ** write_method)
289 {
290     static TCP_STAT_STRUCTURE tcpstat;
291     static long     ret_value;
292 #ifdef TCPTV_NEEDS_HZ
293     /*
294      * I don't know of any such system now, but maybe they'll figure
295      * it out some day.
296      */
297     int             hz = 1000;
298 #endif
299
300     if (header_generic(vp, name, length, exact, var_len, write_method) ==
301         MATCH_FAILED)
302         return NULL;
303
304     ret_value = read_tcp_stat(&tcpstat, vp->magic);
305     if (ret_value < 0)
306         return NULL;
307
308 #ifdef HAVE_SYS_TCPIPSTATS_H
309     /*
310      * This actually reads statistics for *all* the groups together,
311      * so we need to isolate the TCP-specific bits.  
312      */
313 #define tcpstat          tcpstat.tcpstat
314 #endif
315
316     switch (vp->magic) {
317 #ifdef USES_SNMP_DESIGNED_TCPSTAT
318     case TCPRTOALGORITHM:
319         return (u_char *) & tcpstat.tcpRtoAlgorithm;
320     case TCPRTOMIN:
321         return (u_char *) & tcpstat.tcpRtoMin;
322     case TCPRTOMAX:
323         return (u_char *) & tcpstat.tcpRtoMax;
324     case TCPMAXCONN:
325         return (u_char *) & tcpstat.tcpMaxConn;
326     case TCPACTIVEOPENS:
327         return (u_char *) & tcpstat.tcpActiveOpens;
328     case TCPPASSIVEOPENS:
329         return (u_char *) & tcpstat.tcpPassiveOpens;
330     case TCPATTEMPTFAILS:
331         return (u_char *) & tcpstat.tcpAttemptFails;
332     case TCPESTABRESETS:
333         return (u_char *) & tcpstat.tcpEstabResets;
334     case TCPCURRESTAB:
335         return (u_char *) & tcpstat.tcpCurrEstab;
336     case TCPINSEGS:
337         return (u_char *) & tcpstat.tcpInSegs;
338     case TCPOUTSEGS:
339         return (u_char *) & tcpstat.tcpOutSegs;
340     case TCPRETRANSSEGS:
341         return (u_char *) & tcpstat.tcpRetransSegs;
342     case TCPINERRS:
343 #ifdef solaris2
344         return (u_char *) & ret_value;
345 #elif defined(linux)
346         if (tcpstat.tcpInErrsValid)
347             return (u_char *) & tcpstat.tcpInErrs;
348         return NULL;
349 #else
350         return NULL;
351 #endif
352     case TCPOUTRSTS:
353 #ifdef linux
354         if (tcpstat.tcpOutRstsValid)
355             return (u_char *) & tcpstat.tcpOutRsts;
356         return NULL;
357 #else
358         return NULL;
359 #endif
360 #endif
361
362 #ifdef USES_TRADITIONAL_TCPSTAT
363     case TCPRTOALGORITHM:      /* Assume Van Jacobsen's algorithm */
364         long_return = 4;
365         return (u_char *) & long_return;
366     case TCPRTOMIN:
367 #ifdef TCPTV_NEEDS_HZ
368         long_return = TCPTV_MIN;
369 #else
370         long_return = TCPTV_MIN / PR_SLOWHZ * 1000;
371 #endif
372         return (u_char *) & long_return;
373     case TCPRTOMAX:
374 #ifdef TCPTV_NEEDS_HZ
375         long_return = TCPTV_REXMTMAX;
376 #else
377         long_return = TCPTV_REXMTMAX / PR_SLOWHZ * 1000;
378 #endif
379         return (u_char *) & long_return;
380     case TCPMAXCONN:
381         return NULL;
382     case TCPACTIVEOPENS:
383         return (u_char *) & tcpstat.tcps_connattempt;
384     case TCPPASSIVEOPENS:
385         return (u_char *) & tcpstat.tcps_accepts;
386         /*
387          * NB:  tcps_drops is actually the sum of the two MIB
388          *      counters tcpAttemptFails and tcpEstabResets.
389          */
390     case TCPATTEMPTFAILS:
391         return (u_char *) & tcpstat.tcps_conndrops;
392     case TCPESTABRESETS:
393         return (u_char *) & tcpstat.tcps_drops;
394     case TCPCURRESTAB:
395         long_return = TCP_Count_Connections();
396         return (u_char *) & long_return;
397     case TCPINSEGS:
398         return (u_char *) & tcpstat.tcps_rcvtotal;
399     case TCPOUTSEGS:
400         /*
401          * RFC 1213 defines this as the number of segments sent
402          * "excluding those containing only retransmitted octets"
403          */
404         long_return = tcpstat.tcps_sndtotal - tcpstat.tcps_sndrexmitpack;
405         return (u_char *) & long_return;
406     case TCPRETRANSSEGS:
407         return (u_char *) & tcpstat.tcps_sndrexmitpack;
408     case TCPINERRS:
409         long_return = tcpstat.tcps_rcvbadsum + tcpstat.tcps_rcvbadoff
410 #ifdef STRUCT_TCPSTAT_HAS_TCPS_RCVMEMDROP
411             + tcpstat.tcps_rcvmemdrop
412 #endif
413             + tcpstat.tcps_rcvshort;
414         return (u_char *) & long_return;
415     case TCPOUTRSTS:
416         long_return = tcpstat.tcps_sndctrl - tcpstat.tcps_closed;
417         return (u_char *) & long_return;
418 #endif
419 #ifdef WIN32
420     case TCPRTOALGORITHM:
421         return (u_char *) & tcpstat.dwRtoAlgorithm;
422     case TCPRTOMIN:
423         return (u_char *) & tcpstat.dwRtoMin;
424     case TCPRTOMAX:
425         return (u_char *) & tcpstat.dwRtoMax;
426     case TCPMAXCONN:
427         return (u_char *) & tcpstat.dwMaxConn;
428     case TCPACTIVEOPENS:
429         return (u_char *) & tcpstat.dwActiveOpens;
430     case TCPPASSIVEOPENS:
431         return (u_char *) & tcpstat.dwPassiveOpens;
432     case TCPATTEMPTFAILS:
433         return (u_char *) & tcpstat.dwAttemptFails;
434     case TCPESTABRESETS:
435         return (u_char *) & tcpstat.dwEstabResets;
436     case TCPCURRESTAB:
437         return (u_char *) & tcpstat.dwCurrEstab;
438     case TCPINSEGS:
439         return (u_char *) & tcpstat.dwInSegs;
440     case TCPOUTSEGS:
441         return (u_char *) & tcpstat.dwOutSegs;
442     case TCPRETRANSSEGS:
443         return (u_char *) & tcpstat.dwRetransSegs;
444     case TCPINERRS:
445         return (u_char *) & tcpstat.dwInErrs;
446     case TCPOUTRSTS:
447         return (u_char *) & tcpstat.dwOutRsts;
448 #endif
449     default:
450         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_tcp\n", vp->magic));
451     }
452     return NULL;
453
454 #ifdef HAVE_SYS_TCPIPSTATS_H
455 #undef tcpstat
456 #endif
457 }
458
459
460         /*********************
461          *
462          *  Internal implementation functions
463          *
464          *********************/
465
466 long
467 read_tcp_stat(TCP_STAT_STRUCTURE * tcpstat, int magic)
468 {
469     long            ret_value = -1;
470 #if (defined(CAN_USE_SYSCTL) && defined(TCPCTL_STATS))
471     static int      sname[4] =
472         { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS };
473     size_t          len = sizeof(*tcpstat);
474 #endif
475 #ifdef solaris2
476     static mib2_ip_t ipstat;
477 #endif
478 #ifdef hpux11
479     int             fd;
480     struct nmparms  p;
481     unsigned int    ulen;
482     int             ret;
483
484     if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) < 0)
485         return (-1);            /* error */
486
487     switch (magic) {
488     case TCPRTOALGORITHM:
489         p.objid = ID_tcpRtoAlgorithm;
490         break;
491     case TCPRTOMIN:
492         p.objid = ID_tcpRtoMin;
493         break;
494     case TCPRTOMAX:
495         p.objid = ID_tcpRtoMax;
496         break;
497     case TCPMAXCONN:
498         p.objid = ID_tcpMaxConn;
499         break;
500     case TCPACTIVEOPENS:
501         p.objid = ID_tcpActiveOpens;
502         break;
503     case TCPPASSIVEOPENS:
504         p.objid = ID_tcpPassiveOpens;
505         break;
506     case TCPATTEMPTFAILS:
507         p.objid = ID_tcpAttemptFails;
508         break;
509     case TCPESTABRESETS:
510         p.objid = ID_tcpEstabResets;
511         break;
512     case TCPCURRESTAB:
513         p.objid = ID_tcpCurrEstab;
514         break;
515     case TCPINSEGS:
516         p.objid = ID_tcpInSegs;
517         break;
518     case TCPOUTSEGS:
519         p.objid = ID_tcpOutSegs;
520         break;
521     case TCPRETRANSSEGS:
522         p.objid = ID_tcpRetransSegs;
523         break;
524     case TCPINERRS:
525         p.objid = ID_tcpInErrs;
526         break;
527     case TCPOUTRSTS:
528         p.objid = ID_tcpOutRsts;
529         break;
530     default:
531         *tcpstat = 0;
532         close_mib(fd);
533         return (0);
534     }
535
536     p.buffer = (void *) tcpstat;
537     ulen = sizeof(TCP_STAT_STRUCTURE);
538     p.len = &ulen;
539     ret_value = get_mib_info(fd, &p);
540     close_mib(fd);
541
542     return (ret_value);         /* 0: ok, < 0: error */
543 #else                           /* hpux11 */
544
545     if (tcp_stats_cache_marker &&
546         (!atime_ready
547          (tcp_stats_cache_marker, TCP_STATS_CACHE_TIMEOUT * 1000)))
548 #ifdef solaris2
549         return (magic == TCPINERRS ? ipstat.tcpInErrs : 0);
550 #else
551         return 0;
552 #endif
553
554     if (tcp_stats_cache_marker)
555         atime_setMarker(tcp_stats_cache_marker);
556     else
557         tcp_stats_cache_marker = atime_newMarker();
558
559 #ifdef linux
560     ret_value = linux_read_tcp_stat(tcpstat);
561 #endif
562
563 #ifdef solaris2
564     if (magic == TCPINERRS) {
565         if (getMibstat
566             (MIB_IP, &ipstat, sizeof(mib2_ip_t), GET_FIRST,
567              &Get_everything, NULL) < 0)
568             ret_value = -1;
569         else
570             ret_value = ipstat.tcpInErrs;
571     } else
572         ret_value = getMibstat(MIB_TCP, tcpstat, sizeof(mib2_tcp_t),
573                                GET_FIRST, &Get_everything, NULL);
574 #endif
575
576 #ifdef WIN32
577     ret_value = GetTcpStatistics(tcpstat);
578 #endif
579
580 #ifdef HAVE_SYS_TCPIPSTATS_H
581     ret_value = sysmp(MP_SAGET, MPSA_TCPIPSTATS, tcpstat, sizeof *tcpstat);
582 #endif
583
584 #if defined(CAN_USE_SYSCTL) && defined(TCPCTL_STATS)
585     ret_value = sysctl(sname, 4, tcpstat, &len, 0, 0);
586 #endif
587
588 #ifdef TCPSTAT_SYMBOL
589     if (auto_nlist(TCPSTAT_SYMBOL, (char *) tcpstat, sizeof(*tcpstat)))
590         ret_value = 0;
591 #endif
592
593     if (ret_value == -1) {
594         free(tcp_stats_cache_marker);
595         tcp_stats_cache_marker = NULL;
596     }
597     return ret_value;
598 #endif                          /* hpux11 */
599 }
600
601 #else
602 void
603 init_tcp(void)
604 {
605   return;
606 }
607 #endif /* SNMP_TCP_MIB */