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: stable/10/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_addrs.c 310903 2016-12-31 10:34:09Z ngie $
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/*
333310903Sngie * 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
452310903Sngie * 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
480310903Sngie * 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
510310903Sngie * 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