xref: /freebsd/contrib/bsnmp/snmp_mibII/mibII_interfaces.c (revision 7aa383846770374466b1dcb2cefd71bde9acf463)
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.17 2006/02/14 09:04:19 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  */
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 /*
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  */
142 static uint32_t
143 ticks_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  */
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 		/*
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  */
366 int
367 op_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