/contrib/bsnmp/snmp_mibII/mibII_interfaces.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 542 lines · 392 code · 89 blank · 61 comment · 91 complexity · 1369dbe49c1ebfd683dba7244435c897 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_interfaces.c,v 1.17 2006/02/14 09:04:19 brandt_h Exp $
  30. *
  31. * Interfaces group.
  32. */
  33. #include "mibII.h"
  34. #include "mibII_oid.h"
  35. /*
  36. * This structure catches all changes to a interface entry
  37. */
  38. struct ifchange {
  39. struct snmp_dependency dep;
  40. u_int ifindex;
  41. uint32_t set;
  42. int promisc;
  43. int admin;
  44. int traps;
  45. uint32_t rb;
  46. int rb_flags;
  47. int rb_traps;
  48. };
  49. #define IFC_PROMISC 0x0001
  50. #define IFC_ADMIN 0x0002
  51. #define IFC_TRAPS 0x0004
  52. #define IFRB_FLAGS 0x0001
  53. #define IFRB_TRAPS 0x0002
  54. static const struct asn_oid
  55. oid_ifTable = OIDX_ifTable;
  56. /*
  57. * This function handles all changes to the interface table and interface
  58. * extension table.
  59. */
  60. static int
  61. ifchange_func(struct snmp_context *ctx __unused, struct snmp_dependency *dep,
  62. enum snmp_depop op)
  63. {
  64. struct ifchange *ifc = (struct ifchange *)dep;
  65. struct mibif *ifp;
  66. struct ifreq ifr, ifr1;
  67. if ((ifp = mib_find_if(ifc->ifindex)) == NULL)
  68. return (SNMP_ERR_NO_CREATION);
  69. switch (op) {
  70. case SNMP_DEPOP_COMMIT:
  71. strncpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
  72. if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr) == -1) {
  73. syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name);
  74. return (SNMP_ERR_GENERR);
  75. }
  76. if (ifc->set & IFC_PROMISC) {
  77. ifr.ifr_flags &= ~IFF_PROMISC;
  78. if (ifc->promisc)
  79. ifr.ifr_flags |= IFF_PROMISC;
  80. ifc->rb |= IFRB_FLAGS;
  81. }
  82. if (ifc->set & IFC_ADMIN) {
  83. ifr.ifr_flags &= ~IFF_UP;
  84. if (ifc->admin)
  85. ifr.ifr_flags |= IFF_UP;
  86. ifc->rb |= IFRB_FLAGS;
  87. }
  88. if (ifc->rb & IFRB_FLAGS) {
  89. strncpy(ifr1.ifr_name, ifp->name, sizeof(ifr1.ifr_name));
  90. if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr1) == -1) {
  91. syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name);
  92. return (SNMP_ERR_GENERR);
  93. }
  94. ifc->rb_flags = ifr1.ifr_flags;
  95. if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) {
  96. syslog(LOG_ERR, "SIFFLAGS(%s): %m", ifp->name);
  97. return (SNMP_ERR_GENERR);
  98. }
  99. (void)mib_fetch_ifmib(ifp);
  100. }
  101. if (ifc->set & IFC_TRAPS) {
  102. ifc->rb |= IFRB_TRAPS;
  103. ifc->rb_traps = ifp->trap_enable;
  104. ifp->trap_enable = ifc->traps;
  105. }
  106. return (SNMP_ERR_NOERROR);
  107. case SNMP_DEPOP_ROLLBACK:
  108. if (ifc->rb & IFRB_FLAGS) {
  109. strncpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
  110. ifr.ifr_flags = ifc->rb_flags;
  111. if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) {
  112. syslog(LOG_ERR, "SIFFLAGS(%s): %m", ifp->name);
  113. return (SNMP_ERR_UNDO_FAILED);
  114. }
  115. (void)mib_fetch_ifmib(ifp);
  116. }
  117. if (ifc->rb & IFRB_TRAPS)
  118. ifp->trap_enable = ifc->rb_traps;
  119. return (SNMP_ERR_NOERROR);
  120. case SNMP_DEPOP_FINISH:
  121. return (SNMP_ERR_NOERROR);
  122. }
  123. abort();
  124. }
  125. /*
  126. * Return difference to daemon start time in ticks truncated to a
  127. * 32-bit value. If the timeval is 0 then return 0.
  128. */
  129. static uint32_t
  130. ticks_get_timeval(struct timeval *tv)
  131. {
  132. uint64_t v;
  133. if (tv->tv_sec != 0 || tv->tv_usec != 0) {
  134. v = 100ULL * tv->tv_sec + tv->tv_usec / 10000ULL;
  135. if (v > start_tick)
  136. return (v - start_tick);
  137. }
  138. return (0);
  139. }
  140. /*
  141. * Scalars
  142. */
  143. int
  144. op_interfaces(struct snmp_context *ctx __unused, struct snmp_value *value,
  145. u_int sub, u_int idx __unused, enum snmp_op op)
  146. {
  147. switch (op) {
  148. case SNMP_OP_GETNEXT:
  149. abort();
  150. case SNMP_OP_GET:
  151. break;
  152. case SNMP_OP_SET:
  153. return (SNMP_ERR_NOT_WRITEABLE);
  154. case SNMP_OP_ROLLBACK:
  155. case SNMP_OP_COMMIT:
  156. abort();
  157. }
  158. switch (value->var.subs[sub - 1]) {
  159. case LEAF_ifNumber:
  160. value->v.integer = mib_if_number;
  161. break;
  162. }
  163. return (SNMP_ERR_NOERROR);
  164. }
  165. /*
  166. * Iftable entry
  167. */
  168. int
  169. op_ifentry(struct snmp_context *ctx, struct snmp_value *value,
  170. u_int sub, u_int iidx __unused, enum snmp_op op)
  171. {
  172. struct mibif *ifp = NULL;
  173. int ret;
  174. struct ifchange *ifc;
  175. struct asn_oid idx;
  176. switch (op) {
  177. case SNMP_OP_GETNEXT:
  178. if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL)
  179. return (SNMP_ERR_NOSUCHNAME);
  180. value->var.len = sub + 1;
  181. value->var.subs[sub] = ifp->index;
  182. break;
  183. case SNMP_OP_GET:
  184. if (value->var.len - sub != 1)
  185. return (SNMP_ERR_NOSUCHNAME);
  186. if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
  187. return (SNMP_ERR_NOSUCHNAME);
  188. break;
  189. case SNMP_OP_SET:
  190. if (value->var.len - sub != 1)
  191. return (SNMP_ERR_NO_CREATION);
  192. if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
  193. return (SNMP_ERR_NO_CREATION);
  194. if (value->var.subs[sub - 1] != LEAF_ifAdminStatus)
  195. return (SNMP_ERR_NOT_WRITEABLE);
  196. idx.len = 1;
  197. idx.subs[0] = ifp->index;
  198. if (value->v.integer != 1 && value->v.integer != 2)
  199. return (SNMP_ERR_WRONG_VALUE);
  200. if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx,
  201. &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL)
  202. return (SNMP_ERR_RES_UNAVAIL);
  203. ifc->ifindex = ifp->index;
  204. if (ifc->set & IFC_ADMIN)
  205. return (SNMP_ERR_INCONS_VALUE);
  206. ifc->set |= IFC_ADMIN;
  207. ifc->admin = (value->v.integer == 1) ? 1 : 0;
  208. return (SNMP_ERR_NOERROR);
  209. case SNMP_OP_ROLLBACK:
  210. case SNMP_OP_COMMIT:
  211. return (SNMP_ERR_NOERROR);
  212. }
  213. if (ifp->mibtick < this_tick)
  214. (void)mib_fetch_ifmib(ifp);
  215. ret = SNMP_ERR_NOERROR;
  216. switch (value->var.subs[sub - 1]) {
  217. case LEAF_ifIndex:
  218. value->v.integer = ifp->index;
  219. break;
  220. case LEAF_ifDescr:
  221. ret = string_get(value, ifp->descr, -1);
  222. break;
  223. case LEAF_ifType:
  224. value->v.integer = ifp->mib.ifmd_data.ifi_type;
  225. break;
  226. case LEAF_ifMtu:
  227. value->v.integer = ifp->mib.ifmd_data.ifi_mtu;
  228. break;
  229. case LEAF_ifSpeed:
  230. value->v.integer = ifp->mib.ifmd_data.ifi_baudrate;
  231. break;
  232. case LEAF_ifPhysAddress:
  233. ret = string_get(value, ifp->physaddr,
  234. ifp->physaddrlen);
  235. break;
  236. case LEAF_ifAdminStatus:
  237. value->v.integer =
  238. (ifp->mib.ifmd_flags & IFF_UP) ? 1 : 2;
  239. break;
  240. case LEAF_ifOperStatus:
  241. /*
  242. * According to RFC 2863 the state should be Up if the
  243. * interface is ready to transmit packets. We takes this to
  244. * mean that the interface should be running and should have
  245. * a carrier. If it is running and has no carrier we interpret
  246. * this as 'waiting for an external event' (plugging in the
  247. * cable) and hence return 'dormant'.
  248. */
  249. if (ifp->mib.ifmd_flags & IFF_RUNNING) {
  250. if (ifp->mib.ifmd_data.ifi_link_state != LINK_STATE_UP)
  251. value->v.integer = 5; /* state dormant */
  252. else
  253. value->v.integer = 1; /* state up */
  254. } else
  255. value->v.integer = 2; /* state down */
  256. break;
  257. case LEAF_ifLastChange:
  258. value->v.uint32 =
  259. ticks_get_timeval(&ifp->mib.ifmd_data.ifi_lastchange);
  260. break;
  261. case LEAF_ifInOctets:
  262. value->v.uint32 = ifp->mib.ifmd_data.ifi_ibytes;
  263. break;
  264. case LEAF_ifInUcastPkts:
  265. value->v.uint32 = ifp->mib.ifmd_data.ifi_ipackets -
  266. ifp->mib.ifmd_data.ifi_imcasts;
  267. break;
  268. case LEAF_ifInNUcastPkts:
  269. value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
  270. break;
  271. case LEAF_ifInDiscards:
  272. value->v.uint32 = ifp->mib.ifmd_data.ifi_iqdrops;
  273. break;
  274. case LEAF_ifInErrors:
  275. value->v.uint32 = ifp->mib.ifmd_data.ifi_ierrors;
  276. break;
  277. case LEAF_ifInUnknownProtos:
  278. value->v.uint32 = ifp->mib.ifmd_data.ifi_noproto;
  279. break;
  280. case LEAF_ifOutOctets:
  281. value->v.uint32 = ifp->mib.ifmd_data.ifi_obytes;
  282. break;
  283. case LEAF_ifOutUcastPkts:
  284. value->v.uint32 = ifp->mib.ifmd_data.ifi_opackets -
  285. ifp->mib.ifmd_data.ifi_omcasts;
  286. break;
  287. case LEAF_ifOutNUcastPkts:
  288. value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
  289. break;
  290. case LEAF_ifOutDiscards:
  291. value->v.uint32 = ifp->mib.ifmd_snd_drops;
  292. break;
  293. case LEAF_ifOutErrors:
  294. value->v.uint32 = ifp->mib.ifmd_data.ifi_oerrors;
  295. break;
  296. case LEAF_ifOutQLen:
  297. value->v.uint32 = ifp->mib.ifmd_snd_len;
  298. break;
  299. case LEAF_ifSpecific:
  300. value->v.oid = ifp->spec_oid;
  301. break;
  302. }
  303. return (SNMP_ERR_NOERROR);
  304. }
  305. /*
  306. * IfXtable entry
  307. */
  308. int
  309. op_ifxtable(struct snmp_context *ctx, struct snmp_value *value,
  310. u_int sub, u_int iidx __unused, enum snmp_op op)
  311. {
  312. struct mibif *ifp = NULL;
  313. int ret;
  314. struct ifchange *ifc;
  315. struct asn_oid idx;
  316. switch (op) {
  317. again:
  318. if (op != SNMP_OP_GETNEXT)
  319. return (SNMP_ERR_NOSUCHNAME);
  320. /* FALLTHROUGH */
  321. case SNMP_OP_GETNEXT:
  322. if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL)
  323. return (SNMP_ERR_NOSUCHNAME);
  324. value->var.len = sub + 1;
  325. value->var.subs[sub] = ifp->index;
  326. break;
  327. case SNMP_OP_GET:
  328. if (value->var.len - sub != 1)
  329. return (SNMP_ERR_NOSUCHNAME);
  330. if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
  331. return (SNMP_ERR_NOSUCHNAME);
  332. break;
  333. case SNMP_OP_SET:
  334. if (value->var.len - sub != 1)
  335. return (SNMP_ERR_NO_CREATION);
  336. if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
  337. return (SNMP_ERR_NO_CREATION);
  338. idx.len = 1;
  339. idx.subs[0] = ifp->index;
  340. if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx,
  341. &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL)
  342. return (SNMP_ERR_RES_UNAVAIL);
  343. ifc->ifindex = ifp->index;
  344. switch (value->var.subs[sub - 1]) {
  345. case LEAF_ifLinkUpDownTrapEnable:
  346. if (value->v.integer != 1 && value->v.integer != 2)
  347. return (SNMP_ERR_WRONG_VALUE);
  348. if (ifc->set & IFC_TRAPS)
  349. return (SNMP_ERR_INCONS_VALUE);
  350. ifc->set |= IFC_TRAPS;
  351. ifc->traps = (value->v.integer == 1) ? 1 : 0;
  352. return (SNMP_ERR_NOERROR);
  353. case LEAF_ifPromiscuousMode:
  354. if (value->v.integer != 1 && value->v.integer != 2)
  355. return (SNMP_ERR_WRONG_VALUE);
  356. if (ifc->set & IFC_PROMISC)
  357. return (SNMP_ERR_INCONS_VALUE);
  358. ifc->set |= IFC_PROMISC;
  359. ifc->promisc = (value->v.integer == 1) ? 1 : 0;
  360. return (SNMP_ERR_NOERROR);
  361. }
  362. return (SNMP_ERR_NOT_WRITEABLE);
  363. case SNMP_OP_ROLLBACK:
  364. case SNMP_OP_COMMIT:
  365. return (SNMP_ERR_NOERROR);
  366. }
  367. if (ifp->mibtick < this_tick)
  368. (void)mib_fetch_ifmib(ifp);
  369. ret = SNMP_ERR_NOERROR;
  370. switch (value->var.subs[sub - 1]) {
  371. case LEAF_ifName:
  372. ret = string_get(value, ifp->name, -1);
  373. break;
  374. case LEAF_ifInMulticastPkts:
  375. value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
  376. break;
  377. case LEAF_ifInBroadcastPkts:
  378. value->v.uint32 = 0;
  379. break;
  380. case LEAF_ifOutMulticastPkts:
  381. value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
  382. break;
  383. case LEAF_ifOutBroadcastPkts:
  384. value->v.uint32 = 0;
  385. break;
  386. case LEAF_ifHCInOctets:
  387. if (!(ifp->flags & MIBIF_HIGHSPEED))
  388. goto again;
  389. value->v.counter64 = MIBIF_PRIV(ifp)->hc_inoctets;
  390. break;
  391. case LEAF_ifHCInUcastPkts:
  392. if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
  393. goto again;
  394. value->v.counter64 = MIBIF_PRIV(ifp)->hc_ipackets -
  395. MIBIF_PRIV(ifp)->hc_imcasts;
  396. break;
  397. case LEAF_ifHCInMulticastPkts:
  398. if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
  399. goto again;
  400. value->v.counter64 = MIBIF_PRIV(ifp)->hc_imcasts;
  401. break;
  402. case LEAF_ifHCInBroadcastPkts:
  403. if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
  404. goto again;
  405. value->v.counter64 = 0;
  406. break;
  407. case LEAF_ifHCOutOctets:
  408. if (!(ifp->flags & MIBIF_HIGHSPEED))
  409. goto again;
  410. value->v.counter64 = MIBIF_PRIV(ifp)->hc_outoctets;
  411. break;
  412. case LEAF_ifHCOutUcastPkts:
  413. if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
  414. goto again;
  415. value->v.counter64 = MIBIF_PRIV(ifp)->hc_opackets -
  416. MIBIF_PRIV(ifp)->hc_omcasts;
  417. break;
  418. case LEAF_ifHCOutMulticastPkts:
  419. if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
  420. goto again;
  421. value->v.counter64 = MIBIF_PRIV(ifp)->hc_omcasts;
  422. break;
  423. case LEAF_ifHCOutBroadcastPkts:
  424. if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
  425. goto again;
  426. value->v.counter64 = 0;
  427. break;
  428. case LEAF_ifLinkUpDownTrapEnable:
  429. value->v.integer = ifp->trap_enable ? 1 : 2;
  430. break;
  431. case LEAF_ifHighSpeed:
  432. value->v.integer =
  433. (ifp->mib.ifmd_data.ifi_baudrate + 499999) / 1000000;
  434. break;
  435. case LEAF_ifPromiscuousMode:
  436. value->v.integer =
  437. (ifp->mib.ifmd_flags & IFF_PROMISC) ? 1 : 2;
  438. break;
  439. case LEAF_ifConnectorPresent:
  440. value->v.integer = ifp->has_connector ? 1 : 2;
  441. break;
  442. case LEAF_ifAlias:
  443. ret = string_get(value, "", -1);
  444. break;
  445. case LEAF_ifCounterDiscontinuityTime:
  446. if (ifp->counter_disc > start_tick)
  447. value->v.uint32 = ifp->counter_disc - start_tick;
  448. else
  449. value->v.uint32 = 0;
  450. break;
  451. }
  452. return (ret);
  453. }