mibII_interfaces.c revision 142810
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.14 2005/02/25 16:04:42 brandt_h Exp $
30 *
31 * Interfaces group.
32 */
33#include "mibII.h"
34#include "mibII_oid.h"
35
36/*
37 * This structure catches all changes to a interface entry
38 */
39struct ifchange {
40	struct snmp_dependency dep;
41
42	u_int		ifindex;
43
44	uint32_t	set;
45	int		promisc;
46	int		admin;
47	int		traps;
48
49	uint32_t	rb;
50	int		rb_flags;
51	int		rb_traps;
52};
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
58
59static const struct asn_oid
60	oid_ifTable = OIDX_ifTable;
61
62/*
63 * This function handles all changes to the interface table and interface
64 * extension table.
65 */
66static int
67ifchange_func(struct snmp_context *ctx __unused, struct snmp_dependency *dep,
68    enum snmp_depop op)
69{
70	struct ifchange *ifc = (struct ifchange *)dep;
71	struct mibif *ifp;
72	struct ifreq ifr, ifr1;
73
74	if ((ifp = mib_find_if(ifc->ifindex)) == NULL)
75		return (SNMP_ERR_NO_CREATION);
76
77	switch (op) {
78
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);
84		}
85		if (ifc->set & IFC_PROMISC) {
86			ifr.ifr_flags &= ~IFF_PROMISC;
87			if (ifc->promisc)
88				ifr.ifr_flags |= IFF_PROMISC;
89			ifc->rb |= IFRB_FLAGS;
90		}
91		if (ifc->set & IFC_ADMIN) {
92			ifr.ifr_flags &= ~IFF_UP;
93			if (ifc->admin)
94				ifr.ifr_flags |= IFF_UP;
95			ifc->rb |= IFRB_FLAGS;
96		}
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);
102			}
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);
107			}
108			(void)mib_fetch_ifmib(ifp);
109		}
110		if (ifc->set & IFC_TRAPS) {
111			ifc->rb |= IFRB_TRAPS;
112			ifc->rb_traps = ifp->trap_enable;
113			ifp->trap_enable = ifc->traps;
114		}
115		return (SNMP_ERR_NOERROR);
116
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);
124			}
125			(void)mib_fetch_ifmib(ifp);
126		}
127		if (ifc->rb & IFRB_TRAPS)
128			ifp->trap_enable = ifc->rb_traps;
129		return (SNMP_ERR_NOERROR);
130
131	  case SNMP_DEPOP_FINISH:
132		return (SNMP_ERR_NOERROR);
133
134	}
135	abort();
136}
137
138static uint32_t
139ticks_get_timeval(struct timeval *tv)
140{
141	uint32_t v;
142
143	if (tv->tv_sec != 0 || tv->tv_usec != 0) {
144		v = 100 * tv->tv_sec + tv->tv_usec / 10000;
145		if (v > start_tick)
146			return (v - start_tick);
147	}
148	return (0);
149}
150
151/*
152 * Scalars
153 */
154int
155op_interfaces(struct snmp_context *ctx __unused, struct snmp_value *value,
156    u_int sub, u_int idx __unused, enum snmp_op op)
157{
158	switch (op) {
159
160	  case SNMP_OP_GETNEXT:
161		abort();
162
163	  case SNMP_OP_GET:
164		break;
165
166	  case SNMP_OP_SET:
167		return (SNMP_ERR_NOT_WRITEABLE);
168
169	  case SNMP_OP_ROLLBACK:
170	  case SNMP_OP_COMMIT:
171		abort();
172	}
173
174	switch (value->var.subs[sub - 1]) {
175
176	  case LEAF_ifNumber:
177		value->v.integer = mib_if_number;
178		break;
179	}
180	return (SNMP_ERR_NOERROR);
181}
182
183/*
184 * Iftable entry
185 */
186int
187op_ifentry(struct snmp_context *ctx, struct snmp_value *value,
188    u_int sub, u_int iidx __unused, enum snmp_op op)
189{
190	struct mibif *ifp = NULL;
191	int ret;
192	struct ifchange *ifc;
193	struct asn_oid idx;
194
195	switch (op) {
196
197	  case SNMP_OP_GETNEXT:
198		if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL)
199			return (SNMP_ERR_NOSUCHNAME);
200		value->var.len = sub + 1;
201		value->var.subs[sub] = ifp->index;
202		break;
203
204	  case SNMP_OP_GET:
205		if (value->var.len - sub != 1)
206			return (SNMP_ERR_NOSUCHNAME);
207		if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
208			return (SNMP_ERR_NOSUCHNAME);
209		break;
210
211	  case SNMP_OP_SET:
212		if (value->var.len - sub != 1)
213			return (SNMP_ERR_NO_CREATION);
214		if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
215			return (SNMP_ERR_NO_CREATION);
216		if (value->var.subs[sub - 1] != LEAF_ifAdminStatus)
217			return (SNMP_ERR_NOT_WRITEABLE);
218
219		idx.len = 1;
220		idx.subs[0] = ifp->index;
221
222		if (value->v.integer != 1 && value->v.integer != 2)
223			return (SNMP_ERR_WRONG_VALUE);
224
225		if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx,
226		    &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL)
227			return (SNMP_ERR_RES_UNAVAIL);
228		ifc->ifindex = ifp->index;
229
230		if (ifc->set & IFC_ADMIN)
231			return (SNMP_ERR_INCONS_VALUE);
232		ifc->set |= IFC_ADMIN;
233		ifc->admin = (value->v.integer == 1) ? 1 : 0;
234
235		return (SNMP_ERR_NOERROR);
236
237	  case SNMP_OP_ROLLBACK:
238	  case SNMP_OP_COMMIT:
239		return (SNMP_ERR_NOERROR);
240	}
241
242	if (ifp->mibtick < this_tick)
243		(void)mib_fetch_ifmib(ifp);
244
245	ret = SNMP_ERR_NOERROR;
246	switch (value->var.subs[sub - 1]) {
247
248	  case LEAF_ifIndex:
249		value->v.integer = ifp->index;
250		break;
251
252	  case LEAF_ifDescr:
253		ret = string_get(value, ifp->descr, -1);
254		break;
255
256	  case LEAF_ifType:
257		value->v.integer = ifp->mib.ifmd_data.ifi_type;
258		break;
259
260	  case LEAF_ifMtu:
261		value->v.integer = ifp->mib.ifmd_data.ifi_mtu;
262		break;
263
264	  case LEAF_ifSpeed:
265		value->v.integer = ifp->mib.ifmd_data.ifi_baudrate;
266		break;
267
268	  case LEAF_ifPhysAddress:
269		ret = string_get(value, ifp->physaddr,
270		    ifp->physaddrlen);
271		break;
272
273	  case LEAF_ifAdminStatus:
274		value->v.integer =
275		    (ifp->mib.ifmd_flags & IFF_UP) ? 1 : 2;
276		break;
277
278	  case LEAF_ifOperStatus:
279		value->v.integer =
280		    (ifp->mib.ifmd_flags & IFF_RUNNING) ? 1 : 2;
281		break;
282
283	  case LEAF_ifLastChange:
284		value->v.uint32 =
285		    ticks_get_timeval(&ifp->mib.ifmd_data.ifi_lastchange);
286		break;
287
288	  case LEAF_ifInOctets:
289		value->v.uint32 = ifp->mib.ifmd_data.ifi_ibytes;
290		break;
291
292	  case LEAF_ifInUcastPkts:
293		value->v.uint32 = ifp->mib.ifmd_data.ifi_ipackets -
294		    ifp->mib.ifmd_data.ifi_imcasts;
295		break;
296
297	  case LEAF_ifInNUcastPkts:
298		value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
299		break;
300
301	  case LEAF_ifInDiscards:
302		value->v.uint32 = ifp->mib.ifmd_data.ifi_iqdrops;
303		break;
304
305	  case LEAF_ifInErrors:
306		value->v.uint32 = ifp->mib.ifmd_data.ifi_ierrors;
307		break;
308
309	  case LEAF_ifInUnknownProtos:
310		value->v.uint32 = ifp->mib.ifmd_data.ifi_noproto;
311		break;
312
313	  case LEAF_ifOutOctets:
314		value->v.uint32 = ifp->mib.ifmd_data.ifi_obytes;
315		break;
316
317	  case LEAF_ifOutUcastPkts:
318		value->v.uint32 = ifp->mib.ifmd_data.ifi_opackets -
319		    ifp->mib.ifmd_data.ifi_omcasts;
320		break;
321
322	  case LEAF_ifOutNUcastPkts:
323		value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
324		break;
325
326	  case LEAF_ifOutDiscards:
327		value->v.uint32 = ifp->mib.ifmd_snd_drops;
328		break;
329
330	  case LEAF_ifOutErrors:
331		value->v.uint32 = ifp->mib.ifmd_data.ifi_oerrors;
332		break;
333
334	  case LEAF_ifOutQLen:
335		value->v.uint32 = ifp->mib.ifmd_snd_len;
336		break;
337
338	  case LEAF_ifSpecific:
339		value->v.oid = ifp->spec_oid;
340		break;
341	}
342	return (SNMP_ERR_NOERROR);
343}
344
345/*
346 * IfXtable entry
347 */
348int
349op_ifxtable(struct snmp_context *ctx, struct snmp_value *value,
350    u_int sub, u_int iidx __unused, enum snmp_op op)
351{
352	struct mibif *ifp = NULL;
353	int ret;
354	struct ifchange *ifc;
355	struct asn_oid idx;
356
357	switch (op) {
358
359  again:
360		if (op != SNMP_OP_GETNEXT)
361			return (SNMP_ERR_NOSUCHNAME);
362		/* FALLTHROUGH */
363
364	  case SNMP_OP_GETNEXT:
365		if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL)
366			return (SNMP_ERR_NOSUCHNAME);
367		value->var.len = sub + 1;
368		value->var.subs[sub] = ifp->index;
369		break;
370
371	  case SNMP_OP_GET:
372		if (value->var.len - sub != 1)
373			return (SNMP_ERR_NOSUCHNAME);
374		if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
375			return (SNMP_ERR_NOSUCHNAME);
376		break;
377
378	  case SNMP_OP_SET:
379		if (value->var.len - sub != 1)
380			return (SNMP_ERR_NO_CREATION);
381		if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
382			return (SNMP_ERR_NO_CREATION);
383
384		idx.len = 1;
385		idx.subs[0] = ifp->index;
386
387		if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx,
388		    &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL)
389			return (SNMP_ERR_RES_UNAVAIL);
390		ifc->ifindex = ifp->index;
391
392		switch (value->var.subs[sub - 1]) {
393
394		  case LEAF_ifLinkUpDownTrapEnable:
395			if (value->v.integer != 1 && value->v.integer != 2)
396				return (SNMP_ERR_WRONG_VALUE);
397			if (ifc->set & IFC_TRAPS)
398				return (SNMP_ERR_INCONS_VALUE);
399			ifc->set |= IFC_TRAPS;
400			ifc->traps = (value->v.integer == 1) ? 1 : 0;
401			return (SNMP_ERR_NOERROR);
402
403		  case LEAF_ifPromiscuousMode:
404			if (value->v.integer != 1 && value->v.integer != 2)
405				return (SNMP_ERR_WRONG_VALUE);
406			if (ifc->set & IFC_PROMISC)
407				return (SNMP_ERR_INCONS_VALUE);
408			ifc->set |= IFC_PROMISC;
409			ifc->promisc = (value->v.integer == 1) ? 1 : 0;
410			return (SNMP_ERR_NOERROR);
411		}
412		return (SNMP_ERR_NOT_WRITEABLE);
413
414	  case SNMP_OP_ROLLBACK:
415	  case SNMP_OP_COMMIT:
416		return (SNMP_ERR_NOERROR);
417	}
418
419	if (ifp->mibtick < this_tick)
420		(void)mib_fetch_ifmib(ifp);
421
422	ret = SNMP_ERR_NOERROR;
423	switch (value->var.subs[sub - 1]) {
424
425	  case LEAF_ifName:
426		ret = string_get(value, ifp->name, -1);
427		break;
428
429	  case LEAF_ifInMulticastPkts:
430		value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
431		break;
432
433	  case LEAF_ifInBroadcastPkts:
434		value->v.uint32 = 0;
435		break;
436
437	  case LEAF_ifOutMulticastPkts:
438		value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
439		break;
440
441	  case LEAF_ifOutBroadcastPkts:
442		value->v.uint32 = 0;
443		break;
444
445	  case LEAF_ifHCInOctets:
446		if (!(ifp->flags & MIBIF_HIGHSPEED))
447			goto again;
448		value->v.counter64 = ifp->hc_inoctets;
449		break;
450
451	  case LEAF_ifHCInUcastPkts:
452		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
453			goto again;
454		value->v.counter64 = ifp->hc_ipackets - ifp->hc_imcasts;
455		break;
456
457	  case LEAF_ifHCInMulticastPkts:
458		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
459			goto again;
460		value->v.counter64 = ifp->hc_imcasts;
461		break;
462
463	  case LEAF_ifHCInBroadcastPkts:
464		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
465			goto again;
466		value->v.counter64 = 0;
467		break;
468
469	  case LEAF_ifHCOutOctets:
470		if (!(ifp->flags & MIBIF_HIGHSPEED))
471			goto again;
472		value->v.counter64 = ifp->hc_outoctets;
473		break;
474
475	  case LEAF_ifHCOutUcastPkts:
476		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
477			goto again;
478		value->v.counter64 = ifp->hc_opackets - ifp->hc_omcasts;
479		break;
480
481	  case LEAF_ifHCOutMulticastPkts:
482		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
483			goto again;
484		value->v.counter64 = ifp->hc_omcasts;
485		break;
486
487	  case LEAF_ifHCOutBroadcastPkts:
488		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
489			goto again;
490		value->v.counter64 = 0;
491		break;
492
493	  case LEAF_ifLinkUpDownTrapEnable:
494		value->v.integer = ifp->trap_enable ? 1 : 2;
495		break;
496
497	  case LEAF_ifHighSpeed:
498		value->v.integer =
499		    (ifp->mib.ifmd_data.ifi_baudrate + 499999) / 1000000;
500		break;
501
502	  case LEAF_ifPromiscuousMode:
503		value->v.integer =
504		    (ifp->mib.ifmd_flags & IFF_PROMISC) ? 1 : 2;
505		break;
506
507	  case LEAF_ifConnectorPresent:
508		value->v.integer = ifp->has_connector ? 1 : 2;
509		break;
510
511	  case LEAF_ifAlias:
512		ret = string_get(value, "", -1);
513		break;
514
515	  case LEAF_ifCounterDiscontinuityTime:
516		if (ifp->counter_disc > start_tick)
517			value->v.uint32 = ifp->counter_disc - start_tick;
518		else
519			value->v.uint32 = 0;
520		break;
521	}
522	return (ret);
523}
524