bridge_if.c revision 310903
150027Speter/*- 272376Sjake * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org> 372376Sjake * All rights reserved. 450027Speter * 550027Speter * Redistribution and use in source and binary forms, with or without 650027Speter * modification, are permitted provided that the following conditions 750027Speter * are met: 850027Speter * 1. Redistributions of source code must retain the above copyright 950027Speter * notice, this list of conditions and the following disclaimer. 1050027Speter * 2. Redistributions in binary form must reproduce the above copyright 1150027Speter * notice, this list of conditions and the following disclaimer in the 1250027Speter * documentation and/or other materials provided with the distribution. 1350027Speter * 1450027Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1550027Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1650027Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1750027Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1850027Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1950027Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2050027Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2150027Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2250027Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2350027Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2450027Speter * SUCH DAMAGE. 2550027Speter * 2650027Speter * Bridge MIB implementation for SNMPd. 2750027Speter * Bridge interface objects. 2850027Speter * 2999072Sjulian * $FreeBSD: stable/10/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_if.c 310903 2016-12-31 10:34:09Z ngie $ 3099072Sjulian */ 3199072Sjulian 3299072Sjulian#include <sys/queue.h> 3399072Sjulian#include <sys/socket.h> 3499072Sjulian#include <sys/time.h> 3599072Sjulian#include <sys/types.h> 3699072Sjulian 3799072Sjulian#include <net/ethernet.h> 3899072Sjulian#include <net/if.h> 3999072Sjulian#include <net/if_mib.h> 4099072Sjulian#include <net/if_types.h> 4199072Sjulian 4299072Sjulian#include <errno.h> 4399072Sjulian#include <stdarg.h> 4499072Sjulian#include <stdlib.h> 4599072Sjulian#include <string.h> 4699072Sjulian#include <syslog.h> 4799072Sjulian 4899072Sjulian#include <bsnmp/snmpmod.h> 4999072Sjulian#include <bsnmp/snmp_mibII.h> 5099072Sjulian 5199072Sjulian#include "bridge_tree.h" 5299072Sjulian#include "bridge_snmp.h" 5399072Sjulian#include "bridge_oid.h" 5499072Sjulian 5599072Sjulianstatic const struct asn_oid oid_newRoot = OIDX_newRoot; 5699072Sjulianstatic const struct asn_oid oid_TopologyChange = OIDX_topologyChange; 5799072Sjulianstatic const struct asn_oid oid_begemotBrigeName = \ 5899072Sjulian OIDX_begemotBridgeBaseName; 5999072Sjulianstatic const struct asn_oid oid_begemotNewRoot = OIDX_begemotBridgeNewRoot; 6099072Sjulianstatic const struct asn_oid oid_begemotTopologyChange = \ 6199072Sjulian OIDX_begemotBridgeTopologyChange; 6299072Sjulian 6399072SjulianTAILQ_HEAD(bridge_ifs, bridge_if); 6499072Sjulian 6599072Sjulian/* 6699072Sjulian * Free the bridge interface list. 6799072Sjulian */ 6899072Sjulianstatic void 6999072Sjulianbridge_ifs_free(struct bridge_ifs *headp) 7099072Sjulian{ 7199072Sjulian struct bridge_if *b; 7299072Sjulian 7399072Sjulian while ((b = TAILQ_FIRST(headp)) != NULL) { 7499072Sjulian TAILQ_REMOVE(headp, b, b_if); 7599072Sjulian free(b); 7699072Sjulian } 7799072Sjulian} 7899072Sjulian 7999072Sjulian/* 8099072Sjulian * Insert an entry in the bridge interface TAILQ. Keep the 8199072Sjulian * TAILQ sorted by the bridge's interface name. 8299072Sjulian */ 8399072Sjulianstatic void 8499072Sjulianbridge_ifs_insert(struct bridge_ifs *headp, 8599072Sjulian struct bridge_if *b) 8699072Sjulian{ 8799072Sjulian struct bridge_if *temp; 8899072Sjulian 8999072Sjulian if ((temp = TAILQ_FIRST(headp)) == NULL || 9099072Sjulian strcmp(b->bif_name, temp->bif_name) < 0) { 9199072Sjulian TAILQ_INSERT_HEAD(headp, b, b_if); 9250027Speter return; 9350027Speter } 9450027Speter 9565557Sjasone TAILQ_FOREACH(temp, headp, b_if) 9674914Sjhb if(strcmp(b->bif_name, temp->bif_name) < 0) 9767365Sjhb TAILQ_INSERT_BEFORE(temp, b, b_if); 9850027Speter 9950027Speter TAILQ_INSERT_TAIL(headp, b, b_if); 10093607Sdillon} 10150027Speter 10297261Sjake/* The global bridge interface list. */ 10397261Sjakestatic struct bridge_ifs bridge_ifs = TAILQ_HEAD_INITIALIZER(bridge_ifs); 10450027Speterstatic time_t bridge_list_age; 10572376Sjake 10650027Speter/* 10772376Sjake * Free the global list. 10872376Sjake */ 10950027Spetervoid 11099072Sjulianbridge_ifs_fini(void) 11199072Sjulian{ 11299072Sjulian bridge_ifs_free(&bridge_ifs); 11399072Sjulian} 11499072Sjulian 11550027Speter/* 11699072Sjulian * Find a bridge interface entry by the bridge interface system index. 11799072Sjulian */ 11899072Sjulianstruct bridge_if * 11950027Speterbridge_if_find_ifs(uint32_t sysindex) 12083366Sjulian{ 12183366Sjulian struct bridge_if *b; 12250027Speter 12399072Sjulian TAILQ_FOREACH(b, &bridge_ifs, b_if) 12499072Sjulian if (b->sysindex == sysindex) 12599072Sjulian return (b); 12699072Sjulian 127100209Sgallatin return (NULL); 12899072Sjulian} 12999072Sjulian 13099072Sjulian/* 13199072Sjulian * Find a bridge interface entry by the bridge interface name. 13299072Sjulian */ 13399072Sjulianstruct bridge_if * 13499072Sjulianbridge_if_find_ifname(const char *b_name) 13599072Sjulian{ 13699072Sjulian struct bridge_if *b; 13799072Sjulian 13899072Sjulian TAILQ_FOREACH(b, &bridge_ifs, b_if) 13999072Sjulian if (strcmp(b_name, b->bif_name) == 0) 14099072Sjulian return (b); 14199072Sjulian 14299072Sjulian return (NULL); 14399072Sjulian} 14499072Sjulian 14599072Sjulian/* 14699072Sjulian * Find a bridge name by the bridge interface system index. 14799072Sjulian */ 14899072Sjulianconst char * 14999072Sjulianbridge_if_find_name(uint32_t sysindex) 15099072Sjulian{ 15199072Sjulian struct bridge_if *b; 15299072Sjulian 15399072Sjulian TAILQ_FOREACH(b, &bridge_ifs, b_if) 15499072Sjulian if (b->sysindex == sysindex) 15599072Sjulian return (b->bif_name); 15699072Sjulian 15799889Sjulian return (NULL); 15899072Sjulian} 159102592Sjulian 16099072Sjulian/* 16199072Sjulian * Given two bridge interfaces' system indexes, find their 162102592Sjulian * corresponding names and return the result of the name 163100209Sgallatin * comparison. Returns: 164100209Sgallatin * error : -2 165100209Sgallatin * i1 < i2 : -1 166103216Sjulian * i1 > i2 : +1 16799072Sjulian * i1 = i2 : 0 16872376Sjake */ 16950027Speterint 17099072Sjulianbridge_compare_sysidx(uint32_t i1, uint32_t i2) 17199072Sjulian{ 17299072Sjulian int c; 17399072Sjulian const char *b1, *b2; 17499072Sjulian 17599072Sjulian if (i1 == i2) 17699072Sjulian return (0); 17799072Sjulian 17899072Sjulian if ((b1 = bridge_if_find_name(i1)) == NULL) { 17999072Sjulian syslog(LOG_ERR, "Bridge interface %d does not exist", i1); 18099072Sjulian return (-2); 18199072Sjulian } 18299072Sjulian 18399072Sjulian if ((b2 = bridge_if_find_name(i2)) == NULL) { 18499072Sjulian syslog(LOG_ERR, "Bridge interface %d does not exist", i2); 18599072Sjulian return (-2); 18699072Sjulian } 18799072Sjulian 18899072Sjulian if ((c = strcmp(b1, b2)) < 0) 18999072Sjulian return (-1); 19099072Sjulian else if (c > 0) 19199072Sjulian return (1); 19299072Sjulian 19399072Sjulian return (0); 19499072Sjulian} 19599072Sjulian 19699072Sjulian/* 19799072Sjulian * Fetch the first bridge interface from the list. 19899072Sjulian */ 19999072Sjulianstruct bridge_if * 20099072Sjulianbridge_first_bif(void) 20199072Sjulian{ 20299072Sjulian return (TAILQ_FIRST(&bridge_ifs)); 20399072Sjulian} 20499072Sjulian 20599072Sjulian/* 20699072Sjulian * Fetch the next bridge interface from the list. 20799072Sjulian */ 20899072Sjulianstruct bridge_if * 20999072Sjulianbridge_next_bif(struct bridge_if *b_pr) 21099072Sjulian{ 21199072Sjulian return (TAILQ_NEXT(b_pr, b_if)); 21272376Sjake} 21399072Sjulian 21472376Sjake/* 21572376Sjake * Create a new entry for a bridge interface and insert 21650027Speter * it in the list. 21750027Speter */ 21899072Sjulianstatic struct bridge_if * 21999072Sjulianbridge_new_bif(const char *bif_n, uint32_t sysindex, const u_char *physaddr) 22099072Sjulian{ 22199072Sjulian struct bridge_if *bif; 22299072Sjulian 22399072Sjulian if ((bif = (struct bridge_if *) malloc(sizeof(*bif)))== NULL) { 22450027Speter syslog(LOG_ERR, "bridge new interface failed: %s", 22583366Sjulian strerror(errno)); 22672376Sjake return (NULL); 22799072Sjulian } 22899072Sjulian 22999072Sjulian bzero(bif, sizeof(struct bridge_if)); 23099072Sjulian strlcpy(bif->bif_name, bif_n, IFNAMSIZ); 23199072Sjulian bcopy(physaddr, bif->br_addr.octet, ETHER_ADDR_LEN); 232103216Sjulian bif->sysindex = sysindex; 23399072Sjulian bif->br_type = BaseType_transparent_only; 23499072Sjulian /* 1 - all bridges default hold time * 100 - centi-seconds */ 23599072Sjulian bif->hold_time = 1 * 100; 23699072Sjulian bif->prot_spec = dot1dStpProtocolSpecification_ieee8021d; 23799072Sjulian bridge_ifs_insert(&bridge_ifs, bif); 23899072Sjulian 23999072Sjulian return (bif); 24099072Sjulian} 241103216Sjulian 24299072Sjulian/* 24399072Sjulian * Remove a bridge interface from the list, freeing all it's ports 24499072Sjulian * and address entries. 24599942Sjulian */ 24699072Sjulianvoid 24799072Sjulianbridge_remove_bif(struct bridge_if *bif) 24899072Sjulian{ 24999072Sjulian bridge_members_free(bif); 25099072Sjulian bridge_addrs_free(bif); 25199072Sjulian TAILQ_REMOVE(&bridge_ifs, bif, b_if); 25299072Sjulian free(bif); 25399072Sjulian} 25499072Sjulian 25599072Sjulian 25699072Sjulian/* 25799072Sjulian * Prepare the variable (bridge interface name) for the private 25899072Sjulian * begemot notifications. 25999072Sjulian */ 26099072Sjulianstatic struct snmp_value* 26199072Sjulianbridge_basename_var(struct bridge_if *bif, struct snmp_value* b_val) 26299072Sjulian{ 26399072Sjulian uint i; 26499072Sjulian 26599072Sjulian b_val->var = oid_begemotBrigeName; 26699072Sjulian b_val->var.subs[b_val->var.len++] = strlen(bif->bif_name); 26799072Sjulian 26899072Sjulian if ((b_val->v.octetstring.octets = (u_char *) 26999072Sjulian malloc(strlen(bif->bif_name))) == NULL) 27099072Sjulian return (NULL); 27199072Sjulian 27299072Sjulian for (i = 0; i < strlen(bif->bif_name); i++) 27399072Sjulian b_val->var.subs[b_val->var.len++] = bif->bif_name[i]; 27499072Sjulian 27599072Sjulian b_val->v.octetstring.len = strlen(bif->bif_name); 27699072Sjulian bcopy(bif->bif_name, b_val->v.octetstring.octets, 27799072Sjulian strlen(bif->bif_name)); 27899072Sjulian b_val->syntax = SNMP_SYNTAX_OCTETSTRING; 27999072Sjulian 28099072Sjulian return (b_val); 28199072Sjulian} 28299072Sjulian 28399072Sjulian/* 28499072Sjulian * Compare the values of the old and the new root port and 28599072Sjulian * send a new root notification, if they are not matching. 28699072Sjulian */ 28799072Sjulianstatic void 28899072Sjulianbridge_new_root(struct bridge_if *bif) 28999072Sjulian{ 29072376Sjake struct snmp_value bif_idx; 29172376Sjake 29272376Sjake if (bridge_get_default() == bif) 29383366Sjulian snmp_send_trap(&oid_newRoot, (struct snmp_value *) NULL); 29450027Speter 29599072Sjulian if (bridge_basename_var(bif, &bif_idx) == NULL) 29699072Sjulian return; 29799072Sjulian 29899072Sjulian snmp_send_trap(&oid_begemotTopologyChange, 29999072Sjulian &bif_idx, (struct snmp_value *) NULL); 30099072Sjulian} 30199072Sjulian 302103216Sjulian/* 303103216Sjulian * Compare the new and old topology change times and send a 304103216Sjulian * topology change notification if necessary. 30599072Sjulian */ 30699072Sjulianstatic void 30799072Sjulianbridge_top_change(struct bridge_if *bif) 30899072Sjulian{ 30999072Sjulian struct snmp_value bif_idx; 31099072Sjulian 31199072Sjulian if (bridge_get_default() == bif) 31299072Sjulian snmp_send_trap(&oid_TopologyChange, 31399072Sjulian (struct snmp_value *) NULL); 31499072Sjulian 31599072Sjulian if (bridge_basename_var(bif, &bif_idx) == NULL) 31699072Sjulian return; 31799072Sjulian 31899072Sjulian snmp_send_trap(&oid_begemotNewRoot, 31999072Sjulian &bif_idx, (struct snmp_value *) NULL); 32099072Sjulian} 32199072Sjulian 32299072Sjulianstatic int 32399072Sjulianbridge_if_create(const char* b_name, int8_t up) 32499072Sjulian{ 32599072Sjulian if (bridge_create(b_name) < 0) 32699072Sjulian return (-1); 32799072Sjulian 32899072Sjulian if (up == 1 && (bridge_set_if_up(b_name, 1) < 0)) 32999072Sjulian return (-1); 33099072Sjulian 33199072Sjulian /* 33299072Sjulian * Do not create a new bridge entry here - 33399072Sjulian * wait until the mibII module notifies us. 33499072Sjulian */ 33599072Sjulian return (0); 33699942Sjulian} 33799072Sjulian 33899072Sjulianstatic int 33999072Sjulianbridge_if_destroy(struct bridge_if *bif) 34099072Sjulian{ 34199072Sjulian if (bridge_destroy(bif->bif_name) < 0) 34299072Sjulian return (-1); 34399072Sjulian 34499072Sjulian bridge_remove_bif(bif); 34599072Sjulian 34699072Sjulian return (0); 34799072Sjulian} 34899072Sjulian 34999072Sjulian/* 35099942Sjulian * Calculate the timeticks since the last topology change. 35199942Sjulian */ 35299942Sjulianstatic int 35399072Sjulianbridge_get_time_since_tc(struct bridge_if *bif, uint32_t *ticks) 35499072Sjulian{ 35599072Sjulian struct timeval ct; 35699072Sjulian 35799072Sjulian if (gettimeofday(&ct, NULL) < 0) { 35899072Sjulian syslog(LOG_ERR, "bridge get time since last TC:" 35999072Sjulian "getttimeofday failed: %s", strerror(errno)); 36099072Sjulian return (-1); 36199072Sjulian } 36299072Sjulian 36399072Sjulian if (ct.tv_usec - bif->last_tc_time.tv_usec < 0) { 36499072Sjulian ct.tv_sec -= 1; 36599072Sjulian ct.tv_usec += 1000000; 36699072Sjulian } 36799072Sjulian 36899072Sjulian ct.tv_sec -= bif->last_tc_time.tv_sec; 36999072Sjulian ct.tv_usec -= bif->last_tc_time.tv_usec; 37099072Sjulian 37199072Sjulian *ticks = ct.tv_sec * 100 + ct.tv_usec/10000; 37299072Sjulian 37399072Sjulian return (0); 37499072Sjulian} 37599072Sjulian 37699072Sjulian/* 37799072Sjulian * Update the info we have for a single bridge interface. 37899072Sjulian * Return: 37999072Sjulian * 1, if successful 38099942Sjulian * 0, if the interface was deleted 38199072Sjulian * -1, error occurred while fetching the info from the kernel. 38299072Sjulian */ 38399072Sjulianstatic int 38499072Sjulianbridge_update_bif(struct bridge_if *bif) 38599072Sjulian{ 38699072Sjulian struct mibif *ifp; 38799072Sjulian 38899072Sjulian /* Walk through the mibII interface list. */ 38999072Sjulian for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp)) 39099072Sjulian if (strcmp(ifp->name, bif->bif_name) == 0) 39199072Sjulian break; 39299072Sjulian 39399072Sjulian if (ifp == NULL) { 39499072Sjulian /* Ops, we do not exist anymore. */ 39599072Sjulian bridge_remove_bif(bif); 39699072Sjulian return (0); 39799072Sjulian } 39899072Sjulian 39999072Sjulian if (ifp->physaddr != NULL ) 40099072Sjulian bcopy(ifp->physaddr, bif->br_addr.octet, ETHER_ADDR_LEN); 40199072Sjulian else 40299072Sjulian bridge_get_basemac(bif->bif_name, bif->br_addr.octet, 40399072Sjulian ETHER_ADDR_LEN); 40499072Sjulian 40599072Sjulian if (ifp->mib.ifmd_flags & IFF_RUNNING) 40699072Sjulian bif->if_status = RowStatus_active; 40799072Sjulian else 40872376Sjake bif->if_status = RowStatus_notInService; 40950027Speter 41099072Sjulian switch (bridge_getinfo_bif(bif)) { 41199072Sjulian case 2: 41299072Sjulian bridge_new_root(bif); 41388088Sjhb break; 41488088Sjhb case 1: 41588088Sjhb bridge_top_change(bif); 41688088Sjhb break; 41788088Sjhb case -1: 41888088Sjhb bridge_remove_bif(bif); 41988088Sjhb return (-1); 42088088Sjhb default: 42193264Sdillon break; 42288088Sjhb } 42388088Sjhb 42488088Sjhb /* 42588088Sjhb * The number of ports is accessible via SNMP - 42688088Sjhb * update the ports each time the bridge interface data 42788088Sjhb * is refreshed too. 42888088Sjhb */ 42988088Sjhb bif->num_ports = bridge_update_memif(bif); 43088088Sjhb bif->entry_age = time(NULL); 43188088Sjhb 43288088Sjhb return (1); 43393264Sdillon} 43493264Sdillon 43588088Sjhb/* 43693264Sdillon * Update all bridge interfaces' ports only - 43788088Sjhb * make sure each bridge interface exists first. 43888088Sjhb */ 43999072Sjulianvoid 44099072Sjulianbridge_update_all_ports(void) 44199072Sjulian{ 44299072Sjulian struct mibif *ifp; 44372376Sjake struct bridge_if *bif, *t_bif; 44499072Sjulian 44599072Sjulian for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 44699072Sjulian t_bif = bridge_next_bif(bif); 44799072Sjulian 44899072Sjulian for (ifp = mib_first_if(); ifp != NULL; 44999072Sjulian ifp = mib_next_if(ifp)) 45099072Sjulian if (strcmp(ifp->name, bif->bif_name) == 0) 45199072Sjulian break; 45299072Sjulian 45399072Sjulian if (ifp != NULL) 45499072Sjulian bif->num_ports = bridge_update_memif(bif); 45599072Sjulian else /* Ops, we do not exist anymore. */ 45699072Sjulian bridge_remove_bif(bif); 45772376Sjake } 45872376Sjake 45972376Sjake bridge_ports_update_listage(); 46072376Sjake} 46172376Sjake 46272376Sjake/* 46372376Sjake * Update all addresses only. 46465557Sjasone */ 46572376Sjakevoid 46672376Sjakebridge_update_all_addrs(void) 46772376Sjake{ 46872376Sjake struct mibif *ifp; 46972376Sjake struct bridge_if *bif, *t_bif; 47072376Sjake 47150027Speter for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 47250027Speter t_bif = bridge_next_bif(bif); 47350027Speter 47472376Sjake for (ifp = mib_first_if(); ifp != NULL; 47572376Sjake ifp = mib_next_if(ifp)) 47650027Speter if (strcmp(ifp->name, bif->bif_name) == 0) 47772376Sjake break; 47872376Sjake 47972376Sjake if (ifp != NULL) 48072376Sjake bif->num_addrs = bridge_update_addrs(bif); 48172376Sjake else /* Ops, we don't exist anymore. */ 48272376Sjake bridge_remove_bif(bif); 48372376Sjake } 48472376Sjake 48572376Sjake bridge_addrs_update_listage(); 48672376Sjake} 48798469Speter 48872376Sjake/* 48972376Sjake * Update only the bridge interfaces' data - skip addresses. 49072376Sjake */ 49172376Sjakevoid 49272376Sjakebridge_update_all_ifs(void) 49372376Sjake{ 49472376Sjake struct bridge_if *bif, *t_bif; 49572376Sjake 49672376Sjake for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 49772376Sjake t_bif = bridge_next_bif(bif); 49872376Sjake bridge_update_bif(bif); 49972376Sjake } 50072376Sjake 50172376Sjake bridge_ports_update_listage(); 50272376Sjake bridge_list_age = time(NULL); 50372376Sjake} 50472376Sjake 50572376Sjake/* 50672376Sjake * Update all info we have for all bridges. 50772376Sjake */ 50872376Sjakevoid 50972376Sjakebridge_update_all(void *arg __unused) 51072376Sjake{ 51172376Sjake struct bridge_if *bif, *t_bif; 51272376Sjake 51372376Sjake for (bif = bridge_first_bif(); bif != NULL; bif = t_bif) { 51499072Sjulian t_bif = bridge_next_bif(bif); 51572376Sjake if (bridge_update_bif(bif) <= 0) 51672376Sjake continue; 51750027Speter 51883366Sjulian /* Update our learnt addresses. */ 51950027Speter bif->num_addrs = bridge_update_addrs(bif); 52072376Sjake } 52172376Sjake 52250027Speter bridge_list_age = time(NULL); 52399072Sjulian bridge_ports_update_listage(); 52499072Sjulian bridge_addrs_update_listage(); 52599942Sjulian} 52699942Sjulian 52799072Sjulian/* 52899072Sjulian * Callback for polling our last topology change time - 52999072Sjulian * check whether we are root or whether a TC was detected once every 530100913Stanimura * 30 seconds, so that we can send the newRoot and TopologyChange traps 531100913Stanimura * on time. The rest of the data is polled only once every 5 min. 53290538Sjulian */ 53383366Sjulianvoid 53472376Sjakebridge_update_tc_time(void *arg __unused) 53572376Sjake{ 53672376Sjake struct bridge_if *bif; 53790538Sjulian struct mibif *ifp; 53883366Sjulian 53999072Sjulian TAILQ_FOREACH(bif, &bridge_ifs, b_if) { 54099072Sjulian /* Walk through the mibII interface list. */ 54150027Speter for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp)) 54250027Speter if (strcmp(ifp->name, bif->bif_name) == 0) 54350027Speter break; 54472376Sjake 54572376Sjake if (ifp == NULL) { 54672376Sjake bridge_remove_bif(bif); 54750027Speter continue; 54872376Sjake } 54972376Sjake 55050027Speter switch (bridge_get_op_param(bif)) { 55172376Sjake case 2: 55272376Sjake bridge_new_root(bif); 55372376Sjake break; 55472376Sjake case 1: 55572376Sjake bridge_top_change(bif); 55672376Sjake break; 55772376Sjake } 55872376Sjake } 55972376Sjake} 56072376Sjake 56172376Sjake/* 56272376Sjake * Callback for handling new bridge interface creation. 56372376Sjake */ 56450027Speterint 56550027Speterbridge_attach_newif(struct mibif *ifp) 56650027Speter{ 56772376Sjake u_char mac[ETHER_ADDR_LEN]; 56872376Sjake struct bridge_if *bif; 56972376Sjake 57050027Speter if (ifp->mib.ifmd_data.ifi_type != IFT_BRIDGE) 57183366Sjulian return (0); 57272376Sjake 57350027Speter /* Make sure it does not exist in our list. */ 57472376Sjake TAILQ_FOREACH(bif, &bridge_ifs, b_if) 57583366Sjulian if(strcmp(bif->bif_name, ifp->name) == 0) { 57672376Sjake syslog(LOG_ERR, "bridge interface %s already " 57750027Speter "in list", bif->bif_name); 57865557Sjasone return (-1); 57999072Sjulian } 58072376Sjake 58183366Sjulian if (ifp->physaddr == NULL) { 58283366Sjulian if (bridge_get_basemac(ifp->name, mac, sizeof(mac)) == NULL) { 58399072Sjulian syslog(LOG_ERR, "bridge attach new %s failed - " 58499072Sjulian "no bridge mac address", ifp->name); 58583366Sjulian return (-1); 58699072Sjulian } 58772376Sjake } else 58872376Sjake bcopy(ifp->physaddr, &mac, sizeof(mac)); 58972376Sjake 59050027Speter if ((bif = bridge_new_bif(ifp->name, ifp->sysindex, mac)) == NULL) 59199072Sjulian return (-1); 59299942Sjulian 59399072Sjulian if (ifp->mib.ifmd_flags & IFF_RUNNING) 59499072Sjulian bif->if_status = RowStatus_active; 59599072Sjulian else 59699072Sjulian bif->if_status = RowStatus_notInService; 597100913Stanimura 598100913Stanimura /* Skip sending notifications if the interface was just created. */ 59983366Sjulian if (bridge_getinfo_bif(bif) < 0 || 60050027Speter (bif->num_ports = bridge_getinfo_bif_ports(bif)) < 0 || 60172376Sjake (bif->num_addrs = bridge_getinfo_bif_addrs(bif)) < 0) { 60272376Sjake bridge_remove_bif(bif); 60399072Sjulian return (-1); 60450027Speter } 60572376Sjake 60672376Sjake /* Check whether we are the default bridge interface. */ 60799072Sjulian if (strcmp(ifp->name, bridge_get_default_name()) == 0) 60872376Sjake bridge_set_default(bif); 60999072Sjulian 61072376Sjake return (0); 61172376Sjake} 61283366Sjulian 61372376Sjakevoid 61472376Sjakebridge_ifs_dump(void) 61572376Sjake{ 61672376Sjake struct bridge_if *bif; 61799072Sjulian 61872376Sjake for (bif = bridge_first_bif(); bif != NULL; 619100913Stanimura bif = bridge_next_bif(bif)) { 620100913Stanimura syslog(LOG_ERR, "Bridge %s, index - %d", bif->bif_name, 62183366Sjulian bif->sysindex); 62272376Sjake bridge_ports_dump(bif); 62372376Sjake bridge_addrs_dump(bif); 62490538Sjulian } 62583366Sjulian} 62683366Sjulian 62772376Sjake/* 62872376Sjake * RFC4188 specifics. 62972376Sjake */ 63072376Sjakeint 63199942Sjulianop_dot1d_base(struct snmp_context *ctx __unused, struct snmp_value *value, 63299072Sjulian uint sub, uint iidx __unused, enum snmp_op op) 63372376Sjake{ 63499072Sjulian struct bridge_if *bif; 63599072Sjulian 63699072Sjulian if ((bif = bridge_get_default()) == NULL) 63799072Sjulian return (SNMP_ERR_NOSUCHNAME); 63899072Sjulian 63999072Sjulian if (time(NULL) - bif->entry_age > bridge_get_data_maxage() && 64099072Sjulian bridge_update_bif(bif) <= 0) /* It was just deleted. */ 64199072Sjulian return (SNMP_ERR_NOSUCHNAME); 64299072Sjulian 64399072Sjulian switch (op) { 64499072Sjulian case SNMP_OP_GET: 64599834Sjulian switch (value->var.subs[sub - 1]) { 64699072Sjulian case LEAF_dot1dBaseBridgeAddress: 64799072Sjulian return (string_get(value, bif->br_addr.octet, 64899072Sjulian ETHER_ADDR_LEN)); 64999072Sjulian case LEAF_dot1dBaseNumPorts: 65099072Sjulian value->v.integer = bif->num_ports; 65199072Sjulian return (SNMP_ERR_NOERROR); 65299072Sjulian case LEAF_dot1dBaseType: 65399072Sjulian value->v.integer = bif->br_type; 65499072Sjulian return (SNMP_ERR_NOERROR); 65599072Sjulian } 65699072Sjulian abort(); 65799072Sjulian 65899072Sjulian case SNMP_OP_SET: 65999072Sjulian return (SNMP_ERR_NOT_WRITEABLE); 66099072Sjulian 66199072Sjulian case SNMP_OP_GETNEXT: 66299072Sjulian case SNMP_OP_ROLLBACK: 66399072Sjulian case SNMP_OP_COMMIT: 66499072Sjulian break; 66599072Sjulian } 66699072Sjulian 66799072Sjulian abort(); 66899072Sjulian} 66999072Sjulian 67099072Sjulianint 67199072Sjulianop_dot1d_stp(struct snmp_context *ctx, struct snmp_value *val, uint sub, 67299072Sjulian uint iidx __unused, enum snmp_op op) 67399072Sjulian{ 67499072Sjulian struct bridge_if *bif; 67599072Sjulian 67699072Sjulian if ((bif = bridge_get_default()) == NULL) 67799072Sjulian return (SNMP_ERR_NOSUCHNAME); 67899072Sjulian 67999072Sjulian if (time(NULL) - bif->entry_age > bridge_get_data_maxage() && 68099072Sjulian bridge_update_bif(bif) <= 0) /* It was just deleted. */ 68199072Sjulian return (SNMP_ERR_NOSUCHNAME); 68299072Sjulian 68399072Sjulian switch (op) { 68499072Sjulian case SNMP_OP_GET: 68599072Sjulian switch (val->var.subs[sub - 1]) { 68699072Sjulian case LEAF_dot1dStpProtocolSpecification: 68799072Sjulian val->v.integer = bif->prot_spec; 68899072Sjulian return (SNMP_ERR_NOERROR); 68999072Sjulian 69099072Sjulian case LEAF_dot1dStpPriority: 69199072Sjulian val->v.integer = bif->priority; 69299072Sjulian return (SNMP_ERR_NOERROR); 69399072Sjulian 69499072Sjulian case LEAF_dot1dStpTimeSinceTopologyChange: 69599072Sjulian if (bridge_get_time_since_tc(bif, 69699072Sjulian &(val->v.uint32)) < 0) 69799072Sjulian return (SNMP_ERR_GENERR); 69899072Sjulian return (SNMP_ERR_NOERROR); 69999072Sjulian 70099072Sjulian case LEAF_dot1dStpTopChanges: 70199072Sjulian val->v.uint32 = bif->top_changes; 70299072Sjulian return (SNMP_ERR_NOERROR); 70399072Sjulian 70499072Sjulian case LEAF_dot1dStpDesignatedRoot: 70599072Sjulian return (string_get(val, bif->design_root, 70699072Sjulian SNMP_BRIDGE_ID_LEN)); 70799072Sjulian 70899072Sjulian case LEAF_dot1dStpRootCost: 70999072Sjulian val->v.integer = bif->root_cost; 71099072Sjulian return (SNMP_ERR_NOERROR); 71199072Sjulian 71299072Sjulian case LEAF_dot1dStpRootPort: 71399072Sjulian val->v.integer = bif->root_port; 71499072Sjulian return (SNMP_ERR_NOERROR); 71599072Sjulian 71699072Sjulian case LEAF_dot1dStpMaxAge: 71799072Sjulian val->v.integer = bif->max_age; 718103216Sjulian return (SNMP_ERR_NOERROR); 71999072Sjulian 72099072Sjulian case LEAF_dot1dStpHelloTime: 72199072Sjulian val->v.integer = bif->hello_time; 72299072Sjulian return (SNMP_ERR_NOERROR); 72399072Sjulian 72499072Sjulian case LEAF_dot1dStpHoldTime: 72599072Sjulian val->v.integer = bif->hold_time; 72699072Sjulian return (SNMP_ERR_NOERROR); 72799072Sjulian 72899072Sjulian case LEAF_dot1dStpForwardDelay: 72999072Sjulian val->v.integer = bif->fwd_delay; 73099072Sjulian return (SNMP_ERR_NOERROR); 73199072Sjulian 73299834Sjulian case LEAF_dot1dStpBridgeMaxAge: 73399072Sjulian val->v.integer = bif->bridge_max_age; 734 return (SNMP_ERR_NOERROR); 735 736 case LEAF_dot1dStpBridgeHelloTime: 737 val->v.integer = bif->bridge_hello_time; 738 return (SNMP_ERR_NOERROR); 739 740 case LEAF_dot1dStpBridgeForwardDelay: 741 val->v.integer = bif->bridge_fwd_delay; 742 return (SNMP_ERR_NOERROR); 743 744 case LEAF_dot1dStpVersion: 745 val->v.integer = bif->stp_version; 746 return (SNMP_ERR_NOERROR); 747 748 case LEAF_dot1dStpTxHoldCount: 749 val->v.integer = bif->tx_hold_count; 750 return (SNMP_ERR_NOERROR); 751 } 752 abort(); 753 754 case SNMP_OP_GETNEXT: 755 abort(); 756 757 case SNMP_OP_SET: 758 switch (val->var.subs[sub - 1]) { 759 case LEAF_dot1dStpPriority: 760 if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY || 761 val->v.integer % 4096 != 0) 762 return (SNMP_ERR_WRONG_VALUE); 763 764 ctx->scratch->int1 = bif->priority; 765 if (bridge_set_priority(bif, val->v.integer) < 0) 766 return (SNMP_ERR_GENERR); 767 return (SNMP_ERR_NOERROR); 768 769 case LEAF_dot1dStpBridgeMaxAge: 770 if (val->v.integer < SNMP_BRIDGE_MIN_MAGE || 771 val->v.integer > SNMP_BRIDGE_MAX_MAGE) 772 return (SNMP_ERR_WRONG_VALUE); 773 774 ctx->scratch->int1 = bif->bridge_max_age; 775 if (bridge_set_maxage(bif, val->v.integer) < 0) 776 return (SNMP_ERR_GENERR); 777 return (SNMP_ERR_NOERROR); 778 779 case LEAF_dot1dStpBridgeHelloTime: 780 if (val->v.integer < SNMP_BRIDGE_MIN_HTIME || 781 val->v.integer > SNMP_BRIDGE_MAX_HTIME) 782 return (SNMP_ERR_WRONG_VALUE); 783 784 ctx->scratch->int1 = bif->bridge_hello_time; 785 if (bridge_set_hello_time(bif, val->v.integer) < 0) 786 return (SNMP_ERR_GENERR); 787 return (SNMP_ERR_NOERROR); 788 789 case LEAF_dot1dStpBridgeForwardDelay: 790 if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY || 791 val->v.integer > SNMP_BRIDGE_MAX_FDELAY) 792 return (SNMP_ERR_WRONG_VALUE); 793 794 ctx->scratch->int1 = bif->bridge_fwd_delay; 795 if (bridge_set_forward_delay(bif, val->v.integer) < 0) 796 return (SNMP_ERR_GENERR); 797 return (SNMP_ERR_NOERROR); 798 799 case LEAF_dot1dStpVersion: 800 if (val->v.integer != dot1dStpVersion_stpCompatible && 801 val->v.integer != dot1dStpVersion_rstp) 802 return (SNMP_ERR_WRONG_VALUE); 803 804 ctx->scratch->int1 = bif->stp_version; 805 if (bridge_set_stp_version(bif, val->v.integer) < 0) 806 return (SNMP_ERR_GENERR); 807 return (SNMP_ERR_NOERROR); 808 809 case LEAF_dot1dStpTxHoldCount: 810 if (val->v.integer < SNMP_BRIDGE_MIN_TXHC || 811 val->v.integer > SNMP_BRIDGE_MAX_TXHC) 812 return (SNMP_ERR_WRONG_VALUE); 813 814 ctx->scratch->int1 = bif->tx_hold_count; 815 if (bridge_set_tx_hold_count(bif, val->v.integer) < 0) 816 return (SNMP_ERR_GENERR); 817 return (SNMP_ERR_NOERROR); 818 819 case LEAF_dot1dStpProtocolSpecification: 820 case LEAF_dot1dStpTimeSinceTopologyChange: 821 case LEAF_dot1dStpTopChanges: 822 case LEAF_dot1dStpDesignatedRoot: 823 case LEAF_dot1dStpRootCost: 824 case LEAF_dot1dStpRootPort: 825 case LEAF_dot1dStpMaxAge: 826 case LEAF_dot1dStpHelloTime: 827 case LEAF_dot1dStpHoldTime: 828 case LEAF_dot1dStpForwardDelay: 829 return (SNMP_ERR_NOT_WRITEABLE); 830 } 831 abort(); 832 833 case SNMP_OP_ROLLBACK: 834 switch (val->var.subs[sub - 1]) { 835 case LEAF_dot1dStpPriority: 836 bridge_set_priority(bif, ctx->scratch->int1); 837 break; 838 case LEAF_dot1dStpBridgeMaxAge: 839 bridge_set_maxage(bif, ctx->scratch->int1); 840 break; 841 case LEAF_dot1dStpBridgeHelloTime: 842 bridge_set_hello_time(bif, ctx->scratch->int1); 843 break; 844 case LEAF_dot1dStpBridgeForwardDelay: 845 bridge_set_forward_delay(bif, ctx->scratch->int1); 846 break; 847 case LEAF_dot1dStpVersion: 848 bridge_set_stp_version(bif, ctx->scratch->int1); 849 break; 850 case LEAF_dot1dStpTxHoldCount: 851 bridge_set_tx_hold_count(bif, ctx->scratch->int1); 852 break; 853 } 854 return (SNMP_ERR_NOERROR); 855 856 case SNMP_OP_COMMIT: 857 return (SNMP_ERR_NOERROR); 858 } 859 860 abort(); 861} 862 863int 864op_dot1d_tp(struct snmp_context *ctx, struct snmp_value *value, 865 uint sub, uint iidx __unused, enum snmp_op op) 866{ 867 struct bridge_if *bif; 868 869 if ((bif = bridge_get_default()) == NULL) 870 return (SNMP_ERR_NOSUCHNAME); 871 872 if (time(NULL) - bif->entry_age > bridge_get_data_maxage() && 873 bridge_update_bif(bif) <= 0) /* It was just deleted. */ 874 return (SNMP_ERR_NOSUCHNAME); 875 876 switch (op) { 877 case SNMP_OP_GET: 878 switch (value->var.subs[sub - 1]) { 879 case LEAF_dot1dTpLearnedEntryDiscards: 880 value->v.uint32 = bif->lrnt_drops; 881 return (SNMP_ERR_NOERROR); 882 case LEAF_dot1dTpAgingTime: 883 value->v.integer = bif->age_time; 884 return (SNMP_ERR_NOERROR); 885 } 886 abort(); 887 888 case SNMP_OP_GETNEXT: 889 abort(); 890 891 case SNMP_OP_SET: 892 switch (value->var.subs[sub - 1]) { 893 case LEAF_dot1dTpLearnedEntryDiscards: 894 return (SNMP_ERR_NOT_WRITEABLE); 895 896 case LEAF_dot1dTpAgingTime: 897 if (value->v.integer < SNMP_BRIDGE_MIN_AGE_TIME || 898 value->v.integer > SNMP_BRIDGE_MAX_AGE_TIME) 899 return (SNMP_ERR_WRONG_VALUE); 900 901 ctx->scratch->int1 = bif->age_time; 902 if (bridge_set_aging_time(bif, value->v.integer) < 0) 903 return (SNMP_ERR_GENERR); 904 return (SNMP_ERR_NOERROR); 905 } 906 abort(); 907 908 case SNMP_OP_ROLLBACK: 909 if (value->var.subs[sub - 1] == LEAF_dot1dTpAgingTime) 910 bridge_set_aging_time(bif, ctx->scratch->int1); 911 return (SNMP_ERR_NOERROR); 912 913 case SNMP_OP_COMMIT: 914 return (SNMP_ERR_NOERROR); 915 } 916 917 abort(); 918} 919 920/* 921 * Private BEGEMOT-BRIDGE-MIB specifics. 922 */ 923 924/* 925 * Get the bridge name from an OID index. 926 */ 927static char * 928bridge_name_index_get(const struct asn_oid *oid, uint sub, char *b_name) 929{ 930 uint i; 931 932 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ) 933 return (NULL); 934 935 for (i = 0; i < oid->subs[sub]; i++) 936 b_name[i] = oid->subs[sub + i + 1]; 937 b_name[i] = '\0'; 938 939 return (b_name); 940} 941 942static void 943bridge_if_index_append(struct asn_oid *oid, uint sub, 944 const struct bridge_if *bif) 945{ 946 uint i; 947 948 oid->len = sub + strlen(bif->bif_name) + 1; 949 oid->subs[sub] = strlen(bif->bif_name); 950 951 for (i = 1; i <= strlen(bif->bif_name); i++) 952 oid->subs[sub + i] = bif->bif_name[i - 1]; 953} 954 955static struct bridge_if * 956bridge_if_index_get(const struct asn_oid *oid, uint sub) 957{ 958 uint i; 959 char bif_name[IFNAMSIZ]; 960 961 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ) 962 return (NULL); 963 964 for (i = 0; i < oid->subs[sub]; i++) 965 bif_name[i] = oid->subs[sub + i + 1]; 966 bif_name[i] = '\0'; 967 968 return (bridge_if_find_ifname(bif_name)); 969} 970 971static struct bridge_if * 972bridge_if_index_getnext(const struct asn_oid *oid, uint sub) 973{ 974 uint i; 975 char bif_name[IFNAMSIZ]; 976 struct bridge_if *bif; 977 978 if (oid->len - sub == 0) 979 return (bridge_first_bif()); 980 981 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ) 982 return (NULL); 983 984 for (i = 0; i < oid->subs[sub]; i++) 985 bif_name[i] = oid->subs[sub + i + 1]; 986 bif_name[i] = '\0'; 987 988 if ((bif = bridge_if_find_ifname(bif_name)) == NULL) 989 return (NULL); 990 991 return (bridge_next_bif(bif)); 992} 993 994static int 995bridge_set_if_status(struct snmp_context *ctx, 996 struct snmp_value *val, uint sub) 997{ 998 struct bridge_if *bif; 999 char bif_name[IFNAMSIZ]; 1000 1001 bif = bridge_if_index_get(&val->var, sub); 1002 1003 switch (val->v.integer) { 1004 case RowStatus_active: 1005 if (bif == NULL) 1006 return (SNMP_ERR_INCONS_VALUE); 1007 1008 ctx->scratch->int1 = bif->if_status; 1009 1010 switch (bif->if_status) { 1011 case RowStatus_active: 1012 return (SNMP_ERR_NOERROR); 1013 case RowStatus_notInService: 1014 if (bridge_set_if_up(bif->bif_name, 1) < 0) 1015 return (SNMP_ERR_GENERR); 1016 return (SNMP_ERR_NOERROR); 1017 default: 1018 break; 1019 } 1020 return (SNMP_ERR_INCONS_VALUE); 1021 1022 case RowStatus_notInService: 1023 if (bif == NULL) 1024 return (SNMP_ERR_INCONS_VALUE); 1025 1026 ctx->scratch->int1 = bif->if_status; 1027 1028 switch (bif->if_status) { 1029 case RowStatus_active: 1030 if (bridge_set_if_up(bif->bif_name, 1) < 0) 1031 return (SNMP_ERR_GENERR); 1032 return (SNMP_ERR_NOERROR); 1033 case RowStatus_notInService: 1034 return (SNMP_ERR_NOERROR); 1035 default: 1036 break; 1037 } 1038 return (SNMP_ERR_INCONS_VALUE); 1039 1040 case RowStatus_notReady: 1041 return (SNMP_ERR_INCONS_VALUE); 1042 1043 case RowStatus_createAndGo: 1044 if (bif != NULL) 1045 return (SNMP_ERR_INCONS_VALUE); 1046 1047 ctx->scratch->int1 = RowStatus_destroy; 1048 1049 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL) 1050 return (SNMP_ERR_BADVALUE); 1051 if (bridge_if_create(bif_name, 1) < 0) 1052 return (SNMP_ERR_GENERR); 1053 return (SNMP_ERR_NOERROR); 1054 1055 case RowStatus_createAndWait: 1056 if (bif != NULL) 1057 return (SNMP_ERR_INCONS_VALUE); 1058 1059 if (bridge_name_index_get(&val->var, sub, bif_name) == NULL) 1060 return (SNMP_ERR_BADVALUE); 1061 1062 ctx->scratch->int1 = RowStatus_destroy; 1063 1064 if (bridge_if_create(bif_name, 0) < 0) 1065 return (SNMP_ERR_GENERR); 1066 return (SNMP_ERR_NOERROR); 1067 1068 case RowStatus_destroy: 1069 if (bif == NULL) 1070 return (SNMP_ERR_NOSUCHNAME); 1071 1072 ctx->scratch->int1 = bif->if_status; 1073 bif->if_status = RowStatus_destroy; 1074 } 1075 1076 return (SNMP_ERR_NOERROR); 1077} 1078 1079static int 1080bridge_rollback_if_status(struct snmp_context *ctx, 1081 struct snmp_value *val, uint sub) 1082{ 1083 struct bridge_if *bif; 1084 1085 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1086 return (SNMP_ERR_GENERR); 1087 1088 switch (ctx->scratch->int1) { 1089 case RowStatus_destroy: 1090 bridge_if_destroy(bif); 1091 return (SNMP_ERR_NOERROR); 1092 1093 case RowStatus_notInService: 1094 if (bif->if_status != ctx->scratch->int1) 1095 bridge_set_if_up(bif->bif_name, 0); 1096 bif->if_status = RowStatus_notInService; 1097 return (SNMP_ERR_NOERROR); 1098 1099 case RowStatus_active: 1100 if (bif->if_status != ctx->scratch->int1) 1101 bridge_set_if_up(bif->bif_name, 1); 1102 bif->if_status = RowStatus_active; 1103 return (SNMP_ERR_NOERROR); 1104 } 1105 1106 abort(); 1107} 1108 1109static int 1110bridge_commit_if_status(struct snmp_value *val, uint sub) 1111{ 1112 struct bridge_if *bif; 1113 1114 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1115 return (SNMP_ERR_GENERR); 1116 1117 if (bif->if_status == RowStatus_destroy && 1118 bridge_if_destroy(bif) < 0) 1119 return (SNMP_ERR_COMMIT_FAILED); 1120 1121 return (SNMP_ERR_NOERROR); 1122} 1123 1124int 1125op_begemot_base_bridge(struct snmp_context *ctx, struct snmp_value *val, 1126 uint sub, uint iidx __unused, enum snmp_op op) 1127{ 1128 struct bridge_if *bif; 1129 1130 if (time(NULL) - bridge_list_age > bridge_get_data_maxage()) 1131 bridge_update_all_ifs(); 1132 1133 switch (op) { 1134 case SNMP_OP_GET: 1135 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1136 return (SNMP_ERR_NOSUCHNAME); 1137 goto get; 1138 1139 case SNMP_OP_GETNEXT: 1140 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL) 1141 return (SNMP_ERR_NOSUCHNAME); 1142 bridge_if_index_append(&val->var, sub, bif); 1143 goto get; 1144 1145 case SNMP_OP_SET: 1146 switch (val->var.subs[sub - 1]) { 1147 case LEAF_begemotBridgeBaseStatus: 1148 return (bridge_set_if_status(ctx, val, sub)); 1149 case LEAF_begemotBridgeBaseName: 1150 case LEAF_begemotBridgeBaseAddress: 1151 case LEAF_begemotBridgeBaseNumPorts: 1152 case LEAF_begemotBridgeBaseType: 1153 return (SNMP_ERR_NOT_WRITEABLE); 1154 } 1155 abort(); 1156 1157 case SNMP_OP_ROLLBACK: 1158 return (bridge_rollback_if_status(ctx, val, sub)); 1159 1160 case SNMP_OP_COMMIT: 1161 return (bridge_commit_if_status(val, sub)); 1162 } 1163 abort(); 1164 1165get: 1166 switch (val->var.subs[sub - 1]) { 1167 case LEAF_begemotBridgeBaseName: 1168 return (string_get(val, bif->bif_name, -1)); 1169 1170 case LEAF_begemotBridgeBaseAddress: 1171 return (string_get(val, bif->br_addr.octet, ETHER_ADDR_LEN)); 1172 1173 case LEAF_begemotBridgeBaseNumPorts: 1174 val->v.integer = bif->num_ports; 1175 return (SNMP_ERR_NOERROR); 1176 1177 case LEAF_begemotBridgeBaseType: 1178 val->v.integer = bif->br_type; 1179 return (SNMP_ERR_NOERROR); 1180 1181 case LEAF_begemotBridgeBaseStatus: 1182 val->v.integer = bif->if_status; 1183 return (SNMP_ERR_NOERROR); 1184 } 1185 1186 abort(); 1187} 1188 1189int 1190op_begemot_stp(struct snmp_context *ctx, struct snmp_value *val, 1191 uint sub, uint iidx __unused, enum snmp_op op) 1192{ 1193 struct bridge_if *bif; 1194 1195 if (time(NULL) - bridge_list_age > bridge_get_data_maxage()) 1196 bridge_update_all_ifs(); 1197 1198 switch (op) { 1199 case SNMP_OP_GET: 1200 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1201 return (SNMP_ERR_NOSUCHNAME); 1202 goto get; 1203 1204 case SNMP_OP_GETNEXT: 1205 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL) 1206 return (SNMP_ERR_NOSUCHNAME); 1207 bridge_if_index_append(&val->var, sub, bif); 1208 goto get; 1209 1210 case SNMP_OP_SET: 1211 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1212 return (SNMP_ERR_NOSUCHNAME); 1213 1214 switch (val->var.subs[sub - 1]) { 1215 case LEAF_begemotBridgeStpPriority: 1216 if (val->v.integer > SNMP_BRIDGE_MAX_PRIORITY || 1217 val->v.integer % 4096 != 0) 1218 return (SNMP_ERR_WRONG_VALUE); 1219 1220 ctx->scratch->int1 = bif->priority; 1221 if (bridge_set_priority(bif, val->v.integer) < 0) 1222 return (SNMP_ERR_GENERR); 1223 return (SNMP_ERR_NOERROR); 1224 1225 case LEAF_begemotBridgeStpBridgeMaxAge: 1226 if (val->v.integer < SNMP_BRIDGE_MIN_MAGE || 1227 val->v.integer > SNMP_BRIDGE_MAX_MAGE) 1228 return (SNMP_ERR_WRONG_VALUE); 1229 1230 ctx->scratch->int1 = bif->bridge_max_age; 1231 if (bridge_set_maxage(bif, val->v.integer) < 0) 1232 return (SNMP_ERR_GENERR); 1233 return (SNMP_ERR_NOERROR); 1234 1235 case LEAF_begemotBridgeStpBridgeHelloTime: 1236 if (val->v.integer < SNMP_BRIDGE_MIN_HTIME || 1237 val->v.integer > SNMP_BRIDGE_MAX_HTIME) 1238 return (SNMP_ERR_WRONG_VALUE); 1239 1240 ctx->scratch->int1 = bif->bridge_hello_time; 1241 if (bridge_set_hello_time(bif, val->v.integer) < 0) 1242 return (SNMP_ERR_GENERR); 1243 return (SNMP_ERR_NOERROR); 1244 1245 case LEAF_begemotBridgeStpBridgeForwardDelay: 1246 if (val->v.integer < SNMP_BRIDGE_MIN_FDELAY || 1247 val->v.integer > SNMP_BRIDGE_MAX_FDELAY) 1248 return (SNMP_ERR_WRONG_VALUE); 1249 1250 ctx->scratch->int1 = bif->bridge_fwd_delay; 1251 if (bridge_set_forward_delay(bif, val->v.integer) < 0) 1252 return (SNMP_ERR_GENERR); 1253 return (SNMP_ERR_NOERROR); 1254 1255 case LEAF_begemotBridgeStpVersion: 1256 if (val->v.integer != 1257 begemotBridgeStpVersion_stpCompatible && 1258 val->v.integer != begemotBridgeStpVersion_rstp) 1259 return (SNMP_ERR_WRONG_VALUE); 1260 1261 ctx->scratch->int1 = bif->stp_version; 1262 if (bridge_set_stp_version(bif, val->v.integer) < 0) 1263 return (SNMP_ERR_GENERR); 1264 return (SNMP_ERR_NOERROR); 1265 1266 case LEAF_begemotBridgeStpTxHoldCount: 1267 if (val->v.integer < SNMP_BRIDGE_MIN_TXHC || 1268 val->v.integer > SNMP_BRIDGE_MAX_TXHC) 1269 return (SNMP_ERR_WRONG_VALUE); 1270 1271 ctx->scratch->int1 = bif->tx_hold_count; 1272 if (bridge_set_tx_hold_count(bif, val->v.integer) < 0) 1273 return (SNMP_ERR_GENERR); 1274 return (SNMP_ERR_NOERROR); 1275 1276 case LEAF_begemotBridgeStpProtocolSpecification: 1277 case LEAF_begemotBridgeStpTimeSinceTopologyChange: 1278 case LEAF_begemotBridgeStpTopChanges: 1279 case LEAF_begemotBridgeStpDesignatedRoot: 1280 case LEAF_begemotBridgeStpRootCost: 1281 case LEAF_begemotBridgeStpRootPort: 1282 case LEAF_begemotBridgeStpMaxAge: 1283 case LEAF_begemotBridgeStpHelloTime: 1284 case LEAF_begemotBridgeStpHoldTime: 1285 case LEAF_begemotBridgeStpForwardDelay: 1286 return (SNMP_ERR_NOT_WRITEABLE); 1287 } 1288 abort(); 1289 1290 case SNMP_OP_ROLLBACK: 1291 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1292 return (SNMP_ERR_NOSUCHNAME); 1293 1294 switch (val->var.subs[sub - 1]) { 1295 case LEAF_begemotBridgeStpPriority: 1296 bridge_set_priority(bif, ctx->scratch->int1); 1297 break; 1298 1299 case LEAF_begemotBridgeStpBridgeMaxAge: 1300 bridge_set_maxage(bif, ctx->scratch->int1); 1301 break; 1302 1303 case LEAF_begemotBridgeStpBridgeHelloTime: 1304 bridge_set_hello_time(bif, ctx->scratch->int1); 1305 break; 1306 1307 case LEAF_begemotBridgeStpBridgeForwardDelay: 1308 bridge_set_forward_delay(bif, ctx->scratch->int1); 1309 break; 1310 1311 case LEAF_begemotBridgeStpVersion: 1312 bridge_set_stp_version(bif, ctx->scratch->int1); 1313 break; 1314 1315 case LEAF_begemotBridgeStpTxHoldCount: 1316 bridge_set_tx_hold_count(bif, ctx->scratch->int1); 1317 break; 1318 } 1319 return (SNMP_ERR_NOERROR); 1320 1321 case SNMP_OP_COMMIT: 1322 return (SNMP_ERR_NOERROR); 1323 } 1324 abort(); 1325 1326get: 1327 switch (val->var.subs[sub - 1]) { 1328 case LEAF_begemotBridgeStpProtocolSpecification: 1329 val->v.integer = bif->prot_spec; 1330 return (SNMP_ERR_NOERROR); 1331 1332 case LEAF_begemotBridgeStpPriority: 1333 val->v.integer = bif->priority; 1334 return (SNMP_ERR_NOERROR); 1335 1336 case LEAF_begemotBridgeStpTimeSinceTopologyChange: 1337 if (bridge_get_time_since_tc(bif, &(val->v.uint32)) < 0) 1338 return (SNMP_ERR_GENERR); 1339 return (SNMP_ERR_NOERROR); 1340 1341 case LEAF_begemotBridgeStpTopChanges: 1342 val->v.uint32 = bif->top_changes; 1343 return (SNMP_ERR_NOERROR); 1344 1345 case LEAF_begemotBridgeStpDesignatedRoot: 1346 return (string_get(val, bif->design_root, SNMP_BRIDGE_ID_LEN)); 1347 1348 case LEAF_begemotBridgeStpRootCost: 1349 val->v.integer = bif->root_cost; 1350 return (SNMP_ERR_NOERROR); 1351 1352 case LEAF_begemotBridgeStpRootPort: 1353 val->v.integer = bif->root_port; 1354 return (SNMP_ERR_NOERROR); 1355 1356 case LEAF_begemotBridgeStpMaxAge: 1357 val->v.integer = bif->max_age; 1358 return (SNMP_ERR_NOERROR); 1359 1360 case LEAF_begemotBridgeStpHelloTime: 1361 val->v.integer = bif->hello_time; 1362 return (SNMP_ERR_NOERROR); 1363 1364 case LEAF_begemotBridgeStpHoldTime: 1365 val->v.integer = bif->hold_time; 1366 return (SNMP_ERR_NOERROR); 1367 1368 case LEAF_begemotBridgeStpForwardDelay: 1369 val->v.integer = bif->fwd_delay; 1370 return (SNMP_ERR_NOERROR); 1371 1372 case LEAF_begemotBridgeStpBridgeMaxAge: 1373 val->v.integer = bif->bridge_max_age; 1374 return (SNMP_ERR_NOERROR); 1375 1376 case LEAF_begemotBridgeStpBridgeHelloTime: 1377 val->v.integer = bif->bridge_hello_time; 1378 return (SNMP_ERR_NOERROR); 1379 1380 case LEAF_begemotBridgeStpBridgeForwardDelay: 1381 val->v.integer = bif->bridge_fwd_delay; 1382 return (SNMP_ERR_NOERROR); 1383 1384 case LEAF_begemotBridgeStpVersion: 1385 val->v.integer = bif->stp_version; 1386 return (SNMP_ERR_NOERROR); 1387 1388 case LEAF_begemotBridgeStpTxHoldCount: 1389 val->v.integer = bif->tx_hold_count; 1390 return (SNMP_ERR_NOERROR); 1391 } 1392 1393 abort(); 1394} 1395 1396int 1397op_begemot_tp(struct snmp_context *ctx, struct snmp_value *val, 1398 uint sub, uint iidx __unused, enum snmp_op op) 1399{ 1400 struct bridge_if *bif; 1401 1402 if (time(NULL) - bridge_list_age > bridge_get_data_maxage()) 1403 bridge_update_all_ifs(); 1404 1405 switch (op) { 1406 case SNMP_OP_GET: 1407 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1408 return (SNMP_ERR_NOSUCHNAME); 1409 goto get; 1410 1411 case SNMP_OP_GETNEXT: 1412 if ((bif = bridge_if_index_getnext(&val->var, sub)) == NULL) 1413 return (SNMP_ERR_NOSUCHNAME); 1414 bridge_if_index_append(&val->var, sub, bif); 1415 goto get; 1416 1417 case SNMP_OP_SET: 1418 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1419 return (SNMP_ERR_NOSUCHNAME); 1420 1421 switch (val->var.subs[sub - 1]) { 1422 case LEAF_begemotBridgeTpAgingTime: 1423 if (val->v.integer < SNMP_BRIDGE_MIN_AGE_TIME || 1424 val->v.integer > SNMP_BRIDGE_MAX_AGE_TIME) 1425 return (SNMP_ERR_WRONG_VALUE); 1426 1427 ctx->scratch->int1 = bif->age_time; 1428 if (bridge_set_aging_time(bif, val->v.integer) < 0) 1429 return (SNMP_ERR_GENERR); 1430 return (SNMP_ERR_NOERROR); 1431 1432 case LEAF_begemotBridgeTpMaxAddresses: 1433 ctx->scratch->int1 = bif->max_addrs; 1434 if (bridge_set_max_cache(bif, val->v.integer) < 0) 1435 return (SNMP_ERR_GENERR); 1436 return (SNMP_ERR_NOERROR); 1437 1438 case LEAF_begemotBridgeTpLearnedEntryDiscards: 1439 return (SNMP_ERR_NOT_WRITEABLE); 1440 } 1441 abort(); 1442 1443 case SNMP_OP_ROLLBACK: 1444 if ((bif = bridge_if_index_get(&val->var, sub)) == NULL) 1445 return (SNMP_ERR_GENERR); 1446 1447 switch (val->var.subs[sub - 1]) { 1448 case LEAF_begemotBridgeTpAgingTime: 1449 bridge_set_aging_time(bif, ctx->scratch->int1); 1450 break; 1451 1452 case LEAF_begemotBridgeTpMaxAddresses: 1453 bridge_set_max_cache(bif, ctx->scratch->int1); 1454 break; 1455 } 1456 return (SNMP_ERR_NOERROR); 1457 1458 case SNMP_OP_COMMIT: 1459 return (SNMP_ERR_NOERROR); 1460 } 1461 abort(); 1462 1463get: 1464 switch (val->var.subs[sub - 1]) { 1465 case LEAF_begemotBridgeTpLearnedEntryDiscards: 1466 val->v.uint32 = bif->lrnt_drops; 1467 return (SNMP_ERR_NOERROR); 1468 1469 case LEAF_begemotBridgeTpAgingTime: 1470 val->v.integer = bif->age_time; 1471 return (SNMP_ERR_NOERROR); 1472 1473 case LEAF_begemotBridgeTpMaxAddresses: 1474 val->v.integer = bif->max_addrs; 1475 return (SNMP_ERR_NOERROR); 1476 } 1477 1478 abort(); 1479} 1480