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