xref: /freebsd/contrib/bsnmp/snmp_mibII/mibII_interfaces.c (revision 6af83ee0d2941d18880b6aaa2b4facd1d30c6106)
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.13 2004/08/06 08:47:01 brandt 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  */
39 struct 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 
59 static 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  */
66 static int
67 ifchange_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 static uint32_t
139 ticks_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  */
154 int
155 op_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  */
186 int
187 op_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 = oid_zeroDotZero;
340 		break;
341 	}
342 	return (SNMP_ERR_NOERROR);
343 }
344 
345 /*
346  * IfXtable entry
347  */
348 int
349 op_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