1164410Ssyrinx/*- 2164410Ssyrinx * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org> 3164410Ssyrinx * All rights reserved. 4164410Ssyrinx * 5164410Ssyrinx * Redistribution and use in source and binary forms, with or without 6164410Ssyrinx * modification, are permitted provided that the following conditions 7164410Ssyrinx * are met: 8164410Ssyrinx * 1. Redistributions of source code must retain the above copyright 9164410Ssyrinx * notice, this list of conditions and the following disclaimer. 10164410Ssyrinx * 2. Redistributions in binary form must reproduce the above copyright 11164410Ssyrinx * notice, this list of conditions and the following disclaimer in the 12164410Ssyrinx * documentation and/or other materials provided with the distribution. 13164410Ssyrinx * 14164410Ssyrinx * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15164410Ssyrinx * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16164410Ssyrinx * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17164410Ssyrinx * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18164410Ssyrinx * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19164410Ssyrinx * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20164410Ssyrinx * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21164410Ssyrinx * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22164410Ssyrinx * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23164410Ssyrinx * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24164410Ssyrinx * SUCH DAMAGE. 25164410Ssyrinx * 26164410Ssyrinx * Bridge MIB implementation for SNMPd. 27164410Ssyrinx * 28164410Ssyrinx * $FreeBSD: releng/10.3/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_snmp.c 165253 2006-12-15 20:01:57Z syrinx $ 29164410Ssyrinx */ 30164410Ssyrinx 31164410Ssyrinx#include <sys/param.h> 32164410Ssyrinx#include <sys/queue.h> 33164410Ssyrinx#include <sys/socket.h> 34164410Ssyrinx#include <sys/types.h> 35164410Ssyrinx 36164410Ssyrinx#include <net/ethernet.h> 37164410Ssyrinx#include <net/if.h> 38164410Ssyrinx#include <net/if_mib.h> 39164410Ssyrinx#include <net/if_types.h> 40164410Ssyrinx 41164410Ssyrinx#include <errno.h> 42164410Ssyrinx#include <stdarg.h> 43164410Ssyrinx#include <stdlib.h> 44164410Ssyrinx#include <stdio.h> 45164410Ssyrinx#include <string.h> 46164410Ssyrinx#include <syslog.h> 47164410Ssyrinx 48164410Ssyrinx#include <bsnmp/snmpmod.h> 49164410Ssyrinx#include <bsnmp/snmp_mibII.h> 50164410Ssyrinx 51164410Ssyrinx#include "bridge_tree.h" 52164410Ssyrinx#include "bridge_snmp.h" 53164410Ssyrinx#include "bridge_oid.h" 54164410Ssyrinx 55164410Ssyrinxstatic struct lmodule *bridge_module; 56164410Ssyrinx 57164410Ssyrinx/* For the registration. */ 58164410Ssyrinxstatic const struct asn_oid oid_dot1Bridge = OIDX_dot1dBridge; 59164410Ssyrinx/* The registration. */ 60164410Ssyrinxstatic uint reg_bridge; 61164410Ssyrinx 62164410Ssyrinx/* Periodic timer for polling all bridges' data. */ 63164410Ssyrinxstatic void *bridge_data_timer; 64164410Ssyrinxstatic void *bridge_tc_timer; 65164410Ssyrinx 66164410Ssyrinxstatic int bridge_data_maxage = SNMP_BRIDGE_DATA_MAXAGE; 67164410Ssyrinxstatic int bridge_poll_ticks = SNMP_BRIDGE_POLL_INTERVAL * 100; 68164410Ssyrinxstatic int bridge_tc_poll_ticks = SNMP_BRIDGE_TC_POLL_INTERVAL * 100; 69164410Ssyrinx 70164410Ssyrinx/* 71164410Ssyrinx * Our default bridge, whose info will be visible under 72164410Ssyrinx * the dot1dBridge subtree and functions to set/fetch it. 73164410Ssyrinx */ 74164410Ssyrinxstatic char bif_default_name[IFNAMSIZ] = "bridge0"; 75164410Ssyrinxstatic struct bridge_if *bif_default; 76164410Ssyrinx 77164410Ssyrinxstruct bridge_if * 78164410Ssyrinxbridge_get_default(void) 79164410Ssyrinx{ 80164410Ssyrinx struct mibif *ifp; 81164410Ssyrinx 82164410Ssyrinx if (bif_default != NULL) { 83164410Ssyrinx 84164410Ssyrinx /* Walk through the mibII interface list. */ 85164410Ssyrinx for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp)) 86164410Ssyrinx if (strcmp(ifp->name, bif_default->bif_name) == 0) 87164410Ssyrinx break; 88164410Ssyrinx 89164410Ssyrinx if (ifp == NULL) 90164410Ssyrinx bif_default = NULL; 91164410Ssyrinx } 92164410Ssyrinx 93164410Ssyrinx return (bif_default); 94164410Ssyrinx} 95164410Ssyrinx 96164410Ssyrinxvoid 97164410Ssyrinxbridge_set_default(struct bridge_if *bif) 98164410Ssyrinx{ 99164410Ssyrinx bif_default = bif; 100164410Ssyrinx 101164410Ssyrinx syslog(LOG_ERR, "Set default bridge interface to: %s", 102164410Ssyrinx bif == NULL ? "(none)" : bif->bif_name); 103164410Ssyrinx} 104164410Ssyrinx 105164410Ssyrinxconst char * 106164410Ssyrinxbridge_get_default_name(void) 107164410Ssyrinx{ 108164410Ssyrinx return (bif_default_name); 109164410Ssyrinx} 110164410Ssyrinx 111164410Ssyrinxstatic int 112164410Ssyrinxbridge_set_default_name(const char *bif_name, uint len) 113164410Ssyrinx{ 114164410Ssyrinx struct bridge_if *bif; 115164410Ssyrinx 116164410Ssyrinx if (len >= IFNAMSIZ) 117164410Ssyrinx return (-1); 118164410Ssyrinx 119164410Ssyrinx bcopy(bif_name, bif_default_name, len); 120164410Ssyrinx bif_default_name[len] = '\0'; 121164410Ssyrinx 122164997Ssyrinx if ((bif = bridge_if_find_ifname(bif_default_name)) == NULL) { 123164997Ssyrinx bif_default = NULL; 124164410Ssyrinx return (0); 125164997Ssyrinx } 126164410Ssyrinx 127164410Ssyrinx bif_default = bif; 128164410Ssyrinx return (1); 129164410Ssyrinx} 130164410Ssyrinx 131164410Ssyrinxint 132164410Ssyrinxbridge_get_data_maxage(void) 133164410Ssyrinx{ 134164410Ssyrinx return (bridge_data_maxage); 135164410Ssyrinx} 136164410Ssyrinx 137164410Ssyrinxstatic void 138164410Ssyrinxbridge_set_poll_ticks(int poll_ticks) 139164410Ssyrinx{ 140164410Ssyrinx if (bridge_data_timer != NULL) 141164410Ssyrinx timer_stop(bridge_data_timer); 142164410Ssyrinx 143164410Ssyrinx bridge_poll_ticks = poll_ticks; 144164410Ssyrinx bridge_data_timer = timer_start_repeat(bridge_poll_ticks, 145164410Ssyrinx bridge_poll_ticks, bridge_update_all, NULL, bridge_module); 146164410Ssyrinx} 147164410Ssyrinx/* 148164410Ssyrinx * The bridge module configuration via SNMP. 149164410Ssyrinx */ 150164410Ssyrinxstatic int 151164410Ssyrinxbridge_default_name_save(struct snmp_context *ctx, const char *bridge_default) 152164410Ssyrinx{ 153164410Ssyrinx if ((ctx->scratch->int1 = strlen(bridge_default)) >= IFNAMSIZ) 154164410Ssyrinx return (-1); 155164410Ssyrinx 156164410Ssyrinx if ((ctx->scratch->ptr1 = malloc(IFNAMSIZ)) == NULL) 157164410Ssyrinx return (-1); 158164410Ssyrinx 159164410Ssyrinx strncpy(ctx->scratch->ptr1, bridge_default, ctx->scratch->int1); 160164410Ssyrinx return (0); 161164410Ssyrinx} 162164410Ssyrinx 163164410Ssyrinxint 164164410Ssyrinxop_begemot_bridge_config(struct snmp_context *ctx, struct snmp_value *val, 165164410Ssyrinx uint sub, uint iidx __unused, enum snmp_op op) 166164410Ssyrinx{ 167164410Ssyrinx switch (op) { 168164410Ssyrinx case SNMP_OP_GET: 169164410Ssyrinx switch (val->var.subs[sub - 1]) { 170164410Ssyrinx case LEAF_begemotBridgeDefaultBridgeIf: 171165253Ssyrinx return (string_get(val, bridge_get_default_name(), -1)); 172165253Ssyrinx 173164410Ssyrinx case LEAF_begemotBridgeDataUpdate: 174164410Ssyrinx val->v.integer = bridge_data_maxage; 175165253Ssyrinx return (SNMP_ERR_NOERROR); 176165253Ssyrinx 177164410Ssyrinx case LEAF_begemotBridgeDataPoll: 178164410Ssyrinx val->v.integer = bridge_poll_ticks / 100; 179165253Ssyrinx return (SNMP_ERR_NOERROR); 180164410Ssyrinx } 181165253Ssyrinx abort(); 182164410Ssyrinx 183164410Ssyrinx case SNMP_OP_GETNEXT: 184164410Ssyrinx abort(); 185164410Ssyrinx 186164410Ssyrinx case SNMP_OP_SET: 187164410Ssyrinx switch (val->var.subs[sub - 1]) { 188164410Ssyrinx case LEAF_begemotBridgeDefaultBridgeIf: 189164410Ssyrinx /* 190164410Ssyrinx * Cannot use string_save() here - requires either 191164410Ssyrinx * a fixed-sized or var-length string - not less 192164410Ssyrinx * than or equal. 193164410Ssyrinx */ 194164410Ssyrinx if (bridge_default_name_save(ctx, 195164410Ssyrinx bridge_get_default_name()) < 0) 196164410Ssyrinx return (SNMP_ERR_RES_UNAVAIL); 197164410Ssyrinx 198164410Ssyrinx if (bridge_set_default_name(val->v.octetstring.octets, 199164410Ssyrinx val->v.octetstring.len) < 0) 200164410Ssyrinx return (SNMP_ERR_BADVALUE); 201165253Ssyrinx return (SNMP_ERR_NOERROR); 202165253Ssyrinx 203164410Ssyrinx case LEAF_begemotBridgeDataUpdate: 204164997Ssyrinx if (val->v.integer < SNMP_BRIDGE_DATA_MAXAGE_MIN || 205164997Ssyrinx val->v.integer > SNMP_BRIDGE_DATA_MAXAGE_MAX) 206164997Ssyrinx return (SNMP_ERR_WRONG_VALUE); 207164410Ssyrinx ctx->scratch->int1 = bridge_data_maxage; 208164410Ssyrinx bridge_data_maxage = val->v.integer; 209165253Ssyrinx return (SNMP_ERR_NOERROR); 210165253Ssyrinx 211164410Ssyrinx case LEAF_begemotBridgeDataPoll: 212164997Ssyrinx if (val->v.integer < SNMP_BRIDGE_POLL_INTERVAL_MIN || 213164997Ssyrinx val->v.integer > SNMP_BRIDGE_POLL_INTERVAL_MAX) 214164997Ssyrinx return (SNMP_ERR_WRONG_VALUE); 215164410Ssyrinx ctx->scratch->int1 = val->v.integer; 216165253Ssyrinx return (SNMP_ERR_NOERROR); 217164410Ssyrinx } 218165253Ssyrinx abort(); 219164410Ssyrinx 220164410Ssyrinx case SNMP_OP_ROLLBACK: 221164410Ssyrinx switch (val->var.subs[sub - 1]) { 222164410Ssyrinx case LEAF_begemotBridgeDefaultBridgeIf: 223164410Ssyrinx bridge_set_default_name(ctx->scratch->ptr1, 224164410Ssyrinx ctx->scratch->int1); 225164410Ssyrinx free(ctx->scratch->ptr1); 226164410Ssyrinx break; 227164410Ssyrinx case LEAF_begemotBridgeDataUpdate: 228164410Ssyrinx bridge_data_maxage = ctx->scratch->int1; 229164410Ssyrinx break; 230164410Ssyrinx } 231164410Ssyrinx return (SNMP_ERR_NOERROR); 232164410Ssyrinx 233164410Ssyrinx case SNMP_OP_COMMIT: 234164410Ssyrinx switch (val->var.subs[sub - 1]) { 235164410Ssyrinx case LEAF_begemotBridgeDefaultBridgeIf: 236164410Ssyrinx free(ctx->scratch->ptr1); 237164410Ssyrinx break; 238164410Ssyrinx case LEAF_begemotBridgeDataPoll: 239164410Ssyrinx bridge_set_poll_ticks(ctx->scratch->int1 * 100); 240164410Ssyrinx break; 241164410Ssyrinx } 242164410Ssyrinx return (SNMP_ERR_NOERROR); 243164410Ssyrinx } 244164410Ssyrinx 245165253Ssyrinx abort(); 246164410Ssyrinx} 247164410Ssyrinx 248164410Ssyrinx/* 249164410Ssyrinx * Bridge mib module initialization hook. 250164410Ssyrinx * Returns 0 on success, < 0 on error. 251164410Ssyrinx */ 252164410Ssyrinxstatic int 253164410Ssyrinxbridge_init(struct lmodule * mod, int argc __unused, char *argv[] __unused) 254164410Ssyrinx{ 255164410Ssyrinx bridge_module = mod; 256164410Ssyrinx 257164410Ssyrinx if (bridge_kmod_load() < 0) 258164410Ssyrinx return (-1); 259164410Ssyrinx 260164410Ssyrinx if (bridge_ioctl_init() < 0) 261164410Ssyrinx return (-1); 262164410Ssyrinx 263164410Ssyrinx /* Register to get creation messages for bridge interfaces. */ 264164410Ssyrinx if (mib_register_newif(bridge_attach_newif, bridge_module)) { 265164410Ssyrinx syslog(LOG_ERR, "Cannot register newif function: %s", 266164410Ssyrinx strerror(errno)); 267164410Ssyrinx return (-1); 268164410Ssyrinx } 269164410Ssyrinx 270164410Ssyrinx return (0); 271164410Ssyrinx} 272164410Ssyrinx 273164410Ssyrinx/* 274164410Ssyrinx * Bridge mib module finalization hook. 275164410Ssyrinx */ 276164410Ssyrinxstatic int 277164410Ssyrinxbridge_fini(void) 278164410Ssyrinx{ 279164410Ssyrinx mib_unregister_newif(bridge_module); 280164410Ssyrinx or_unregister(reg_bridge); 281164410Ssyrinx 282164410Ssyrinx if (bridge_data_timer != NULL) { 283164410Ssyrinx timer_stop(bridge_data_timer); 284164410Ssyrinx bridge_data_timer = NULL; 285164410Ssyrinx } 286164410Ssyrinx 287164410Ssyrinx if (bridge_tc_timer != NULL) { 288164410Ssyrinx timer_stop(bridge_tc_timer); 289164410Ssyrinx bridge_tc_timer = NULL; 290164410Ssyrinx } 291164410Ssyrinx 292164410Ssyrinx bridge_ifs_fini(); 293164410Ssyrinx bridge_ports_fini(); 294164410Ssyrinx bridge_addrs_fini(); 295164410Ssyrinx 296164410Ssyrinx return (0); 297164410Ssyrinx} 298164410Ssyrinx 299164410Ssyrinx/* 300164410Ssyrinx * Bridge mib module start operation. 301164410Ssyrinx */ 302164410Ssyrinxstatic void 303164410Ssyrinxbridge_start(void) 304164410Ssyrinx{ 305164410Ssyrinx reg_bridge = or_register(&oid_dot1Bridge, 306164410Ssyrinx "The IETF MIB for Bridges (RFC 4188).", bridge_module); 307164410Ssyrinx 308164410Ssyrinx bridge_data_timer = timer_start_repeat(bridge_poll_ticks, 309164410Ssyrinx bridge_poll_ticks, bridge_update_all, NULL, bridge_module); 310164410Ssyrinx 311164410Ssyrinx bridge_tc_timer = timer_start_repeat(bridge_tc_poll_ticks, 312164410Ssyrinx bridge_tc_poll_ticks, bridge_update_tc_time, NULL, bridge_module); 313164410Ssyrinx} 314164410Ssyrinx 315164410Ssyrinxstatic void 316164410Ssyrinxbridge_dump(void) 317164410Ssyrinx{ 318164410Ssyrinx struct bridge_if *bif; 319164410Ssyrinx 320164410Ssyrinx if ((bif = bridge_get_default()) == NULL) 321164410Ssyrinx syslog(LOG_ERR, "Dump: no default bridge interface"); 322164410Ssyrinx else 323164410Ssyrinx syslog(LOG_ERR, "Dump: default bridge interface %s", 324164410Ssyrinx bif->bif_name); 325164410Ssyrinx 326164410Ssyrinx bridge_ifs_dump(); 327164410Ssyrinx bridge_pf_dump(); 328164410Ssyrinx} 329164410Ssyrinx 330164410Ssyrinxconst struct snmp_module config = { 331164410Ssyrinx .comment = "This module implements the bridge mib (RFC 4188).", 332164410Ssyrinx .init = bridge_init, 333164410Ssyrinx .fini = bridge_fini, 334164410Ssyrinx .start = bridge_start, 335164410Ssyrinx .tree = bridge_ctree, 336164410Ssyrinx .dump = bridge_dump, 337164410Ssyrinx .tree_size = bridge_CTREE_SIZE, 338164410Ssyrinx}; 339