xref: /freebsd/contrib/bsnmp/snmp_mibII/mibII_interfaces.c (revision 6b3455a7665208c366849f0b2b3bc916fb97516e)
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  */
43 struct 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 
63 static 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  */
70 static int
71 ifchange_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 
142 static u_int32_t
143 ticks_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  */
158 int
159 op_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  */
190 int
191 op_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  */
352 int
353 op_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