]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/bsnmpd/modules/snmp_hostres/hostres_network_tbl.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / bsnmpd / modules / snmp_hostres / hostres_network_tbl.c
1 /*-
2  * Copyright (c) 2005-2006 The FreeBSD Project
3  * All rights reserved.
4  *
5  * Author: Victor Cruceru <soc-victor@freebsd.org>
6  *
7  * Redistribution of this software and documentation and use in source and
8  * binary forms, with or without modification, are permitted provided that
9  * the following conditions are met:
10  *
11  * 1. Redistributions of source code or documentation must retain the above
12  *    copyright 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 THE 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 THE 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  * $FreeBSD$
30  */
31
32 /*
33  * Host Resources MIB implementation for SNMPd: instrumentation for
34  * hrNetworkTable
35  */
36
37 #include <sys/types.h>
38 #include <sys/ioctl.h>
39 #include <sys/socket.h>
40 #include <sys/sysctl.h>
41
42 #include <net/if.h>
43 #include <net/if_mib.h>
44
45 #include <assert.h>
46 #include <ctype.h>
47 #include <err.h>
48 #include <errno.h>
49 #include <ifaddrs.h>
50 #include <stdarg.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <syslog.h>
54 #include <unistd.h>
55
56 #include "hostres_snmp.h"
57 #include "hostres_oid.h"
58 #include "hostres_tree.h"
59
60 #include <bsnmp/snmp_mibII.h>
61
62 /*
63  * This structure is used to hold a SNMP table entry
64  * for HOST-RESOURCES-MIB's hrNetworkTable
65  */
66 struct network_entry {
67         int32_t         index;
68         int32_t         ifIndex;
69         TAILQ_ENTRY(network_entry) link;
70 #define HR_NETWORK_FOUND                0x001
71         uint32_t        flags;
72
73 };
74 TAILQ_HEAD(network_tbl, network_entry);
75
76 /* the head of the list with hrNetworkTable's entries */
77 static struct network_tbl network_tbl = TAILQ_HEAD_INITIALIZER(network_tbl);
78
79 /* last (agent) tick when hrNetworkTable was updated */
80 static uint64_t network_tick;
81
82 /* maximum number of ticks between updates of network table */
83 uint32_t network_tbl_refresh = HR_NETWORK_TBL_REFRESH * 100;
84
85 /* Constants */
86 static const struct asn_oid OIDX_hrDeviceNetwork_c = OIDX_hrDeviceNetwork;
87
88 /**
89  * Create a new entry into the network table
90  */
91 static struct network_entry *
92 network_entry_create(const struct device_entry *devEntry)
93 {
94         struct network_entry *entry;
95
96         assert(devEntry != NULL);
97         if (devEntry == NULL)
98                 return (NULL);
99
100         if ((entry = malloc(sizeof(*entry))) == NULL) {
101                 syslog(LOG_WARNING, "%s: %m", __func__);
102                 return (NULL);
103         }
104
105         memset(entry, 0, sizeof(*entry));
106         entry->index = devEntry->index;
107         INSERT_OBJECT_INT(entry, &network_tbl);
108
109         return (entry);
110 }
111
112 /**
113  * Delete an entry in the network table
114  */
115 static void
116 network_entry_delete(struct network_entry* entry)
117 {
118
119         TAILQ_REMOVE(&network_tbl, entry, link);
120         free(entry);
121 }
122
123 /**
124  * Fetch the interfaces from the mibII module, get their real name from the
125  * kernel and try to find it in the device table.
126  */
127 static void
128 network_get_interfaces(void)
129 {
130         struct device_entry *dev;
131         struct network_entry *net;
132         struct mibif *ifp;
133         int name[6];
134         size_t len;
135         char *dname;
136
137         name[0] = CTL_NET;
138         name[1] = PF_LINK;
139         name[2] = NETLINK_GENERIC;
140         name[3] = IFMIB_IFDATA;
141         name[5] = IFDATA_DRIVERNAME;
142
143         for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp)) {
144                 HRDBG("%s %s", ifp->name, ifp->descr);
145
146                 name[4] = ifp->sysindex;
147
148                 /* get the original name */
149                 len = 0;
150                 if (sysctl(name, 6, NULL, &len, 0, 0) < 0) {
151                         syslog(LOG_ERR, "sysctl(net.link.ifdata.%d."
152                             "drivername): %m", ifp->sysindex);
153                         continue;
154                 }
155                 if ((dname = malloc(len)) == NULL) {
156                         syslog(LOG_ERR, "malloc: %m");
157                         continue;
158                 }
159                 if (sysctl(name, 6, dname, &len, 0, 0) < 0) {
160                         syslog(LOG_ERR, "sysctl(net.link.ifdata.%d."
161                             "drivername): %m", ifp->sysindex);
162                         free(dname);
163                         continue;
164                 }
165
166                 HRDBG("got device %s (%s)", ifp->name, dname);
167
168                 if ((dev = device_find_by_name(dname)) == NULL) {
169                         HRDBG("%s not in hrDeviceTable", dname);
170                         free(dname);
171                         continue;
172                 }
173                 HRDBG("%s found in hrDeviceTable", dname);
174
175                 dev->type = &OIDX_hrDeviceNetwork_c;
176                 dev->flags |= HR_DEVICE_IMMUTABLE;
177
178                 free(dname);
179
180                 /* Then check hrNetworkTable for this device */
181                 TAILQ_FOREACH(net, &network_tbl, link)
182                         if (net->index == dev->index)
183                                 break;
184
185                 if (net == NULL && (net = network_entry_create(dev)) == NULL)
186                         continue;
187
188                 net->flags |= HR_NETWORK_FOUND;
189                 net->ifIndex = ifp->index;
190         }
191
192         network_tick = this_tick;
193 }
194
195 /**
196  * Finalization routine for hrNetworkTable.
197  * It destroys the lists and frees any allocated heap memory.
198  */
199 void
200 fini_network_tbl(void)
201 {
202         struct network_entry *n1;
203
204         while ((n1 = TAILQ_FIRST(&network_tbl)) != NULL) {
205                 TAILQ_REMOVE(&network_tbl, n1, link);
206                 free(n1);
207         }
208 }
209
210 /**
211  * Get the interface list from mibII only at this point to be sure that
212  * it is there already.
213  */
214 void
215 start_network_tbl(void)
216 {
217
218         mib_refresh_iflist();
219         network_get_interfaces();
220 }
221
222 /**
223  * Refresh the table.
224  */
225 static void
226 refresh_network_tbl(void)
227 {
228         struct network_entry *entry, *entry_tmp;
229
230         if (this_tick - network_tick < network_tbl_refresh) {
231                 HRDBG("no refresh needed");
232                 return;
233         }
234
235         /* mark each entry as missing */
236         TAILQ_FOREACH(entry, &network_tbl, link)
237                 entry->flags &= ~HR_NETWORK_FOUND;
238
239         network_get_interfaces();
240
241         /*
242          * Purge items that disappeared
243          */
244         TAILQ_FOREACH_SAFE(entry, &network_tbl, link, entry_tmp) {
245                 if (!(entry->flags & HR_NETWORK_FOUND))
246                         network_entry_delete(entry);
247         }
248
249         HRDBG("refresh DONE");
250 }
251
252 /*
253  * This is the implementation for a generated (by our SNMP tool)
254  * function prototype, see hostres_tree.h
255  * It handles the SNMP operations for hrNetworkTable
256  */
257 int
258 op_hrNetworkTable(struct snmp_context *ctx __unused, struct snmp_value *value,
259     u_int sub, u_int iidx __unused, enum snmp_op curr_op)
260 {
261         struct network_entry *entry;
262
263         refresh_network_tbl();
264
265         switch (curr_op) {
266
267         case SNMP_OP_GETNEXT:
268                 if ((entry = NEXT_OBJECT_INT(&network_tbl,
269                     &value->var, sub)) == NULL)
270                         return (SNMP_ERR_NOSUCHNAME);
271                 value->var.len = sub + 1;
272                 value->var.subs[sub] = entry->index;
273                 goto get;
274
275         case SNMP_OP_GET:
276                 if ((entry = FIND_OBJECT_INT(&network_tbl,
277                     &value->var, sub)) == NULL)
278                         return (SNMP_ERR_NOSUCHNAME);
279                 goto get;
280
281         case SNMP_OP_SET:
282                 if ((entry = FIND_OBJECT_INT(&network_tbl,
283                     &value->var, sub)) == NULL)
284                         return (SNMP_ERR_NO_CREATION);
285                 return (SNMP_ERR_NOT_WRITEABLE);
286
287         case SNMP_OP_ROLLBACK:
288         case SNMP_OP_COMMIT:
289                 abort();
290         }
291         abort();
292
293   get:
294         switch (value->var.subs[sub - 1]) {
295
296         case LEAF_hrNetworkIfIndex:
297                 value->v.integer = entry->ifIndex;
298                 return (SNMP_ERR_NOERROR);
299
300         }
301         abort();
302 }