mibII_interfaces.c revision 155602
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.16 2005/11/02 12:07:40 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
138/*
139 * Return difference to daemon start time in ticks truncated to a
140 * 32-bit value. If the timeval is 0 then return 0.
141 */
142static uint32_t
143ticks_get_timeval(struct timeval *tv)
144{
145	uint64_t v;
146
147	if (tv->tv_sec != 0 || tv->tv_usec != 0) {
148		v = 100ULL * tv->tv_sec + tv->tv_usec / 10000ULL;
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		/*
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 ==
293			    LINK_STATE_DOWN)
294				value->v.integer = 5;   /* state dormant */
295			else
296				value->v.integer = 1;   /* state up */
297		} else
298			value->v.integer = 2;   /* state down */
299		break;
300
301	  case LEAF_ifLastChange:
302		value->v.uint32 =
303		    ticks_get_timeval(&ifp->mib.ifmd_data.ifi_lastchange);
304		break;
305
306	  case LEAF_ifInOctets:
307		value->v.uint32 = ifp->mib.ifmd_data.ifi_ibytes;
308		break;
309
310	  case LEAF_ifInUcastPkts:
311		value->v.uint32 = ifp->mib.ifmd_data.ifi_ipackets -
312		    ifp->mib.ifmd_data.ifi_imcasts;
313		break;
314
315	  case LEAF_ifInNUcastPkts:
316		value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
317		break;
318
319	  case LEAF_ifInDiscards:
320		value->v.uint32 = ifp->mib.ifmd_data.ifi_iqdrops;
321		break;
322
323	  case LEAF_ifInErrors:
324		value->v.uint32 = ifp->mib.ifmd_data.ifi_ierrors;
325		break;
326
327	  case LEAF_ifInUnknownProtos:
328		value->v.uint32 = ifp->mib.ifmd_data.ifi_noproto;
329		break;
330
331	  case LEAF_ifOutOctets:
332		value->v.uint32 = ifp->mib.ifmd_data.ifi_obytes;
333		break;
334
335	  case LEAF_ifOutUcastPkts:
336		value->v.uint32 = ifp->mib.ifmd_data.ifi_opackets -
337		    ifp->mib.ifmd_data.ifi_omcasts;
338		break;
339
340	  case LEAF_ifOutNUcastPkts:
341		value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
342		break;
343
344	  case LEAF_ifOutDiscards:
345		value->v.uint32 = ifp->mib.ifmd_snd_drops;
346		break;
347
348	  case LEAF_ifOutErrors:
349		value->v.uint32 = ifp->mib.ifmd_data.ifi_oerrors;
350		break;
351
352	  case LEAF_ifOutQLen:
353		value->v.uint32 = ifp->mib.ifmd_snd_len;
354		break;
355
356	  case LEAF_ifSpecific:
357		value->v.oid = ifp->spec_oid;
358		break;
359	}
360	return (SNMP_ERR_NOERROR);
361}
362
363/*
364 * IfXtable entry
365 */
366int
367op_ifxtable(struct snmp_context *ctx, struct snmp_value *value,
368    u_int sub, u_int iidx __unused, enum snmp_op op)
369{
370	struct mibif *ifp = NULL;
371	int ret;
372	struct ifchange *ifc;
373	struct asn_oid idx;
374
375	switch (op) {
376
377  again:
378		if (op != SNMP_OP_GETNEXT)
379			return (SNMP_ERR_NOSUCHNAME);
380		/* FALLTHROUGH */
381
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;
387		break;
388
389	  case SNMP_OP_GET:
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);
394		break;
395
396	  case SNMP_OP_SET:
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);
401
402		idx.len = 1;
403		idx.subs[0] = ifp->index;
404
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;
409
410		switch (value->var.subs[sub - 1]) {
411
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);
420
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);
429		}
430		return (SNMP_ERR_NOT_WRITEABLE);
431
432	  case SNMP_OP_ROLLBACK:
433	  case SNMP_OP_COMMIT:
434		return (SNMP_ERR_NOERROR);
435	}
436
437	if (ifp->mibtick < this_tick)
438		(void)mib_fetch_ifmib(ifp);
439
440	ret = SNMP_ERR_NOERROR;
441	switch (value->var.subs[sub - 1]) {
442
443	  case LEAF_ifName:
444		ret = string_get(value, ifp->name, -1);
445		break;
446
447	  case LEAF_ifInMulticastPkts:
448		value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
449		break;
450
451	  case LEAF_ifInBroadcastPkts:
452		value->v.uint32 = 0;
453		break;
454
455	  case LEAF_ifOutMulticastPkts:
456		value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
457		break;
458
459	  case LEAF_ifOutBroadcastPkts:
460		value->v.uint32 = 0;
461		break;
462
463	  case LEAF_ifHCInOctets:
464		if (!(ifp->flags & MIBIF_HIGHSPEED))
465			goto again;
466		value->v.counter64 = MIBIF_PRIV(ifp)->hc_inoctets;
467		break;
468
469	  case LEAF_ifHCInUcastPkts:
470		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
471			goto again;
472		value->v.counter64 = MIBIF_PRIV(ifp)->hc_ipackets -
473		    MIBIF_PRIV(ifp)->hc_imcasts;
474		break;
475
476	  case LEAF_ifHCInMulticastPkts:
477		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
478			goto again;
479		value->v.counter64 = MIBIF_PRIV(ifp)->hc_imcasts;
480		break;
481
482	  case LEAF_ifHCInBroadcastPkts:
483		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
484			goto again;
485		value->v.counter64 = 0;
486		break;
487
488	  case LEAF_ifHCOutOctets:
489		if (!(ifp->flags & MIBIF_HIGHSPEED))
490			goto again;
491		value->v.counter64 = MIBIF_PRIV(ifp)->hc_outoctets;
492		break;
493
494	  case LEAF_ifHCOutUcastPkts:
495		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
496			goto again;
497		value->v.counter64 = MIBIF_PRIV(ifp)->hc_opackets -
498		    MIBIF_PRIV(ifp)->hc_omcasts;
499		break;
500
501	  case LEAF_ifHCOutMulticastPkts:
502		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
503			goto again;
504		value->v.counter64 = MIBIF_PRIV(ifp)->hc_omcasts;
505		break;
506
507	  case LEAF_ifHCOutBroadcastPkts:
508		if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
509			goto again;
510		value->v.counter64 = 0;
511		break;
512
513	  case LEAF_ifLinkUpDownTrapEnable:
514		value->v.integer = ifp->trap_enable ? 1 : 2;
515		break;
516
517	  case LEAF_ifHighSpeed:
518		value->v.integer =
519		    (ifp->mib.ifmd_data.ifi_baudrate + 499999) / 1000000;
520		break;
521
522	  case LEAF_ifPromiscuousMode:
523		value->v.integer =
524		    (ifp->mib.ifmd_flags & IFF_PROMISC) ? 1 : 2;
525		break;
526
527	  case LEAF_ifConnectorPresent:
528		value->v.integer = ifp->has_connector ? 1 : 2;
529		break;
530
531	  case LEAF_ifAlias:
532		ret = string_get(value, "", -1);
533		break;
534
535	  case LEAF_ifCounterDiscontinuityTime:
536		if (ifp->counter_disc > start_tick)
537			value->v.uint32 = ifp->counter_disc - start_tick;
538		else
539			value->v.uint32 = 0;
540		break;
541	}
542	return (ret);
543}
544