/contrib/bsnmp/snmp_mibII/mibII_tcp.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 359 lines · 273 code · 51 blank · 35 comment · 44 complexity · 735a6c8c43f79e935c070a35b1d4c737 MD5 · raw file

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