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 bif_default = NULL; 124 return (0); 125 } 126 127 bif_default = bif; 128 return (1); 129 } 130 131 int 132 bridge_get_data_maxage(void) 133 { 134 return (bridge_data_maxage); 135 } 136 137 static void 138 bridge_set_poll_ticks(int poll_ticks) 139 { 140 if (bridge_data_timer != NULL) 141 timer_stop(bridge_data_timer); 142 143 bridge_poll_ticks = poll_ticks; 144 bridge_data_timer = timer_start_repeat(bridge_poll_ticks, 145 bridge_poll_ticks, bridge_update_all, NULL, bridge_module); 146 } 147 /* 148 * The bridge module configuration via SNMP. 149 */ 150 static int 151 bridge_default_name_save(struct snmp_context *ctx, const char *bridge_default) 152 { 153 if ((ctx->scratch->int1 = strlen(bridge_default)) >= IFNAMSIZ) 154 return (-1); 155 156 if ((ctx->scratch->ptr1 = malloc(IFNAMSIZ)) == NULL) 157 return (-1); 158 159 strncpy(ctx->scratch->ptr1, bridge_default, ctx->scratch->int1); 160 return (0); 161 } 162 163 int 164 op_begemot_bridge_config(struct snmp_context *ctx, struct snmp_value *val, 165 uint sub, uint iidx __unused, enum snmp_op op) 166 { 167 switch (op) { 168 case SNMP_OP_GET: 169 switch (val->var.subs[sub - 1]) { 170 case LEAF_begemotBridgeDefaultBridgeIf: 171 return (string_get(val, bridge_get_default_name(), -1)); 172 173 case LEAF_begemotBridgeDataUpdate: 174 val->v.integer = bridge_data_maxage; 175 return (SNMP_ERR_NOERROR); 176 177 case LEAF_begemotBridgeDataPoll: 178 val->v.integer = bridge_poll_ticks / 100; 179 return (SNMP_ERR_NOERROR); 180 } 181 abort(); 182 183 case SNMP_OP_GETNEXT: 184 abort(); 185 186 case SNMP_OP_SET: 187 switch (val->var.subs[sub - 1]) { 188 case LEAF_begemotBridgeDefaultBridgeIf: 189 /* 190 * Cannot use string_save() here - requires either 191 * a fixed-sized or var-length string - not less 192 * than or equal. 193 */ 194 if (bridge_default_name_save(ctx, 195 bridge_get_default_name()) < 0) 196 return (SNMP_ERR_RES_UNAVAIL); 197 198 if (bridge_set_default_name(val->v.octetstring.octets, 199 val->v.octetstring.len) < 0) 200 return (SNMP_ERR_BADVALUE); 201 return (SNMP_ERR_NOERROR); 202 203 case LEAF_begemotBridgeDataUpdate: 204 if (val->v.integer < SNMP_BRIDGE_DATA_MAXAGE_MIN || 205 val->v.integer > SNMP_BRIDGE_DATA_MAXAGE_MAX) 206 return (SNMP_ERR_WRONG_VALUE); 207 ctx->scratch->int1 = bridge_data_maxage; 208 bridge_data_maxage = val->v.integer; 209 return (SNMP_ERR_NOERROR); 210 211 case LEAF_begemotBridgeDataPoll: 212 if (val->v.integer < SNMP_BRIDGE_POLL_INTERVAL_MIN || 213 val->v.integer > SNMP_BRIDGE_POLL_INTERVAL_MAX) 214 return (SNMP_ERR_WRONG_VALUE); 215 ctx->scratch->int1 = val->v.integer; 216 return (SNMP_ERR_NOERROR); 217 } 218 abort(); 219 220 case SNMP_OP_ROLLBACK: 221 switch (val->var.subs[sub - 1]) { 222 case LEAF_begemotBridgeDefaultBridgeIf: 223 bridge_set_default_name(ctx->scratch->ptr1, 224 ctx->scratch->int1); 225 free(ctx->scratch->ptr1); 226 break; 227 case LEAF_begemotBridgeDataUpdate: 228 bridge_data_maxage = ctx->scratch->int1; 229 break; 230 } 231 return (SNMP_ERR_NOERROR); 232 233 case SNMP_OP_COMMIT: 234 switch (val->var.subs[sub - 1]) { 235 case LEAF_begemotBridgeDefaultBridgeIf: 236 free(ctx->scratch->ptr1); 237 break; 238 case LEAF_begemotBridgeDataPoll: 239 bridge_set_poll_ticks(ctx->scratch->int1 * 100); 240 break; 241 } 242 return (SNMP_ERR_NOERROR); 243 } 244 245 abort(); 246 } 247 248 /* 249 * Bridge mib module initialization hook. 250 * Returns 0 on success, < 0 on error. 251 */ 252 static int 253 bridge_init(struct lmodule * mod, int argc __unused, char *argv[] __unused) 254 { 255 bridge_module = mod; 256 257 if (bridge_kmod_load() < 0) 258 return (-1); 259 260 if (bridge_ioctl_init() < 0) 261 return (-1); 262 263 /* Register to get creation messages for bridge interfaces. */ 264 if (mib_register_newif(bridge_attach_newif, bridge_module)) { 265 syslog(LOG_ERR, "Cannot register newif function: %s", 266 strerror(errno)); 267 return (-1); 268 } 269 270 return (0); 271 } 272 273 /* 274 * Bridge mib module finalization hook. 275 */ 276 static int 277 bridge_fini(void) 278 { 279 mib_unregister_newif(bridge_module); 280 or_unregister(reg_bridge); 281 282 if (bridge_data_timer != NULL) { 283 timer_stop(bridge_data_timer); 284 bridge_data_timer = NULL; 285 } 286 287 if (bridge_tc_timer != NULL) { 288 timer_stop(bridge_tc_timer); 289 bridge_tc_timer = NULL; 290 } 291 292 bridge_ifs_fini(); 293 bridge_ports_fini(); 294 bridge_addrs_fini(); 295 296 return (0); 297 } 298 299 /* 300 * Bridge mib module start operation. 301 */ 302 static void 303 bridge_start(void) 304 { 305 reg_bridge = or_register(&oid_dot1Bridge, 306 "The IETF MIB for Bridges (RFC 4188).", bridge_module); 307 308 bridge_data_timer = timer_start_repeat(bridge_poll_ticks, 309 bridge_poll_ticks, bridge_update_all, NULL, bridge_module); 310 311 bridge_tc_timer = timer_start_repeat(bridge_tc_poll_ticks, 312 bridge_tc_poll_ticks, bridge_update_tc_time, NULL, bridge_module); 313 } 314 315 static void 316 bridge_dump(void) 317 { 318 struct bridge_if *bif; 319 320 if ((bif = bridge_get_default()) == NULL) 321 syslog(LOG_ERR, "Dump: no default bridge interface"); 322 else 323 syslog(LOG_ERR, "Dump: default bridge interface %s", 324 bif->bif_name); 325 326 bridge_ifs_dump(); 327 bridge_pf_dump(); 328 } 329 330 const struct snmp_module config = { 331 .comment = "This module implements the bridge mib (RFC 4188).", 332 .init = bridge_init, 333 .fini = bridge_fini, 334 .start = bridge_start, 335 .tree = bridge_ctree, 336 .dump = bridge_dump, 337 .tree_size = bridge_CTREE_SIZE, 338 }; 339