]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/bsnmp/snmp_mibII/mibII_interfaces.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 != LINK_STATE_UP)
293                                 value->v.integer = 5;   /* state dormant */
294                         else
295                                 value->v.integer = 1;   /* state up */
296                 } else
297                         value->v.integer = 2;   /* state down */
298                 break;
299
300           case LEAF_ifLastChange:
301                 value->v.uint32 =
302                     ticks_get_timeval(&ifp->mib.ifmd_data.ifi_lastchange);
303                 break;
304
305           case LEAF_ifInOctets:
306                 value->v.uint32 = ifp->mib.ifmd_data.ifi_ibytes;
307                 break;
308
309           case LEAF_ifInUcastPkts:
310                 value->v.uint32 = ifp->mib.ifmd_data.ifi_ipackets -
311                     ifp->mib.ifmd_data.ifi_imcasts;
312                 break;
313
314           case LEAF_ifInNUcastPkts:
315                 value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
316                 break;
317
318           case LEAF_ifInDiscards:
319                 value->v.uint32 = ifp->mib.ifmd_data.ifi_iqdrops;
320                 break;
321
322           case LEAF_ifInErrors:
323                 value->v.uint32 = ifp->mib.ifmd_data.ifi_ierrors;
324                 break;
325
326           case LEAF_ifInUnknownProtos:
327                 value->v.uint32 = ifp->mib.ifmd_data.ifi_noproto;
328                 break;
329
330           case LEAF_ifOutOctets:
331                 value->v.uint32 = ifp->mib.ifmd_data.ifi_obytes;
332                 break;
333
334           case LEAF_ifOutUcastPkts:
335                 value->v.uint32 = ifp->mib.ifmd_data.ifi_opackets -
336                     ifp->mib.ifmd_data.ifi_omcasts;
337                 break;
338
339           case LEAF_ifOutNUcastPkts:
340                 value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
341                 break;
342
343           case LEAF_ifOutDiscards:
344                 value->v.uint32 = ifp->mib.ifmd_snd_drops;
345                 break;
346
347           case LEAF_ifOutErrors:
348                 value->v.uint32 = ifp->mib.ifmd_data.ifi_oerrors;
349                 break;
350
351           case LEAF_ifOutQLen:
352                 value->v.uint32 = ifp->mib.ifmd_snd_len;
353                 break;
354
355           case LEAF_ifSpecific:
356                 value->v.oid = ifp->spec_oid;
357                 break;
358         }
359         return (SNMP_ERR_NOERROR);
360 }
361
362 /*
363  * IfXtable entry
364  */
365 int
366 op_ifxtable(struct snmp_context *ctx, struct snmp_value *value,
367     u_int sub, u_int iidx __unused, enum snmp_op op)
368 {
369         struct mibif *ifp = NULL;
370         int ret;
371         struct ifchange *ifc;
372         struct asn_oid idx;
373
374         switch (op) {
375
376   again:
377                 if (op != SNMP_OP_GETNEXT)
378                         return (SNMP_ERR_NOSUCHNAME);
379                 /* FALLTHROUGH */
380
381           case SNMP_OP_GETNEXT:
382                 if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL)
383                         return (SNMP_ERR_NOSUCHNAME);
384                 value->var.len = sub + 1;
385                 value->var.subs[sub] = ifp->index;
386                 break;
387
388           case SNMP_OP_GET:
389                 if (value->var.len - sub != 1)
390                         return (SNMP_ERR_NOSUCHNAME);
391                 if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
392                         return (SNMP_ERR_NOSUCHNAME);
393                 break;
394
395           case SNMP_OP_SET:
396                 if (value->var.len - sub != 1)
397                         return (SNMP_ERR_NO_CREATION);
398                 if ((ifp = mib_find_if(value->var.subs[sub])) == NULL)
399                         return (SNMP_ERR_NO_CREATION);
400
401                 idx.len = 1;
402                 idx.subs[0] = ifp->index;
403
404                 if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx,
405                     &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL)
406                         return (SNMP_ERR_RES_UNAVAIL);
407                 ifc->ifindex = ifp->index;
408
409                 switch (value->var.subs[sub - 1]) {
410
411                   case LEAF_ifLinkUpDownTrapEnable:
412                         if (value->v.integer != 1 && value->v.integer != 2)
413                                 return (SNMP_ERR_WRONG_VALUE);
414                         if (ifc->set & IFC_TRAPS)
415                                 return (SNMP_ERR_INCONS_VALUE);
416                         ifc->set |= IFC_TRAPS;
417                         ifc->traps = (value->v.integer == 1) ? 1 : 0;
418                         return (SNMP_ERR_NOERROR);
419
420                   case LEAF_ifPromiscuousMode:
421                         if (value->v.integer != 1 && value->v.integer != 2)
422                                 return (SNMP_ERR_WRONG_VALUE);
423                         if (ifc->set & IFC_PROMISC)
424                                 return (SNMP_ERR_INCONS_VALUE);
425                         ifc->set |= IFC_PROMISC;
426                         ifc->promisc = (value->v.integer == 1) ? 1 : 0;
427                         return (SNMP_ERR_NOERROR);
428                 }
429                 return (SNMP_ERR_NOT_WRITEABLE);
430
431           case SNMP_OP_ROLLBACK:
432           case SNMP_OP_COMMIT:
433                 return (SNMP_ERR_NOERROR);
434         }
435
436         if (ifp->mibtick < this_tick)
437                 (void)mib_fetch_ifmib(ifp);
438
439         ret = SNMP_ERR_NOERROR;
440         switch (value->var.subs[sub - 1]) {
441
442           case LEAF_ifName:
443                 ret = string_get(value, ifp->name, -1);
444                 break;
445
446           case LEAF_ifInMulticastPkts:
447                 value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts;
448                 break;
449
450           case LEAF_ifInBroadcastPkts:
451                 value->v.uint32 = 0;
452                 break;
453
454           case LEAF_ifOutMulticastPkts:
455                 value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts;
456                 break;
457
458           case LEAF_ifOutBroadcastPkts:
459                 value->v.uint32 = 0;
460                 break;
461
462           case LEAF_ifHCInOctets:
463                 if (!(ifp->flags & MIBIF_HIGHSPEED))
464                         goto again;
465                 value->v.counter64 = MIBIF_PRIV(ifp)->hc_inoctets;
466                 break;
467
468           case LEAF_ifHCInUcastPkts:
469                 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
470                         goto again;
471                 value->v.counter64 = MIBIF_PRIV(ifp)->hc_ipackets -
472                     MIBIF_PRIV(ifp)->hc_imcasts;
473                 break;
474
475           case LEAF_ifHCInMulticastPkts:
476                 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
477                         goto again;
478                 value->v.counter64 = MIBIF_PRIV(ifp)->hc_imcasts;
479                 break;
480
481           case LEAF_ifHCInBroadcastPkts:
482                 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
483                         goto again;
484                 value->v.counter64 = 0;
485                 break;
486
487           case LEAF_ifHCOutOctets:
488                 if (!(ifp->flags & MIBIF_HIGHSPEED))
489                         goto again;
490                 value->v.counter64 = MIBIF_PRIV(ifp)->hc_outoctets;
491                 break;
492
493           case LEAF_ifHCOutUcastPkts:
494                 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
495                         goto again;
496                 value->v.counter64 = MIBIF_PRIV(ifp)->hc_opackets -
497                     MIBIF_PRIV(ifp)->hc_omcasts;
498                 break;
499
500           case LEAF_ifHCOutMulticastPkts:
501                 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
502                         goto again;
503                 value->v.counter64 = MIBIF_PRIV(ifp)->hc_omcasts;
504                 break;
505
506           case LEAF_ifHCOutBroadcastPkts:
507                 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED)))
508                         goto again;
509                 value->v.counter64 = 0;
510                 break;
511
512           case LEAF_ifLinkUpDownTrapEnable:
513                 value->v.integer = ifp->trap_enable ? 1 : 2;
514                 break;
515
516           case LEAF_ifHighSpeed:
517                 value->v.integer =
518                     (ifp->mib.ifmd_data.ifi_baudrate + 499999) / 1000000;
519                 break;
520
521           case LEAF_ifPromiscuousMode:
522                 value->v.integer =
523                     (ifp->mib.ifmd_flags & IFF_PROMISC) ? 1 : 2;
524                 break;
525
526           case LEAF_ifConnectorPresent:
527                 value->v.integer = ifp->has_connector ? 1 : 2;
528                 break;
529
530           case LEAF_ifAlias:
531                 ret = string_get(value, "", -1);
532                 break;
533
534           case LEAF_ifCounterDiscontinuityTime:
535                 if (ifp->counter_disc > start_tick)
536                         value->v.uint32 = ifp->counter_disc - start_tick;
537                 else
538                         value->v.uint32 = 0;
539                 break;
540         }
541         return (ret);
542 }