mibII_interfaces.c revision 267654
172445Sassar/*
2233294Sstas * Copyright (c) 2001-2003
372445Sassar *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
472445Sassar *	All rights reserved.
5233294Sstas *
672445Sassar * Author: Harti Brandt <harti@freebsd.org>
772445Sassar *
872445Sassar * Redistribution and use in source and binary forms, with or without
9233294Sstas * modification, are permitted provided that the following conditions
1072445Sassar * are met:
1172445Sassar * 1. Redistributions of source code must retain the above copyright
12233294Sstas *    notice, this list of conditions and the following disclaimer.
1372445Sassar * 2. Redistributions in binary form must reproduce the above copyright
1472445Sassar *    notice, this list of conditions and the following disclaimer in the
1572445Sassar *    documentation and/or other materials provided with the distribution.
16233294Sstas *
1772445Sassar * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1872445Sassar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1972445Sassar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
2172445Sassar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2272445Sassar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2372445Sassar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2472445Sassar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2572445Sassar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2672445Sassar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2772445Sassar * SUCH DAMAGE.
2872445Sassar *
2972445Sassar * $Begemot: bsnmp/snmp_mibII/mibII_interfaces.c,v 1.17 2006/02/14 09:04:19 brandt_h Exp $
3072445Sassar *
3172445Sassar * Interfaces group.
3272445Sassar */
3372445Sassar#include "mibII.h"
3472445Sassar#include "mibII_oid.h"
3572445Sassar
3672445Sassar/*
3772445Sassar * This structure catches all changes to a interface entry
3872445Sassar */
39178825Sdfrstruct ifchange {
4072445Sassar	struct snmp_dependency dep;
4172445Sassar
42178825Sdfr	u_int		ifindex;
43233294Sstas
44178825Sdfr	uint32_t	set;
45178825Sdfr	int		promisc;
46178825Sdfr	int		admin;
47178825Sdfr	int		traps;
48178825Sdfr
49178825Sdfr	uint32_t	rb;
50178825Sdfr	int		rb_flags;
51178825Sdfr	int		rb_traps;
52178825Sdfr};
53178825Sdfr#define IFC_PROMISC	0x0001
54178825Sdfr#define IFC_ADMIN	0x0002
55178825Sdfr#define IFC_TRAPS	0x0004
5672445Sassar#define IFRB_FLAGS	0x0001
57178825Sdfr#define IFRB_TRAPS	0x0002
58178825Sdfr
59178825Sdfrstatic const struct asn_oid
6072445Sassar	oid_ifTable = OIDX_ifTable;
6172445Sassar
62178825Sdfr/*
63233294Sstas * This function handles all changes to the interface table and interface
6472445Sassar * extension table.
65178825Sdfr */
66178825Sdfrstatic int
6772445Sassarifchange_func(struct snmp_context *ctx __unused, struct snmp_dependency *dep,
6872445Sassar    enum snmp_depop op)
69178825Sdfr{
70178825Sdfr	struct ifchange *ifc = (struct ifchange *)dep;
7172445Sassar	struct mibif *ifp;
72178825Sdfr	struct ifreq ifr, ifr1;
7372445Sassar
74178825Sdfr	if ((ifp = mib_find_if(ifc->ifindex)) == NULL)
7572445Sassar		return (SNMP_ERR_NO_CREATION);
76178825Sdfr
7772445Sassar	switch (op) {
7872445Sassar
7972445Sassar	  case SNMP_DEPOP_COMMIT:
8072445Sassar		strncpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
81178825Sdfr		if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr) == -1) {
8272445Sassar			syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name);
83178825Sdfr			return (SNMP_ERR_GENERR);
8472445Sassar		}
8572445Sassar		if (ifc->set & IFC_PROMISC) {
8672445Sassar			ifr.ifr_flags &= ~IFF_PROMISC;
87178825Sdfr			if (ifc->promisc)
8872445Sassar				ifr.ifr_flags |= IFF_PROMISC;
8972445Sassar			ifc->rb |= IFRB_FLAGS;
9072445Sassar		}
9172445Sassar		if (ifc->set & IFC_ADMIN) {
92178825Sdfr			ifr.ifr_flags &= ~IFF_UP;
93178825Sdfr			if (ifc->admin)
94178825Sdfr				ifr.ifr_flags |= IFF_UP;
95178825Sdfr			ifc->rb |= IFRB_FLAGS;
96178825Sdfr		}
97178825Sdfr		if (ifc->rb & IFRB_FLAGS) {
98178825Sdfr			strncpy(ifr1.ifr_name, ifp->name, sizeof(ifr1.ifr_name));
99178825Sdfr			if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr1) == -1) {
100178825Sdfr				syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name);
101178825Sdfr				return (SNMP_ERR_GENERR);
102178825Sdfr			}
103178825Sdfr			ifc->rb_flags = ifr1.ifr_flags;
104178825Sdfr			if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) {
105178825Sdfr				syslog(LOG_ERR, "SIFFLAGS(%s): %m", ifp->name);
106178825Sdfr				return (SNMP_ERR_GENERR);
107178825Sdfr			}
108178825Sdfr			(void)mib_fetch_ifmib(ifp);
109178825Sdfr		}
110178825Sdfr		if (ifc->set & IFC_TRAPS) {
111178825Sdfr			ifc->rb |= IFRB_TRAPS;
112178825Sdfr			ifc->rb_traps = ifp->trap_enable;
113178825Sdfr			ifp->trap_enable = ifc->traps;
114178825Sdfr		}
115178825Sdfr		return (SNMP_ERR_NOERROR);
116178825Sdfr
117178825Sdfr	  case SNMP_DEPOP_ROLLBACK:
11872445Sassar		if (ifc->rb & IFRB_FLAGS) {
119178825Sdfr			strncpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
120178825Sdfr			ifr.ifr_flags = ifc->rb_flags;
12172445Sassar			if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) {
122178825Sdfr				syslog(LOG_ERR, "SIFFLAGS(%s): %m", ifp->name);
12372445Sassar				return (SNMP_ERR_UNDO_FAILED);
124178825Sdfr			}
125178825Sdfr			(void)mib_fetch_ifmib(ifp);
126233294Sstas		}
127178825Sdfr		if (ifc->rb & IFRB_TRAPS)
128178825Sdfr			ifp->trap_enable = ifc->rb_traps;
129178825Sdfr		return (SNMP_ERR_NOERROR);
130233294Sstas
131178825Sdfr	  case SNMP_DEPOP_FINISH:
132178825Sdfr		return (SNMP_ERR_NOERROR);
133178825Sdfr
134178825Sdfr	}
135178825Sdfr	abort();
136178825Sdfr}
137178825Sdfr
138178825Sdfr/*
139233294Sstas * Return difference to daemon start time in ticks truncated to a
140178825Sdfr * 32-bit value. If the timeval is 0 then return 0.
141178825Sdfr */
142178825Sdfrstatic uint32_t
143178825Sdfrticks_get_timeval(struct timeval *tv)
144233294Sstas{
145178825Sdfr	uint64_t v;
146178825Sdfr
147178825Sdfr	if (tv->tv_sec != 0 || tv->tv_usec != 0) {
148178825Sdfr		v = 100ULL * tv->tv_sec + tv->tv_usec / 10000ULL;
149178825Sdfr		if (v > start_tick)
150178825Sdfr			return (v - start_tick);
151178825Sdfr	}
152178825Sdfr	return (0);
153178825Sdfr}
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		/*
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'.
290		 */
291		if (ifp->mib.ifmd_flags & IFF_RUNNING) {
292			if (ifp->mib.ifmd_data.ifi_link_state != LINK_STATE_UP)
293				value->v.integer = 5;   /* state dormant */
294			else
295				value->v.integer = 1;   /* state up */
296		} else
297			value->v.integer = 2;   /* state down */
298		break;
299
300	  case LEAF_ifLastChange:
301		value->v.uint32 =
302		    ticks_get_timeval(&ifp->mib.ifmd_data.ifi_lastchange);
303		break;
304
305	  case LEAF_ifInOctets:
306		value->v.uint32 = ifp->mib.ifmd_data.ifi_ibytes;
307		break;
308
309	  case LEAF_ifInUcastPkts:
310		value->v.uint32 = ifp->mib.ifmd_data.ifi_ipackets -
311		    ifp->mib.ifmd_data.ifi_imcasts;
312		break;
313
314	  case LEAF_ifInNUcastPkts:
315		value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
316		break;
317
318	  case LEAF_ifInDiscards:
319		value->v.uint32 = ifp->mib.ifmd_data.ifi_iqdrops;
320		break;
321
322	  case LEAF_ifInErrors:
323		value->v.uint32 = ifp->mib.ifmd_data.ifi_ierrors;
324		break;
325
326	  case LEAF_ifInUnknownProtos:
327		value->v.uint32 = ifp->mib.ifmd_data.ifi_noproto;
328		break;
329
330	  case LEAF_ifOutOctets:
331		value->v.uint32 = ifp->mib.ifmd_data.ifi_obytes;
332		break;
333
334	  case LEAF_ifOutUcastPkts:
335		value->v.uint32 = ifp->mib.ifmd_data.ifi_opackets -
336		    ifp->mib.ifmd_data.ifi_omcasts;
337		break;
338
339	  case LEAF_ifOutNUcastPkts:
340		value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
341		break;
342
343	  case LEAF_ifOutDiscards:
344		value->v.uint32 = ifp->mib.ifmd_snd_drops;
345		break;
346
347	  case LEAF_ifOutErrors:
348		value->v.uint32 = ifp->mib.ifmd_data.ifi_oerrors;
349		break;
350
351	  case LEAF_ifOutQLen:
352		value->v.uint32 = ifp->mib.ifmd_snd_len;
353		break;
354
355	  case LEAF_ifSpecific:
356		value->v.oid = ifp->spec_oid;
357		break;
358	}
359	return (SNMP_ERR_NOERROR);
360}
361
362/*
363 * IfXtable entry
364 */
365int
366op_ifxtable(struct snmp_context *ctx, struct snmp_value *value,
367    u_int sub, u_int iidx __unused, enum snmp_op op)
368{
369	struct mibif *ifp = NULL;
370	int ret;
371	struct ifchange *ifc;
372	struct asn_oid idx;
373
374	switch (op) {
375
376  again:
377		if (op != SNMP_OP_GETNEXT)
378			return (SNMP_ERR_NOSUCHNAME);
379		/* FALLTHROUGH */
380
381	  case SNMP_OP_GETNEXT:
382		if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL)
383			return (SNMP_ERR_NOSUCHNAME);
384		value->var.len = sub + 1;
385		value->var.subs[sub] = ifp->index;
386		break;
387
388	  case SNMP_OP_GET:
389		if (value->var.len - sub != 1)
390			return (SNMP_ERR_NOSUCHNAME);
391		if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
392			return (SNMP_ERR_NOSUCHNAME);
393		break;
394
395	  case SNMP_OP_SET:
396		if (value->var.len - sub != 1)
397			return (SNMP_ERR_NO_CREATION);
398		if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
399			return (SNMP_ERR_NO_CREATION);
400
401		idx.len = 1;
402		idx.subs[0] = ifp->index;
403
404		if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx,
405		    &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL)
406			return (SNMP_ERR_RES_UNAVAIL);
407		ifc->ifindex = ifp->index;
408
409		switch (value->var.subs[sub - 1]) {
410
411		  case LEAF_ifLinkUpDownTrapEnable:
412			if (value->v.integer != 1 && value->v.integer != 2)
413				return (SNMP_ERR_WRONG_VALUE);
414			if (ifc->set & IFC_TRAPS)
415				return (SNMP_ERR_INCONS_VALUE);
416			ifc->set |= IFC_TRAPS;
417			ifc->traps = (value->v.integer == 1) ? 1 : 0;
418			return (SNMP_ERR_NOERROR);
419
420		  case LEAF_ifPromiscuousMode:
421			if (value->v.integer != 1 && value->v.integer != 2)
422				return (SNMP_ERR_WRONG_VALUE);
423			if (ifc->set & IFC_PROMISC)
424				return (SNMP_ERR_INCONS_VALUE);
425			ifc->set |= IFC_PROMISC;
426			ifc->promisc = (value->v.integer == 1) ? 1 : 0;
427			return (SNMP_ERR_NOERROR);
428		}
429		return (SNMP_ERR_NOT_WRITEABLE);
430
431	  case SNMP_OP_ROLLBACK:
432	  case SNMP_OP_COMMIT:
433		return (SNMP_ERR_NOERROR);
434	}
435
436	if (ifp->mibtick < this_tick)
437		(void)mib_fetch_ifmib(ifp);
438
439	ret = SNMP_ERR_NOERROR;
440	switch (value->var.subs[sub - 1]) {
441
442	  case LEAF_ifName:
443		ret = string_get(value, ifp->name, -1);
444		break;
445
446	  case LEAF_ifInMulticastPkts:
447		value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
448		break;
449
450	  case LEAF_ifInBroadcastPkts:
451		value->v.uint32 = 0;
452		break;
453
454	  case LEAF_ifOutMulticastPkts:
455		value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
456		break;
457
458	  case LEAF_ifOutBroadcastPkts:
459		value->v.uint32 = 0;
460		break;
461
462	  case LEAF_ifHCInOctets:
463		if (!(ifp->flags & MIBIF_HIGHSPEED))
464			goto again;
465		value->v.counter64 = MIBIF_PRIV(ifp)->hc_inoctets;
466		break;
467
468	  case LEAF_ifHCInUcastPkts:
469		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
470			goto again;
471		value->v.counter64 = MIBIF_PRIV(ifp)->hc_ipackets -
472		    MIBIF_PRIV(ifp)->hc_imcasts;
473		break;
474
475	  case LEAF_ifHCInMulticastPkts:
476		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
477			goto again;
478		value->v.counter64 = MIBIF_PRIV(ifp)->hc_imcasts;
479		break;
480
481	  case LEAF_ifHCInBroadcastPkts:
482		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
483			goto again;
484		value->v.counter64 = 0;
485		break;
486
487	  case LEAF_ifHCOutOctets:
488		if (!(ifp->flags & MIBIF_HIGHSPEED))
489			goto again;
490		value->v.counter64 = MIBIF_PRIV(ifp)->hc_outoctets;
491		break;
492
493	  case LEAF_ifHCOutUcastPkts:
494		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
495			goto again;
496		value->v.counter64 = MIBIF_PRIV(ifp)->hc_opackets -
497		    MIBIF_PRIV(ifp)->hc_omcasts;
498		break;
499
500	  case LEAF_ifHCOutMulticastPkts:
501		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
502			goto again;
503		value->v.counter64 = MIBIF_PRIV(ifp)->hc_omcasts;
504		break;
505
506	  case LEAF_ifHCOutBroadcastPkts:
507		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
508			goto again;
509		value->v.counter64 = 0;
510		break;
511
512	  case LEAF_ifLinkUpDownTrapEnable:
513		value->v.integer = ifp->trap_enable ? 1 : 2;
514		break;
515
516	  case LEAF_ifHighSpeed:
517		value->v.integer =
518		    (ifp->mib.ifmd_data.ifi_baudrate + 499999) / 1000000;
519		break;
520
521	  case LEAF_ifPromiscuousMode:
522		value->v.integer =
523		    (ifp->mib.ifmd_flags & IFF_PROMISC) ? 1 : 2;
524		break;
525
526	  case LEAF_ifConnectorPresent:
527		value->v.integer = ifp->has_connector ? 1 : 2;
528		break;
529
530	  case LEAF_ifAlias:
531		ret = string_get(value, "", -1);
532		break;
533
534	  case LEAF_ifCounterDiscontinuityTime:
535		if (ifp->counter_disc > start_tick)
536			value->v.uint32 = ifp->counter_disc - start_tick;
537		else
538			value->v.uint32 = 0;
539		break;
540	}
541	return (ret);
542}
543