mibII_interfaces.c revision 128237
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 of this software and documentation and use in source and
9 * binary forms, with or without modification, are permitted provided that
10 * the following conditions are met:
11 *
12 * 1. Redistributions of source code or documentation must retain the above
13 *    copyright notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
22 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
25 * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
28 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Begemot: bsnmp/snmp_mibII/mibII_interfaces.c,v 1.12 2004/04/13 15:19:59 novo Exp $
34 *
35 * Interfaces group.
36 */
37#include "mibII.h"
38#include "mibII_oid.h"
39
40/*
41 * This structure catches all changes to a interface entry
42 */
43struct ifchange {
44	struct snmp_dependency dep;
45
46	u_int		ifindex;
47
48	u_int32_t	set;
49	int		promisc;
50	int		admin;
51	int		traps;
52
53	u_int32_t	rb;
54	int		rb_flags;
55	int		rb_traps;
56};
57#define IFC_PROMISC	0x0001
58#define IFC_ADMIN	0x0002
59#define IFC_TRAPS	0x0004
60#define IFRB_FLAGS	0x0001
61#define IFRB_TRAPS	0x0002
62
63static const struct asn_oid
64	oid_ifTable = OIDX_ifTable;
65
66/*
67 * This function handles all changes to the interface table and interface
68 * extension table.
69 */
70static int
71ifchange_func(struct snmp_context *ctx __unused, struct snmp_dependency *dep,
72    enum snmp_depop op)
73{
74	struct ifchange *ifc = (struct ifchange *)dep;
75	struct mibif *ifp;
76	struct ifreq ifr, ifr1;
77
78	if ((ifp = mib_find_if(ifc->ifindex)) == NULL)
79		return (SNMP_ERR_NO_CREATION);
80
81	switch (op) {
82
83	  case SNMP_DEPOP_COMMIT:
84		strncpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
85		if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr) == -1) {
86			syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name);
87			return (SNMP_ERR_GENERR);
88		}
89		if (ifc->set & IFC_PROMISC) {
90			ifr.ifr_flags &= ~IFF_PROMISC;
91			if (ifc->promisc)
92				ifr.ifr_flags |= IFF_PROMISC;
93			ifc->rb |= IFRB_FLAGS;
94		}
95		if (ifc->set & IFC_ADMIN) {
96			ifr.ifr_flags &= ~IFF_UP;
97			if (ifc->admin)
98				ifr.ifr_flags |= IFF_UP;
99			ifc->rb |= IFRB_FLAGS;
100		}
101		if (ifc->rb & IFRB_FLAGS) {
102			strncpy(ifr1.ifr_name, ifp->name, sizeof(ifr1.ifr_name));
103			if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr1) == -1) {
104				syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name);
105				return (SNMP_ERR_GENERR);
106			}
107			ifc->rb_flags = ifr1.ifr_flags;
108			if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) {
109				syslog(LOG_ERR, "SIFFLAGS(%s): %m", ifp->name);
110				return (SNMP_ERR_GENERR);
111			}
112			(void)mib_fetch_ifmib(ifp);
113		}
114		if (ifc->set & IFC_TRAPS) {
115			ifc->rb |= IFRB_TRAPS;
116			ifc->rb_traps = ifp->trap_enable;
117			ifp->trap_enable = ifc->traps;
118		}
119		return (SNMP_ERR_NOERROR);
120
121	  case SNMP_DEPOP_ROLLBACK:
122		if (ifc->rb & IFRB_FLAGS) {
123			strncpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
124			ifr.ifr_flags = ifc->rb_flags;
125			if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) {
126				syslog(LOG_ERR, "SIFFLAGS(%s): %m", ifp->name);
127				return (SNMP_ERR_UNDO_FAILED);
128			}
129			(void)mib_fetch_ifmib(ifp);
130		}
131		if (ifc->rb & IFRB_TRAPS)
132			ifp->trap_enable = ifc->rb_traps;
133		return (SNMP_ERR_NOERROR);
134
135	  case SNMP_DEPOP_FINISH:
136		return (SNMP_ERR_NOERROR);
137
138	}
139	abort();
140}
141
142static u_int32_t
143ticks_get_timeval(struct timeval *tv)
144{
145	u_int32_t v;
146
147	if (tv->tv_sec != 0 || tv->tv_usec != 0) {
148		v = 100 * tv->tv_sec + tv->tv_usec / 10000;
149		if (v > start_tick)
150			return (v - start_tick);
151	}
152	return (0);
153}
154
155/*
156 * Scalars
157 */
158int
159op_interfaces(struct snmp_context *ctx __unused, struct snmp_value *value,
160    u_int sub, u_int idx __unused, enum snmp_op op)
161{
162	switch (op) {
163
164	  case SNMP_OP_GETNEXT:
165		abort();
166
167	  case SNMP_OP_GET:
168		break;
169
170	  case SNMP_OP_SET:
171		return (SNMP_ERR_NOT_WRITEABLE);
172
173	  case SNMP_OP_ROLLBACK:
174	  case SNMP_OP_COMMIT:
175		abort();
176	}
177
178	switch (value->var.subs[sub - 1]) {
179
180	  case LEAF_ifNumber:
181		value->v.integer = mib_if_number;
182		break;
183	}
184	return (SNMP_ERR_NOERROR);
185}
186
187/*
188 * Iftable entry
189 */
190int
191op_ifentry(struct snmp_context *ctx, struct snmp_value *value,
192    u_int sub, u_int iidx __unused, enum snmp_op op)
193{
194	struct mibif *ifp = NULL;
195	int ret;
196	struct ifchange *ifc;
197	struct asn_oid idx;
198
199	switch (op) {
200
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;
206		break;
207
208	  case SNMP_OP_GET:
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);
213		break;
214
215	  case SNMP_OP_SET:
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);
222
223		idx.len = 1;
224		idx.subs[0] = ifp->index;
225
226		if (value->v.integer != 1 && value->v.integer != 2)
227			return (SNMP_ERR_WRONG_VALUE);
228
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;
233
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;
238
239		return (SNMP_ERR_NOERROR);
240
241	  case SNMP_OP_ROLLBACK:
242	  case SNMP_OP_COMMIT:
243		return (SNMP_ERR_NOERROR);
244	}
245
246	if (ifp->mibtick < this_tick)
247		(void)mib_fetch_ifmib(ifp);
248
249	ret = SNMP_ERR_NOERROR;
250	switch (value->var.subs[sub - 1]) {
251
252	  case LEAF_ifIndex:
253		value->v.integer = ifp->index;
254		break;
255
256	  case LEAF_ifDescr:
257		ret = string_get(value, ifp->descr, -1);
258		break;
259
260	  case LEAF_ifType:
261		value->v.integer = ifp->mib.ifmd_data.ifi_type;
262		break;
263
264	  case LEAF_ifMtu:
265		value->v.integer = ifp->mib.ifmd_data.ifi_mtu;
266		break;
267
268	  case LEAF_ifSpeed:
269		value->v.integer = ifp->mib.ifmd_data.ifi_baudrate;
270		break;
271
272	  case LEAF_ifPhysAddress:
273		ret = string_get(value, ifp->physaddr,
274		    ifp->physaddrlen);
275		break;
276
277	  case LEAF_ifAdminStatus:
278		value->v.integer =
279		    (ifp->mib.ifmd_flags & IFF_UP) ? 1 : 2;
280		break;
281
282	  case LEAF_ifOperStatus:
283		value->v.integer =
284		    (ifp->mib.ifmd_flags & IFF_RUNNING) ? 1 : 2;
285		break;
286
287	  case LEAF_ifLastChange:
288		value->v.uint32 =
289		    ticks_get_timeval(&ifp->mib.ifmd_data.ifi_lastchange);
290		break;
291
292	  case LEAF_ifInOctets:
293		value->v.uint32 = ifp->mib.ifmd_data.ifi_ibytes;
294		break;
295
296	  case LEAF_ifInUcastPkts:
297		value->v.uint32 = ifp->mib.ifmd_data.ifi_ipackets -
298		    ifp->mib.ifmd_data.ifi_imcasts;
299		break;
300
301	  case LEAF_ifInNUcastPkts:
302		value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
303		break;
304
305	  case LEAF_ifInDiscards:
306		value->v.uint32 = ifp->mib.ifmd_data.ifi_iqdrops;
307		break;
308
309	  case LEAF_ifInErrors:
310		value->v.uint32 = ifp->mib.ifmd_data.ifi_ierrors;
311		break;
312
313	  case LEAF_ifInUnknownProtos:
314		value->v.uint32 = ifp->mib.ifmd_data.ifi_noproto;
315		break;
316
317	  case LEAF_ifOutOctets:
318		value->v.uint32 = ifp->mib.ifmd_data.ifi_obytes;
319		break;
320
321	  case LEAF_ifOutUcastPkts:
322		value->v.uint32 = ifp->mib.ifmd_data.ifi_opackets -
323		    ifp->mib.ifmd_data.ifi_omcasts;
324		break;
325
326	  case LEAF_ifOutNUcastPkts:
327		value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
328		break;
329
330	  case LEAF_ifOutDiscards:
331		value->v.uint32 = ifp->mib.ifmd_snd_drops;
332		break;
333
334	  case LEAF_ifOutErrors:
335		value->v.uint32 = ifp->mib.ifmd_data.ifi_oerrors;
336		break;
337
338	  case LEAF_ifOutQLen:
339		value->v.uint32 = ifp->mib.ifmd_snd_len;
340		break;
341
342	  case LEAF_ifSpecific:
343		value->v.oid = oid_zeroDotZero;
344		break;
345	}
346	return (SNMP_ERR_NOERROR);
347}
348
349/*
350 * IfXtable entry
351 */
352int
353op_ifxtable(struct snmp_context *ctx, struct snmp_value *value,
354    u_int sub, u_int iidx __unused, enum snmp_op op)
355{
356	struct mibif *ifp = NULL;
357	int ret;
358	struct ifchange *ifc;
359	struct asn_oid idx;
360
361	switch (op) {
362
363  again:
364		if (op != SNMP_OP_GETNEXT)
365			return (SNMP_ERR_NOSUCHNAME);
366		/* FALLTHROUGH */
367
368	  case SNMP_OP_GETNEXT:
369		if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL)
370			return (SNMP_ERR_NOSUCHNAME);
371		value->var.len = sub + 1;
372		value->var.subs[sub] = ifp->index;
373		break;
374
375	  case SNMP_OP_GET:
376		if (value->var.len - sub != 1)
377			return (SNMP_ERR_NOSUCHNAME);
378		if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
379			return (SNMP_ERR_NOSUCHNAME);
380		break;
381
382	  case SNMP_OP_SET:
383		if (value->var.len - sub != 1)
384			return (SNMP_ERR_NO_CREATION);
385		if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
386			return (SNMP_ERR_NO_CREATION);
387
388		idx.len = 1;
389		idx.subs[0] = ifp->index;
390
391		if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx,
392		    &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL)
393			return (SNMP_ERR_RES_UNAVAIL);
394		ifc->ifindex = ifp->index;
395
396		switch (value->var.subs[sub - 1]) {
397
398		  case LEAF_ifLinkUpDownTrapEnable:
399			if (value->v.integer != 1 && value->v.integer != 2)
400				return (SNMP_ERR_WRONG_VALUE);
401			if (ifc->set & IFC_TRAPS)
402				return (SNMP_ERR_INCONS_VALUE);
403			ifc->set |= IFC_TRAPS;
404			ifc->traps = (value->v.integer == 1) ? 1 : 0;
405			return (SNMP_ERR_NOERROR);
406
407		  case LEAF_ifPromiscuousMode:
408			if (value->v.integer != 1 && value->v.integer != 2)
409				return (SNMP_ERR_WRONG_VALUE);
410			if (ifc->set & IFC_PROMISC)
411				return (SNMP_ERR_INCONS_VALUE);
412			ifc->set |= IFC_PROMISC;
413			ifc->promisc = (value->v.integer == 1) ? 1 : 0;
414			return (SNMP_ERR_NOERROR);
415		}
416		return (SNMP_ERR_NOT_WRITEABLE);
417
418	  case SNMP_OP_ROLLBACK:
419	  case SNMP_OP_COMMIT:
420		return (SNMP_ERR_NOERROR);
421	}
422
423	if (ifp->mibtick < this_tick)
424		(void)mib_fetch_ifmib(ifp);
425
426	ret = SNMP_ERR_NOERROR;
427	switch (value->var.subs[sub - 1]) {
428
429	  case LEAF_ifName:
430		ret = string_get(value, ifp->name, -1);
431		break;
432
433	  case LEAF_ifInMulticastPkts:
434		value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
435		break;
436
437	  case LEAF_ifInBroadcastPkts:
438		value->v.uint32 = 0;
439		break;
440
441	  case LEAF_ifOutMulticastPkts:
442		value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
443		break;
444
445	  case LEAF_ifOutBroadcastPkts:
446		value->v.uint32 = 0;
447		break;
448
449	  case LEAF_ifHCInOctets:
450		if (!(ifp->flags & MIBIF_HIGHSPEED))
451			goto again;
452		value->v.counter64 = ifp->hc_inoctets;
453		break;
454
455	  case LEAF_ifHCInUcastPkts:
456		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
457			goto again;
458		value->v.counter64 = ifp->hc_ipackets - ifp->hc_imcasts;
459		break;
460
461	  case LEAF_ifHCInMulticastPkts:
462		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
463			goto again;
464		value->v.counter64 = ifp->hc_imcasts;
465		break;
466
467	  case LEAF_ifHCInBroadcastPkts:
468		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
469			goto again;
470		value->v.counter64 = 0;
471		break;
472
473	  case LEAF_ifHCOutOctets:
474		if (!(ifp->flags & MIBIF_HIGHSPEED))
475			goto again;
476		value->v.counter64 = ifp->hc_outoctets;
477		break;
478
479	  case LEAF_ifHCOutUcastPkts:
480		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
481			goto again;
482		value->v.counter64 = ifp->hc_opackets - ifp->hc_omcasts;
483		break;
484
485	  case LEAF_ifHCOutMulticastPkts:
486		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
487			goto again;
488		value->v.counter64 = ifp->hc_omcasts;
489		break;
490
491	  case LEAF_ifHCOutBroadcastPkts:
492		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
493			goto again;
494		value->v.counter64 = 0;
495		break;
496
497	  case LEAF_ifLinkUpDownTrapEnable:
498		value->v.integer = ifp->trap_enable ? 1 : 2;
499		break;
500
501	  case LEAF_ifHighSpeed:
502		value->v.integer =
503		    (ifp->mib.ifmd_data.ifi_baudrate + 499999) / 1000000;
504		break;
505
506	  case LEAF_ifPromiscuousMode:
507		value->v.integer =
508		    (ifp->mib.ifmd_flags & IFF_PROMISC) ? 1 : 2;
509		break;
510
511	  case LEAF_ifConnectorPresent:
512		value->v.integer = ifp->has_connector ? 1 : 2;
513		break;
514
515	  case LEAF_ifAlias:
516		ret = string_get(value, "", -1);
517		break;
518
519	  case LEAF_ifCounterDiscontinuityTime:
520		if (ifp->counter_disc > start_tick)
521			value->v.uint32 = ifp->counter_disc - start_tick;
522		else
523			value->v.uint32 = 0;
524		break;
525	}
526	return (ret);
527}
528