xref: /freebsd/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_snmp.c (revision 7850265edd10f3d79a5e81ffedb25aefffaaa768)
1 /*-
2  * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * Bridge MIB implementation for SNMPd.
27  *
28  * $FreeBSD$
29  */
30 
31 #include <sys/param.h>
32 #include <sys/queue.h>
33 #include <sys/socket.h>
34 #include <sys/types.h>
35 
36 #include <net/ethernet.h>
37 #include <net/if.h>
38 #include <net/if_mib.h>
39 #include <net/if_types.h>
40 
41 #include <errno.h>
42 #include <stdarg.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <syslog.h>
47 
48 #include <bsnmp/snmpmod.h>
49 #include <bsnmp/snmp_mibII.h>
50 
51 #include "bridge_tree.h"
52 #include "bridge_snmp.h"
53 #include "bridge_oid.h"
54 
55 static struct lmodule *bridge_module;
56 
57 /* For the registration. */
58 static const struct asn_oid oid_dot1Bridge = OIDX_dot1dBridge;
59 /* The registration. */
60 static uint reg_bridge;
61 
62 /* Periodic timer for polling all bridges' data. */
63 static void *bridge_data_timer;
64 static void *bridge_tc_timer;
65 
66 static int bridge_data_maxage = SNMP_BRIDGE_DATA_MAXAGE;
67 static int bridge_poll_ticks = SNMP_BRIDGE_POLL_INTERVAL * 100;
68 static int bridge_tc_poll_ticks = SNMP_BRIDGE_TC_POLL_INTERVAL * 100;
69 
70 /*
71  * Our default bridge, whose info will be visible under
72  * the dot1dBridge subtree and functions to set/fetch it.
73  */
74 static char bif_default_name[IFNAMSIZ] = "bridge0";
75 static struct bridge_if *bif_default;
76 
77 struct bridge_if *
78 bridge_get_default(void)
79 {
80 	struct mibif *ifp;
81 
82 	if (bif_default != NULL) {
83 
84 		/* Walk through the mibII interface list. */
85 		for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
86 			if (strcmp(ifp->name, bif_default->bif_name) == 0)
87 				break;
88 
89 		if (ifp == NULL)
90 			bif_default = NULL;
91 	}
92 
93 	return (bif_default);
94 }
95 
96 void
97 bridge_set_default(struct bridge_if *bif)
98 {
99 	bif_default = bif;
100 
101 	syslog(LOG_ERR, "Set default bridge interface to: %s",
102 	    bif == NULL ? "(none)" : bif->bif_name);
103 }
104 
105 const char *
106 bridge_get_default_name(void)
107 {
108 	return (bif_default_name);
109 }
110 
111 static int
112 bridge_set_default_name(const char *bif_name, uint len)
113 {
114 	struct bridge_if *bif;
115 
116 	if (len >= IFNAMSIZ)
117 		return (-1);
118 
119 	bcopy(bif_name, bif_default_name, len);
120 	bif_default_name[len] = '\0';
121 
122 	if ((bif = bridge_if_find_ifname(bif_default_name)) == NULL)
123 		return (0);
124 
125 	bif_default = bif;
126 	return (1);
127 }
128 
129 int
130 bridge_get_data_maxage(void)
131 {
132 	return (bridge_data_maxage);
133 }
134 
135 static void
136 bridge_set_poll_ticks(int poll_ticks)
137 {
138 	if (bridge_data_timer != NULL)
139 		timer_stop(bridge_data_timer);
140 
141 	bridge_poll_ticks = poll_ticks;
142 	bridge_data_timer = timer_start_repeat(bridge_poll_ticks,
143 	    bridge_poll_ticks, bridge_update_all, NULL, bridge_module);
144 }
145 /*
146  * The bridge module configuration via SNMP.
147  */
148 static int
149 bridge_default_name_save(struct snmp_context *ctx, const char *bridge_default)
150 {
151 	if ((ctx->scratch->int1 = strlen(bridge_default)) >= IFNAMSIZ)
152 		return (-1);
153 
154 	if ((ctx->scratch->ptr1 = malloc(IFNAMSIZ)) == NULL)
155 		return (-1);
156 
157 	strncpy(ctx->scratch->ptr1, bridge_default, ctx->scratch->int1);
158 	return (0);
159 }
160 
161 int
162 op_begemot_bridge_config(struct snmp_context *ctx, struct snmp_value *val,
163     uint sub, uint iidx __unused, enum snmp_op op)
164 {
165 	switch (op) {
166 	    case SNMP_OP_GET:
167 		switch (val->var.subs[sub - 1]) {
168 		    case LEAF_begemotBridgeDefaultBridgeIf:
169 			string_get(val, bridge_get_default_name(), -1);
170 			break;
171 		    case LEAF_begemotBridgeDataUpdate:
172 			val->v.integer = bridge_data_maxage;
173 			break;
174 		    case LEAF_begemotBridgeDataPoll:
175 			val->v.integer = bridge_poll_ticks / 100;
176 			break;
177 		}
178 		return (SNMP_ERR_NOERROR);
179 
180 	    case SNMP_OP_GETNEXT:
181 		abort();
182 
183 	    case SNMP_OP_SET:
184 		switch (val->var.subs[sub - 1]) {
185 		    case LEAF_begemotBridgeDefaultBridgeIf:
186 			/*
187 			 * Cannot use string_save() here - requires either
188 			 * a fixed-sized or var-length string - not less
189 			 * than or equal.
190 			 */
191 			if (bridge_default_name_save(ctx,
192 			    bridge_get_default_name()) < 0)
193 				return (SNMP_ERR_RES_UNAVAIL);
194 
195 			if (bridge_set_default_name(val->v.octetstring.octets,
196 			    val->v.octetstring.len) < 0)
197 				return (SNMP_ERR_BADVALUE);
198 			break;
199 		    case LEAF_begemotBridgeDataUpdate:
200 			ctx->scratch->int1 = bridge_data_maxage;
201 			bridge_data_maxage = val->v.integer;
202 			break;
203 		    case LEAF_begemotBridgeDataPoll:
204 			ctx->scratch->int1 = val->v.integer;
205 			break;
206 		}
207 		return (SNMP_ERR_NOERROR);
208 
209 	    case SNMP_OP_ROLLBACK:
210 		switch (val->var.subs[sub - 1]) {
211 		    case LEAF_begemotBridgeDefaultBridgeIf:
212 			bridge_set_default_name(ctx->scratch->ptr1,
213 			    ctx->scratch->int1);
214 			free(ctx->scratch->ptr1);
215 			break;
216 		    case LEAF_begemotBridgeDataUpdate:
217 			bridge_data_maxage = ctx->scratch->int1;
218 			break;
219 		}
220 		return (SNMP_ERR_NOERROR);
221 
222 	    case SNMP_OP_COMMIT:
223 		switch (val->var.subs[sub - 1]) {
224 		    case LEAF_begemotBridgeDefaultBridgeIf:
225 			free(ctx->scratch->ptr1);
226 			break;
227 		    case LEAF_begemotBridgeDataPoll:
228 			bridge_set_poll_ticks(ctx->scratch->int1 * 100);
229 			break;
230 		}
231 		return (SNMP_ERR_NOERROR);
232 	}
233 
234 	return (SNMP_ERR_NOERROR);
235 }
236 
237 /*
238  * Bridge mib module initialization hook.
239  * Returns 0 on success, < 0 on error.
240  */
241 static int
242 bridge_init(struct lmodule * mod, int argc __unused, char *argv[] __unused)
243 {
244 	bridge_module = mod;
245 
246 	if (bridge_kmod_load() < 0)
247 		return (-1);
248 
249 	if (bridge_ioctl_init() < 0)
250 		return (-1);
251 
252 	/* Register to get creation messages for bridge interfaces. */
253 	if (mib_register_newif(bridge_attach_newif, bridge_module)) {
254 		syslog(LOG_ERR, "Cannot register newif function: %s",
255 		    strerror(errno));
256 		return (-1);
257 	}
258 
259 	return (0);
260 }
261 
262 /*
263  * Bridge mib module finalization hook.
264  */
265 static int
266 bridge_fini(void)
267 {
268 	mib_unregister_newif(bridge_module);
269 	or_unregister(reg_bridge);
270 
271 	if (bridge_data_timer != NULL) {
272 		timer_stop(bridge_data_timer);
273 		bridge_data_timer = NULL;
274 	}
275 
276 	if (bridge_tc_timer != NULL) {
277 		timer_stop(bridge_tc_timer);
278 		bridge_tc_timer = NULL;
279 	}
280 
281 	bridge_ifs_fini();
282 	bridge_ports_fini();
283 	bridge_addrs_fini();
284 
285 	return (0);
286 }
287 
288 /*
289  * Bridge mib module start operation.
290  */
291 static void
292 bridge_start(void)
293 {
294 	reg_bridge = or_register(&oid_dot1Bridge,
295 	    "The IETF MIB for Bridges (RFC 4188).", bridge_module);
296 
297 	bridge_data_timer = timer_start_repeat(bridge_poll_ticks,
298 	    bridge_poll_ticks, bridge_update_all, NULL, bridge_module);
299 
300 	bridge_tc_timer = timer_start_repeat(bridge_tc_poll_ticks,
301 	    bridge_tc_poll_ticks, bridge_update_tc_time, NULL, bridge_module);
302 }
303 
304 static void
305 bridge_dump(void)
306 {
307 	struct bridge_if *bif;
308 
309 	if ((bif = bridge_get_default()) == NULL)
310 		syslog(LOG_ERR, "Dump: no default bridge interface");
311 	else
312 		syslog(LOG_ERR, "Dump: default bridge interface %s",
313 		     bif->bif_name);
314 
315 	bridge_ifs_dump();
316 	bridge_pf_dump();
317 }
318 
319 const struct snmp_module config = {
320 	.comment = "This module implements the bridge mib (RFC 4188).",
321 	.init =		bridge_init,
322 	.fini =		bridge_fini,
323 	.start =	bridge_start,
324 	.tree =		bridge_ctree,
325 	.dump =		bridge_dump,
326 	.tree_size =	bridge_CTREE_SIZE,
327 };
328