2 * Copyright (c) 2001-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Author: Harti Brandt <harti@freebsd.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
29 * $Begemot: bsnmp/snmp_mibII/mibII_interfaces.c,v 1.17 2006/02/14 09:04:19 brandt_h Exp $
34 #include "mibII_oid.h"
37 * This structure catches all changes to a interface entry
40 struct snmp_dependency dep;
53 #define IFC_PROMISC 0x0001
54 #define IFC_ADMIN 0x0002
55 #define IFC_TRAPS 0x0004
56 #define IFRB_FLAGS 0x0001
57 #define IFRB_TRAPS 0x0002
59 static const struct asn_oid
60 oid_ifTable = OIDX_ifTable;
63 * This function handles all changes to the interface table and interface
67 ifchange_func(struct snmp_context *ctx __unused, struct snmp_dependency *dep,
70 struct ifchange *ifc = (struct ifchange *)dep;
72 struct ifreq ifr, ifr1;
74 if ((ifp = mib_find_if(ifc->ifindex)) == NULL)
75 return (SNMP_ERR_NO_CREATION);
79 case SNMP_DEPOP_COMMIT:
80 strncpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
81 if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr) == -1) {
82 syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name);
83 return (SNMP_ERR_GENERR);
85 if (ifc->set & IFC_PROMISC) {
86 ifr.ifr_flags &= ~IFF_PROMISC;
88 ifr.ifr_flags |= IFF_PROMISC;
89 ifc->rb |= IFRB_FLAGS;
91 if (ifc->set & IFC_ADMIN) {
92 ifr.ifr_flags &= ~IFF_UP;
94 ifr.ifr_flags |= IFF_UP;
95 ifc->rb |= IFRB_FLAGS;
97 if (ifc->rb & IFRB_FLAGS) {
98 strncpy(ifr1.ifr_name, ifp->name, sizeof(ifr1.ifr_name));
99 if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr1) == -1) {
100 syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name);
101 return (SNMP_ERR_GENERR);
103 ifc->rb_flags = ifr1.ifr_flags;
104 if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) {
105 syslog(LOG_ERR, "SIFFLAGS(%s): %m", ifp->name);
106 return (SNMP_ERR_GENERR);
108 (void)mib_fetch_ifmib(ifp);
110 if (ifc->set & IFC_TRAPS) {
111 ifc->rb |= IFRB_TRAPS;
112 ifc->rb_traps = ifp->trap_enable;
113 ifp->trap_enable = ifc->traps;
115 return (SNMP_ERR_NOERROR);
117 case SNMP_DEPOP_ROLLBACK:
118 if (ifc->rb & IFRB_FLAGS) {
119 strncpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
120 ifr.ifr_flags = ifc->rb_flags;
121 if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) {
122 syslog(LOG_ERR, "SIFFLAGS(%s): %m", ifp->name);
123 return (SNMP_ERR_UNDO_FAILED);
125 (void)mib_fetch_ifmib(ifp);
127 if (ifc->rb & IFRB_TRAPS)
128 ifp->trap_enable = ifc->rb_traps;
129 return (SNMP_ERR_NOERROR);
131 case SNMP_DEPOP_FINISH:
132 return (SNMP_ERR_NOERROR);
139 * Return difference to daemon start time in ticks truncated to a
140 * 32-bit value. If the timeval is 0 then return 0.
143 ticks_get_timeval(struct timeval *tv)
147 if (tv->tv_sec != 0 || tv->tv_usec != 0) {
148 v = 100ULL * tv->tv_sec + tv->tv_usec / 10000ULL;
150 return (v - start_tick);
159 op_interfaces(struct snmp_context *ctx __unused, struct snmp_value *value,
160 u_int sub, u_int idx __unused, enum snmp_op op)
164 case SNMP_OP_GETNEXT:
171 return (SNMP_ERR_NOT_WRITEABLE);
173 case SNMP_OP_ROLLBACK:
178 switch (value->var.subs[sub - 1]) {
181 value->v.integer = mib_if_number;
184 return (SNMP_ERR_NOERROR);
191 op_ifentry(struct snmp_context *ctx, struct snmp_value *value,
192 u_int sub, u_int iidx __unused, enum snmp_op op)
194 struct mibif *ifp = NULL;
196 struct ifchange *ifc;
201 case SNMP_OP_GETNEXT:
202 if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL)
203 return (SNMP_ERR_NOSUCHNAME);
204 value->var.len = sub + 1;
205 value->var.subs[sub] = ifp->index;
209 if (value->var.len - sub != 1)
210 return (SNMP_ERR_NOSUCHNAME);
211 if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
212 return (SNMP_ERR_NOSUCHNAME);
216 if (value->var.len - sub != 1)
217 return (SNMP_ERR_NO_CREATION);
218 if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
219 return (SNMP_ERR_NO_CREATION);
220 if (value->var.subs[sub - 1] != LEAF_ifAdminStatus)
221 return (SNMP_ERR_NOT_WRITEABLE);
224 idx.subs[0] = ifp->index;
226 if (value->v.integer != 1 && value->v.integer != 2)
227 return (SNMP_ERR_WRONG_VALUE);
229 if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx,
230 &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL)
231 return (SNMP_ERR_RES_UNAVAIL);
232 ifc->ifindex = ifp->index;
234 if (ifc->set & IFC_ADMIN)
235 return (SNMP_ERR_INCONS_VALUE);
236 ifc->set |= IFC_ADMIN;
237 ifc->admin = (value->v.integer == 1) ? 1 : 0;
239 return (SNMP_ERR_NOERROR);
241 case SNMP_OP_ROLLBACK:
243 return (SNMP_ERR_NOERROR);
246 if (ifp->mibtick < this_tick)
247 (void)mib_fetch_ifmib(ifp);
249 ret = SNMP_ERR_NOERROR;
250 switch (value->var.subs[sub - 1]) {
253 value->v.integer = ifp->index;
257 ret = string_get(value, ifp->descr, -1);
261 value->v.integer = ifp->mib.ifmd_data.ifi_type;
265 value->v.integer = ifp->mib.ifmd_data.ifi_mtu;
269 value->v.integer = ifp->mib.ifmd_data.ifi_baudrate;
272 case LEAF_ifPhysAddress:
273 ret = string_get(value, ifp->physaddr,
277 case LEAF_ifAdminStatus:
279 (ifp->mib.ifmd_flags & IFF_UP) ? 1 : 2;
282 case LEAF_ifOperStatus:
284 * According to RFC 2863 the state should be Up if the
285 * interface is ready to transmit packets. We takes this to
286 * mean that the interface should be running and should have
287 * a carrier. If it is running and has no carrier we interpret
288 * this as 'waiting for an external event' (plugging in the
289 * cable) and hence return 'dormant'.
291 if (ifp->mib.ifmd_flags & IFF_RUNNING) {
292 if (ifp->mib.ifmd_data.ifi_link_state ==
294 value->v.integer = 5; /* state dormant */
296 value->v.integer = 1; /* state up */
298 value->v.integer = 2; /* state down */
301 case LEAF_ifLastChange:
303 ticks_get_timeval(&ifp->mib.ifmd_data.ifi_lastchange);
306 case LEAF_ifInOctets:
307 value->v.uint32 = ifp->mib.ifmd_data.ifi_ibytes;
310 case LEAF_ifInUcastPkts:
311 value->v.uint32 = ifp->mib.ifmd_data.ifi_ipackets -
312 ifp->mib.ifmd_data.ifi_imcasts;
315 case LEAF_ifInNUcastPkts:
316 value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
319 case LEAF_ifInDiscards:
320 value->v.uint32 = ifp->mib.ifmd_data.ifi_iqdrops;
323 case LEAF_ifInErrors:
324 value->v.uint32 = ifp->mib.ifmd_data.ifi_ierrors;
327 case LEAF_ifInUnknownProtos:
328 value->v.uint32 = ifp->mib.ifmd_data.ifi_noproto;
331 case LEAF_ifOutOctets:
332 value->v.uint32 = ifp->mib.ifmd_data.ifi_obytes;
335 case LEAF_ifOutUcastPkts:
336 value->v.uint32 = ifp->mib.ifmd_data.ifi_opackets -
337 ifp->mib.ifmd_data.ifi_omcasts;
340 case LEAF_ifOutNUcastPkts:
341 value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
344 case LEAF_ifOutDiscards:
345 value->v.uint32 = ifp->mib.ifmd_snd_drops;
348 case LEAF_ifOutErrors:
349 value->v.uint32 = ifp->mib.ifmd_data.ifi_oerrors;
353 value->v.uint32 = ifp->mib.ifmd_snd_len;
356 case LEAF_ifSpecific:
357 value->v.oid = ifp->spec_oid;
360 return (SNMP_ERR_NOERROR);
367 op_ifxtable(struct snmp_context *ctx, struct snmp_value *value,
368 u_int sub, u_int iidx __unused, enum snmp_op op)
370 struct mibif *ifp = NULL;
372 struct ifchange *ifc;
378 if (op != SNMP_OP_GETNEXT)
379 return (SNMP_ERR_NOSUCHNAME);
382 case SNMP_OP_GETNEXT:
383 if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL)
384 return (SNMP_ERR_NOSUCHNAME);
385 value->var.len = sub + 1;
386 value->var.subs[sub] = ifp->index;
390 if (value->var.len - sub != 1)
391 return (SNMP_ERR_NOSUCHNAME);
392 if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
393 return (SNMP_ERR_NOSUCHNAME);
397 if (value->var.len - sub != 1)
398 return (SNMP_ERR_NO_CREATION);
399 if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
400 return (SNMP_ERR_NO_CREATION);
403 idx.subs[0] = ifp->index;
405 if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx,
406 &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL)
407 return (SNMP_ERR_RES_UNAVAIL);
408 ifc->ifindex = ifp->index;
410 switch (value->var.subs[sub - 1]) {
412 case LEAF_ifLinkUpDownTrapEnable:
413 if (value->v.integer != 1 && value->v.integer != 2)
414 return (SNMP_ERR_WRONG_VALUE);
415 if (ifc->set & IFC_TRAPS)
416 return (SNMP_ERR_INCONS_VALUE);
417 ifc->set |= IFC_TRAPS;
418 ifc->traps = (value->v.integer == 1) ? 1 : 0;
419 return (SNMP_ERR_NOERROR);
421 case LEAF_ifPromiscuousMode:
422 if (value->v.integer != 1 && value->v.integer != 2)
423 return (SNMP_ERR_WRONG_VALUE);
424 if (ifc->set & IFC_PROMISC)
425 return (SNMP_ERR_INCONS_VALUE);
426 ifc->set |= IFC_PROMISC;
427 ifc->promisc = (value->v.integer == 1) ? 1 : 0;
428 return (SNMP_ERR_NOERROR);
430 return (SNMP_ERR_NOT_WRITEABLE);
432 case SNMP_OP_ROLLBACK:
434 return (SNMP_ERR_NOERROR);
437 if (ifp->mibtick < this_tick)
438 (void)mib_fetch_ifmib(ifp);
440 ret = SNMP_ERR_NOERROR;
441 switch (value->var.subs[sub - 1]) {
444 ret = string_get(value, ifp->name, -1);
447 case LEAF_ifInMulticastPkts:
448 value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
451 case LEAF_ifInBroadcastPkts:
455 case LEAF_ifOutMulticastPkts:
456 value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
459 case LEAF_ifOutBroadcastPkts:
463 case LEAF_ifHCInOctets:
464 if (!(ifp->flags & MIBIF_HIGHSPEED))
466 value->v.counter64 = MIBIF_PRIV(ifp)->hc_inoctets;
469 case LEAF_ifHCInUcastPkts:
470 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
472 value->v.counter64 = MIBIF_PRIV(ifp)->hc_ipackets -
473 MIBIF_PRIV(ifp)->hc_imcasts;
476 case LEAF_ifHCInMulticastPkts:
477 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
479 value->v.counter64 = MIBIF_PRIV(ifp)->hc_imcasts;
482 case LEAF_ifHCInBroadcastPkts:
483 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
485 value->v.counter64 = 0;
488 case LEAF_ifHCOutOctets:
489 if (!(ifp->flags & MIBIF_HIGHSPEED))
491 value->v.counter64 = MIBIF_PRIV(ifp)->hc_outoctets;
494 case LEAF_ifHCOutUcastPkts:
495 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
497 value->v.counter64 = MIBIF_PRIV(ifp)->hc_opackets -
498 MIBIF_PRIV(ifp)->hc_omcasts;
501 case LEAF_ifHCOutMulticastPkts:
502 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
504 value->v.counter64 = MIBIF_PRIV(ifp)->hc_omcasts;
507 case LEAF_ifHCOutBroadcastPkts:
508 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
510 value->v.counter64 = 0;
513 case LEAF_ifLinkUpDownTrapEnable:
514 value->v.integer = ifp->trap_enable ? 1 : 2;
517 case LEAF_ifHighSpeed:
519 (ifp->mib.ifmd_data.ifi_baudrate + 499999) / 1000000;
522 case LEAF_ifPromiscuousMode:
524 (ifp->mib.ifmd_flags & IFF_PROMISC) ? 1 : 2;
527 case LEAF_ifConnectorPresent:
528 value->v.integer = ifp->has_connector ? 1 : 2;
532 ret = string_get(value, "", -1);
535 case LEAF_ifCounterDiscontinuityTime:
536 if (ifp->counter_disc > start_tick)
537 value->v.uint32 = ifp->counter_disc - start_tick;