mibII_interfaces.c revision 122394
165185Sache/*
265185Sache * Copyright (c) 2001-2003
365185Sache *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
465185Sache *	All rights reserved.
565185Sache *
665185Sache * Author: Harti Brandt <harti@freebsd.org>
765185Sache *
865185Sache * Redistribution of this software and documentation and use in source and
965185Sache * binary forms, with or without modification, are permitted provided that
1065185Sache * the following conditions are met:
1165185Sache *
1265185Sache * 1. Redistributions of source code or documentation must retain the above
1365185Sache *    copyright notice, this list of conditions and the following disclaimer.
1465185Sache * 2. Redistributions in binary form must reproduce the above copyright
1565185Sache *    notice, this list of conditions and the following disclaimer in the
1665185Sache *    documentation and/or other materials provided with the distribution.
1765185Sache * 3. Neither the name of the Institute nor the names of its contributors
1865185Sache *    may be used to endorse or promote products derived from this software
1965185Sache *    without specific prior written permission.
2065185Sache *
2165185Sache * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
2265185Sache * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
2365185Sache * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
2465185Sache * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
2565185Sache * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
2665185Sache * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2765185Sache * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
2865185Sache * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
2965185Sache * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3065185Sache * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
3165185Sache * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3265185Sache *
3365185Sache * $Begemot: bsnmp/snmp_mibII/mibII_interfaces.c,v 1.9 2003/01/28 13:44:35 hbb Exp $
3465185Sache *
3565185Sache * Interfaces group.
3665185Sache */
3765185Sache#include "mibII.h"
3865185Sache#include "mibII_oid.h"
3965185Sache
4065185Sache/*
4165185Sache * This structure catches all changes to a interface entry
4265185Sache */
4365185Sachestruct ifchange {
4465185Sache	struct snmp_dependency dep;
4565185Sache
4665185Sache	u_int		ifindex;
4765185Sache
4865185Sache	u_int32_t	set;
4965185Sache	int		promisc;
5065185Sache	int		admin;
5165185Sache	int		traps;
5265185Sache
5365185Sache	u_int32_t	rb;
5465185Sache	int		rb_flags;
5565185Sache	int		rb_traps;
5665185Sache};
5765185Sache#define IFC_PROMISC	0x0001
5865185Sache#define IFC_ADMIN	0x0002
5965185Sache#define IFC_TRAPS	0x0004
6065185Sache#define IFRB_FLAGS	0x0001
6165185Sache#define IFRB_TRAPS	0x0002
6265185Sache
6365185Sachestatic const struct asn_oid
6465185Sache	oid_ifTable = OIDX_ifTable;
6565185Sache
6665185Sache/*
6765185Sache * This function handles all changes to the interface table and interface
6865185Sache * extension table.
6965185Sache */
7065185Sachestatic int
7165185Sacheifchange_func(struct snmp_context *ctx __unused, struct snmp_dependency *dep,
7265185Sache    enum snmp_depop op)
7365185Sache{
7465185Sache	struct ifchange *ifc = (struct ifchange *)dep;
7565185Sache	struct mibif *ifp;
7665185Sache	struct ifreq ifr, ifr1;
7765185Sache
7865185Sache	if ((ifp = mib_find_if(ifc->ifindex)) == NULL)
7965185Sache		return (SNMP_ERR_NO_CREATION);
8065185Sache
8165185Sache	switch (op) {
8265185Sache
8365185Sache	  case SNMP_DEPOP_COMMIT:
8465185Sache		strncpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
8565185Sache		if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr) == -1) {
8665185Sache			syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name);
8765185Sache			return (SNMP_ERR_GENERR);
8865185Sache		}
8965185Sache		if (ifc->set & IFC_PROMISC) {
9065185Sache			ifr.ifr_flags &= ~IFF_PROMISC;
9165185Sache			if (ifc->promisc)
9265185Sache				ifr.ifr_flags |= IFF_PROMISC;
9365185Sache			ifc->rb |= IFRB_FLAGS;
9465185Sache		}
9565185Sache		if (ifc->set & IFC_ADMIN) {
9665185Sache			ifr.ifr_flags &= ~IFF_UP;
9765185Sache			if (ifc->admin)
9874119Sache				ifr.ifr_flags |= IFF_UP;
9965185Sache			ifc->rb |= IFRB_FLAGS;
10065185Sache		}
10165185Sache		if (ifc->rb & IFRB_FLAGS) {
10265185Sache			strncpy(ifr1.ifr_name, ifp->name, sizeof(ifr1.ifr_name));
10365185Sache			if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr1) == -1) {
10465185Sache				syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name);
10565185Sache				return (SNMP_ERR_GENERR);
10665185Sache			}
10765185Sache			ifc->rb_flags = ifr1.ifr_flags;
10874119Sache			if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) {
10965185Sache				syslog(LOG_ERR, "SIFFLAGS(%s): %m", ifp->name);
11065185Sache				return (SNMP_ERR_GENERR);
11165185Sache			}
11265185Sache			(void)mib_fetch_ifmib(ifp);
11365185Sache		}
11465185Sache		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	}
136	abort();
137}
138
139static u_int32_t
140ticks_get_timeval(struct timeval *tv)
141{
142	u_int32_t v;
143
144	if (tv->tv_sec != 0 || tv->tv_usec != 0) {
145		v = 100 * tv->tv_sec + tv->tv_usec / 10000;
146		if (v > start_tick)
147			return (v - start_tick);
148	}
149	return (0);
150}
151
152/*
153 * Scalars
154 */
155int
156op_interfaces(struct snmp_context *ctx __unused, struct snmp_value *value,
157    u_int sub, u_int idx __unused, enum snmp_op op)
158{
159	switch (op) {
160
161	  case SNMP_OP_GETNEXT:
162		abort();
163
164	  case SNMP_OP_GET:
165		break;
166
167	  case SNMP_OP_SET:
168		return (SNMP_ERR_NOT_WRITEABLE);
169
170	  case SNMP_OP_ROLLBACK:
171	  case SNMP_OP_COMMIT:
172		abort();
173	}
174
175	switch (value->var.subs[sub - 1]) {
176
177	  case LEAF_ifNumber:
178		value->v.integer = mib_if_number;
179		break;
180	}
181	return (SNMP_ERR_NOERROR);
182}
183
184/*
185 * Iftable entry
186 */
187int
188op_ifentry(struct snmp_context *ctx, struct snmp_value *value,
189    u_int sub, u_int iidx __unused, enum snmp_op op)
190{
191	struct mibif *ifp = NULL;
192	int ret;
193	struct ifchange *ifc;
194	struct asn_oid idx;
195
196	switch (op) {
197
198	  case SNMP_OP_GETNEXT:
199		if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL)
200			return (SNMP_ERR_NOSUCHNAME);
201		value->var.len = sub + 1;
202		value->var.subs[sub] = ifp->index;
203		break;
204
205	  case SNMP_OP_GET:
206		if (value->var.len - sub != 1)
207			return (SNMP_ERR_NOSUCHNAME);
208		if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
209			return (SNMP_ERR_NOSUCHNAME);
210		break;
211
212	  case SNMP_OP_SET:
213		if (value->var.len - sub != 1)
214			return (SNMP_ERR_NO_CREATION);
215		if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
216			return (SNMP_ERR_NO_CREATION);
217		if (value->var.subs[sub - 1] != LEAF_ifAdminStatus)
218			return (SNMP_ERR_NOT_WRITEABLE);
219
220		idx.len = 1;
221		idx.subs[0] = ifp->index;
222
223		if (value->v.integer != 1 && value->v.integer != 2)
224			return (SNMP_ERR_WRONG_VALUE);
225
226		if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx,
227		    &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL)
228			return (SNMP_ERR_RES_UNAVAIL);
229		ifc->ifindex = ifp->index;
230
231		if (ifc->set & IFC_ADMIN)
232			return (SNMP_ERR_INCONS_VALUE);
233		ifc->set |= IFC_ADMIN;
234		ifc->admin = (value->v.integer == 1) ? 1 : 0;
235
236		return (SNMP_ERR_NOERROR);
237
238	  case SNMP_OP_ROLLBACK:
239	  case SNMP_OP_COMMIT:
240		return (SNMP_ERR_NOERROR);
241	}
242
243	if (ifp->mibtick < this_tick)
244		(void)mib_fetch_ifmib(ifp);
245
246	ret = SNMP_ERR_NOERROR;
247	switch (value->var.subs[sub - 1]) {
248
249	  case LEAF_ifIndex:
250		value->v.integer = ifp->index;
251		break;
252
253	  case LEAF_ifDescr:
254		ret = string_get(value, ifp->descr, -1);
255		break;
256
257	  case LEAF_ifType:
258		value->v.integer = ifp->mib.ifmd_data.ifi_type;
259		break;
260
261	  case LEAF_ifMtu:
262		value->v.integer = ifp->mib.ifmd_data.ifi_mtu;
263		break;
264
265	  case LEAF_ifSpeed:
266		value->v.integer = ifp->mib.ifmd_data.ifi_baudrate;
267		break;
268
269	  case LEAF_ifPhysAddress:
270		ret = string_get(value, ifp->physaddr,
271		    ifp->physaddrlen);
272		break;
273
274	  case LEAF_ifAdminStatus:
275		value->v.integer =
276		    (ifp->mib.ifmd_flags & IFF_UP) ? 1 : 2;
277		break;
278
279	  case LEAF_ifOperStatus:
280		value->v.integer =
281		    (ifp->mib.ifmd_flags & IFF_RUNNING) ? 1 : 2;
282		break;
283
284	  case LEAF_ifLastChange:
285		value->v.uint32 =
286		    ticks_get_timeval(&ifp->mib.ifmd_data.ifi_lastchange);
287		break;
288
289	  case LEAF_ifInOctets:
290		value->v.uint32 = ifp->mib.ifmd_data.ifi_ibytes;
291		break;
292
293	  case LEAF_ifInUcastPkts:
294		value->v.uint32 = ifp->mib.ifmd_data.ifi_ipackets -
295		    ifp->mib.ifmd_data.ifi_imcasts;
296		break;
297
298	  case LEAF_ifInNUcastPkts:
299		value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
300		break;
301
302	  case LEAF_ifInDiscards:
303		value->v.uint32 = ifp->mib.ifmd_data.ifi_iqdrops;
304		break;
305
306	  case LEAF_ifInErrors:
307		value->v.uint32 = ifp->mib.ifmd_data.ifi_ierrors;
308		break;
309
310	  case LEAF_ifInUnknownProtos:
311		value->v.uint32 = ifp->mib.ifmd_data.ifi_noproto;
312		break;
313
314	  case LEAF_ifOutOctets:
315		value->v.uint32 = ifp->mib.ifmd_data.ifi_obytes;
316		break;
317
318	  case LEAF_ifOutUcastPkts:
319		value->v.uint32 = ifp->mib.ifmd_data.ifi_opackets -
320		    ifp->mib.ifmd_data.ifi_omcasts;
321		break;
322
323	  case LEAF_ifOutNUcastPkts:
324		value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
325		break;
326
327	  case LEAF_ifOutDiscards:
328		value->v.uint32 = ifp->mib.ifmd_snd_drops;
329		break;
330
331	  case LEAF_ifOutErrors:
332		value->v.uint32 = ifp->mib.ifmd_data.ifi_oerrors;
333		break;
334
335	  case LEAF_ifOutQLen:
336		value->v.uint32 = ifp->mib.ifmd_snd_len;
337		break;
338
339	  case LEAF_ifSpecific:
340		value->v.oid = oid_zeroDotZero;
341		break;
342	}
343	return (SNMP_ERR_NOERROR);
344}
345
346/*
347 * IfXtable entry
348 */
349int
350op_ifxtable(struct snmp_context *ctx, struct snmp_value *value,
351    u_int sub, u_int iidx __unused, enum snmp_op op)
352{
353	struct mibif *ifp = NULL;
354	int ret;
355	struct ifchange *ifc;
356	struct asn_oid idx;
357
358	switch (op) {
359
360  again:
361		if (op != SNMP_OP_GETNEXT)
362			return (SNMP_ERR_NOSUCHNAME);
363		/* FALLTHROUGH */
364
365	  case SNMP_OP_GETNEXT:
366		if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL)
367			return (SNMP_ERR_NOSUCHNAME);
368		value->var.len = sub + 1;
369		value->var.subs[sub] = ifp->index;
370		break;
371
372	  case SNMP_OP_GET:
373		if (value->var.len - sub != 1)
374			return (SNMP_ERR_NOSUCHNAME);
375		if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
376			return (SNMP_ERR_NOSUCHNAME);
377		break;
378
379	  case SNMP_OP_SET:
380		if (value->var.len - sub != 1)
381			return (SNMP_ERR_NO_CREATION);
382		if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
383			return (SNMP_ERR_NO_CREATION);
384
385		idx.len = 1;
386		idx.subs[0] = ifp->index;
387
388		if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx,
389		    &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL)
390			return (SNMP_ERR_RES_UNAVAIL);
391		ifc->ifindex = ifp->index;
392
393		switch (value->var.subs[sub - 1]) {
394
395		  case LEAF_ifLinkUpDownTrapEnable:
396			if (value->v.integer != 1 && value->v.integer != 2)
397				return (SNMP_ERR_WRONG_VALUE);
398			if (ifc->set & IFC_TRAPS)
399				return (SNMP_ERR_INCONS_VALUE);
400			ifc->set |= IFC_TRAPS;
401			ifc->traps = (value->v.integer == 1) ? 1 : 0;
402			return (SNMP_ERR_NOERROR);
403
404		  case LEAF_ifPromiscuousMode:
405			if (value->v.integer != 1 && value->v.integer != 2)
406				return (SNMP_ERR_WRONG_VALUE);
407			if (ifc->set & IFC_PROMISC)
408				return (SNMP_ERR_INCONS_VALUE);
409			ifc->set |= IFC_PROMISC;
410			ifc->promisc = (value->v.integer == 1) ? 1 : 0;
411			return (SNMP_ERR_NOERROR);
412		}
413		return (SNMP_ERR_NOT_WRITEABLE);
414
415	  case SNMP_OP_ROLLBACK:
416	  case SNMP_OP_COMMIT:
417		return (SNMP_ERR_NOERROR);
418	}
419
420	if (ifp->mibtick < this_tick)
421		(void)mib_fetch_ifmib(ifp);
422
423	ret = SNMP_ERR_NOERROR;
424	switch (value->var.subs[sub - 1]) {
425
426	  case LEAF_ifName:
427		ret = string_get(value, ifp->name, -1);
428		break;
429
430	  case LEAF_ifInMulticastPkts:
431		value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
432		break;
433
434	  case LEAF_ifInBroadcastPkts:
435		value->v.uint32 = 0;
436		break;
437
438	  case LEAF_ifOutMulticastPkts:
439		value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
440		break;
441
442	  case LEAF_ifOutBroadcastPkts:
443		value->v.uint32 = 0;
444		break;
445
446	  case LEAF_ifHCInOctets:
447		if (!(ifp->flags & MIBIF_HIGHSPEED))
448			goto again;
449		value->v.counter64 = ifp->hc_inoctets;
450		break;
451
452	  case LEAF_ifHCInUcastPkts:
453		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
454			goto again;
455		value->v.counter64 = ifp->hc_ipackets - ifp->hc_imcasts;
456		break;
457
458	  case LEAF_ifHCInMulticastPkts:
459		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
460			goto again;
461		value->v.counter64 = ifp->hc_imcasts;
462		break;
463
464	  case LEAF_ifHCInBroadcastPkts:
465		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
466			goto again;
467		value->v.counter64 = 0;
468		break;
469
470	  case LEAF_ifHCOutOctets:
471		if (!(ifp->flags & MIBIF_HIGHSPEED))
472			goto again;
473		value->v.counter64 = ifp->hc_inoctets;
474		break;
475
476	  case LEAF_ifHCOutUcastPkts:
477		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
478			goto again;
479		value->v.counter64 = ifp->hc_opackets - ifp->hc_omcasts;
480		break;
481
482	  case LEAF_ifHCOutMulticastPkts:
483		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
484			goto again;
485		value->v.counter64 = ifp->hc_omcasts;
486		break;
487
488	  case LEAF_ifHCOutBroadcastPkts:
489		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
490			goto again;
491		value->v.counter64 = 0;
492		break;
493
494	  case LEAF_ifLinkUpDownTrapEnable:
495		value->v.integer = ifp->trap_enable ? 1 : 2;
496		break;
497
498	  case LEAF_ifHighSpeed:
499		value->v.integer =
500		    (ifp->mib.ifmd_data.ifi_baudrate + 499999) / 1000000;
501		break;
502
503	  case LEAF_ifPromiscuousMode:
504		value->v.integer =
505		    (ifp->mib.ifmd_flags & IFF_PROMISC) ? 1 : 2;
506		break;
507
508	  case LEAF_ifConnectorPresent:
509		value->v.integer = ifp->has_connector ? 1 : 2;
510		break;
511
512	  case LEAF_ifAlias:
513		ret = string_get(value, "", -1);
514		break;
515
516	  case LEAF_ifCounterDiscontinuityTime:
517		if (ifp->counter_disc > start_tick)
518			value->v.uint32 = ifp->counter_disc - start_tick;
519		else
520			value->v.uint32 = 0;
521		break;
522	}
523	return (ret);
524}
525