]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/bsnmp/snmp_mibII/mibII_interfaces.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / bsnmp / snmp_mibII / mibII_interfaces.c
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 }