bridge_port.c revision 164410
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 ports.
28164410Ssyrinx *
29164410Ssyrinx * $FreeBSD: head/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_port.c 164410 2006-11-19 15:42:48Z syrinx $
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(bridge_ports, bridge_port);
54164410Ssyrinx
55164410Ssyrinx/*
56164410Ssyrinx * Free the bridge base ports list.
57164410Ssyrinx */
58164410Ssyrinxstatic void
59164410Ssyrinxbridge_ports_free(struct bridge_ports *headp)
60164410Ssyrinx{
61164410Ssyrinx	struct bridge_port *bp;
62164410Ssyrinx
63164410Ssyrinx	while ((bp = TAILQ_FIRST(headp)) != NULL) {
64164410Ssyrinx		TAILQ_REMOVE(headp, bp, b_p);
65164410Ssyrinx		free(bp);
66164410Ssyrinx	}
67164410Ssyrinx}
68164410Ssyrinx
69164410Ssyrinx/*
70164410Ssyrinx * Free the bridge base ports from the base ports list,
71164410Ssyrinx * members of a specified bridge interface only.
72164410Ssyrinx */
73164410Ssyrinxstatic void
74164410Ssyrinxbridge_port_memif_free(struct bridge_ports *headp,
75164410Ssyrinx	struct bridge_if *bif)
76164410Ssyrinx{
77164410Ssyrinx	struct bridge_port *bp;
78164410Ssyrinx
79164410Ssyrinx	while (bif->f_bp != NULL && bif->sysindex == bif->f_bp->sysindex) {
80164410Ssyrinx		bp = TAILQ_NEXT(bif->f_bp, b_p);
81164410Ssyrinx		TAILQ_REMOVE(headp, bif->f_bp, b_p);
82164410Ssyrinx		free(bif->f_bp);
83164410Ssyrinx		bif->f_bp = bp;
84164410Ssyrinx	}
85164410Ssyrinx}
86164410Ssyrinx
87164410Ssyrinx/*
88164410Ssyrinx * Insert a port entry in the base port TAILQ starting to search
89164410Ssyrinx * for its place from the position of the first bridge port for the bridge
90164410Ssyrinx * interface. Update the first bridge port if neccessary.
91164410Ssyrinx */
92164410Ssyrinxstatic void
93164410Ssyrinxbridge_port_insert_at(struct bridge_ports *headp,
94164410Ssyrinx	struct bridge_port *bp, struct bridge_port **f_bp)
95164410Ssyrinx{
96164410Ssyrinx	struct bridge_port *t1;
97164410Ssyrinx
98164410Ssyrinx	assert(f_bp != NULL);
99164410Ssyrinx
100164410Ssyrinx	for (t1 = *f_bp;
101164410Ssyrinx	    t1 != NULL && bp->sysindex == t1->sysindex;
102164410Ssyrinx	    t1 = TAILQ_NEXT(t1, b_p)) {
103164410Ssyrinx		if (bp->if_idx < t1->if_idx) {
104164410Ssyrinx			TAILQ_INSERT_BEFORE(t1, bp, b_p);
105164410Ssyrinx			if (*f_bp == t1)
106164410Ssyrinx				*f_bp = bp;
107164410Ssyrinx			return;
108164410Ssyrinx		}
109164410Ssyrinx	}
110164410Ssyrinx
111164410Ssyrinx	/*
112164410Ssyrinx	 * Handle the case when our first port was actually the
113164410Ssyrinx	 * last element of the TAILQ.
114164410Ssyrinx	 */
115164410Ssyrinx	if (t1 == NULL)
116164410Ssyrinx		TAILQ_INSERT_TAIL(headp, bp, b_p);
117164410Ssyrinx	else
118164410Ssyrinx		TAILQ_INSERT_BEFORE(t1, bp, b_p);
119164410Ssyrinx}
120164410Ssyrinx
121164410Ssyrinx/*
122164410Ssyrinx * Find a port entry's possition in the ports list according
123164410Ssyrinx * to it's parent bridge interface name. Returns a NULL if
124164410Ssyrinx * we should be at the TAILQ head, otherwise the entry after
125164410Ssyrinx * which we should be inserted.
126164410Ssyrinx */
127164410Ssyrinxstatic struct bridge_port *
128164410Ssyrinxbridge_port_find_pos(struct bridge_ports *headp, uint32_t b_idx)
129164410Ssyrinx{
130164410Ssyrinx	uint32_t t_idx;
131164410Ssyrinx	struct bridge_port *t1;
132164410Ssyrinx
133164410Ssyrinx	if ((t1 = TAILQ_FIRST(headp)) == NULL ||
134164410Ssyrinx	    bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
135164410Ssyrinx		return (NULL);
136164410Ssyrinx
137164410Ssyrinx	t_idx = t1->sysindex;
138164410Ssyrinx
139164410Ssyrinx	for (t1 = TAILQ_NEXT(t1, b_p); t1 != NULL; t1 = TAILQ_NEXT(t1, b_p)) {
140164410Ssyrinx		if (t1->sysindex != t_idx) {
141164410Ssyrinx			if (bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
142164410Ssyrinx				return (TAILQ_PREV(t1, bridge_ports, b_p));
143164410Ssyrinx			else
144164410Ssyrinx				t_idx = t1->sysindex;
145164410Ssyrinx		}
146164410Ssyrinx	}
147164410Ssyrinx
148164410Ssyrinx	if (t1 == NULL)
149164410Ssyrinx		t1 = TAILQ_LAST(headp, bridge_ports);
150164410Ssyrinx
151164410Ssyrinx	return (t1);
152164410Ssyrinx}
153164410Ssyrinx
154164410Ssyrinx/*
155164410Ssyrinx * Insert a bridge member interface in the ports TAILQ.
156164410Ssyrinx */
157164410Ssyrinxstatic void
158164410Ssyrinxbridge_port_memif_insert(struct bridge_ports *headp,
159164410Ssyrinx	struct bridge_port *bp, struct bridge_port **f_bp)
160164410Ssyrinx{
161164410Ssyrinx	struct bridge_port *temp;
162164410Ssyrinx
163164410Ssyrinx	if (*f_bp != NULL)
164164410Ssyrinx		bridge_port_insert_at(headp, bp, f_bp);
165164410Ssyrinx	else {
166164410Ssyrinx		temp = bridge_port_find_pos(headp, bp->sysindex);
167164410Ssyrinx
168164410Ssyrinx		if (temp == NULL)
169164410Ssyrinx			TAILQ_INSERT_HEAD(headp, bp, b_p);
170164410Ssyrinx		else
171164410Ssyrinx			TAILQ_INSERT_AFTER(headp, temp, bp, b_p);
172164410Ssyrinx		*f_bp = bp;
173164410Ssyrinx	}
174164410Ssyrinx}
175164410Ssyrinx
176164410Ssyrinx/* The global ports list. */
177164410Ssyrinxstatic struct bridge_ports bridge_ports = TAILQ_HEAD_INITIALIZER(bridge_ports);
178164410Ssyrinxstatic time_t ports_list_age;
179164410Ssyrinx
180164410Ssyrinxvoid
181164410Ssyrinxbridge_ports_update_listage(void)
182164410Ssyrinx{
183164410Ssyrinx	ports_list_age = time(NULL);
184164410Ssyrinx}
185164410Ssyrinx
186164410Ssyrinxvoid
187164410Ssyrinxbridge_ports_fini(void)
188164410Ssyrinx{
189164410Ssyrinx	bridge_ports_free(&bridge_ports);
190164410Ssyrinx}
191164410Ssyrinx
192164410Ssyrinxvoid
193164410Ssyrinxbridge_members_free(struct bridge_if *bif)
194164410Ssyrinx{
195164410Ssyrinx	bridge_port_memif_free(&bridge_ports, bif);
196164410Ssyrinx}
197164410Ssyrinx
198164410Ssyrinx/*
199164410Ssyrinx * Find the first port in the ports list.
200164410Ssyrinx */
201164410Ssyrinxstatic struct bridge_port *
202164410Ssyrinxbridge_port_first(void)
203164410Ssyrinx{
204164410Ssyrinx	return (TAILQ_FIRST(&bridge_ports));
205164410Ssyrinx}
206164410Ssyrinx
207164410Ssyrinx/*
208164410Ssyrinx * Find the next port in the ports list.
209164410Ssyrinx */
210164410Ssyrinxstatic struct bridge_port *
211164410Ssyrinxbridge_port_next(struct bridge_port *bp)
212164410Ssyrinx{
213164410Ssyrinx	return (TAILQ_NEXT(bp, b_p));
214164410Ssyrinx}
215164410Ssyrinx
216164410Ssyrinx/*
217164410Ssyrinx * Find the first member of the specified bridge interface.
218164410Ssyrinx */
219164410Ssyrinxstruct bridge_port *
220164410Ssyrinxbridge_port_bif_first(struct bridge_if *bif)
221164410Ssyrinx{
222164410Ssyrinx	return (bif->f_bp);
223164410Ssyrinx}
224164410Ssyrinx
225164410Ssyrinx/*
226164410Ssyrinx * Find the next member of the specified bridge interface.
227164410Ssyrinx */
228164410Ssyrinxstruct bridge_port *
229164410Ssyrinxbridge_port_bif_next(struct bridge_port *bp)
230164410Ssyrinx{
231164410Ssyrinx	struct bridge_port *bp_next;
232164410Ssyrinx
233164410Ssyrinx	if ((bp_next = TAILQ_NEXT(bp, b_p)) == NULL ||
234164410Ssyrinx	    bp_next->sysindex != bp->sysindex)
235164410Ssyrinx		return (NULL);
236164410Ssyrinx
237164410Ssyrinx	return (bp_next);
238164410Ssyrinx}
239164410Ssyrinx
240164410Ssyrinx/*
241164410Ssyrinx * Remove a bridge port from the ports list.
242164410Ssyrinx */
243164410Ssyrinxvoid
244164410Ssyrinxbridge_port_remove(struct bridge_port *bp, struct bridge_if *bif)
245164410Ssyrinx{
246164410Ssyrinx	if (bif->f_bp == bp)
247164410Ssyrinx		bif->f_bp = bridge_port_bif_next(bp);
248164410Ssyrinx
249164410Ssyrinx	TAILQ_REMOVE(&bridge_ports, bp, b_p);
250164410Ssyrinx	free(bp);
251164410Ssyrinx}
252164410Ssyrinx
253164410Ssyrinx/*
254164410Ssyrinx * Allocate memory for a new bridge port and insert it
255164410Ssyrinx * in the base ports list. Return a pointer to the port's
256164410Ssyrinx * structure in case we want to do anything else with it.
257164410Ssyrinx */
258164410Ssyrinxstruct bridge_port *
259164410Ssyrinxbridge_new_port(struct mibif *mif, struct bridge_if *bif)
260164410Ssyrinx{
261164410Ssyrinx	struct bridge_port *bp;
262164410Ssyrinx
263164410Ssyrinx	if ((bp = (struct bridge_port *) malloc(sizeof(*bp))) == NULL) {
264164410Ssyrinx		syslog(LOG_ERR, "bridge new member: failed: %s",
265164410Ssyrinx			strerror(errno));
266164410Ssyrinx		return (NULL);
267164410Ssyrinx	}
268164410Ssyrinx
269164410Ssyrinx	bzero(bp, sizeof(*bp));
270164410Ssyrinx
271164410Ssyrinx	bp->sysindex = bif->sysindex;
272164410Ssyrinx	bp->if_idx = mif->index;
273164410Ssyrinx	bp->port_no = mif->sysindex;
274164410Ssyrinx	strlcpy(bp->p_name, mif->name, IFNAMSIZ);
275164410Ssyrinx	bp->circuit = oid_zeroDotZero;
276164410Ssyrinx
277164410Ssyrinx	bridge_port_memif_insert(&bridge_ports, bp, &(bif->f_bp));
278164410Ssyrinx
279164410Ssyrinx	return (bp);
280164410Ssyrinx}
281164410Ssyrinx
282164410Ssyrinx/*
283164410Ssyrinx * Update our info from the corresponding mibII interface info.
284164410Ssyrinx */
285164410Ssyrinxvoid
286164410Ssyrinxbridge_port_getinfo_mibif(struct mibif *m_if, struct bridge_port *bp)
287164410Ssyrinx{
288164410Ssyrinx	bp->max_info = m_if->mib.ifmd_data.ifi_mtu;
289164410Ssyrinx	bp->in_frames = m_if->mib.ifmd_data.ifi_ipackets;
290164410Ssyrinx	bp->out_frames = m_if->mib.ifmd_data.ifi_opackets;
291164410Ssyrinx	bp->in_drops = m_if->mib.ifmd_data.ifi_iqdrops;
292164410Ssyrinx}
293164410Ssyrinx
294164410Ssyrinx/*
295164410Ssyrinx * Find a port, whose SNMP's mibII ifIndex matches one of the ports,
296164410Ssyrinx * members of the specified bridge interface.
297164410Ssyrinx */
298164410Ssyrinxstruct bridge_port *
299164410Ssyrinxbridge_port_find(int32_t if_idx, struct bridge_if *bif)
300164410Ssyrinx{
301164410Ssyrinx	struct bridge_port *bp;
302164410Ssyrinx
303164410Ssyrinx	for (bp = bif->f_bp; bp != NULL; bp = TAILQ_NEXT(bp, b_p)) {
304164410Ssyrinx		if (bp->sysindex != bif->sysindex) {
305164410Ssyrinx			bp = NULL;
306164410Ssyrinx			break;
307164410Ssyrinx		}
308164410Ssyrinx
309164410Ssyrinx		if (bp->if_idx == if_idx)
310164410Ssyrinx			break;
311164410Ssyrinx	}
312164410Ssyrinx
313164410Ssyrinx	return (bp);
314164410Ssyrinx}
315164410Ssyrinx
316164410Ssyrinxvoid
317164410Ssyrinxbridge_ports_dump(struct bridge_if *bif)
318164410Ssyrinx{
319164410Ssyrinx	struct bridge_port *bp;
320164410Ssyrinx
321164410Ssyrinx	for (bp = bridge_port_bif_first(bif); bp != NULL;
322164410Ssyrinx	    bp = bridge_port_bif_next(bp)) {
323164410Ssyrinx		syslog(LOG_ERR, "memif - %s, index - %d",
324164410Ssyrinx		bp->p_name, bp->port_no);
325164410Ssyrinx	}
326164410Ssyrinx}
327164410Ssyrinx
328164410Ssyrinx/*
329164410Ssyrinx * RFC4188 specifics.
330164410Ssyrinx */
331164410Ssyrinxint
332164410Ssyrinxop_dot1d_base_port(struct snmp_context *c __unused, struct snmp_value *val,
333164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
334164410Ssyrinx{
335164410Ssyrinx	struct bridge_if *bif;
336164410Ssyrinx	struct bridge_port *bp;
337164410Ssyrinx
338164410Ssyrinx	if ((bif = bridge_get_default()) == NULL)
339164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
340164410Ssyrinx
341164410Ssyrinx	if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
342164410Ssyrinx	    bridge_update_memif(bif) <= 0)
343164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
344164410Ssyrinx
345164410Ssyrinx	bp = NULL; /* Make the compiler happy. */
346164410Ssyrinx	switch (op) {
347164410Ssyrinx		case SNMP_OP_GET:
348164410Ssyrinx		    if (val->var.len - sub != 1)
349164410Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
350164410Ssyrinx		    if ((bp = bridge_port_find(val->var.subs[sub],
351164410Ssyrinx			bif)) == NULL)
352164410Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
353164410Ssyrinx		    break;
354164410Ssyrinx
355164410Ssyrinx		case SNMP_OP_GETNEXT:
356164410Ssyrinx		    if (val->var.len - sub == 0) {
357164410Ssyrinx			if ((bp = bridge_port_bif_first(bif)) == NULL)
358164410Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
359164410Ssyrinx		    } else {
360164410Ssyrinx			if ((bp = bridge_port_find(val->var.subs[sub],
361164410Ssyrinx			    bif)) == NULL ||
362164410Ssyrinx			    (bp = bridge_port_bif_next(bp)) == NULL)
363164410Ssyrinx				return (SNMP_ERR_NOSUCHNAME);
364164410Ssyrinx		    }
365164410Ssyrinx		    val->var.len = sub + 1;
366164410Ssyrinx		    val->var.subs[sub] = bp->port_no;
367164410Ssyrinx		    break;
368164410Ssyrinx
369164410Ssyrinx		case SNMP_OP_SET:
370164410Ssyrinx		    return (SNMP_ERR_NOT_WRITEABLE);
371164410Ssyrinx
372164410Ssyrinx		case SNMP_OP_ROLLBACK:
373164410Ssyrinx		case SNMP_OP_COMMIT:
374164410Ssyrinx		    abort();
375164410Ssyrinx	}
376164410Ssyrinx
377164410Ssyrinx	switch (val->var.subs[sub - 1]) {
378164410Ssyrinx	    case LEAF_dot1dBasePort:
379164410Ssyrinx		val->v.integer = bp->port_no;
380164410Ssyrinx		break;
381164410Ssyrinx	    case LEAF_dot1dBasePortIfIndex:
382164410Ssyrinx		val->v.integer = bp->if_idx;
383164410Ssyrinx		break;
384164410Ssyrinx	    case LEAF_dot1dBasePortCircuit:
385164410Ssyrinx		val->v.oid = bp->circuit;
386164410Ssyrinx		break;
387164410Ssyrinx	    case LEAF_dot1dBasePortDelayExceededDiscards:
388164410Ssyrinx		val->v.uint32 = bp->dly_ex_drops;
389164410Ssyrinx		break;
390164410Ssyrinx	    case LEAF_dot1dBasePortMtuExceededDiscards:
391164410Ssyrinx		val->v.uint32 = bp->dly_mtu_drops;
392164410Ssyrinx		break;
393164410Ssyrinx	}
394164410Ssyrinx
395164410Ssyrinx	return (SNMP_ERR_NOERROR);
396164410Ssyrinx}
397164410Ssyrinx
398164410Ssyrinxint
399164410Ssyrinxop_dot1d_stp_port(struct snmp_context *ctx, struct snmp_value *val,
400164410Ssyrinx	 uint sub, uint iidx __unused, enum snmp_op op)
401164410Ssyrinx{
402164410Ssyrinx	int ret;
403164410Ssyrinx	struct bridge_if *bif;
404164410Ssyrinx	struct bridge_port *bp;
405164410Ssyrinx
406164410Ssyrinx	if ((bif = bridge_get_default()) == NULL)
407164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
408164410Ssyrinx
409164410Ssyrinx	if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
410164410Ssyrinx	    bridge_update_memif(bif) <= 0)
411164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
412164410Ssyrinx
413164410Ssyrinx	bp = NULL; /* Make the compiler happy. */
414164410Ssyrinx	ret = SNMP_ERR_NOERROR;
415164410Ssyrinx
416164410Ssyrinx	switch (op) {
417164410Ssyrinx		case SNMP_OP_GET:
418164410Ssyrinx		    if (val->var.len - sub != 1)
419164410Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
420164410Ssyrinx		    if ((bp = bridge_port_find(val->var.subs[sub],
421164410Ssyrinx			bif)) == NULL)
422164410Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
423164410Ssyrinx		    break;
424164410Ssyrinx
425164410Ssyrinx		case SNMP_OP_GETNEXT:
426164410Ssyrinx		    if (val->var.len - sub == 0) {
427164410Ssyrinx			if ((bp = bridge_port_bif_first(bif)) == NULL)
428164410Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
429164410Ssyrinx		    } else {
430164410Ssyrinx			if ((bp = bridge_port_find(val->var.subs[sub],
431164410Ssyrinx			    bif)) == NULL ||
432164410Ssyrinx			    (bp = bridge_port_bif_next(bp)) == NULL)
433164410Ssyrinx				return (SNMP_ERR_NOSUCHNAME);
434164410Ssyrinx		    }
435164410Ssyrinx		    val->var.len = sub + 1;
436164410Ssyrinx		    val->var.subs[sub] = bp->port_no;
437164410Ssyrinx		    break;
438164410Ssyrinx
439164410Ssyrinx		case SNMP_OP_SET:
440164410Ssyrinx		    if ((bp = bridge_port_find(val->var.subs[sub],
441164410Ssyrinx			bif)) == NULL)
442164410Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
443164410Ssyrinx
444164410Ssyrinx		    switch (val->var.subs[sub - 1]) {
445164410Ssyrinx			case LEAF_dot1dStpPortPriority:
446164410Ssyrinx			    ctx->scratch->int1 = bp->priority;
447164410Ssyrinx			    ret = bridge_port_set_priority(bif->bif_name, bp,
448164410Ssyrinx				val->v.integer);
449164410Ssyrinx			    break;
450164410Ssyrinx			case LEAF_dot1dStpPortEnable:
451164410Ssyrinx			    ctx->scratch->int1 = bp->enable;
452164410Ssyrinx			    ret = bridge_port_set_stp_enable(bif->bif_name,
453164410Ssyrinx				bp, val->v.integer);
454164410Ssyrinx			    break;
455164410Ssyrinx			case LEAF_dot1dStpPortPathCost:
456164410Ssyrinx			    ctx->scratch->int1 = bp->path_cost;
457164410Ssyrinx			    ret = bridge_port_set_path_cost(bif->bif_name, bp,
458164410Ssyrinx				val->v.integer);
459164410Ssyrinx			    break;
460164410Ssyrinx			case LEAF_dot1dStpPort:
461164410Ssyrinx			case LEAF_dot1dStpPortState:
462164410Ssyrinx			case LEAF_dot1dStpPortDesignatedRoot:
463164410Ssyrinx			case LEAF_dot1dStpPortDesignatedCost:
464164410Ssyrinx			case LEAF_dot1dStpPortDesignatedBridge:
465164410Ssyrinx			case LEAF_dot1dStpPortDesignatedPort:
466164410Ssyrinx			case LEAF_dot1dStpPortForwardTransitions:
467164410Ssyrinx			    return (SNMP_ERR_NOT_WRITEABLE);
468164410Ssyrinx		    }
469164410Ssyrinx		    if (ret == 0)
470164410Ssyrinx		    	return (SNMP_ERR_NOERROR);
471164410Ssyrinx		    else if (ret == -2)
472164410Ssyrinx			return (SNMP_ERR_WRONG_VALUE);
473164410Ssyrinx		    return (SNMP_ERR_GENERR);
474164410Ssyrinx
475164410Ssyrinx		case SNMP_OP_ROLLBACK:
476164410Ssyrinx		    if ((bp = bridge_port_find(val->var.subs[sub],
477164410Ssyrinx			bif)) == NULL)
478164410Ssyrinx			    return (SNMP_ERR_GENERR);
479164410Ssyrinx		    switch (val->var.subs[sub - 1]) {
480164410Ssyrinx			case LEAF_dot1dStpPortPriority:
481164410Ssyrinx			    bridge_port_set_priority(bif->bif_name, bp,
482164410Ssyrinx				ctx->scratch->int1);
483164410Ssyrinx			    break;
484164410Ssyrinx			case LEAF_dot1dStpPortEnable:
485164410Ssyrinx			    bridge_port_set_stp_enable(bif->bif_name, bp,
486164410Ssyrinx				ctx->scratch->int1);
487164410Ssyrinx			    break;
488164410Ssyrinx			case LEAF_dot1dStpPortPathCost:
489164410Ssyrinx			    bridge_port_set_path_cost(bif->bif_name, bp,
490164410Ssyrinx				ctx->scratch->int1);
491164410Ssyrinx			    break;
492164410Ssyrinx		    }
493164410Ssyrinx		    return (SNMP_ERR_NOERROR);
494164410Ssyrinx
495164410Ssyrinx		case SNMP_OP_COMMIT:
496164410Ssyrinx		    return (SNMP_ERR_NOERROR);
497164410Ssyrinx	}
498164410Ssyrinx
499164410Ssyrinx	switch (val->var.subs[sub - 1]) {
500164410Ssyrinx		case LEAF_dot1dStpPort:
501164410Ssyrinx			val->v.integer = bp->port_no;
502164410Ssyrinx			break;
503164410Ssyrinx		case LEAF_dot1dStpPortPriority:
504164410Ssyrinx			val->v.integer = bp->priority;
505164410Ssyrinx			break;
506164410Ssyrinx		case LEAF_dot1dStpPortState:
507164410Ssyrinx			val->v.integer = bp->state;
508164410Ssyrinx			break;
509164410Ssyrinx		case LEAF_dot1dStpPortEnable:
510164410Ssyrinx			val->v.integer = bp->enable;
511164410Ssyrinx			break;
512164410Ssyrinx		case LEAF_dot1dStpPortPathCost:
513164410Ssyrinx			val->v.integer = bp->path_cost;
514164410Ssyrinx			break;
515164410Ssyrinx		case LEAF_dot1dStpPortDesignatedRoot:
516164410Ssyrinx			ret = string_get(val, bp->design_root,
517164410Ssyrinx			    SNMP_BRIDGE_ID_LEN);
518164410Ssyrinx			break;
519164410Ssyrinx		case LEAF_dot1dStpPortDesignatedCost:
520164410Ssyrinx			val->v.integer = bp->design_cost;
521164410Ssyrinx			break;
522164410Ssyrinx		case LEAF_dot1dStpPortDesignatedBridge:
523164410Ssyrinx			ret = string_get(val, bp->design_bridge,
524164410Ssyrinx			    SNMP_BRIDGE_ID_LEN);
525164410Ssyrinx			break;
526164410Ssyrinx		case LEAF_dot1dStpPortDesignatedPort:
527164410Ssyrinx			ret = string_get(val, bp->design_port, 2);
528164410Ssyrinx			break;
529164410Ssyrinx		case LEAF_dot1dStpPortForwardTransitions:
530164410Ssyrinx			val->v.uint32 = bp->fwd_trans;
531164410Ssyrinx			break;
532164410Ssyrinx	}
533164410Ssyrinx
534164410Ssyrinx	return (ret);
535164410Ssyrinx}
536164410Ssyrinx
537164410Ssyrinxint
538164410Ssyrinxop_dot1d_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
539164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
540164410Ssyrinx{
541164410Ssyrinx	struct bridge_if *bif;
542164410Ssyrinx	struct bridge_port *bp;
543164410Ssyrinx
544164410Ssyrinx	if ((bif = bridge_get_default()) == NULL)
545164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
546164410Ssyrinx
547164410Ssyrinx	if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
548164410Ssyrinx	    bridge_update_memif(bif) <= 0)
549164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
550164410Ssyrinx
551164410Ssyrinx	bp = NULL; /* Make the compiler happy. */
552164410Ssyrinx	switch (op) {
553164410Ssyrinx		case SNMP_OP_GET:
554164410Ssyrinx		    if (val->var.len - sub != 1)
555164410Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
556164410Ssyrinx		    if ((bp = bridge_port_find(val->var.subs[sub],
557164410Ssyrinx			bif)) == NULL)
558164410Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
559164410Ssyrinx		    break;
560164410Ssyrinx
561164410Ssyrinx		case SNMP_OP_GETNEXT:
562164410Ssyrinx		    if (val->var.len - sub == 0) {
563164410Ssyrinx			if ((bp = bridge_port_bif_first(bif)) == NULL)
564164410Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
565164410Ssyrinx		    } else {
566164410Ssyrinx			if ((bp = bridge_port_find(val->var.subs[sub],
567164410Ssyrinx			    bif)) == NULL ||
568164410Ssyrinx			    (bp = bridge_port_bif_next(bp)) == NULL)
569164410Ssyrinx				return (SNMP_ERR_NOSUCHNAME);
570164410Ssyrinx		    }
571164410Ssyrinx		    val->var.len = sub + 1;
572164410Ssyrinx		    val->var.subs[sub] = bp->port_no;
573164410Ssyrinx		    break;
574164410Ssyrinx
575164410Ssyrinx		case SNMP_OP_SET:
576164410Ssyrinx		    return (SNMP_ERR_NOT_WRITEABLE);
577164410Ssyrinx
578164410Ssyrinx		case SNMP_OP_ROLLBACK:
579164410Ssyrinx		case SNMP_OP_COMMIT:
580164410Ssyrinx		    abort();
581164410Ssyrinx	}
582164410Ssyrinx
583164410Ssyrinx	switch (val->var.subs[sub - 1]) {
584164410Ssyrinx		case LEAF_dot1dTpPort:
585164410Ssyrinx			val->v.integer = bp->port_no;
586164410Ssyrinx			break;
587164410Ssyrinx		case LEAF_dot1dTpPortMaxInfo:
588164410Ssyrinx			val->v.integer = bp->max_info;
589164410Ssyrinx			break;
590164410Ssyrinx		case LEAF_dot1dTpPortInFrames:
591164410Ssyrinx			val->v.uint32 = bp->in_frames;
592164410Ssyrinx			break;
593164410Ssyrinx		case LEAF_dot1dTpPortOutFrames:
594164410Ssyrinx			val->v.uint32 = bp->out_frames;
595164410Ssyrinx			break;
596164410Ssyrinx		case LEAF_dot1dTpPortInDiscards:
597164410Ssyrinx			val->v.uint32 = bp->in_drops;
598164410Ssyrinx			break;
599164410Ssyrinx	}
600164410Ssyrinx
601164410Ssyrinx	return (SNMP_ERR_NOERROR);
602164410Ssyrinx}
603164410Ssyrinx
604164410Ssyrinx/*
605164410Ssyrinx * Private BEGEMOT-BRIDGE-MIB specifics.
606164410Ssyrinx */
607164410Ssyrinx
608164410Ssyrinx/*
609164410Ssyrinx * Construct a bridge port entry index.
610164410Ssyrinx */
611164410Ssyrinxstatic int
612164410Ssyrinxbridge_port_index_append(struct asn_oid *oid, uint sub,
613164410Ssyrinx	const struct bridge_port *bp)
614164410Ssyrinx{
615164410Ssyrinx	uint i;
616164410Ssyrinx	const char *b_name;
617164410Ssyrinx
618164410Ssyrinx	if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
619164410Ssyrinx		return (-1);
620164410Ssyrinx
621164410Ssyrinx	oid->len = sub + strlen(b_name) + 1 + 1;
622164410Ssyrinx	oid->subs[sub] = strlen(b_name);
623164410Ssyrinx
624164410Ssyrinx	for (i = 1; i <= strlen(b_name); i++)
625164410Ssyrinx		oid->subs[sub + i] = b_name[i - 1];
626164410Ssyrinx
627164410Ssyrinx	oid->subs[sub + i] = bp->port_no;
628164410Ssyrinx
629164410Ssyrinx	return (0);
630164410Ssyrinx}
631164410Ssyrinx
632164410Ssyrinx/*
633164410Ssyrinx * Get the port entry from an entry's index.
634164410Ssyrinx */
635164410Ssyrinxstatic struct bridge_port *
636164410Ssyrinxbridge_port_index_get(const struct asn_oid *oid, uint sub, int8_t status)
637164410Ssyrinx{
638164410Ssyrinx	uint i;
639164410Ssyrinx	int32_t port_no;
640164410Ssyrinx	char bif_name[IFNAMSIZ];
641164410Ssyrinx	struct bridge_if *bif;
642164410Ssyrinx	struct bridge_port *bp;
643164410Ssyrinx
644164410Ssyrinx	if (oid->len - sub != oid->subs[sub] + 2 ||
645164410Ssyrinx	    oid->subs[sub] >= IFNAMSIZ)
646164410Ssyrinx		return (NULL);
647164410Ssyrinx
648164410Ssyrinx	for (i = 0; i < oid->subs[sub]; i++)
649164410Ssyrinx		bif_name[i] = oid->subs[sub + i + 1];
650164410Ssyrinx	bif_name[i] = '\0';
651164410Ssyrinx
652164410Ssyrinx	port_no = oid->subs[sub + i + 1];
653164410Ssyrinx
654164410Ssyrinx	if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
655164410Ssyrinx		return (NULL);
656164410Ssyrinx
657164410Ssyrinx	if ((bp = bridge_port_find(port_no, bif)) == NULL ||
658164410Ssyrinx	    (status == 0 && bp->status != RowStatus_active))
659164410Ssyrinx		return (NULL);
660164410Ssyrinx
661164410Ssyrinx	return (bp);
662164410Ssyrinx}
663164410Ssyrinx
664164410Ssyrinx/*
665164410Ssyrinx * Get the next port entry from an entry's index.
666164410Ssyrinx */
667164410Ssyrinxstatic struct bridge_port *
668164410Ssyrinxbridge_port_index_getnext(const struct asn_oid *oid, uint sub, int8_t status)
669164410Ssyrinx{
670164410Ssyrinx	uint i;
671164410Ssyrinx	int32_t port_no;
672164410Ssyrinx	char bif_name[IFNAMSIZ];
673164410Ssyrinx	struct bridge_if *bif;
674164410Ssyrinx	struct bridge_port *bp;
675164410Ssyrinx
676164410Ssyrinx	if (oid->len - sub == 0)
677164410Ssyrinx		bp = bridge_port_first();
678164410Ssyrinx	else {
679164410Ssyrinx		if (oid->len - sub != oid->subs[sub] + 2 ||
680164410Ssyrinx		    oid->subs[sub] >= IFNAMSIZ)
681164410Ssyrinx			return (NULL);
682164410Ssyrinx
683164410Ssyrinx		for (i = 0; i < oid->subs[sub]; i++)
684164410Ssyrinx			bif_name[i] = oid->subs[sub + i + 1];
685164410Ssyrinx		bif_name[i] = '\0';
686164410Ssyrinx
687164410Ssyrinx		port_no = oid->subs[sub + i + 1];
688164410Ssyrinx
689164410Ssyrinx		if ((bif = bridge_if_find_ifname(bif_name)) == NULL ||
690164410Ssyrinx		    (bp = bridge_port_find(port_no, bif)) == NULL)
691164410Ssyrinx			return (NULL);
692164410Ssyrinx
693164410Ssyrinx		bp = bridge_port_next(bp);
694164410Ssyrinx	}
695164410Ssyrinx
696164410Ssyrinx	if (status == 1)
697164410Ssyrinx		return (bp);
698164410Ssyrinx
699164410Ssyrinx	while (bp != NULL) {
700164410Ssyrinx		if (bp->status == RowStatus_active)
701164410Ssyrinx			break;
702164410Ssyrinx		bp = bridge_port_next(bp);
703164410Ssyrinx	}
704164410Ssyrinx
705164410Ssyrinx	return (bp);
706164410Ssyrinx}
707164410Ssyrinx
708164410Ssyrinx/*
709164410Ssyrinx * Read the bridge name and port index from a ASN OID structure.
710164410Ssyrinx */
711164410Ssyrinxstatic int
712164410Ssyrinxbridge_port_index_decode(const struct asn_oid *oid, uint sub,
713164410Ssyrinx	char *b_name, int32_t *idx)
714164410Ssyrinx{
715164410Ssyrinx	uint i;
716164410Ssyrinx
717164410Ssyrinx	if (oid->len - sub != oid->subs[sub] + 2 ||
718164410Ssyrinx	    oid->subs[sub] >= IFNAMSIZ)
719164410Ssyrinx		return (-1);
720164410Ssyrinx
721164410Ssyrinx	for (i = 0; i < oid->subs[sub]; i++)
722164410Ssyrinx		b_name[i] = oid->subs[sub + i + 1];
723164410Ssyrinx	b_name[i] = '\0';
724164410Ssyrinx
725164410Ssyrinx	*idx = oid->subs[sub + i + 1];
726164410Ssyrinx	return (0);
727164410Ssyrinx}
728164410Ssyrinx
729164410Ssyrinxstatic int
730164410Ssyrinxbridge_port_set_status(struct snmp_context *ctx,
731164410Ssyrinx	struct snmp_value *val, uint sub)
732164410Ssyrinx{
733164410Ssyrinx	int32_t if_idx;
734164410Ssyrinx	char b_name[IFNAMSIZ];
735164410Ssyrinx	struct bridge_if *bif;
736164410Ssyrinx	struct bridge_port *bp;
737164410Ssyrinx	struct mibif *mif;
738164410Ssyrinx
739164410Ssyrinx	if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
740164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
741164410Ssyrinx
742164410Ssyrinx	if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
743164410Ssyrinx	    (mif = mib_find_if(if_idx)) == NULL)
744164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
745164410Ssyrinx
746164410Ssyrinx	bp = bridge_port_find(if_idx, bif);
747164410Ssyrinx
748164410Ssyrinx	switch (val->v.integer) {
749164410Ssyrinx	    case RowStatus_active:
750164410Ssyrinx		if (bp == NULL)
751164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
752164410Ssyrinx
753164410Ssyrinx		if (bp->span_enable == 0)
754164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
755164410Ssyrinx
756164410Ssyrinx		ctx->scratch->int1 = bp->status;
757164410Ssyrinx		bp->status = RowStatus_active;
758164410Ssyrinx		break;
759164410Ssyrinx
760164410Ssyrinx	    case RowStatus_notInService:
761164410Ssyrinx		if (bp == NULL || bp->span_enable == 0 ||
762164410Ssyrinx		    bp->status == RowStatus_active)
763164410Ssyrinx			return (SNMP_ERR_INCONS_VALUE);
764164410Ssyrinx
765164410Ssyrinx		ctx->scratch->int1 = bp->status;
766164410Ssyrinx		bp->status = RowStatus_notInService;
767164410Ssyrinx
768164410Ssyrinx	    case RowStatus_notReady:
769164410Ssyrinx		/* FALLTHROUGH */
770164410Ssyrinx	    case RowStatus_createAndGo:
771164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
772164410Ssyrinx
773164410Ssyrinx	    case RowStatus_createAndWait:
774164410Ssyrinx		if (bp != NULL)
775164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
776164410Ssyrinx
777164410Ssyrinx		if ((bp = bridge_new_port(mif, bif)) == NULL)
778164410Ssyrinx			return (SNMP_ERR_GENERR);
779164410Ssyrinx
780164410Ssyrinx		ctx->scratch->int1 = RowStatus_destroy;
781164410Ssyrinx		bp->status = RowStatus_notReady;
782164410Ssyrinx		break;
783164410Ssyrinx
784164410Ssyrinx	    case RowStatus_destroy:
785164410Ssyrinx		if (bp == NULL)
786164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
787164410Ssyrinx
788164410Ssyrinx		ctx->scratch->int1 = bp->status;
789164410Ssyrinx		bp->status = RowStatus_destroy;
790164410Ssyrinx		break;
791164410Ssyrinx	}
792164410Ssyrinx
793164410Ssyrinx	return (SNMP_ERR_NOERROR);
794164410Ssyrinx}
795164410Ssyrinx
796164410Ssyrinxstatic int
797164410Ssyrinxbridge_port_rollback_status(struct snmp_context *ctx,
798164410Ssyrinx	struct snmp_value *val, uint sub)
799164410Ssyrinx{
800164410Ssyrinx	int32_t if_idx;
801164410Ssyrinx	char b_name[IFNAMSIZ];
802164410Ssyrinx	struct bridge_if *bif;
803164410Ssyrinx	struct bridge_port *bp;
804164410Ssyrinx
805164410Ssyrinx	if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
806164410Ssyrinx		return (SNMP_ERR_GENERR);
807164410Ssyrinx
808164410Ssyrinx	if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
809164410Ssyrinx	    (bp = bridge_port_find(if_idx, bif)) == NULL)
810164410Ssyrinx		return (SNMP_ERR_GENERR);
811164410Ssyrinx
812164410Ssyrinx	if (ctx->scratch->int1 == RowStatus_destroy)
813164410Ssyrinx		bridge_port_remove(bp, bif);
814164410Ssyrinx	else
815164410Ssyrinx		bp->status = ctx->scratch->int1;
816164410Ssyrinx
817164410Ssyrinx	return (SNMP_ERR_NOERROR);
818164410Ssyrinx}
819164410Ssyrinx
820164410Ssyrinxstatic int
821164410Ssyrinxbridge_port_commit_status(struct snmp_value *val, uint sub)
822164410Ssyrinx{
823164410Ssyrinx	int32_t if_idx;
824164410Ssyrinx	char b_name[IFNAMSIZ];
825164410Ssyrinx	struct bridge_if *bif;
826164410Ssyrinx	struct bridge_port *bp;
827164410Ssyrinx
828164410Ssyrinx	if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
829164410Ssyrinx		return (SNMP_ERR_GENERR);
830164410Ssyrinx
831164410Ssyrinx	if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
832164410Ssyrinx	    (bp = bridge_port_find(if_idx, bif)) == NULL)
833164410Ssyrinx		return (SNMP_ERR_GENERR);
834164410Ssyrinx
835164410Ssyrinx	switch (bp->status) {
836164410Ssyrinx		case RowStatus_active:
837164410Ssyrinx			if (bridge_port_addm(bp, b_name) < 0)
838164410Ssyrinx				return (SNMP_ERR_COMMIT_FAILED);
839164410Ssyrinx			break;
840164410Ssyrinx
841164410Ssyrinx		case RowStatus_destroy:
842164410Ssyrinx			if (bridge_port_delm(bp, b_name) < 0)
843164410Ssyrinx				return (SNMP_ERR_COMMIT_FAILED);
844164410Ssyrinx			bridge_port_remove(bp, bif);
845164410Ssyrinx			break;
846164410Ssyrinx	}
847164410Ssyrinx
848164410Ssyrinx	return (SNMP_ERR_NOERROR);
849164410Ssyrinx}
850164410Ssyrinx
851164410Ssyrinxstatic int
852164410Ssyrinxbridge_port_set_span_enable(struct snmp_context *ctx,
853164410Ssyrinx		struct snmp_value *val, uint sub)
854164410Ssyrinx{
855164410Ssyrinx	int32_t if_idx;
856164410Ssyrinx	char b_name[IFNAMSIZ];
857164410Ssyrinx	struct bridge_if *bif;
858164410Ssyrinx	struct bridge_port *bp;
859164410Ssyrinx	struct mibif *mif;
860164410Ssyrinx
861164410Ssyrinx	if (val->v.integer != begemotBridgeBaseSpanEnabled_enabled &&
862164410Ssyrinx	    val->v.integer != begemotBridgeBaseSpanEnabled_disabled)
863164410Ssyrinx		return (SNMP_ERR_BADVALUE);
864164410Ssyrinx
865164410Ssyrinx	if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
866164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
867164410Ssyrinx
868164410Ssyrinx	if ((bif = bridge_if_find_ifname(b_name)) == NULL)
869164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
870164410Ssyrinx
871164410Ssyrinx	if ((bp = bridge_port_find(if_idx, bif)) == NULL) {
872164410Ssyrinx		if ((mif = mib_find_if(if_idx)) == NULL)
873164410Ssyrinx			return (SNMP_ERR_INCONS_VALUE);
874164410Ssyrinx
875164410Ssyrinx		if ((bp = bridge_new_port(mif, bif)) == NULL)
876164410Ssyrinx			return (SNMP_ERR_GENERR);
877164410Ssyrinx
878164410Ssyrinx		ctx->scratch->int1 = RowStatus_destroy;
879164410Ssyrinx	} else if (bp->status == RowStatus_active) {
880164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
881164410Ssyrinx	} else {
882164410Ssyrinx		ctx->scratch->int1 = bp->status;
883164410Ssyrinx	}
884164410Ssyrinx
885164410Ssyrinx	bp->span_enable = val->v.integer;
886164410Ssyrinx	bp->status = RowStatus_notInService;
887164410Ssyrinx
888164410Ssyrinx	return (SNMP_ERR_NOERROR);
889164410Ssyrinx}
890164410Ssyrinx
891164410Ssyrinxint
892164410Ssyrinxop_begemot_base_port(struct snmp_context *ctx, struct snmp_value *val,
893164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
894164410Ssyrinx{
895164410Ssyrinx	int8_t status, which;
896164410Ssyrinx	struct bridge_port *bp = NULL;
897164410Ssyrinx
898164410Ssyrinx	if (time(NULL) - ports_list_age > bridge_get_data_maxage())
899164410Ssyrinx		bridge_update_all_ports();
900164410Ssyrinx
901164410Ssyrinx	which = val->var.subs[sub - 1];
902164410Ssyrinx	status = 0;
903164410Ssyrinx
904164410Ssyrinx	switch (op) {
905164410Ssyrinx	    case SNMP_OP_GET:
906164410Ssyrinx		if (which == LEAF_begemotBridgeBaseSpanEnabled ||
907164410Ssyrinx		    which == LEAF_begemotBridgeBasePortStatus)
908164410Ssyrinx			status = 1;
909164410Ssyrinx		if ((bp = bridge_port_index_get(&val->var, sub,
910164410Ssyrinx		    status)) == NULL)
911164410Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
912164410Ssyrinx		break;
913164410Ssyrinx
914164410Ssyrinx	    case SNMP_OP_GETNEXT:
915164410Ssyrinx		if (which == LEAF_begemotBridgeBaseSpanEnabled ||
916164410Ssyrinx		    which == LEAF_begemotBridgeBasePortStatus)
917164410Ssyrinx			status = 1;
918164410Ssyrinx		if ((bp = bridge_port_index_getnext(&val->var, sub,
919164410Ssyrinx		    status)) == NULL ||
920164410Ssyrinx		    bridge_port_index_append(&val->var, sub, bp) < 0)
921164410Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
922164410Ssyrinx		break;
923164410Ssyrinx
924164410Ssyrinx	    case SNMP_OP_SET:
925164410Ssyrinx		switch (which) {
926164410Ssyrinx		    case LEAF_begemotBridgeBaseSpanEnabled:
927164410Ssyrinx			return (bridge_port_set_span_enable(ctx, val, sub));
928164410Ssyrinx
929164410Ssyrinx		    case LEAF_begemotBridgeBasePortStatus:
930164410Ssyrinx			return (bridge_port_set_status(ctx, val, sub));
931164410Ssyrinx
932164410Ssyrinx		    case LEAF_begemotBridgeBasePort:
933164410Ssyrinx		    case LEAF_begemotBridgeBasePortIfIndex:
934164410Ssyrinx		    case LEAF_begemotBridgeBasePortDelayExceededDiscards:
935164410Ssyrinx		    case LEAF_begemotBridgeBasePortMtuExceededDiscards:
936164410Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
937164410Ssyrinx		}
938164410Ssyrinx		abort();
939164410Ssyrinx
940164410Ssyrinx	    case SNMP_OP_ROLLBACK:
941164410Ssyrinx		switch (which) {
942164410Ssyrinx		    case LEAF_begemotBridgeBaseSpanEnabled:
943164410Ssyrinx			/* FALLTHROUGH */
944164410Ssyrinx		    case LEAF_begemotBridgeBasePortStatus:
945164410Ssyrinx			return (bridge_port_rollback_status(ctx, val, sub));
946164410Ssyrinx		}
947164410Ssyrinx		return (SNMP_ERR_NOERROR);
948164410Ssyrinx
949164410Ssyrinx	    case SNMP_OP_COMMIT:
950164410Ssyrinx		if (which == LEAF_begemotBridgeBasePortStatus)
951164410Ssyrinx			return (bridge_port_commit_status(val, sub));
952164410Ssyrinx
953164410Ssyrinx		return (SNMP_ERR_NOERROR);
954164410Ssyrinx	}
955164410Ssyrinx
956164410Ssyrinx	switch (which) {
957164410Ssyrinx	    case LEAF_begemotBridgeBasePort:
958164410Ssyrinx		val->v.integer = bp->port_no;
959164410Ssyrinx		break;
960164410Ssyrinx	    case LEAF_begemotBridgeBasePortIfIndex:
961164410Ssyrinx		val->v.integer = bp->if_idx;
962164410Ssyrinx		break;
963164410Ssyrinx	    case LEAF_begemotBridgeBaseSpanEnabled:
964164410Ssyrinx		val->v.integer = bp->span_enable;
965164410Ssyrinx		break;
966164410Ssyrinx	    case LEAF_begemotBridgeBasePortDelayExceededDiscards:
967164410Ssyrinx		val->v.uint32 = bp->dly_ex_drops;
968164410Ssyrinx		break;
969164410Ssyrinx	    case LEAF_begemotBridgeBasePortMtuExceededDiscards:
970164410Ssyrinx		val->v.uint32 = bp->dly_mtu_drops;
971164410Ssyrinx		break;
972164410Ssyrinx	    case LEAF_begemotBridgeBasePortStatus:
973164410Ssyrinx		val->v.integer = bp->status;
974164410Ssyrinx		break;
975164410Ssyrinx	}
976164410Ssyrinx
977164410Ssyrinx	return (SNMP_ERR_NOERROR);
978164410Ssyrinx}
979164410Ssyrinx
980164410Ssyrinxint
981164410Ssyrinxop_begemot_stp_port(struct snmp_context *ctx, struct snmp_value *val,
982164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
983164410Ssyrinx{
984164410Ssyrinx	int ret;
985164410Ssyrinx	struct bridge_port *bp = NULL;
986164410Ssyrinx	const char *b_name;
987164410Ssyrinx
988164410Ssyrinx	if (time(NULL) - ports_list_age > bridge_get_data_maxage())
989164410Ssyrinx		bridge_update_all_ports();
990164410Ssyrinx
991164410Ssyrinx	switch (op) {
992164410Ssyrinx	    case SNMP_OP_GET:
993164410Ssyrinx		if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
994164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
995164410Ssyrinx		break;
996164410Ssyrinx
997164410Ssyrinx	    case SNMP_OP_GETNEXT:
998164410Ssyrinx		if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
999164410Ssyrinx		    NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1000164410Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
1001164410Ssyrinx		break;
1002164410Ssyrinx
1003164410Ssyrinx	    case SNMP_OP_SET:
1004164410Ssyrinx		if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1005164410Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
1006164410Ssyrinx		if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1007164410Ssyrinx			return (SNMP_ERR_GENERR);
1008164410Ssyrinx
1009164410Ssyrinx		ret = SNMP_ERR_NOERROR;
1010164410Ssyrinx		switch (val->var.subs[sub - 1]) {
1011164410Ssyrinx		    case LEAF_begemotBridgeStpPortPriority:
1012164410Ssyrinx			ctx->scratch->int1 = bp->priority;
1013164410Ssyrinx			ret = bridge_port_set_priority(b_name, bp,
1014164410Ssyrinx			    val->v.integer);
1015164410Ssyrinx			break;
1016164410Ssyrinx		    case LEAF_begemotBridgeStpPortEnable:
1017164410Ssyrinx			ctx->scratch->int1 = bp->enable;
1018164410Ssyrinx			ret = bridge_port_set_stp_enable(b_name, bp,
1019164410Ssyrinx			    val->v.integer);
1020164410Ssyrinx			break;
1021164410Ssyrinx		    case LEAF_begemotBridgeStpPortPathCost:
1022164410Ssyrinx			ctx->scratch->int1 = bp->path_cost;
1023164410Ssyrinx			ret = bridge_port_set_path_cost(b_name, bp,
1024164410Ssyrinx			    val->v.integer);
1025164410Ssyrinx			break;
1026164410Ssyrinx		    case LEAF_begemotBridgeStpPort:
1027164410Ssyrinx		    case LEAF_begemotBridgeStpPortState:
1028164410Ssyrinx		    case LEAF_begemotBridgeStpPortDesignatedRoot:
1029164410Ssyrinx		    case LEAF_begemotBridgeStpPortDesignatedCost:
1030164410Ssyrinx		    case LEAF_begemotBridgeStpPortDesignatedBridge:
1031164410Ssyrinx		    case LEAF_begemotBridgeStpPortDesignatedPort:
1032164410Ssyrinx		    case LEAF_begemotBridgeStpPortForwardTransitions:
1033164410Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
1034164410Ssyrinx		}
1035164410Ssyrinx		if (ret == 0)
1036164410Ssyrinx			return (SNMP_ERR_NOERROR);
1037164410Ssyrinx		else if (ret == -2)
1038164410Ssyrinx			return (SNMP_ERR_WRONG_VALUE);
1039164410Ssyrinx		return (SNMP_ERR_GENERR);
1040164410Ssyrinx
1041164410Ssyrinx	    case SNMP_OP_ROLLBACK:
1042164410Ssyrinx		if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
1043164410Ssyrinx		    (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1044164410Ssyrinx			return (SNMP_ERR_GENERR);
1045164410Ssyrinx
1046164410Ssyrinx		switch (val->var.subs[sub - 1]) {
1047164410Ssyrinx		    case LEAF_begemotBridgeStpPortPriority:
1048164410Ssyrinx			bridge_port_set_priority(b_name, bp,
1049164410Ssyrinx			    ctx->scratch->int1);
1050164410Ssyrinx			break;
1051164410Ssyrinx		    case LEAF_begemotBridgeStpPortEnable:
1052164410Ssyrinx			bridge_port_set_stp_enable(b_name, bp,
1053164410Ssyrinx			    ctx->scratch->int1);
1054164410Ssyrinx			break;
1055164410Ssyrinx		    case LEAF_begemotBridgeStpPortPathCost:
1056164410Ssyrinx			bridge_port_set_path_cost(b_name, bp,
1057164410Ssyrinx			    ctx->scratch->int1);
1058164410Ssyrinx			break;
1059164410Ssyrinx		}
1060164410Ssyrinx		return (SNMP_ERR_NOERROR);
1061164410Ssyrinx
1062164410Ssyrinx	    case SNMP_OP_COMMIT:
1063164410Ssyrinx		return (SNMP_ERR_NOERROR);
1064164410Ssyrinx	}
1065164410Ssyrinx
1066164410Ssyrinx	ret = SNMP_ERR_NOERROR;
1067164410Ssyrinx
1068164410Ssyrinx	switch (val->var.subs[sub - 1]) {
1069164410Ssyrinx	    case LEAF_begemotBridgeStpPort:
1070164410Ssyrinx		val->v.integer = bp->port_no;
1071164410Ssyrinx		break;
1072164410Ssyrinx	    case LEAF_begemotBridgeStpPortPriority:
1073164410Ssyrinx		val->v.integer = bp->priority;
1074164410Ssyrinx		break;
1075164410Ssyrinx	    case LEAF_begemotBridgeStpPortState:
1076164410Ssyrinx		val->v.integer = bp->state;
1077164410Ssyrinx		break;
1078164410Ssyrinx	    case LEAF_begemotBridgeStpPortEnable:
1079164410Ssyrinx		val->v.integer = bp->enable;
1080164410Ssyrinx		break;
1081164410Ssyrinx	    case LEAF_begemotBridgeStpPortPathCost:
1082164410Ssyrinx		val->v.integer = bp->path_cost;
1083164410Ssyrinx		break;
1084164410Ssyrinx	    case LEAF_begemotBridgeStpPortDesignatedRoot:
1085164410Ssyrinx		ret = string_get(val, bp->design_root, SNMP_BRIDGE_ID_LEN);
1086164410Ssyrinx		break;
1087164410Ssyrinx	    case LEAF_begemotBridgeStpPortDesignatedCost:
1088164410Ssyrinx		val->v.integer = bp->design_cost;
1089164410Ssyrinx		break;
1090164410Ssyrinx	    case LEAF_begemotBridgeStpPortDesignatedBridge:
1091164410Ssyrinx		ret = string_get(val, bp->design_bridge, SNMP_BRIDGE_ID_LEN);
1092164410Ssyrinx		break;
1093164410Ssyrinx	    case LEAF_begemotBridgeStpPortDesignatedPort:
1094164410Ssyrinx		ret = string_get(val, bp->design_port, 2);
1095164410Ssyrinx		break;
1096164410Ssyrinx	    case LEAF_begemotBridgeStpPortForwardTransitions:
1097164410Ssyrinx		val->v.uint32 = bp->fwd_trans;
1098164410Ssyrinx		break;
1099164410Ssyrinx	}
1100164410Ssyrinx
1101164410Ssyrinx	return (ret);
1102164410Ssyrinx}
1103164410Ssyrinx
1104164410Ssyrinxint
1105164410Ssyrinxop_begemot_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
1106164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
1107164410Ssyrinx{
1108164410Ssyrinx	struct bridge_port *bp = NULL;
1109164410Ssyrinx
1110164410Ssyrinx	if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1111164410Ssyrinx		bridge_update_all_ports();
1112164410Ssyrinx
1113164410Ssyrinx	switch (op) {
1114164410Ssyrinx	    case SNMP_OP_GET:
1115164410Ssyrinx		if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1116164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1117164410Ssyrinx		break;
1118164410Ssyrinx
1119164410Ssyrinx	    case SNMP_OP_GETNEXT:
1120164410Ssyrinx		if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1121164410Ssyrinx		    NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1122164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1123164410Ssyrinx		break;
1124164410Ssyrinx
1125164410Ssyrinx	    case SNMP_OP_SET:
1126164410Ssyrinx		return (SNMP_ERR_NOT_WRITEABLE);
1127164410Ssyrinx
1128164410Ssyrinx	    case SNMP_OP_ROLLBACK:
1129164410Ssyrinx	    case SNMP_OP_COMMIT:
1130164410Ssyrinx		return (SNMP_ERR_NOERROR);
1131164410Ssyrinx	}
1132164410Ssyrinx
1133164410Ssyrinx	switch (val->var.subs[sub - 1]) {
1134164410Ssyrinx	    case LEAF_begemotBridgeTpPort:
1135164410Ssyrinx		val->v.integer = bp->port_no;
1136164410Ssyrinx		break;
1137164410Ssyrinx	    case LEAF_begemotBridgeTpPortMaxInfo:
1138164410Ssyrinx		val->v.integer = bp->max_info;
1139164410Ssyrinx		break;
1140164410Ssyrinx	    case LEAF_begemotBridgeTpPortInFrames:
1141164410Ssyrinx		val->v.uint32 = bp->in_frames;
1142164410Ssyrinx		break;
1143164410Ssyrinx	    case LEAF_begemotBridgeTpPortOutFrames:
1144164410Ssyrinx		val->v.uint32 = bp->out_frames;
1145164410Ssyrinx		break;
1146164410Ssyrinx	    case LEAF_begemotBridgeTpPortInDiscards:
1147164410Ssyrinx		val->v.uint32 = bp->in_drops;
1148164410Ssyrinx		break;
1149164410Ssyrinx	}
1150164410Ssyrinx
1151164410Ssyrinx	return (SNMP_ERR_NOERROR);
1152164410Ssyrinx}
1153