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 #include "bridge_tree.h" 54 #include "bridge_snmp.h" 55 #include "bridge_oid.h" 56 57 static struct lmodule *bridge_module; 58 59 /* For the registration. */ 60 static const struct asn_oid oid_dot1Bridge = OIDX_dot1dBridge; 61 /* The registration. */ 62 static uint reg_bridge; 63 64 /* Periodic timer for polling all bridges' data. */ 65 static void *bridge_data_timer; 66 static void *bridge_tc_timer; 67 68 static int bridge_data_maxage = SNMP_BRIDGE_DATA_MAXAGE; 69 static int bridge_poll_ticks = SNMP_BRIDGE_POLL_INTERVAL * 100; 70 static int bridge_tc_poll_ticks = SNMP_BRIDGE_TC_POLL_INTERVAL * 100; 71 72 /* 73 * Our default bridge, whose info will be visible under 74 * the dot1dBridge subtree and functions to set/fetch it. 75 */ 76 static char bif_default_name[IFNAMSIZ] = "bridge0"; 77 static struct bridge_if *bif_default; 78 79 struct bridge_if * 80 bridge_get_default(void) 81 { 82 struct mibif *ifp; 83 84 if (bif_default != NULL) { 85 86 /* Walk through the mibII interface list. */ 87 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp)) 88 if (strcmp(ifp->name, bif_default->bif_name) == 0) 89 break; 90 91 if (ifp == NULL) 92 bif_default = NULL; 93 } 94 95 return (bif_default); 96 } 97 98 void 99 bridge_set_default(struct bridge_if *bif) 100 { 101 bif_default = bif; 102 103 syslog(LOG_ERR, "Set default bridge interface to: %s", 104 bif == NULL ? "(none)" : bif->bif_name); 105 } 106 107 const char * 108 bridge_get_default_name(void) 109 { 110 return (bif_default_name); 111 } 112 113 static int 114 bridge_set_default_name(const char *bif_name, uint len) 115 { 116 struct bridge_if *bif; 117 118 if (len >= IFNAMSIZ) 119 return (-1); 120 121 bcopy(bif_name, bif_default_name, len); 122 bif_default_name[len] = '\0'; 123 124 if ((bif = bridge_if_find_ifname(bif_default_name)) == NULL) { 125 bif_default = NULL; 126 return (0); 127 } 128 129 bif_default = bif; 130 return (1); 131 } 132 133 int 134 bridge_get_data_maxage(void) 135 { 136 return (bridge_data_maxage); 137 } 138 139 static void 140 bridge_set_poll_ticks(int poll_ticks) 141 { 142 if (bridge_data_timer != NULL) 143 timer_stop(bridge_data_timer); 144 145 bridge_poll_ticks = poll_ticks; 146 bridge_data_timer = timer_start_repeat(bridge_poll_ticks, 147 bridge_poll_ticks, bridge_update_all, NULL, bridge_module); 148 } 149 /* 150 * The bridge module configuration via SNMP. 151 */ 152 static int 153 bridge_default_name_save(struct snmp_context *ctx, const char *bridge_default) 154 { 155 if ((ctx->scratch->int1 = strlen(bridge_default)) >= IFNAMSIZ) 156 return (-1); 157 158 if ((ctx->scratch->ptr1 = malloc(IFNAMSIZ)) == NULL) 159 return (-1); 160 161 strncpy(ctx->scratch->ptr1, bridge_default, ctx->scratch->int1); 162 return (0); 163 } 164 165 int 166 op_begemot_bridge_config(struct snmp_context *ctx, struct snmp_value *val, 167 uint sub, uint iidx __unused, enum snmp_op op) 168 { 169 switch (op) { 170 case SNMP_OP_GET: 171 switch (val->var.subs[sub - 1]) { 172 case LEAF_begemotBridgeDefaultBridgeIf: 173 return (string_get(val, bridge_get_default_name(), -1)); 174 175 case LEAF_begemotBridgeDataUpdate: 176 val->v.integer = bridge_data_maxage; 177 return (SNMP_ERR_NOERROR); 178 179 case LEAF_begemotBridgeDataPoll: 180 val->v.integer = bridge_poll_ticks / 100; 181 return (SNMP_ERR_NOERROR); 182 } 183 abort(); 184 185 case SNMP_OP_GETNEXT: 186 abort(); 187 188 case SNMP_OP_SET: 189 switch (val->var.subs[sub - 1]) { 190 case LEAF_begemotBridgeDefaultBridgeIf: 191 /* 192 * Cannot use string_save() here - requires either 193 * a fixed-sized or var-length string - not less 194 * than or equal. 195 */ 196 if (bridge_default_name_save(ctx, 197 bridge_get_default_name()) < 0) 198 return (SNMP_ERR_RES_UNAVAIL); 199 200 if (bridge_set_default_name(val->v.octetstring.octets, 201 val->v.octetstring.len) < 0) 202 return (SNMP_ERR_BADVALUE); 203 return (SNMP_ERR_NOERROR); 204 205 case LEAF_begemotBridgeDataUpdate: 206 if (val->v.integer < SNMP_BRIDGE_DATA_MAXAGE_MIN || 207 val->v.integer > SNMP_BRIDGE_DATA_MAXAGE_MAX) 208 return (SNMP_ERR_WRONG_VALUE); 209 ctx->scratch->int1 = bridge_data_maxage; 210 bridge_data_maxage = val->v.integer; 211 return (SNMP_ERR_NOERROR); 212 213 case LEAF_begemotBridgeDataPoll: 214 if (val->v.integer < SNMP_BRIDGE_POLL_INTERVAL_MIN || 215 val->v.integer > SNMP_BRIDGE_POLL_INTERVAL_MAX) 216 return (SNMP_ERR_WRONG_VALUE); 217 ctx->scratch->int1 = val->v.integer; 218 return (SNMP_ERR_NOERROR); 219 } 220 abort(); 221 222 case SNMP_OP_ROLLBACK: 223 switch (val->var.subs[sub - 1]) { 224 case LEAF_begemotBridgeDefaultBridgeIf: 225 bridge_set_default_name(ctx->scratch->ptr1, 226 ctx->scratch->int1); 227 free(ctx->scratch->ptr1); 228 break; 229 case LEAF_begemotBridgeDataUpdate: 230 bridge_data_maxage = ctx->scratch->int1; 231 break; 232 } 233 return (SNMP_ERR_NOERROR); 234 235 case SNMP_OP_COMMIT: 236 switch (val->var.subs[sub - 1]) { 237 case LEAF_begemotBridgeDefaultBridgeIf: 238 free(ctx->scratch->ptr1); 239 break; 240 case LEAF_begemotBridgeDataPoll: 241 bridge_set_poll_ticks(ctx->scratch->int1 * 100); 242 break; 243 } 244 return (SNMP_ERR_NOERROR); 245 } 246 247 abort(); 248 } 249 250 /* 251 * Bridge mib module initialization hook. 252 * Returns 0 on success, < 0 on error. 253 */ 254 static int 255 bridge_init(struct lmodule * mod, int argc __unused, char *argv[] __unused) 256 { 257 bridge_module = mod; 258 259 if (bridge_kmod_load() < 0) 260 return (-1); 261 262 if (bridge_ioctl_init() < 0) 263 return (-1); 264 265 /* Register to get creation messages for bridge interfaces. */ 266 if (mib_register_newif(bridge_attach_newif, bridge_module)) { 267 syslog(LOG_ERR, "Cannot register newif function: %s", 268 strerror(errno)); 269 return (-1); 270 } 271 272 return (0); 273 } 274 275 /* 276 * Bridge mib module finalization hook. 277 */ 278 static int 279 bridge_fini(void) 280 { 281 mib_unregister_newif(bridge_module); 282 or_unregister(reg_bridge); 283 284 if (bridge_data_timer != NULL) { 285 timer_stop(bridge_data_timer); 286 bridge_data_timer = NULL; 287 } 288 289 if (bridge_tc_timer != NULL) { 290 timer_stop(bridge_tc_timer); 291 bridge_tc_timer = NULL; 292 } 293 294 bridge_ifs_fini(); 295 bridge_ports_fini(); 296 bridge_addrs_fini(); 297 298 return (0); 299 } 300 301 /* 302 * Bridge mib module start operation. 303 */ 304 static void 305 bridge_start(void) 306 { 307 reg_bridge = or_register(&oid_dot1Bridge, 308 "The IETF MIB for Bridges (RFC 4188).", bridge_module); 309 310 bridge_data_timer = timer_start_repeat(bridge_poll_ticks, 311 bridge_poll_ticks, bridge_update_all, NULL, bridge_module); 312 313 bridge_tc_timer = timer_start_repeat(bridge_tc_poll_ticks, 314 bridge_tc_poll_ticks, bridge_update_tc_time, NULL, bridge_module); 315 } 316 317 static void 318 bridge_dump(void) 319 { 320 struct bridge_if *bif; 321 322 if ((bif = bridge_get_default()) == NULL) 323 syslog(LOG_ERR, "Dump: no default bridge interface"); 324 else 325 syslog(LOG_ERR, "Dump: default bridge interface %s", 326 bif->bif_name); 327 328 bridge_ifs_dump(); 329 bridge_pf_dump(); 330 } 331 332 const struct snmp_module config = { 333 .comment = "This module implements the bridge mib (RFC 4188).", 334 .init = bridge_init, 335 .fini = bridge_fini, 336 .start = bridge_start, 337 .tree = bridge_ctree, 338 .dump = bridge_dump, 339 .tree_size = bridge_CTREE_SIZE, 340 }; 341