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