1164410Ssyrinx/*-
2164410Ssyrinx * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
3164410Ssyrinx * All rights reserved.
4164410Ssyrinx *
5164410Ssyrinx * Redistribution and use in source and binary forms, with or without
6164410Ssyrinx * modification, are permitted provided that the following conditions
7164410Ssyrinx * are met:
8164410Ssyrinx * 1. Redistributions of source code must retain the above copyright
9164410Ssyrinx *    notice, this list of conditions and the following disclaimer.
10164410Ssyrinx * 2. Redistributions in binary form must reproduce the above copyright
11164410Ssyrinx *    notice, this list of conditions and the following disclaimer in the
12164410Ssyrinx *    documentation and/or other materials provided with the distribution.
13164410Ssyrinx *
14164410Ssyrinx * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15164410Ssyrinx * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16164410Ssyrinx * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17164410Ssyrinx * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18164410Ssyrinx * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19164410Ssyrinx * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20164410Ssyrinx * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21164410Ssyrinx * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22164410Ssyrinx * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23164410Ssyrinx * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24164410Ssyrinx * SUCH DAMAGE.
25164410Ssyrinx *
26164410Ssyrinx * Bridge MIB implementation for SNMPd.
27164410Ssyrinx *
28164410Ssyrinx * $FreeBSD: releng/10.3/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_snmp.c 165253 2006-12-15 20:01:57Z syrinx $
29164410Ssyrinx */
30164410Ssyrinx
31164410Ssyrinx#include <sys/param.h>
32164410Ssyrinx#include <sys/queue.h>
33164410Ssyrinx#include <sys/socket.h>
34164410Ssyrinx#include <sys/types.h>
35164410Ssyrinx
36164410Ssyrinx#include <net/ethernet.h>
37164410Ssyrinx#include <net/if.h>
38164410Ssyrinx#include <net/if_mib.h>
39164410Ssyrinx#include <net/if_types.h>
40164410Ssyrinx
41164410Ssyrinx#include <errno.h>
42164410Ssyrinx#include <stdarg.h>
43164410Ssyrinx#include <stdlib.h>
44164410Ssyrinx#include <stdio.h>
45164410Ssyrinx#include <string.h>
46164410Ssyrinx#include <syslog.h>
47164410Ssyrinx
48164410Ssyrinx#include <bsnmp/snmpmod.h>
49164410Ssyrinx#include <bsnmp/snmp_mibII.h>
50164410Ssyrinx
51164410Ssyrinx#include "bridge_tree.h"
52164410Ssyrinx#include "bridge_snmp.h"
53164410Ssyrinx#include "bridge_oid.h"
54164410Ssyrinx
55164410Ssyrinxstatic struct lmodule *bridge_module;
56164410Ssyrinx
57164410Ssyrinx/* For the registration. */
58164410Ssyrinxstatic const struct asn_oid oid_dot1Bridge = OIDX_dot1dBridge;
59164410Ssyrinx/* The registration. */
60164410Ssyrinxstatic uint reg_bridge;
61164410Ssyrinx
62164410Ssyrinx/* Periodic timer for polling all bridges' data. */
63164410Ssyrinxstatic void *bridge_data_timer;
64164410Ssyrinxstatic void *bridge_tc_timer;
65164410Ssyrinx
66164410Ssyrinxstatic int bridge_data_maxage = SNMP_BRIDGE_DATA_MAXAGE;
67164410Ssyrinxstatic int bridge_poll_ticks = SNMP_BRIDGE_POLL_INTERVAL * 100;
68164410Ssyrinxstatic int bridge_tc_poll_ticks = SNMP_BRIDGE_TC_POLL_INTERVAL * 100;
69164410Ssyrinx
70164410Ssyrinx/*
71164410Ssyrinx * Our default bridge, whose info will be visible under
72164410Ssyrinx * the dot1dBridge subtree and functions to set/fetch it.
73164410Ssyrinx */
74164410Ssyrinxstatic char bif_default_name[IFNAMSIZ] = "bridge0";
75164410Ssyrinxstatic struct bridge_if *bif_default;
76164410Ssyrinx
77164410Ssyrinxstruct bridge_if *
78164410Ssyrinxbridge_get_default(void)
79164410Ssyrinx{
80164410Ssyrinx	struct mibif *ifp;
81164410Ssyrinx
82164410Ssyrinx	if (bif_default != NULL) {
83164410Ssyrinx
84164410Ssyrinx		/* Walk through the mibII interface list. */
85164410Ssyrinx		for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
86164410Ssyrinx			if (strcmp(ifp->name, bif_default->bif_name) == 0)
87164410Ssyrinx				break;
88164410Ssyrinx
89164410Ssyrinx		if (ifp == NULL)
90164410Ssyrinx			bif_default = NULL;
91164410Ssyrinx	}
92164410Ssyrinx
93164410Ssyrinx	return (bif_default);
94164410Ssyrinx}
95164410Ssyrinx
96164410Ssyrinxvoid
97164410Ssyrinxbridge_set_default(struct bridge_if *bif)
98164410Ssyrinx{
99164410Ssyrinx	bif_default = bif;
100164410Ssyrinx
101164410Ssyrinx	syslog(LOG_ERR, "Set default bridge interface to: %s",
102164410Ssyrinx	    bif == NULL ? "(none)" : bif->bif_name);
103164410Ssyrinx}
104164410Ssyrinx
105164410Ssyrinxconst char *
106164410Ssyrinxbridge_get_default_name(void)
107164410Ssyrinx{
108164410Ssyrinx	return (bif_default_name);
109164410Ssyrinx}
110164410Ssyrinx
111164410Ssyrinxstatic int
112164410Ssyrinxbridge_set_default_name(const char *bif_name, uint len)
113164410Ssyrinx{
114164410Ssyrinx	struct bridge_if *bif;
115164410Ssyrinx
116164410Ssyrinx	if (len >= IFNAMSIZ)
117164410Ssyrinx		return (-1);
118164410Ssyrinx
119164410Ssyrinx	bcopy(bif_name, bif_default_name, len);
120164410Ssyrinx	bif_default_name[len] = '\0';
121164410Ssyrinx
122164997Ssyrinx	if ((bif = bridge_if_find_ifname(bif_default_name)) == NULL) {
123164997Ssyrinx		bif_default = NULL;
124164410Ssyrinx		return (0);
125164997Ssyrinx	}
126164410Ssyrinx
127164410Ssyrinx	bif_default = bif;
128164410Ssyrinx	return (1);
129164410Ssyrinx}
130164410Ssyrinx
131164410Ssyrinxint
132164410Ssyrinxbridge_get_data_maxage(void)
133164410Ssyrinx{
134164410Ssyrinx	return (bridge_data_maxage);
135164410Ssyrinx}
136164410Ssyrinx
137164410Ssyrinxstatic void
138164410Ssyrinxbridge_set_poll_ticks(int poll_ticks)
139164410Ssyrinx{
140164410Ssyrinx	if (bridge_data_timer != NULL)
141164410Ssyrinx		timer_stop(bridge_data_timer);
142164410Ssyrinx
143164410Ssyrinx	bridge_poll_ticks = poll_ticks;
144164410Ssyrinx	bridge_data_timer = timer_start_repeat(bridge_poll_ticks,
145164410Ssyrinx	    bridge_poll_ticks, bridge_update_all, NULL, bridge_module);
146164410Ssyrinx}
147164410Ssyrinx/*
148164410Ssyrinx * The bridge module configuration via SNMP.
149164410Ssyrinx */
150164410Ssyrinxstatic int
151164410Ssyrinxbridge_default_name_save(struct snmp_context *ctx, const char *bridge_default)
152164410Ssyrinx{
153164410Ssyrinx	if ((ctx->scratch->int1 = strlen(bridge_default)) >= IFNAMSIZ)
154164410Ssyrinx		return (-1);
155164410Ssyrinx
156164410Ssyrinx	if ((ctx->scratch->ptr1 = malloc(IFNAMSIZ)) == NULL)
157164410Ssyrinx		return (-1);
158164410Ssyrinx
159164410Ssyrinx	strncpy(ctx->scratch->ptr1, bridge_default, ctx->scratch->int1);
160164410Ssyrinx	return (0);
161164410Ssyrinx}
162164410Ssyrinx
163164410Ssyrinxint
164164410Ssyrinxop_begemot_bridge_config(struct snmp_context *ctx, struct snmp_value *val,
165164410Ssyrinx    uint sub, uint iidx __unused, enum snmp_op op)
166164410Ssyrinx{
167164410Ssyrinx	switch (op) {
168164410Ssyrinx	    case SNMP_OP_GET:
169164410Ssyrinx		switch (val->var.subs[sub - 1]) {
170164410Ssyrinx		    case LEAF_begemotBridgeDefaultBridgeIf:
171165253Ssyrinx			return (string_get(val, bridge_get_default_name(), -1));
172165253Ssyrinx
173164410Ssyrinx		    case LEAF_begemotBridgeDataUpdate:
174164410Ssyrinx			val->v.integer = bridge_data_maxage;
175165253Ssyrinx			return (SNMP_ERR_NOERROR);
176165253Ssyrinx
177164410Ssyrinx		    case LEAF_begemotBridgeDataPoll:
178164410Ssyrinx			val->v.integer = bridge_poll_ticks / 100;
179165253Ssyrinx			return (SNMP_ERR_NOERROR);
180164410Ssyrinx		}
181165253Ssyrinx		abort();
182164410Ssyrinx
183164410Ssyrinx	    case SNMP_OP_GETNEXT:
184164410Ssyrinx		abort();
185164410Ssyrinx
186164410Ssyrinx	    case SNMP_OP_SET:
187164410Ssyrinx		switch (val->var.subs[sub - 1]) {
188164410Ssyrinx		    case LEAF_begemotBridgeDefaultBridgeIf:
189164410Ssyrinx			/*
190164410Ssyrinx			 * Cannot use string_save() here - requires either
191164410Ssyrinx			 * a fixed-sized or var-length string - not less
192164410Ssyrinx			 * than or equal.
193164410Ssyrinx			 */
194164410Ssyrinx			if (bridge_default_name_save(ctx,
195164410Ssyrinx			    bridge_get_default_name()) < 0)
196164410Ssyrinx				return (SNMP_ERR_RES_UNAVAIL);
197164410Ssyrinx
198164410Ssyrinx			if (bridge_set_default_name(val->v.octetstring.octets,
199164410Ssyrinx			    val->v.octetstring.len) < 0)
200164410Ssyrinx				return (SNMP_ERR_BADVALUE);
201165253Ssyrinx			return (SNMP_ERR_NOERROR);
202165253Ssyrinx
203164410Ssyrinx		    case LEAF_begemotBridgeDataUpdate:
204164997Ssyrinx			if (val->v.integer < SNMP_BRIDGE_DATA_MAXAGE_MIN ||
205164997Ssyrinx			    val->v.integer > SNMP_BRIDGE_DATA_MAXAGE_MAX)
206164997Ssyrinx				return (SNMP_ERR_WRONG_VALUE);
207164410Ssyrinx			ctx->scratch->int1 = bridge_data_maxage;
208164410Ssyrinx			bridge_data_maxage = val->v.integer;
209165253Ssyrinx			return (SNMP_ERR_NOERROR);
210165253Ssyrinx
211164410Ssyrinx		    case LEAF_begemotBridgeDataPoll:
212164997Ssyrinx			if (val->v.integer < SNMP_BRIDGE_POLL_INTERVAL_MIN ||
213164997Ssyrinx			    val->v.integer > SNMP_BRIDGE_POLL_INTERVAL_MAX)
214164997Ssyrinx				return (SNMP_ERR_WRONG_VALUE);
215164410Ssyrinx			ctx->scratch->int1 = val->v.integer;
216165253Ssyrinx			return (SNMP_ERR_NOERROR);
217164410Ssyrinx		}
218165253Ssyrinx		abort();
219164410Ssyrinx
220164410Ssyrinx	    case SNMP_OP_ROLLBACK:
221164410Ssyrinx		switch (val->var.subs[sub - 1]) {
222164410Ssyrinx		    case LEAF_begemotBridgeDefaultBridgeIf:
223164410Ssyrinx			bridge_set_default_name(ctx->scratch->ptr1,
224164410Ssyrinx			    ctx->scratch->int1);
225164410Ssyrinx			free(ctx->scratch->ptr1);
226164410Ssyrinx			break;
227164410Ssyrinx		    case LEAF_begemotBridgeDataUpdate:
228164410Ssyrinx			bridge_data_maxage = ctx->scratch->int1;
229164410Ssyrinx			break;
230164410Ssyrinx		}
231164410Ssyrinx		return (SNMP_ERR_NOERROR);
232164410Ssyrinx
233164410Ssyrinx	    case SNMP_OP_COMMIT:
234164410Ssyrinx		switch (val->var.subs[sub - 1]) {
235164410Ssyrinx		    case LEAF_begemotBridgeDefaultBridgeIf:
236164410Ssyrinx			free(ctx->scratch->ptr1);
237164410Ssyrinx			break;
238164410Ssyrinx		    case LEAF_begemotBridgeDataPoll:
239164410Ssyrinx			bridge_set_poll_ticks(ctx->scratch->int1 * 100);
240164410Ssyrinx			break;
241164410Ssyrinx		}
242164410Ssyrinx		return (SNMP_ERR_NOERROR);
243164410Ssyrinx	}
244164410Ssyrinx
245165253Ssyrinx	abort();
246164410Ssyrinx}
247164410Ssyrinx
248164410Ssyrinx/*
249164410Ssyrinx * Bridge mib module initialization hook.
250164410Ssyrinx * Returns 0 on success, < 0 on error.
251164410Ssyrinx */
252164410Ssyrinxstatic int
253164410Ssyrinxbridge_init(struct lmodule * mod, int argc __unused, char *argv[] __unused)
254164410Ssyrinx{
255164410Ssyrinx	bridge_module = mod;
256164410Ssyrinx
257164410Ssyrinx	if (bridge_kmod_load() < 0)
258164410Ssyrinx		return (-1);
259164410Ssyrinx
260164410Ssyrinx	if (bridge_ioctl_init() < 0)
261164410Ssyrinx		return (-1);
262164410Ssyrinx
263164410Ssyrinx	/* Register to get creation messages for bridge interfaces. */
264164410Ssyrinx	if (mib_register_newif(bridge_attach_newif, bridge_module)) {
265164410Ssyrinx		syslog(LOG_ERR, "Cannot register newif function: %s",
266164410Ssyrinx		    strerror(errno));
267164410Ssyrinx		return (-1);
268164410Ssyrinx	}
269164410Ssyrinx
270164410Ssyrinx	return (0);
271164410Ssyrinx}
272164410Ssyrinx
273164410Ssyrinx/*
274164410Ssyrinx * Bridge mib module finalization hook.
275164410Ssyrinx */
276164410Ssyrinxstatic int
277164410Ssyrinxbridge_fini(void)
278164410Ssyrinx{
279164410Ssyrinx	mib_unregister_newif(bridge_module);
280164410Ssyrinx	or_unregister(reg_bridge);
281164410Ssyrinx
282164410Ssyrinx	if (bridge_data_timer != NULL) {
283164410Ssyrinx		timer_stop(bridge_data_timer);
284164410Ssyrinx		bridge_data_timer = NULL;
285164410Ssyrinx	}
286164410Ssyrinx
287164410Ssyrinx	if (bridge_tc_timer != NULL) {
288164410Ssyrinx		timer_stop(bridge_tc_timer);
289164410Ssyrinx		bridge_tc_timer = NULL;
290164410Ssyrinx	}
291164410Ssyrinx
292164410Ssyrinx	bridge_ifs_fini();
293164410Ssyrinx	bridge_ports_fini();
294164410Ssyrinx	bridge_addrs_fini();
295164410Ssyrinx
296164410Ssyrinx	return (0);
297164410Ssyrinx}
298164410Ssyrinx
299164410Ssyrinx/*
300164410Ssyrinx * Bridge mib module start operation.
301164410Ssyrinx */
302164410Ssyrinxstatic void
303164410Ssyrinxbridge_start(void)
304164410Ssyrinx{
305164410Ssyrinx	reg_bridge = or_register(&oid_dot1Bridge,
306164410Ssyrinx	    "The IETF MIB for Bridges (RFC 4188).", bridge_module);
307164410Ssyrinx
308164410Ssyrinx	bridge_data_timer = timer_start_repeat(bridge_poll_ticks,
309164410Ssyrinx	    bridge_poll_ticks, bridge_update_all, NULL, bridge_module);
310164410Ssyrinx
311164410Ssyrinx	bridge_tc_timer = timer_start_repeat(bridge_tc_poll_ticks,
312164410Ssyrinx	    bridge_tc_poll_ticks, bridge_update_tc_time, NULL, bridge_module);
313164410Ssyrinx}
314164410Ssyrinx
315164410Ssyrinxstatic void
316164410Ssyrinxbridge_dump(void)
317164410Ssyrinx{
318164410Ssyrinx	struct bridge_if *bif;
319164410Ssyrinx
320164410Ssyrinx	if ((bif = bridge_get_default()) == NULL)
321164410Ssyrinx		syslog(LOG_ERR, "Dump: no default bridge interface");
322164410Ssyrinx	else
323164410Ssyrinx		syslog(LOG_ERR, "Dump: default bridge interface %s",
324164410Ssyrinx		     bif->bif_name);
325164410Ssyrinx
326164410Ssyrinx	bridge_ifs_dump();
327164410Ssyrinx	bridge_pf_dump();
328164410Ssyrinx}
329164410Ssyrinx
330164410Ssyrinxconst struct snmp_module config = {
331164410Ssyrinx	.comment = "This module implements the bridge mib (RFC 4188).",
332164410Ssyrinx	.init =		bridge_init,
333164410Ssyrinx	.fini =		bridge_fini,
334164410Ssyrinx	.start =	bridge_start,
335164410Ssyrinx	.tree =		bridge_ctree,
336164410Ssyrinx	.dump =		bridge_dump,
337164410Ssyrinx	.tree_size =	bridge_CTREE_SIZE,
338164410Ssyrinx};
339