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