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 * Bridge addresses. 28164410Ssyrinx * 29164410Ssyrinx * $FreeBSD: releng/10.3/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_addrs.c 228990 2011-12-30 10:58:14Z uqs $ 30164410Ssyrinx */ 31164410Ssyrinx 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 40164410Ssyrinx#include <assert.h> 41164410Ssyrinx#include <errno.h> 42164410Ssyrinx#include <stdarg.h> 43164410Ssyrinx#include <string.h> 44164410Ssyrinx#include <stdlib.h> 45164410Ssyrinx#include <syslog.h> 46164410Ssyrinx 47164410Ssyrinx#include <bsnmp/snmpmod.h> 48164410Ssyrinx#include <bsnmp/snmp_mibII.h> 49164410Ssyrinx 50164410Ssyrinx#include "bridge_tree.h" 51164410Ssyrinx#include "bridge_snmp.h" 52164410Ssyrinx 53164410SsyrinxTAILQ_HEAD(tp_entries, tp_entry); 54164410Ssyrinx 55164410Ssyrinx/* 56164410Ssyrinx * Free the bridge address list. 57164410Ssyrinx */ 58164410Ssyrinxstatic void 59164410Ssyrinxbridge_tpe_free(struct tp_entries *headp) 60164410Ssyrinx{ 61164410Ssyrinx struct tp_entry *t; 62164410Ssyrinx 63164410Ssyrinx while ((t = TAILQ_FIRST(headp)) != NULL) { 64164410Ssyrinx TAILQ_REMOVE(headp, t, tp_e); 65164410Ssyrinx free(t); 66164410Ssyrinx } 67164410Ssyrinx} 68164410Ssyrinx 69164410Ssyrinx/* 70164410Ssyrinx * Free the bridge address entries from the address list, 71164410Ssyrinx * for the specified bridge interface only. 72164410Ssyrinx */ 73164410Ssyrinxstatic void 74164410Ssyrinxbridge_tpe_bif_free(struct tp_entries *headp, 75164410Ssyrinx struct bridge_if *bif) 76164410Ssyrinx{ 77164410Ssyrinx struct tp_entry *tp; 78164410Ssyrinx 79164410Ssyrinx while (bif->f_tpa != NULL && bif->sysindex == bif->f_tpa->sysindex) { 80164410Ssyrinx tp = TAILQ_NEXT(bif->f_tpa, tp_e); 81164410Ssyrinx TAILQ_REMOVE(headp, bif->f_tpa, tp_e); 82164410Ssyrinx free(bif->f_tpa); 83164410Ssyrinx bif->f_tpa = tp; 84164410Ssyrinx } 85164410Ssyrinx} 86164410Ssyrinx 87164410Ssyrinx/* 88164410Ssyrinx * Compare two mac addresses. 89164410Ssyrinx * m1 < m2 : -1 90164410Ssyrinx * m1 > m2 : +1 91164410Ssyrinx * m1 = m2 : 0 92164410Ssyrinx */ 93164410Ssyrinxstatic int 94164410Ssyrinxbridge_compare_macs(const uint8_t *m1, const uint8_t *m2) 95164410Ssyrinx{ 96164410Ssyrinx int i; 97164410Ssyrinx 98164410Ssyrinx for (i = 0; i < ETHER_ADDR_LEN; i++) { 99164410Ssyrinx if (m1[i] < m2[i]) 100164410Ssyrinx return (-1); 101164410Ssyrinx if (m1[i] > m2[i]) 102164410Ssyrinx return (1); 103164410Ssyrinx } 104164410Ssyrinx 105164410Ssyrinx return (0); 106164410Ssyrinx} 107164410Ssyrinx 108164410Ssyrinx/* 109164410Ssyrinx * Insert an address entry in the bridge address TAILQ starting to search 110164410Ssyrinx * for its place from the position of the first bridge address for the bridge 111228990Suqs * interface. Update the first bridge address if necessary. 112164410Ssyrinx */ 113164410Ssyrinxstatic void 114164410Ssyrinxbridge_addrs_insert_at(struct tp_entries *headp, 115164410Ssyrinx struct tp_entry *ta, struct tp_entry **f_tpa) 116164410Ssyrinx{ 117164410Ssyrinx struct tp_entry *t1; 118164410Ssyrinx 119164410Ssyrinx assert(f_tpa != NULL); 120164410Ssyrinx 121164410Ssyrinx for (t1 = *f_tpa; 122164410Ssyrinx t1 != NULL && ta->sysindex == t1->sysindex; 123164410Ssyrinx t1 = TAILQ_NEXT(t1, tp_e)) { 124164410Ssyrinx if (bridge_compare_macs(ta->tp_addr, t1->tp_addr) < 0) { 125164410Ssyrinx TAILQ_INSERT_BEFORE(t1, ta, tp_e); 126164410Ssyrinx if (*f_tpa == t1) 127164410Ssyrinx (*f_tpa) = ta; 128164410Ssyrinx return; 129164410Ssyrinx } 130164410Ssyrinx } 131164410Ssyrinx 132164410Ssyrinx if (t1 == NULL) 133164410Ssyrinx TAILQ_INSERT_TAIL(headp, ta, tp_e); 134164410Ssyrinx else 135164410Ssyrinx TAILQ_INSERT_BEFORE(t1, ta, tp_e); 136164410Ssyrinx} 137164410Ssyrinx 138164410Ssyrinx/* 139228990Suqs * Find an address entry's position in the address list 140164410Ssyrinx * according to bridge interface name. 141164410Ssyrinx */ 142164410Ssyrinxstatic struct tp_entry * 143164410Ssyrinxbridge_addrs_find_pos(struct tp_entries *headp, uint32_t b_idx) 144164410Ssyrinx{ 145164410Ssyrinx uint32_t t_idx; 146164410Ssyrinx struct tp_entry *t1; 147164410Ssyrinx 148164410Ssyrinx if ((t1 = TAILQ_FIRST(headp)) == NULL || 149164410Ssyrinx bridge_compare_sysidx(b_idx, t1->sysindex) < 0) 150164410Ssyrinx return (NULL); 151164410Ssyrinx 152164410Ssyrinx t_idx = t1->sysindex; 153164410Ssyrinx 154164410Ssyrinx for (t1 = TAILQ_NEXT(t1, tp_e); t1 != NULL; t1 = TAILQ_NEXT(t1, tp_e)) { 155164410Ssyrinx 156164410Ssyrinx if (t1->sysindex != t_idx) { 157164410Ssyrinx if (bridge_compare_sysidx(b_idx, t1->sysindex) < 0) 158164410Ssyrinx return (TAILQ_PREV(t1, tp_entries, tp_e)); 159164410Ssyrinx else 160164410Ssyrinx t_idx = t1->sysindex; 161164410Ssyrinx } 162164410Ssyrinx } 163164410Ssyrinx 164164410Ssyrinx if (t1 == NULL) 165164410Ssyrinx t1 = TAILQ_LAST(headp, tp_entries); 166164410Ssyrinx 167164410Ssyrinx return (t1); 168164410Ssyrinx} 169164410Ssyrinx 170164410Ssyrinx/* 171164410Ssyrinx * Insert a bridge address in the bridge addresses list. 172164410Ssyrinx */ 173164410Ssyrinxstatic void 174164410Ssyrinxbridge_addrs_bif_insert(struct tp_entries *headp, struct tp_entry *te, 175164410Ssyrinx struct tp_entry **f_tpa) 176164410Ssyrinx{ 177164410Ssyrinx struct tp_entry *temp; 178164410Ssyrinx 179164410Ssyrinx if (*f_tpa != NULL) 180164410Ssyrinx bridge_addrs_insert_at(headp, te, f_tpa); 181164410Ssyrinx else { 182164410Ssyrinx temp = bridge_addrs_find_pos(headp, te->sysindex); 183164410Ssyrinx 184164410Ssyrinx if (temp == NULL) 185164410Ssyrinx TAILQ_INSERT_HEAD(headp, te, tp_e); 186164410Ssyrinx else 187164410Ssyrinx TAILQ_INSERT_AFTER(headp, temp, te, tp_e); 188164410Ssyrinx *f_tpa = te; 189164410Ssyrinx } 190164410Ssyrinx} 191164410Ssyrinx 192164410Ssyrinxstatic struct tp_entries tp_entries = TAILQ_HEAD_INITIALIZER(tp_entries); 193164410Ssyrinxstatic time_t address_list_age; 194164410Ssyrinx 195164410Ssyrinxvoid 196164410Ssyrinxbridge_addrs_update_listage(void) 197164410Ssyrinx{ 198164410Ssyrinx address_list_age = time(NULL); 199164410Ssyrinx} 200164410Ssyrinx 201164410Ssyrinxvoid 202164410Ssyrinxbridge_addrs_fini(void) 203164410Ssyrinx{ 204164410Ssyrinx bridge_tpe_free(&tp_entries); 205164410Ssyrinx} 206164410Ssyrinx 207164410Ssyrinxvoid 208164410Ssyrinxbridge_addrs_free(struct bridge_if *bif) 209164410Ssyrinx{ 210164410Ssyrinx bridge_tpe_bif_free(&tp_entries, bif); 211164410Ssyrinx} 212164410Ssyrinx 213164410Ssyrinx/* 214164410Ssyrinx * Find the first address in the list. 215164410Ssyrinx */ 216164410Ssyrinxstatic struct tp_entry * 217164410Ssyrinxbridge_addrs_first(void) 218164410Ssyrinx{ 219164410Ssyrinx return (TAILQ_FIRST(&tp_entries)); 220164410Ssyrinx} 221164410Ssyrinx 222164410Ssyrinx/* 223164410Ssyrinx * Find the next address in the list. 224164410Ssyrinx */ 225164410Ssyrinxstatic struct tp_entry * 226164410Ssyrinxbridge_addrs_next(struct tp_entry *te) 227164410Ssyrinx{ 228164410Ssyrinx return (TAILQ_NEXT(te, tp_e)); 229164410Ssyrinx} 230164410Ssyrinx 231164410Ssyrinx/* 232164410Ssyrinx * Find the first address, learnt by the specified bridge interface. 233164410Ssyrinx */ 234164410Ssyrinxstruct tp_entry * 235164410Ssyrinxbridge_addrs_bif_first(struct bridge_if *bif) 236164410Ssyrinx{ 237164410Ssyrinx return (bif->f_tpa); 238164410Ssyrinx} 239164410Ssyrinx 240164410Ssyrinx/* 241164410Ssyrinx * Find the next address, learnt by the specified bridge interface. 242164410Ssyrinx */ 243164410Ssyrinxstruct tp_entry * 244164410Ssyrinxbridge_addrs_bif_next(struct tp_entry *te) 245164410Ssyrinx{ 246164410Ssyrinx struct tp_entry *te_next; 247164410Ssyrinx 248164410Ssyrinx if ((te_next = TAILQ_NEXT(te, tp_e)) == NULL || 249164410Ssyrinx te_next->sysindex != te->sysindex) 250164410Ssyrinx return (NULL); 251164410Ssyrinx 252164410Ssyrinx return (te_next); 253164410Ssyrinx} 254164410Ssyrinx 255164410Ssyrinx/* 256164410Ssyrinx * Remove a bridge address from the list. 257164410Ssyrinx */ 258164410Ssyrinxvoid 259164410Ssyrinxbridge_addrs_remove(struct tp_entry *te, struct bridge_if *bif) 260164410Ssyrinx{ 261164410Ssyrinx if (bif->f_tpa == te) 262164410Ssyrinx bif->f_tpa = bridge_addrs_bif_next(te); 263164410Ssyrinx 264164410Ssyrinx TAILQ_REMOVE(&tp_entries, te, tp_e); 265164410Ssyrinx free(te); 266164410Ssyrinx} 267164410Ssyrinx 268164410Ssyrinx/* 269164410Ssyrinx * Allocate memory for a new bridge address and insert it in the list. 270164410Ssyrinx */ 271164410Ssyrinxstruct tp_entry * 272164410Ssyrinxbridge_new_addrs(uint8_t *mac, struct bridge_if *bif) 273164410Ssyrinx{ 274164410Ssyrinx struct tp_entry *te; 275164410Ssyrinx 276164410Ssyrinx if ((te = (struct tp_entry *) malloc(sizeof(*te))) == NULL) { 277164410Ssyrinx syslog(LOG_ERR, "bridge new address: failed: %s", 278164410Ssyrinx strerror(errno)); 279164410Ssyrinx return (NULL); 280164410Ssyrinx } 281164410Ssyrinx 282164410Ssyrinx bzero(te, sizeof(*te)); 283164410Ssyrinx 284164410Ssyrinx te->sysindex = bif->sysindex; 285164410Ssyrinx bcopy(mac, te->tp_addr, ETHER_ADDR_LEN); 286164410Ssyrinx bridge_addrs_bif_insert(&tp_entries, te, &(bif->f_tpa)); 287164410Ssyrinx 288164410Ssyrinx return (te); 289164410Ssyrinx} 290164410Ssyrinx 291164410Ssyrinx/* 292164410Ssyrinx * Given a mac address, learnt on a bridge, 293164410Ssyrinx * find the corrsponding TP entry for it. 294164410Ssyrinx */ 295164410Ssyrinxstruct tp_entry * 296164410Ssyrinxbridge_addrs_find(uint8_t *mac, struct bridge_if *bif) 297164410Ssyrinx{ 298164410Ssyrinx struct tp_entry *te; 299164410Ssyrinx 300164410Ssyrinx for (te = bif->f_tpa; te != NULL; te = TAILQ_NEXT(te, tp_e)) { 301164410Ssyrinx if (te->sysindex != bif->sysindex) { 302164410Ssyrinx te = NULL; 303164410Ssyrinx break; 304164410Ssyrinx } 305164410Ssyrinx 306164410Ssyrinx if (bridge_compare_macs(te->tp_addr, mac) == 0) 307164410Ssyrinx break; 308164410Ssyrinx } 309164410Ssyrinx 310164410Ssyrinx return (te); 311164410Ssyrinx} 312164410Ssyrinx 313164410Ssyrinxvoid 314164410Ssyrinxbridge_addrs_dump(struct bridge_if *bif) 315164410Ssyrinx{ 316164410Ssyrinx struct tp_entry *te; 317164410Ssyrinx 318164410Ssyrinx syslog(LOG_ERR, "Addresses count - %d", bif->num_addrs); 319164410Ssyrinx for (te = bridge_addrs_bif_first(bif); te != NULL; 320164410Ssyrinx te = bridge_addrs_bif_next(te)) { 321164410Ssyrinx syslog(LOG_ERR, "address %x:%x:%x:%x:%x:%x on port %d.%d", 322164410Ssyrinx te->tp_addr[0], te->tp_addr[1], te->tp_addr[2], 323164410Ssyrinx te->tp_addr[3], te->tp_addr[4], te->tp_addr[5], 324164410Ssyrinx te->sysindex, te->port_no); 325164410Ssyrinx } 326164410Ssyrinx} 327164410Ssyrinx 328164410Ssyrinx/* 329164410Ssyrinx * RFC4188 specifics. 330164410Ssyrinx */ 331164410Ssyrinx 332164410Ssyrinx/* 333164410Ssyrinx * Construct the SNMP index from the address DST Mac. 334164410Ssyrinx */ 335164410Ssyrinxstatic void 336164410Ssyrinxbridge_addrs_index_append(struct asn_oid *oid, uint sub, 337164410Ssyrinx const struct tp_entry *te) 338164410Ssyrinx{ 339164410Ssyrinx int i; 340164410Ssyrinx 341164410Ssyrinx oid->len = sub + ETHER_ADDR_LEN + 1; 342164410Ssyrinx oid->subs[sub] = ETHER_ADDR_LEN; 343164410Ssyrinx 344164410Ssyrinx for (i = 1; i <= ETHER_ADDR_LEN; i++) 345164410Ssyrinx oid->subs[sub + i] = te->tp_addr[i - 1]; 346164410Ssyrinx} 347164410Ssyrinx 348164410Ssyrinx/* 349164410Ssyrinx * Find the address entry for the SNMP index from the default bridge only. 350164410Ssyrinx */ 351164410Ssyrinxstatic struct tp_entry * 352164410Ssyrinxbridge_addrs_get(const struct asn_oid *oid, uint sub, 353164410Ssyrinx struct bridge_if *bif) 354164410Ssyrinx{ 355164410Ssyrinx int i; 356164410Ssyrinx uint8_t tp_addr[ETHER_ADDR_LEN]; 357164410Ssyrinx 358164410Ssyrinx if (oid->len - sub != ETHER_ADDR_LEN + 1 || 359164410Ssyrinx oid->subs[sub] != ETHER_ADDR_LEN) 360164410Ssyrinx return (NULL); 361164410Ssyrinx 362164410Ssyrinx for (i = 0; i < ETHER_ADDR_LEN; i++) 363164410Ssyrinx tp_addr[i] = oid->subs[sub + i + 1]; 364164410Ssyrinx 365164410Ssyrinx return (bridge_addrs_find(tp_addr, bif)); 366164410Ssyrinx} 367164410Ssyrinx 368164410Ssyrinx/* 369164410Ssyrinx * Find the next address entry for the SNMP index 370164410Ssyrinx * from the default bridge only. 371164410Ssyrinx */ 372164410Ssyrinxstatic struct tp_entry * 373164410Ssyrinxbridge_addrs_getnext(const struct asn_oid *oid, uint sub, 374164410Ssyrinx struct bridge_if *bif) 375164410Ssyrinx{ 376164410Ssyrinx int i; 377164410Ssyrinx uint8_t tp_addr[ETHER_ADDR_LEN]; 378164410Ssyrinx static struct tp_entry *te; 379164410Ssyrinx 380164410Ssyrinx if (oid->len - sub == 0) 381164410Ssyrinx return (bridge_addrs_bif_first(bif)); 382164410Ssyrinx 383164410Ssyrinx if (oid->len - sub != ETHER_ADDR_LEN + 1 || 384164410Ssyrinx oid->subs[sub] != ETHER_ADDR_LEN) 385164410Ssyrinx return (NULL); 386164410Ssyrinx 387164410Ssyrinx for (i = 0; i < ETHER_ADDR_LEN; i++) 388164410Ssyrinx tp_addr[i] = oid->subs[sub + i + 1]; 389164410Ssyrinx 390164410Ssyrinx if ((te = bridge_addrs_find(tp_addr, bif)) == NULL) 391164410Ssyrinx return (NULL); 392164410Ssyrinx 393164410Ssyrinx return (bridge_addrs_bif_next(te)); 394164410Ssyrinx} 395164410Ssyrinx 396164410Ssyrinxint 397164410Ssyrinxop_dot1d_tp_fdb(struct snmp_context *c __unused, struct snmp_value *val, 398164410Ssyrinx uint sub, uint iidx __unused, enum snmp_op op) 399164410Ssyrinx{ 400164410Ssyrinx struct bridge_if *bif; 401164410Ssyrinx struct tp_entry *te; 402164410Ssyrinx 403164410Ssyrinx if ((bif = bridge_get_default()) == NULL) 404164410Ssyrinx return (SNMP_ERR_NOSUCHNAME); 405164410Ssyrinx 406164410Ssyrinx if (time(NULL) - bif->addrs_age > bridge_get_data_maxage() && 407164410Ssyrinx bridge_update_addrs(bif) <= 0) 408164410Ssyrinx return (SNMP_ERR_NOSUCHNAME); 409164410Ssyrinx 410164410Ssyrinx switch (op) { 411164410Ssyrinx case SNMP_OP_GET: 412164410Ssyrinx if ((te = bridge_addrs_get(&val->var, sub, bif)) == NULL) 413164410Ssyrinx return (SNMP_ERR_NOSUCHNAME); 414165253Ssyrinx goto get; 415164410Ssyrinx 416164410Ssyrinx case SNMP_OP_GETNEXT: 417164410Ssyrinx if ((te = bridge_addrs_getnext(&val->var, sub, bif)) == NULL) 418164410Ssyrinx return (SNMP_ERR_NOSUCHNAME); 419164410Ssyrinx bridge_addrs_index_append(&val->var, sub, te); 420165253Ssyrinx goto get; 421164410Ssyrinx 422164410Ssyrinx case SNMP_OP_SET: 423164410Ssyrinx return (SNMP_ERR_NOT_WRITEABLE); 424164410Ssyrinx 425164410Ssyrinx case SNMP_OP_ROLLBACK: 426164410Ssyrinx case SNMP_OP_COMMIT: 427165253Ssyrinx break; 428164410Ssyrinx } 429165253Ssyrinx abort(); 430164410Ssyrinx 431165253Ssyrinxget: 432164410Ssyrinx switch (val->var.subs[sub - 1]) { 433164410Ssyrinx case LEAF_dot1dTpFdbAddress: 434165253Ssyrinx return (string_get(val, te->tp_addr, ETHER_ADDR_LEN)); 435164410Ssyrinx case LEAF_dot1dTpFdbPort : 436164410Ssyrinx val->v.integer = te->port_no; 437165253Ssyrinx return (SNMP_ERR_NOERROR); 438164410Ssyrinx case LEAF_dot1dTpFdbStatus: 439164410Ssyrinx val->v.integer = te->status; 440165253Ssyrinx return (SNMP_ERR_NOERROR); 441164410Ssyrinx } 442164410Ssyrinx 443165253Ssyrinx abort(); 444164410Ssyrinx} 445164410Ssyrinx 446164410Ssyrinx/* 447164410Ssyrinx * Private BEGEMOT-BRIDGE-MIB specifics. 448164410Ssyrinx */ 449164410Ssyrinx 450164410Ssyrinx/* 451164410Ssyrinx * Construct the SNMP index from the bridge interface name 452164410Ssyrinx * and the address DST Mac. 453164410Ssyrinx */ 454164410Ssyrinxstatic int 455164410Ssyrinxbridge_addrs_begemot_index_append(struct asn_oid *oid, uint sub, 456164410Ssyrinx const struct tp_entry *te) 457164410Ssyrinx{ 458164410Ssyrinx uint i, n_len; 459164410Ssyrinx const char *b_name; 460164410Ssyrinx 461164410Ssyrinx if ((b_name = bridge_if_find_name(te->sysindex)) == NULL) 462164410Ssyrinx return (-1); 463164410Ssyrinx 464164410Ssyrinx n_len = strlen(b_name); 465164410Ssyrinx oid->len = sub++; 466164410Ssyrinx oid->subs[oid->len++] = n_len; 467164410Ssyrinx 468164410Ssyrinx for (i = 1; i <= n_len; i++) 469164410Ssyrinx oid->subs[oid->len++] = b_name[i - 1]; 470164410Ssyrinx 471164410Ssyrinx oid->subs[oid->len++] = ETHER_ADDR_LEN; 472164410Ssyrinx for (i = 1 ; i <= ETHER_ADDR_LEN; i++) 473164410Ssyrinx oid->subs[oid->len++] = te->tp_addr[i - 1]; 474164410Ssyrinx 475164410Ssyrinx return (0); 476164410Ssyrinx} 477164410Ssyrinx 478164410Ssyrinx/* 479164410Ssyrinx * Find a bridge address entry by the bridge interface name 480164410Ssyrinx * and the address DST Mac. 481164410Ssyrinx */ 482164410Ssyrinxstatic struct tp_entry * 483164410Ssyrinxbridge_addrs_begemot_get(const struct asn_oid *oid, uint sub) 484164410Ssyrinx{ 485164410Ssyrinx uint i, n_len; 486164410Ssyrinx uint8_t tp_addr[ETHER_ADDR_LEN]; 487164410Ssyrinx char bif_name[IFNAMSIZ]; 488164410Ssyrinx struct bridge_if *bif; 489164410Ssyrinx 490164410Ssyrinx n_len = oid->subs[sub]; 491164410Ssyrinx if (oid->len - sub != n_len + ETHER_ADDR_LEN + 3 || 492164410Ssyrinx n_len >= IFNAMSIZ || oid->subs[sub + n_len + 1] != ETHER_ADDR_LEN) 493164410Ssyrinx return (NULL); 494164410Ssyrinx 495164410Ssyrinx for (i = 0; i < n_len; i++) 496164410Ssyrinx bif_name[i] = oid->subs[n_len + i + 1]; 497164410Ssyrinx bif_name[i] = '\0'; 498164410Ssyrinx 499164410Ssyrinx for (i = 1; i <= ETHER_ADDR_LEN; i++) 500164410Ssyrinx tp_addr[i - 1] = oid->subs[n_len + i + 1]; 501164410Ssyrinx 502164410Ssyrinx if ((bif = bridge_if_find_ifname(bif_name)) == NULL) 503164410Ssyrinx return (NULL); 504164410Ssyrinx 505164410Ssyrinx return (bridge_addrs_find(tp_addr, bif)); 506164410Ssyrinx} 507164410Ssyrinx 508164410Ssyrinx/* 509164410Ssyrinx * Find the next bridge address entry by the bridge interface name 510164410Ssyrinx * and the address DST Mac. 511164410Ssyrinx */ 512164410Ssyrinxstatic struct tp_entry * 513164410Ssyrinxbridge_addrs_begemot_getnext(const struct asn_oid *oid, uint sub) 514164410Ssyrinx{ 515164410Ssyrinx uint i, n_len; 516164410Ssyrinx uint8_t tp_addr[ETHER_ADDR_LEN]; 517164410Ssyrinx char bif_name[IFNAMSIZ]; 518164410Ssyrinx struct bridge_if *bif; 519164410Ssyrinx struct tp_entry *tp; 520164410Ssyrinx 521164410Ssyrinx if (oid->len - sub == 0) 522164410Ssyrinx return (bridge_addrs_first()); 523164410Ssyrinx 524164410Ssyrinx n_len = oid->subs[sub]; 525164410Ssyrinx if (oid->len - sub != n_len + ETHER_ADDR_LEN + 2 || 526164410Ssyrinx n_len >= IFNAMSIZ || oid->subs[sub + n_len + 1] != ETHER_ADDR_LEN) 527164410Ssyrinx return (NULL); 528164410Ssyrinx 529164410Ssyrinx for (i = 1; i <= n_len; i++) 530164410Ssyrinx bif_name[i - 1] = oid->subs[sub + i]; 531164410Ssyrinx 532164410Ssyrinx bif_name[i - 1] = '\0'; 533164410Ssyrinx 534164410Ssyrinx for (i = 1; i <= ETHER_ADDR_LEN; i++) 535164410Ssyrinx tp_addr[i - 1] = oid->subs[sub + n_len + i + 1]; 536164410Ssyrinx 537164410Ssyrinx if ((bif = bridge_if_find_ifname(bif_name)) == NULL || 538164410Ssyrinx (tp = bridge_addrs_find(tp_addr, bif)) == NULL) 539164410Ssyrinx return (NULL); 540164410Ssyrinx 541164410Ssyrinx return (bridge_addrs_next(tp)); 542164410Ssyrinx} 543164410Ssyrinx 544164410Ssyrinxint 545164410Ssyrinxop_begemot_tp_fdb(struct snmp_context *c __unused, struct snmp_value *val, 546164410Ssyrinx uint sub, uint iidx __unused, enum snmp_op op) 547164410Ssyrinx{ 548165046Ssyrinx struct tp_entry *te; 549164410Ssyrinx 550164410Ssyrinx if (time(NULL) - address_list_age > bridge_get_data_maxage()) 551164410Ssyrinx bridge_update_all_addrs(); 552164410Ssyrinx 553164410Ssyrinx switch (op) { 554164410Ssyrinx case SNMP_OP_GET: 555164410Ssyrinx if ((te = bridge_addrs_begemot_get(&val->var, sub)) == NULL) 556164410Ssyrinx return (SNMP_ERR_NOSUCHNAME); 557165253Ssyrinx goto get; 558164410Ssyrinx 559164410Ssyrinx case SNMP_OP_GETNEXT: 560164410Ssyrinx if ((te = bridge_addrs_begemot_getnext(&val->var, 561164410Ssyrinx sub)) == NULL || 562164410Ssyrinx bridge_addrs_begemot_index_append(&val->var, 563164410Ssyrinx sub, te) < 0) 564164410Ssyrinx return (SNMP_ERR_NOSUCHNAME); 565165253Ssyrinx goto get; 566164410Ssyrinx 567164410Ssyrinx case SNMP_OP_SET: 568164410Ssyrinx return (SNMP_ERR_NOT_WRITEABLE); 569164410Ssyrinx 570164410Ssyrinx case SNMP_OP_ROLLBACK: 571164410Ssyrinx case SNMP_OP_COMMIT: 572165253Ssyrinx break; 573164410Ssyrinx } 574165253Ssyrinx abort(); 575164410Ssyrinx 576165253Ssyrinxget: 577164410Ssyrinx switch (val->var.subs[sub - 1]) { 578164410Ssyrinx case LEAF_begemotBridgeTpFdbAddress: 579165253Ssyrinx return (string_get(val, te->tp_addr, ETHER_ADDR_LEN)); 580164410Ssyrinx case LEAF_begemotBridgeTpFdbPort: 581164410Ssyrinx val->v.integer = te->port_no; 582165253Ssyrinx return (SNMP_ERR_NOERROR); 583164410Ssyrinx case LEAF_begemotBridgeTpFdbStatus: 584164410Ssyrinx val->v.integer = te->status; 585165253Ssyrinx return (SNMP_ERR_NOERROR); 586164410Ssyrinx } 587164410Ssyrinx 588165253Ssyrinx abort(); 589164410Ssyrinx} 590