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: stable/10/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_port.c 357520 2020-02-04 19:35:40Z dim $
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
90228990Suqs * interface. Update the first bridge port if necessary.
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/*
122228990Suqs * Find a port entry's position 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
277164997Ssyrinx	/*
278164997Ssyrinx	 * Initialize all rstpMib specific values to false/default.
279164997Ssyrinx	 * These will be set to their true values later if the bridge
280164997Ssyrinx	 * supports RSTP.
281164997Ssyrinx	 */
282164997Ssyrinx	bp->proto_migr = TruthValue_false;
283164997Ssyrinx	bp->admin_edge = TruthValue_false;
284164997Ssyrinx	bp->oper_edge = TruthValue_false;
285165416Ssyrinx	bp->oper_ptp = TruthValue_false;
286165416Ssyrinx	bp->admin_ptp = StpPortAdminPointToPointType_auto;
287164997Ssyrinx
288164410Ssyrinx	bridge_port_memif_insert(&bridge_ports, bp, &(bif->f_bp));
289164410Ssyrinx
290164410Ssyrinx	return (bp);
291164410Ssyrinx}
292164410Ssyrinx
293164410Ssyrinx/*
294164410Ssyrinx * Update our info from the corresponding mibII interface info.
295164410Ssyrinx */
296164410Ssyrinxvoid
297164410Ssyrinxbridge_port_getinfo_mibif(struct mibif *m_if, struct bridge_port *bp)
298164410Ssyrinx{
299164410Ssyrinx	bp->max_info = m_if->mib.ifmd_data.ifi_mtu;
300164410Ssyrinx	bp->in_frames = m_if->mib.ifmd_data.ifi_ipackets;
301164410Ssyrinx	bp->out_frames = m_if->mib.ifmd_data.ifi_opackets;
302164410Ssyrinx	bp->in_drops = m_if->mib.ifmd_data.ifi_iqdrops;
303164410Ssyrinx}
304164410Ssyrinx
305164410Ssyrinx/*
306164410Ssyrinx * Find a port, whose SNMP's mibII ifIndex matches one of the ports,
307164410Ssyrinx * members of the specified bridge interface.
308164410Ssyrinx */
309164410Ssyrinxstruct bridge_port *
310164410Ssyrinxbridge_port_find(int32_t if_idx, struct bridge_if *bif)
311164410Ssyrinx{
312164410Ssyrinx	struct bridge_port *bp;
313164410Ssyrinx
314164410Ssyrinx	for (bp = bif->f_bp; bp != NULL; bp = TAILQ_NEXT(bp, b_p)) {
315164410Ssyrinx		if (bp->sysindex != bif->sysindex) {
316164410Ssyrinx			bp = NULL;
317164410Ssyrinx			break;
318164410Ssyrinx		}
319164410Ssyrinx
320164410Ssyrinx		if (bp->if_idx == if_idx)
321164410Ssyrinx			break;
322164410Ssyrinx	}
323164410Ssyrinx
324164410Ssyrinx	return (bp);
325164410Ssyrinx}
326164410Ssyrinx
327164410Ssyrinxvoid
328164410Ssyrinxbridge_ports_dump(struct bridge_if *bif)
329164410Ssyrinx{
330164410Ssyrinx	struct bridge_port *bp;
331164410Ssyrinx
332164410Ssyrinx	for (bp = bridge_port_bif_first(bif); bp != NULL;
333164410Ssyrinx	    bp = bridge_port_bif_next(bp)) {
334164410Ssyrinx		syslog(LOG_ERR, "memif - %s, index - %d",
335164410Ssyrinx		bp->p_name, bp->port_no);
336164410Ssyrinx	}
337164410Ssyrinx}
338164410Ssyrinx
339164410Ssyrinx/*
340164410Ssyrinx * RFC4188 specifics.
341164410Ssyrinx */
342164410Ssyrinxint
343164410Ssyrinxop_dot1d_base_port(struct snmp_context *c __unused, struct snmp_value *val,
344164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
345164410Ssyrinx{
346164410Ssyrinx	struct bridge_if *bif;
347164410Ssyrinx	struct bridge_port *bp;
348164410Ssyrinx
349164410Ssyrinx	if ((bif = bridge_get_default()) == NULL)
350164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
351164410Ssyrinx
352164410Ssyrinx	if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
353164410Ssyrinx	    bridge_update_memif(bif) <= 0)
354164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
355164410Ssyrinx
356164410Ssyrinx	switch (op) {
357164410Ssyrinx		case SNMP_OP_GET:
358164410Ssyrinx		    if (val->var.len - sub != 1)
359164410Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
360164410Ssyrinx		    if ((bp = bridge_port_find(val->var.subs[sub],
361164410Ssyrinx			bif)) == NULL)
362164410Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
363165253Ssyrinx		    goto get;
364164410Ssyrinx
365164410Ssyrinx		case SNMP_OP_GETNEXT:
366164410Ssyrinx		    if (val->var.len - sub == 0) {
367164410Ssyrinx			if ((bp = bridge_port_bif_first(bif)) == NULL)
368164410Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
369164410Ssyrinx		    } else {
370164410Ssyrinx			if ((bp = bridge_port_find(val->var.subs[sub],
371164410Ssyrinx			    bif)) == NULL ||
372164410Ssyrinx			    (bp = bridge_port_bif_next(bp)) == NULL)
373164410Ssyrinx				return (SNMP_ERR_NOSUCHNAME);
374164410Ssyrinx		    }
375164410Ssyrinx		    val->var.len = sub + 1;
376164410Ssyrinx		    val->var.subs[sub] = bp->port_no;
377165253Ssyrinx		    goto get;
378164410Ssyrinx
379164410Ssyrinx		case SNMP_OP_SET:
380164410Ssyrinx		    return (SNMP_ERR_NOT_WRITEABLE);
381164410Ssyrinx
382164410Ssyrinx		case SNMP_OP_ROLLBACK:
383164410Ssyrinx		case SNMP_OP_COMMIT:
384165253Ssyrinx		    break;
385164410Ssyrinx	}
386165253Ssyrinx	abort();
387164410Ssyrinx
388165253Ssyrinxget:
389164410Ssyrinx	switch (val->var.subs[sub - 1]) {
390164410Ssyrinx	    case LEAF_dot1dBasePort:
391164410Ssyrinx		val->v.integer = bp->port_no;
392165253Ssyrinx		return (SNMP_ERR_NOERROR);
393165253Ssyrinx
394164410Ssyrinx	    case LEAF_dot1dBasePortIfIndex:
395164410Ssyrinx		val->v.integer = bp->if_idx;
396165253Ssyrinx		return (SNMP_ERR_NOERROR);
397165253Ssyrinx
398164410Ssyrinx	    case LEAF_dot1dBasePortCircuit:
399164410Ssyrinx		val->v.oid = bp->circuit;
400165253Ssyrinx		return (SNMP_ERR_NOERROR);
401165253Ssyrinx
402164410Ssyrinx	    case LEAF_dot1dBasePortDelayExceededDiscards:
403164410Ssyrinx		val->v.uint32 = bp->dly_ex_drops;
404165253Ssyrinx		return (SNMP_ERR_NOERROR);
405165253Ssyrinx
406164410Ssyrinx	    case LEAF_dot1dBasePortMtuExceededDiscards:
407164410Ssyrinx		val->v.uint32 = bp->dly_mtu_drops;
408165253Ssyrinx		return (SNMP_ERR_NOERROR);
409164410Ssyrinx	}
410164410Ssyrinx
411165253Ssyrinx	abort();
412164410Ssyrinx}
413164410Ssyrinx
414164410Ssyrinxint
415164410Ssyrinxop_dot1d_stp_port(struct snmp_context *ctx, struct snmp_value *val,
416164410Ssyrinx	 uint sub, uint iidx __unused, enum snmp_op op)
417164410Ssyrinx{
418164410Ssyrinx	struct bridge_if *bif;
419164410Ssyrinx	struct bridge_port *bp;
420164410Ssyrinx
421164410Ssyrinx	if ((bif = bridge_get_default()) == NULL)
422164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
423164410Ssyrinx
424164410Ssyrinx	if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
425164410Ssyrinx	    bridge_update_memif(bif) <= 0)
426164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
427164410Ssyrinx
428164410Ssyrinx	switch (op) {
429164410Ssyrinx		case SNMP_OP_GET:
430164410Ssyrinx		    if (val->var.len - sub != 1)
431164410Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
432164410Ssyrinx		    if ((bp = bridge_port_find(val->var.subs[sub],
433164410Ssyrinx			bif)) == NULL)
434164410Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
435165253Ssyrinx		    goto get;
436164410Ssyrinx
437164410Ssyrinx		case SNMP_OP_GETNEXT:
438164410Ssyrinx		    if (val->var.len - sub == 0) {
439164410Ssyrinx			if ((bp = bridge_port_bif_first(bif)) == NULL)
440164410Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
441164410Ssyrinx		    } else {
442164410Ssyrinx			if ((bp = bridge_port_find(val->var.subs[sub],
443164410Ssyrinx			    bif)) == NULL ||
444164410Ssyrinx			    (bp = bridge_port_bif_next(bp)) == NULL)
445164410Ssyrinx				return (SNMP_ERR_NOSUCHNAME);
446164410Ssyrinx		    }
447164410Ssyrinx		    val->var.len = sub + 1;
448164410Ssyrinx		    val->var.subs[sub] = bp->port_no;
449165253Ssyrinx		    goto get;
450164410Ssyrinx
451164410Ssyrinx		case SNMP_OP_SET:
452164997Ssyrinx		    if (val->var.len - sub != 1)
453164997Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
454164410Ssyrinx		    if ((bp = bridge_port_find(val->var.subs[sub],
455164410Ssyrinx			bif)) == NULL)
456164410Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
457164410Ssyrinx
458164410Ssyrinx		    switch (val->var.subs[sub - 1]) {
459164410Ssyrinx			case LEAF_dot1dStpPortPriority:
460165253Ssyrinx			    if (val->v.integer < 0 || val->v.integer > 255)
461165253Ssyrinx				return (SNMP_ERR_WRONG_VALUE);
462165253Ssyrinx
463164410Ssyrinx			    ctx->scratch->int1 = bp->priority;
464165253Ssyrinx			    if (bridge_port_set_priority(bif->bif_name, bp,
465165253Ssyrinx				val->v.integer) < 0)
466165253Ssyrinx				return (SNMP_ERR_GENERR);
467165253Ssyrinx			    return (SNMP_ERR_NOERROR);
468165253Ssyrinx
469164410Ssyrinx			case LEAF_dot1dStpPortEnable:
470165253Ssyrinx			    if (val->v.integer != dot1dStpPortEnable_enabled &&
471165253Ssyrinx				val->v.integer != dot1dStpPortEnable_disabled)
472165253Ssyrinx				return (SNMP_ERR_WRONG_VALUE);
473165253Ssyrinx
474164410Ssyrinx			    ctx->scratch->int1 = bp->enable;
475165253Ssyrinx			    if (bridge_port_set_stp_enable(bif->bif_name,
476165253Ssyrinx				bp, val->v.integer) < 0)
477165253Ssyrinx				return (SNMP_ERR_GENERR);
478165253Ssyrinx			    return (SNMP_ERR_NOERROR);
479165253Ssyrinx
480164410Ssyrinx			case LEAF_dot1dStpPortPathCost:
481165253Ssyrinx			    if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
482165253Ssyrinx				val->v.integer > SNMP_PORT_MAX_PATHCOST)
483165253Ssyrinx				return (SNMP_ERR_WRONG_VALUE);
484165253Ssyrinx
485164410Ssyrinx			    ctx->scratch->int1 = bp->path_cost;
486165253Ssyrinx			    if (bridge_port_set_path_cost(bif->bif_name, bp,
487165253Ssyrinx				val->v.integer) < 0)
488165253Ssyrinx				return (SNMP_ERR_GENERR);
489165253Ssyrinx			    return (SNMP_ERR_NOERROR);
490165253Ssyrinx
491164410Ssyrinx			case LEAF_dot1dStpPort:
492164410Ssyrinx			case LEAF_dot1dStpPortState:
493164410Ssyrinx			case LEAF_dot1dStpPortDesignatedRoot:
494164410Ssyrinx			case LEAF_dot1dStpPortDesignatedCost:
495164410Ssyrinx			case LEAF_dot1dStpPortDesignatedBridge:
496164410Ssyrinx			case LEAF_dot1dStpPortDesignatedPort:
497164410Ssyrinx			case LEAF_dot1dStpPortForwardTransitions:
498164410Ssyrinx			    return (SNMP_ERR_NOT_WRITEABLE);
499164410Ssyrinx		    }
500165253Ssyrinx		    abort();
501164410Ssyrinx
502164410Ssyrinx		case SNMP_OP_ROLLBACK:
503164410Ssyrinx		    if ((bp = bridge_port_find(val->var.subs[sub],
504164410Ssyrinx			bif)) == NULL)
505164410Ssyrinx			    return (SNMP_ERR_GENERR);
506164410Ssyrinx		    switch (val->var.subs[sub - 1]) {
507164410Ssyrinx			case LEAF_dot1dStpPortPriority:
508164410Ssyrinx			    bridge_port_set_priority(bif->bif_name, bp,
509164410Ssyrinx				ctx->scratch->int1);
510164410Ssyrinx			    break;
511164410Ssyrinx			case LEAF_dot1dStpPortEnable:
512164410Ssyrinx			    bridge_port_set_stp_enable(bif->bif_name, bp,
513164410Ssyrinx				ctx->scratch->int1);
514164410Ssyrinx			    break;
515164410Ssyrinx			case LEAF_dot1dStpPortPathCost:
516164410Ssyrinx			    bridge_port_set_path_cost(bif->bif_name, bp,
517164410Ssyrinx				ctx->scratch->int1);
518164410Ssyrinx			    break;
519164410Ssyrinx		    }
520164410Ssyrinx		    return (SNMP_ERR_NOERROR);
521164410Ssyrinx
522164410Ssyrinx		case SNMP_OP_COMMIT:
523164410Ssyrinx		    return (SNMP_ERR_NOERROR);
524164410Ssyrinx	}
525165253Ssyrinx	abort();
526164997Ssyrinx
527165253Ssyrinxget:
528164410Ssyrinx	switch (val->var.subs[sub - 1]) {
529164410Ssyrinx		case LEAF_dot1dStpPort:
530164410Ssyrinx			val->v.integer = bp->port_no;
531165253Ssyrinx			return (SNMP_ERR_NOERROR);
532165253Ssyrinx
533164410Ssyrinx		case LEAF_dot1dStpPortPriority:
534164410Ssyrinx			val->v.integer = bp->priority;
535165253Ssyrinx			return (SNMP_ERR_NOERROR);
536165253Ssyrinx
537164410Ssyrinx		case LEAF_dot1dStpPortState:
538164410Ssyrinx			val->v.integer = bp->state;
539165253Ssyrinx			return (SNMP_ERR_NOERROR);
540165253Ssyrinx
541164410Ssyrinx		case LEAF_dot1dStpPortEnable:
542164410Ssyrinx			val->v.integer = bp->enable;
543165253Ssyrinx			return (SNMP_ERR_NOERROR);
544165253Ssyrinx
545164410Ssyrinx		case LEAF_dot1dStpPortPathCost:
546164410Ssyrinx			val->v.integer = bp->path_cost;
547165253Ssyrinx			return (SNMP_ERR_NOERROR);
548165253Ssyrinx
549164410Ssyrinx		case LEAF_dot1dStpPortDesignatedRoot:
550165253Ssyrinx			return (string_get(val, bp->design_root,
551165253Ssyrinx			    SNMP_BRIDGE_ID_LEN));
552165253Ssyrinx
553164410Ssyrinx		case LEAF_dot1dStpPortDesignatedCost:
554164410Ssyrinx			val->v.integer = bp->design_cost;
555165253Ssyrinx			return (SNMP_ERR_NOERROR);
556165253Ssyrinx
557164410Ssyrinx		case LEAF_dot1dStpPortDesignatedBridge:
558165253Ssyrinx			return (string_get(val, bp->design_bridge,
559165253Ssyrinx			    SNMP_BRIDGE_ID_LEN));
560165253Ssyrinx
561164410Ssyrinx		case LEAF_dot1dStpPortDesignatedPort:
562165253Ssyrinx			return (string_get(val, bp->design_port, 2));
563165253Ssyrinx
564164410Ssyrinx		case LEAF_dot1dStpPortForwardTransitions:
565164410Ssyrinx			val->v.uint32 = bp->fwd_trans;
566165253Ssyrinx			return (SNMP_ERR_NOERROR);
567164410Ssyrinx	}
568164410Ssyrinx
569165253Ssyrinx	abort();
570164410Ssyrinx}
571164410Ssyrinx
572164410Ssyrinxint
573164997Ssyrinxop_dot1d_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val,
574164997Ssyrinx    uint sub, uint iidx __unused, enum snmp_op op)
575164997Ssyrinx{
576164997Ssyrinx	struct bridge_if *bif;
577164997Ssyrinx	struct bridge_port *bp;
578164997Ssyrinx
579164997Ssyrinx	if ((bif = bridge_get_default()) == NULL)
580164997Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
581164997Ssyrinx
582164997Ssyrinx	if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
583164997Ssyrinx	    bridge_update_memif(bif) <= 0)
584164997Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
585164997Ssyrinx
586164997Ssyrinx	switch (op) {
587164997Ssyrinx		case SNMP_OP_GET:
588164997Ssyrinx		    if (val->var.len - sub != 1)
589164997Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
590164997Ssyrinx		    if ((bp = bridge_port_find(val->var.subs[sub],
591164997Ssyrinx			bif)) == NULL)
592164997Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
593165253Ssyrinx		    goto get;
594164997Ssyrinx
595164997Ssyrinx		case SNMP_OP_GETNEXT:
596164997Ssyrinx		    if (val->var.len - sub == 0) {
597164997Ssyrinx			if ((bp = bridge_port_bif_first(bif)) == NULL)
598164997Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
599164997Ssyrinx		    } else {
600164997Ssyrinx			if ((bp = bridge_port_find(val->var.subs[sub],
601164997Ssyrinx			    bif)) == NULL ||
602164997Ssyrinx			    (bp = bridge_port_bif_next(bp)) == NULL)
603164997Ssyrinx				return (SNMP_ERR_NOSUCHNAME);
604164997Ssyrinx		    }
605164997Ssyrinx		    val->var.len = sub + 1;
606164997Ssyrinx		    val->var.subs[sub] = bp->port_no;
607165253Ssyrinx		    goto get;
608164997Ssyrinx
609164997Ssyrinx		case SNMP_OP_SET:
610164997Ssyrinx		    if (val->var.len - sub != 1)
611164997Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
612164997Ssyrinx		    if ((bp = bridge_port_find(val->var.subs[sub],
613164997Ssyrinx			bif)) == NULL)
614164997Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
615164997Ssyrinx
616164997Ssyrinx		    switch (val->var.subs[sub - 1]) {
617164997Ssyrinx			case LEAF_dot1dStpPortAdminEdgePort:
618165253Ssyrinx			    if (val->v.integer != TruthValue_true &&
619165253Ssyrinx				val->v.integer != TruthValue_false)
620165253Ssyrinx				return (SNMP_ERR_WRONG_VALUE);
621165253Ssyrinx
622164997Ssyrinx			    ctx->scratch->int1 = bp->admin_edge;
623165253Ssyrinx			    if (bridge_port_set_admin_edge(bif->bif_name, bp,
624165253Ssyrinx				val->v.integer) < 0)
625165253Ssyrinx				return (SNMP_ERR_GENERR);
626165253Ssyrinx			    return (SNMP_ERR_NOERROR);
627165253Ssyrinx
628164997Ssyrinx			case LEAF_dot1dStpPortAdminPointToPoint:
629310903Sngie			    if (val->v.integer < 0 || val->v.integer >
630165253Ssyrinx				StpPortAdminPointToPointType_auto)
631165253Ssyrinx				return (SNMP_ERR_WRONG_VALUE);
632165253Ssyrinx
633165416Ssyrinx			    ctx->scratch->int1 = bp->admin_ptp;
634165416Ssyrinx			    if (bridge_port_set_admin_ptp(bif->bif_name, bp,
635165253Ssyrinx				val->v.integer) < 0)
636165253Ssyrinx				return (SNMP_ERR_GENERR);
637165253Ssyrinx			    return (SNMP_ERR_NOERROR);
638165253Ssyrinx
639164997Ssyrinx			case LEAF_dot1dStpPortAdminPathCost:
640165253Ssyrinx			    if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
641165253Ssyrinx				val->v.integer > SNMP_PORT_MAX_PATHCOST)
642165253Ssyrinx				return (SNMP_ERR_WRONG_VALUE);
643165253Ssyrinx
644164997Ssyrinx			    ctx->scratch->int1 = bp->admin_path_cost;
645165253Ssyrinx			    if (bridge_port_set_path_cost(bif->bif_name, bp,
646165253Ssyrinx				val->v.integer) < 0)
647165253Ssyrinx				return (SNMP_ERR_GENERR);
648165253Ssyrinx			    return (SNMP_ERR_NOERROR);
649165253Ssyrinx
650164997Ssyrinx			case LEAF_dot1dStpPortProtocolMigration:
651164997Ssyrinx			case LEAF_dot1dStpPortOperEdgePort:
652164997Ssyrinx			case LEAF_dot1dStpPortOperPointToPoint:
653164997Ssyrinx			    return (SNMP_ERR_NOT_WRITEABLE);
654164997Ssyrinx		    }
655165253Ssyrinx		    abort();
656164997Ssyrinx
657164997Ssyrinx		case SNMP_OP_ROLLBACK:
658164997Ssyrinx		    if ((bp = bridge_port_find(val->var.subs[sub],
659164997Ssyrinx			bif)) == NULL)
660164997Ssyrinx			    return (SNMP_ERR_GENERR);
661164997Ssyrinx
662164997Ssyrinx		    switch (val->var.subs[sub - 1]) {
663164997Ssyrinx			case LEAF_dot1dStpPortAdminEdgePort:
664164997Ssyrinx			    bridge_port_set_admin_edge(bif->bif_name, bp,
665164997Ssyrinx				ctx->scratch->int1);
666164997Ssyrinx			    break;
667164997Ssyrinx			case LEAF_dot1dStpPortAdminPointToPoint:
668165416Ssyrinx			    bridge_port_set_admin_ptp(bif->bif_name, bp,
669164997Ssyrinx				ctx->scratch->int1);
670164997Ssyrinx			    break;
671164997Ssyrinx			case LEAF_dot1dStpPortAdminPathCost:
672164997Ssyrinx			    bridge_port_set_path_cost(bif->bif_name, bp,
673164997Ssyrinx				ctx->scratch->int1);
674164997Ssyrinx			    break;
675164997Ssyrinx		    }
676164997Ssyrinx		    return (SNMP_ERR_NOERROR);
677164997Ssyrinx
678164997Ssyrinx		case SNMP_OP_COMMIT:
679164997Ssyrinx		    return (SNMP_ERR_NOERROR);
680164997Ssyrinx	}
681165253Ssyrinx	abort();
682164997Ssyrinx
683165253Ssyrinxget:
684164997Ssyrinx	switch (val->var.subs[sub - 1]) {
685164997Ssyrinx		case LEAF_dot1dStpPortProtocolMigration:
686164997Ssyrinx			val->v.integer = bp->proto_migr;
687165253Ssyrinx			return (SNMP_ERR_NOERROR);
688165253Ssyrinx
689164997Ssyrinx		case LEAF_dot1dStpPortAdminEdgePort:
690164997Ssyrinx			val->v.integer = bp->admin_edge;
691165253Ssyrinx			return (SNMP_ERR_NOERROR);
692165253Ssyrinx
693164997Ssyrinx		case LEAF_dot1dStpPortOperEdgePort:
694164997Ssyrinx			val->v.integer = bp->oper_edge;
695165253Ssyrinx			return (SNMP_ERR_NOERROR);
696165253Ssyrinx
697164997Ssyrinx		case LEAF_dot1dStpPortAdminPointToPoint:
698165416Ssyrinx			val->v.integer = bp->admin_ptp;
699165253Ssyrinx			return (SNMP_ERR_NOERROR);
700165253Ssyrinx
701164997Ssyrinx		case LEAF_dot1dStpPortOperPointToPoint:
702165416Ssyrinx			val->v.integer = bp->oper_ptp;
703165253Ssyrinx			return (SNMP_ERR_NOERROR);
704165253Ssyrinx
705164997Ssyrinx		case LEAF_dot1dStpPortAdminPathCost:
706164997Ssyrinx			val->v.integer = bp->admin_path_cost;
707165253Ssyrinx			return (SNMP_ERR_NOERROR);
708164997Ssyrinx	}
709164997Ssyrinx
710165253Ssyrinx	abort();
711164997Ssyrinx}
712164997Ssyrinx
713164997Ssyrinxint
714164410Ssyrinxop_dot1d_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
715164997Ssyrinx    uint sub, uint iidx __unused, enum snmp_op op)
716164410Ssyrinx{
717164410Ssyrinx	struct bridge_if *bif;
718164410Ssyrinx	struct bridge_port *bp;
719164410Ssyrinx
720164410Ssyrinx	if ((bif = bridge_get_default()) == NULL)
721164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
722164410Ssyrinx
723164410Ssyrinx	if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
724164410Ssyrinx	    bridge_update_memif(bif) <= 0)
725164410Ssyrinx		return (SNMP_ERR_NOSUCHNAME);
726164410Ssyrinx
727164410Ssyrinx	switch (op) {
728164410Ssyrinx		case SNMP_OP_GET:
729164410Ssyrinx		    if (val->var.len - sub != 1)
730164410Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
731164410Ssyrinx		    if ((bp = bridge_port_find(val->var.subs[sub],
732164410Ssyrinx			bif)) == NULL)
733164410Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
734165253Ssyrinx		    goto get;
735164410Ssyrinx
736164410Ssyrinx		case SNMP_OP_GETNEXT:
737164410Ssyrinx		    if (val->var.len - sub == 0) {
738164410Ssyrinx			if ((bp = bridge_port_bif_first(bif)) == NULL)
739164410Ssyrinx			    return (SNMP_ERR_NOSUCHNAME);
740164410Ssyrinx		    } else {
741164410Ssyrinx			if ((bp = bridge_port_find(val->var.subs[sub],
742164410Ssyrinx			    bif)) == NULL ||
743164410Ssyrinx			    (bp = bridge_port_bif_next(bp)) == NULL)
744164410Ssyrinx				return (SNMP_ERR_NOSUCHNAME);
745164410Ssyrinx		    }
746164410Ssyrinx		    val->var.len = sub + 1;
747164410Ssyrinx		    val->var.subs[sub] = bp->port_no;
748165253Ssyrinx		    goto get;
749164410Ssyrinx
750164410Ssyrinx		case SNMP_OP_SET:
751164410Ssyrinx		    return (SNMP_ERR_NOT_WRITEABLE);
752164410Ssyrinx
753164410Ssyrinx		case SNMP_OP_ROLLBACK:
754164410Ssyrinx		case SNMP_OP_COMMIT:
755165253Ssyrinx		    break;
756164410Ssyrinx	}
757165253Ssyrinx	abort();
758164410Ssyrinx
759165253Ssyrinxget:
760164410Ssyrinx	switch (val->var.subs[sub - 1]) {
761164410Ssyrinx		case LEAF_dot1dTpPort:
762164410Ssyrinx			val->v.integer = bp->port_no;
763165253Ssyrinx			return (SNMP_ERR_NOERROR);
764165253Ssyrinx
765164410Ssyrinx		case LEAF_dot1dTpPortMaxInfo:
766164410Ssyrinx			val->v.integer = bp->max_info;
767165253Ssyrinx			return (SNMP_ERR_NOERROR);
768165253Ssyrinx
769164410Ssyrinx		case LEAF_dot1dTpPortInFrames:
770164410Ssyrinx			val->v.uint32 = bp->in_frames;
771165253Ssyrinx			return (SNMP_ERR_NOERROR);
772165253Ssyrinx
773164410Ssyrinx		case LEAF_dot1dTpPortOutFrames:
774164410Ssyrinx			val->v.uint32 = bp->out_frames;
775165253Ssyrinx			return (SNMP_ERR_NOERROR);
776165253Ssyrinx
777164410Ssyrinx		case LEAF_dot1dTpPortInDiscards:
778164410Ssyrinx			val->v.uint32 = bp->in_drops;
779165253Ssyrinx			return (SNMP_ERR_NOERROR);
780164410Ssyrinx	}
781164410Ssyrinx
782165253Ssyrinx	abort();
783164410Ssyrinx}
784164410Ssyrinx
785164410Ssyrinx/*
786164410Ssyrinx * Private BEGEMOT-BRIDGE-MIB specifics.
787164410Ssyrinx */
788164410Ssyrinx
789164410Ssyrinx/*
790164410Ssyrinx * Construct a bridge port entry index.
791164410Ssyrinx */
792164410Ssyrinxstatic int
793164410Ssyrinxbridge_port_index_append(struct asn_oid *oid, uint sub,
794164410Ssyrinx	const struct bridge_port *bp)
795164410Ssyrinx{
796164410Ssyrinx	uint i;
797164410Ssyrinx	const char *b_name;
798164410Ssyrinx
799164410Ssyrinx	if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
800164410Ssyrinx		return (-1);
801164410Ssyrinx
802164410Ssyrinx	oid->len = sub + strlen(b_name) + 1 + 1;
803164410Ssyrinx	oid->subs[sub] = strlen(b_name);
804164410Ssyrinx
805164410Ssyrinx	for (i = 1; i <= strlen(b_name); i++)
806164410Ssyrinx		oid->subs[sub + i] = b_name[i - 1];
807164410Ssyrinx
808164410Ssyrinx	oid->subs[sub + i] = bp->port_no;
809164410Ssyrinx
810164410Ssyrinx	return (0);
811164410Ssyrinx}
812164410Ssyrinx
813164410Ssyrinx/*
814164410Ssyrinx * Get the port entry from an entry's index.
815164410Ssyrinx */
816164410Ssyrinxstatic struct bridge_port *
817164410Ssyrinxbridge_port_index_get(const struct asn_oid *oid, uint sub, int8_t status)
818164410Ssyrinx{
819164410Ssyrinx	uint i;
820164410Ssyrinx	int32_t port_no;
821164410Ssyrinx	char bif_name[IFNAMSIZ];
822164410Ssyrinx	struct bridge_if *bif;
823164410Ssyrinx	struct bridge_port *bp;
824164410Ssyrinx
825164410Ssyrinx	if (oid->len - sub != oid->subs[sub] + 2 ||
826164410Ssyrinx	    oid->subs[sub] >= IFNAMSIZ)
827164410Ssyrinx		return (NULL);
828164410Ssyrinx
829164410Ssyrinx	for (i = 0; i < oid->subs[sub]; i++)
830164410Ssyrinx		bif_name[i] = oid->subs[sub + i + 1];
831164410Ssyrinx	bif_name[i] = '\0';
832164410Ssyrinx
833164410Ssyrinx	port_no = oid->subs[sub + i + 1];
834164410Ssyrinx
835164410Ssyrinx	if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
836164410Ssyrinx		return (NULL);
837164410Ssyrinx
838164410Ssyrinx	if ((bp = bridge_port_find(port_no, bif)) == NULL ||
839164410Ssyrinx	    (status == 0 && bp->status != RowStatus_active))
840164410Ssyrinx		return (NULL);
841164410Ssyrinx
842164410Ssyrinx	return (bp);
843164410Ssyrinx}
844164410Ssyrinx
845164410Ssyrinx/*
846164410Ssyrinx * Get the next port entry from an entry's index.
847164410Ssyrinx */
848164410Ssyrinxstatic struct bridge_port *
849164410Ssyrinxbridge_port_index_getnext(const struct asn_oid *oid, uint sub, int8_t status)
850164410Ssyrinx{
851164410Ssyrinx	uint i;
852164410Ssyrinx	int32_t port_no;
853164410Ssyrinx	char bif_name[IFNAMSIZ];
854164410Ssyrinx	struct bridge_if *bif;
855164410Ssyrinx	struct bridge_port *bp;
856164410Ssyrinx
857164410Ssyrinx	if (oid->len - sub == 0)
858164410Ssyrinx		bp = bridge_port_first();
859164410Ssyrinx	else {
860164410Ssyrinx		if (oid->len - sub != oid->subs[sub] + 2 ||
861164410Ssyrinx		    oid->subs[sub] >= IFNAMSIZ)
862164410Ssyrinx			return (NULL);
863164410Ssyrinx
864164410Ssyrinx		for (i = 0; i < oid->subs[sub]; i++)
865164410Ssyrinx			bif_name[i] = oid->subs[sub + i + 1];
866164410Ssyrinx		bif_name[i] = '\0';
867310903Sngie
868164410Ssyrinx		port_no = oid->subs[sub + i + 1];
869164410Ssyrinx
870164410Ssyrinx		if ((bif = bridge_if_find_ifname(bif_name)) == NULL ||
871164410Ssyrinx		    (bp = bridge_port_find(port_no, bif)) == NULL)
872164410Ssyrinx			return (NULL);
873164410Ssyrinx
874164410Ssyrinx		bp = bridge_port_next(bp);
875164410Ssyrinx	}
876164410Ssyrinx
877164410Ssyrinx	if (status == 1)
878164410Ssyrinx		return (bp);
879164410Ssyrinx
880164410Ssyrinx	while (bp != NULL) {
881164410Ssyrinx		if (bp->status == RowStatus_active)
882164410Ssyrinx			break;
883164410Ssyrinx		bp = bridge_port_next(bp);
884164410Ssyrinx	}
885164410Ssyrinx
886164410Ssyrinx	return (bp);
887164410Ssyrinx}
888164410Ssyrinx
889164410Ssyrinx/*
890164410Ssyrinx * Read the bridge name and port index from a ASN OID structure.
891164410Ssyrinx */
892164410Ssyrinxstatic int
893164410Ssyrinxbridge_port_index_decode(const struct asn_oid *oid, uint sub,
894164410Ssyrinx	char *b_name, int32_t *idx)
895164410Ssyrinx{
896164410Ssyrinx	uint i;
897164410Ssyrinx
898164410Ssyrinx	if (oid->len - sub != oid->subs[sub] + 2 ||
899164410Ssyrinx	    oid->subs[sub] >= IFNAMSIZ)
900164410Ssyrinx		return (-1);
901164410Ssyrinx
902164410Ssyrinx	for (i = 0; i < oid->subs[sub]; i++)
903164410Ssyrinx		b_name[i] = oid->subs[sub + i + 1];
904164410Ssyrinx	b_name[i] = '\0';
905164410Ssyrinx
906164410Ssyrinx	*idx = oid->subs[sub + i + 1];
907164410Ssyrinx	return (0);
908164410Ssyrinx}
909164410Ssyrinx
910164410Ssyrinxstatic int
911164410Ssyrinxbridge_port_set_status(struct snmp_context *ctx,
912164410Ssyrinx	struct snmp_value *val, uint sub)
913164410Ssyrinx{
914164410Ssyrinx	int32_t if_idx;
915164410Ssyrinx	char b_name[IFNAMSIZ];
916164410Ssyrinx	struct bridge_if *bif;
917164410Ssyrinx	struct bridge_port *bp;
918164410Ssyrinx	struct mibif *mif;
919164410Ssyrinx
920164410Ssyrinx	if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
921164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
922164410Ssyrinx
923164410Ssyrinx	if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
924164410Ssyrinx	    (mif = mib_find_if(if_idx)) == NULL)
925164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
926164410Ssyrinx
927164410Ssyrinx	bp = bridge_port_find(if_idx, bif);
928164410Ssyrinx
929164410Ssyrinx	switch (val->v.integer) {
930164410Ssyrinx	    case RowStatus_active:
931164410Ssyrinx		if (bp == NULL)
932164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
933164410Ssyrinx
934164410Ssyrinx		if (bp->span_enable == 0)
935164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
936164410Ssyrinx
937164410Ssyrinx		ctx->scratch->int1 = bp->status;
938164410Ssyrinx		bp->status = RowStatus_active;
939164410Ssyrinx		break;
940310903Sngie
941164410Ssyrinx	    case RowStatus_notInService:
942164410Ssyrinx		if (bp == NULL || bp->span_enable == 0 ||
943164410Ssyrinx		    bp->status == RowStatus_active)
944164410Ssyrinx			return (SNMP_ERR_INCONS_VALUE);
945164410Ssyrinx
946164410Ssyrinx		ctx->scratch->int1 = bp->status;
947164410Ssyrinx		bp->status = RowStatus_notInService;
948164410Ssyrinx
949164410Ssyrinx	    case RowStatus_notReady:
950164410Ssyrinx		/* FALLTHROUGH */
951164410Ssyrinx	    case RowStatus_createAndGo:
952164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
953164410Ssyrinx
954164410Ssyrinx	    case RowStatus_createAndWait:
955164410Ssyrinx		if (bp != NULL)
956164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
957164410Ssyrinx
958164410Ssyrinx		if ((bp = bridge_new_port(mif, bif)) == NULL)
959164410Ssyrinx			return (SNMP_ERR_GENERR);
960164410Ssyrinx
961164410Ssyrinx		ctx->scratch->int1 = RowStatus_destroy;
962164410Ssyrinx		bp->status = RowStatus_notReady;
963164410Ssyrinx		break;
964164410Ssyrinx
965164410Ssyrinx	    case RowStatus_destroy:
966164410Ssyrinx		if (bp == NULL)
967164410Ssyrinx		    return (SNMP_ERR_INCONS_VALUE);
968164410Ssyrinx
969164410Ssyrinx		ctx->scratch->int1 = bp->status;
970164410Ssyrinx		bp->status = RowStatus_destroy;
971164410Ssyrinx		break;
972164410Ssyrinx	}
973164410Ssyrinx
974164410Ssyrinx	return (SNMP_ERR_NOERROR);
975164410Ssyrinx}
976164410Ssyrinx
977164410Ssyrinxstatic int
978164410Ssyrinxbridge_port_rollback_status(struct snmp_context *ctx,
979164410Ssyrinx	struct snmp_value *val, uint sub)
980164410Ssyrinx{
981164410Ssyrinx	int32_t if_idx;
982164410Ssyrinx	char b_name[IFNAMSIZ];
983164410Ssyrinx	struct bridge_if *bif;
984164410Ssyrinx	struct bridge_port *bp;
985164410Ssyrinx
986164410Ssyrinx	if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
987164410Ssyrinx		return (SNMP_ERR_GENERR);
988164410Ssyrinx
989164410Ssyrinx	if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
990164410Ssyrinx	    (bp = bridge_port_find(if_idx, bif)) == NULL)
991164410Ssyrinx		return (SNMP_ERR_GENERR);
992164410Ssyrinx
993164410Ssyrinx	if (ctx->scratch->int1 == RowStatus_destroy)
994164410Ssyrinx		bridge_port_remove(bp, bif);
995164410Ssyrinx	else
996164410Ssyrinx		bp->status = ctx->scratch->int1;
997164410Ssyrinx
998164410Ssyrinx	return (SNMP_ERR_NOERROR);
999164410Ssyrinx}
1000164410Ssyrinx
1001164410Ssyrinxstatic int
1002164410Ssyrinxbridge_port_commit_status(struct snmp_value *val, uint sub)
1003164410Ssyrinx{
1004164410Ssyrinx	int32_t if_idx;
1005164410Ssyrinx	char b_name[IFNAMSIZ];
1006164410Ssyrinx	struct bridge_if *bif;
1007164410Ssyrinx	struct bridge_port *bp;
1008164410Ssyrinx
1009164410Ssyrinx	if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
1010164410Ssyrinx		return (SNMP_ERR_GENERR);
1011164410Ssyrinx
1012164410Ssyrinx	if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
1013164410Ssyrinx	    (bp = bridge_port_find(if_idx, bif)) == NULL)
1014164410Ssyrinx		return (SNMP_ERR_GENERR);
1015164410Ssyrinx
1016164410Ssyrinx	switch (bp->status) {
1017164410Ssyrinx		case RowStatus_active:
1018164410Ssyrinx			if (bridge_port_addm(bp, b_name) < 0)
1019164410Ssyrinx				return (SNMP_ERR_COMMIT_FAILED);
1020164410Ssyrinx			break;
1021164410Ssyrinx
1022164410Ssyrinx		case RowStatus_destroy:
1023164410Ssyrinx			if (bridge_port_delm(bp, b_name) < 0)
1024164410Ssyrinx				return (SNMP_ERR_COMMIT_FAILED);
1025164410Ssyrinx			bridge_port_remove(bp, bif);
1026164410Ssyrinx			break;
1027164410Ssyrinx	}
1028164410Ssyrinx
1029164410Ssyrinx	return (SNMP_ERR_NOERROR);
1030164410Ssyrinx}
1031164410Ssyrinx
1032164410Ssyrinxstatic int
1033164410Ssyrinxbridge_port_set_span_enable(struct snmp_context *ctx,
1034164410Ssyrinx		struct snmp_value *val, uint sub)
1035164410Ssyrinx{
1036164410Ssyrinx	int32_t if_idx;
1037164410Ssyrinx	char b_name[IFNAMSIZ];
1038164410Ssyrinx	struct bridge_if *bif;
1039164410Ssyrinx	struct bridge_port *bp;
1040164410Ssyrinx	struct mibif *mif;
1041164410Ssyrinx
1042164410Ssyrinx	if (val->v.integer != begemotBridgeBaseSpanEnabled_enabled &&
1043164410Ssyrinx	    val->v.integer != begemotBridgeBaseSpanEnabled_disabled)
1044164410Ssyrinx		return (SNMP_ERR_BADVALUE);
1045164410Ssyrinx
1046164410Ssyrinx	if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
1047164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
1048164410Ssyrinx
1049164410Ssyrinx	if ((bif = bridge_if_find_ifname(b_name)) == NULL)
1050164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
1051164410Ssyrinx
1052164410Ssyrinx	if ((bp = bridge_port_find(if_idx, bif)) == NULL) {
1053164410Ssyrinx		if ((mif = mib_find_if(if_idx)) == NULL)
1054164410Ssyrinx			return (SNMP_ERR_INCONS_VALUE);
1055164410Ssyrinx
1056164410Ssyrinx		if ((bp = bridge_new_port(mif, bif)) == NULL)
1057164410Ssyrinx			return (SNMP_ERR_GENERR);
1058164410Ssyrinx
1059164410Ssyrinx		ctx->scratch->int1 = RowStatus_destroy;
1060164410Ssyrinx	} else if (bp->status == RowStatus_active) {
1061164410Ssyrinx		return (SNMP_ERR_INCONS_VALUE);
1062164410Ssyrinx	} else {
1063164410Ssyrinx		ctx->scratch->int1 = bp->status;
1064164410Ssyrinx	}
1065164410Ssyrinx
1066164410Ssyrinx	bp->span_enable = val->v.integer;
1067164410Ssyrinx	bp->status = RowStatus_notInService;
1068164410Ssyrinx
1069164410Ssyrinx	return (SNMP_ERR_NOERROR);
1070164410Ssyrinx}
1071164410Ssyrinx
1072164410Ssyrinxint
1073164410Ssyrinxop_begemot_base_port(struct snmp_context *ctx, struct snmp_value *val,
1074164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
1075164410Ssyrinx{
1076164410Ssyrinx	int8_t status, which;
1077171791Ssyrinx	const char *bname;
1078165253Ssyrinx	struct bridge_port *bp;
1079164410Ssyrinx
1080164410Ssyrinx	if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1081164410Ssyrinx		bridge_update_all_ports();
1082164410Ssyrinx
1083164410Ssyrinx	which = val->var.subs[sub - 1];
1084164410Ssyrinx	status = 0;
1085164410Ssyrinx
1086164410Ssyrinx	switch (op) {
1087164410Ssyrinx	    case SNMP_OP_GET:
1088164410Ssyrinx		if (which == LEAF_begemotBridgeBaseSpanEnabled ||
1089164410Ssyrinx		    which == LEAF_begemotBridgeBasePortStatus)
1090164410Ssyrinx			status = 1;
1091164410Ssyrinx		if ((bp = bridge_port_index_get(&val->var, sub,
1092164410Ssyrinx		    status)) == NULL)
1093164410Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
1094165253Ssyrinx		goto get;
1095164410Ssyrinx
1096164410Ssyrinx	    case SNMP_OP_GETNEXT:
1097164410Ssyrinx		if (which == LEAF_begemotBridgeBaseSpanEnabled ||
1098164410Ssyrinx		    which == LEAF_begemotBridgeBasePortStatus)
1099164410Ssyrinx			status = 1;
1100164410Ssyrinx		if ((bp = bridge_port_index_getnext(&val->var, sub,
1101164410Ssyrinx		    status)) == NULL ||
1102164410Ssyrinx		    bridge_port_index_append(&val->var, sub, bp) < 0)
1103164410Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
1104165253Ssyrinx		goto get;
1105164410Ssyrinx
1106164410Ssyrinx	    case SNMP_OP_SET:
1107164410Ssyrinx		switch (which) {
1108164410Ssyrinx		    case LEAF_begemotBridgeBaseSpanEnabled:
1109164410Ssyrinx			return (bridge_port_set_span_enable(ctx, val, sub));
1110164410Ssyrinx
1111164410Ssyrinx		    case LEAF_begemotBridgeBasePortStatus:
1112164410Ssyrinx			return (bridge_port_set_status(ctx, val, sub));
1113164410Ssyrinx
1114171791Ssyrinx		    case LEAF_begemotBridgeBasePortPrivate:
1115171791Ssyrinx			if ((bp = bridge_port_index_get(&val->var, sub,
1116171791Ssyrinx			    status)) == NULL)
1117171791Ssyrinx				return (SNMP_ERR_NOSUCHNAME);
1118171791Ssyrinx			if ((bname = bridge_if_find_name(bp->sysindex)) == NULL)
1119171791Ssyrinx				return (SNMP_ERR_GENERR);
1120171791Ssyrinx			ctx->scratch->int1 = bp->priv_set;
1121171791Ssyrinx			return (bridge_port_set_private(bname, bp,
1122171791Ssyrinx			    val->v.integer));
1123171791Ssyrinx
1124164410Ssyrinx		    case LEAF_begemotBridgeBasePort:
1125164410Ssyrinx		    case LEAF_begemotBridgeBasePortIfIndex:
1126164410Ssyrinx		    case LEAF_begemotBridgeBasePortDelayExceededDiscards:
1127164410Ssyrinx		    case LEAF_begemotBridgeBasePortMtuExceededDiscards:
1128164410Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
1129164410Ssyrinx		}
1130164410Ssyrinx		abort();
1131164410Ssyrinx
1132164410Ssyrinx	    case SNMP_OP_ROLLBACK:
1133164410Ssyrinx		switch (which) {
1134164410Ssyrinx		    case LEAF_begemotBridgeBaseSpanEnabled:
1135164410Ssyrinx			/* FALLTHROUGH */
1136164410Ssyrinx		    case LEAF_begemotBridgeBasePortStatus:
1137164410Ssyrinx			return (bridge_port_rollback_status(ctx, val, sub));
1138171791Ssyrinx		    case LEAF_begemotBridgeBasePortPrivate:
1139171791Ssyrinx			if ((bp = bridge_port_index_get(&val->var, sub,
1140171791Ssyrinx			    status)) == NULL)
1141171791Ssyrinx				return (SNMP_ERR_GENERR);
1142171791Ssyrinx			if ((bname = bridge_if_find_name(bp->sysindex)) == NULL)
1143171791Ssyrinx				return (SNMP_ERR_GENERR);
1144171791Ssyrinx			return (bridge_port_set_private(bname, bp,
1145171791Ssyrinx			    ctx->scratch->int1));
1146164410Ssyrinx		}
1147164410Ssyrinx		return (SNMP_ERR_NOERROR);
1148164410Ssyrinx
1149164410Ssyrinx	    case SNMP_OP_COMMIT:
1150164410Ssyrinx		if (which == LEAF_begemotBridgeBasePortStatus)
1151164410Ssyrinx			return (bridge_port_commit_status(val, sub));
1152164410Ssyrinx
1153164410Ssyrinx		return (SNMP_ERR_NOERROR);
1154164410Ssyrinx	}
1155165253Ssyrinx	abort();
1156164410Ssyrinx
1157165253Ssyrinxget:
1158164410Ssyrinx	switch (which) {
1159164410Ssyrinx	    case LEAF_begemotBridgeBasePort:
1160164410Ssyrinx		val->v.integer = bp->port_no;
1161165253Ssyrinx		return (SNMP_ERR_NOERROR);
1162165253Ssyrinx
1163164410Ssyrinx	    case LEAF_begemotBridgeBasePortIfIndex:
1164164410Ssyrinx		val->v.integer = bp->if_idx;
1165165253Ssyrinx		return (SNMP_ERR_NOERROR);
1166165253Ssyrinx
1167164410Ssyrinx	    case LEAF_begemotBridgeBaseSpanEnabled:
1168164410Ssyrinx		val->v.integer = bp->span_enable;
1169165253Ssyrinx		return (SNMP_ERR_NOERROR);
1170165253Ssyrinx
1171164410Ssyrinx	    case LEAF_begemotBridgeBasePortDelayExceededDiscards:
1172164410Ssyrinx		val->v.uint32 = bp->dly_ex_drops;
1173165253Ssyrinx		return (SNMP_ERR_NOERROR);
1174165253Ssyrinx
1175164410Ssyrinx	    case LEAF_begemotBridgeBasePortMtuExceededDiscards:
1176164410Ssyrinx		val->v.uint32 = bp->dly_mtu_drops;
1177165253Ssyrinx		return (SNMP_ERR_NOERROR);
1178165253Ssyrinx
1179164410Ssyrinx	    case LEAF_begemotBridgeBasePortStatus:
1180164410Ssyrinx		val->v.integer = bp->status;
1181165253Ssyrinx		return (SNMP_ERR_NOERROR);
1182171791Ssyrinx
1183171791Ssyrinx	    case LEAF_begemotBridgeBasePortPrivate:
1184171791Ssyrinx		val->v.integer = bp->priv_set;
1185171791Ssyrinx		return (SNMP_ERR_NOERROR);
1186164410Ssyrinx	}
1187164410Ssyrinx
1188165253Ssyrinx	abort();
1189164410Ssyrinx}
1190164410Ssyrinx
1191164410Ssyrinxint
1192164410Ssyrinxop_begemot_stp_port(struct snmp_context *ctx, struct snmp_value *val,
1193164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
1194164410Ssyrinx{
1195165046Ssyrinx	struct bridge_port *bp;
1196164410Ssyrinx	const char *b_name;
1197164410Ssyrinx
1198164410Ssyrinx	if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1199164410Ssyrinx		bridge_update_all_ports();
1200164410Ssyrinx
1201164410Ssyrinx	switch (op) {
1202164410Ssyrinx	    case SNMP_OP_GET:
1203164410Ssyrinx		if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1204164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1205165253Ssyrinx		goto get;
1206164410Ssyrinx
1207164410Ssyrinx	    case SNMP_OP_GETNEXT:
1208164410Ssyrinx		if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1209164410Ssyrinx		    NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1210164410Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
1211165253Ssyrinx		goto get;
1212164410Ssyrinx
1213164410Ssyrinx	    case SNMP_OP_SET:
1214164410Ssyrinx		if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1215164410Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
1216164410Ssyrinx		if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1217164410Ssyrinx			return (SNMP_ERR_GENERR);
1218164410Ssyrinx
1219164410Ssyrinx		switch (val->var.subs[sub - 1]) {
1220164410Ssyrinx		    case LEAF_begemotBridgeStpPortPriority:
1221165253Ssyrinx			if (val->v.integer < 0 || val->v.integer > 255)
1222165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1223165253Ssyrinx
1224164410Ssyrinx			ctx->scratch->int1 = bp->priority;
1225165253Ssyrinx			if (bridge_port_set_priority(b_name, bp,
1226165253Ssyrinx			    val->v.integer) < 0)
1227165253Ssyrinx			    return (SNMP_ERR_GENERR);
1228165253Ssyrinx			return (SNMP_ERR_NOERROR);
1229165253Ssyrinx
1230164410Ssyrinx		    case LEAF_begemotBridgeStpPortEnable:
1231165253Ssyrinx			if (val->v.integer !=
1232357520Sdim			    (int32_t)begemotBridgeStpPortEnable_enabled ||
1233165253Ssyrinx			    val->v.integer !=
1234357520Sdim			    (int32_t)begemotBridgeStpPortEnable_disabled)
1235165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1236165253Ssyrinx
1237164410Ssyrinx			ctx->scratch->int1 = bp->enable;
1238165253Ssyrinx			if (bridge_port_set_stp_enable(b_name, bp,
1239165253Ssyrinx			    val->v.integer) < 0)
1240165253Ssyrinx			    return (SNMP_ERR_GENERR);
1241165253Ssyrinx			return (SNMP_ERR_NOERROR);
1242165253Ssyrinx
1243164410Ssyrinx		    case LEAF_begemotBridgeStpPortPathCost:
1244165253Ssyrinx			if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
1245165253Ssyrinx			    val->v.integer > SNMP_PORT_MAX_PATHCOST)
1246165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1247165253Ssyrinx
1248164410Ssyrinx			ctx->scratch->int1 = bp->path_cost;
1249165253Ssyrinx			if (bridge_port_set_path_cost(b_name, bp,
1250165253Ssyrinx			    val->v.integer) < 0)
1251165253Ssyrinx			    return (SNMP_ERR_GENERR);
1252165253Ssyrinx			return (SNMP_ERR_NOERROR);
1253165253Ssyrinx
1254164410Ssyrinx		    case LEAF_begemotBridgeStpPort:
1255164410Ssyrinx		    case LEAF_begemotBridgeStpPortState:
1256164410Ssyrinx		    case LEAF_begemotBridgeStpPortDesignatedRoot:
1257164410Ssyrinx		    case LEAF_begemotBridgeStpPortDesignatedCost:
1258164410Ssyrinx		    case LEAF_begemotBridgeStpPortDesignatedBridge:
1259164410Ssyrinx		    case LEAF_begemotBridgeStpPortDesignatedPort:
1260164410Ssyrinx		    case LEAF_begemotBridgeStpPortForwardTransitions:
1261164410Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
1262164410Ssyrinx		}
1263165253Ssyrinx		abort();
1264164410Ssyrinx
1265164410Ssyrinx	    case SNMP_OP_ROLLBACK:
1266164410Ssyrinx		if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
1267164410Ssyrinx		    (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1268164410Ssyrinx			return (SNMP_ERR_GENERR);
1269164410Ssyrinx
1270164410Ssyrinx		switch (val->var.subs[sub - 1]) {
1271164410Ssyrinx		    case LEAF_begemotBridgeStpPortPriority:
1272164410Ssyrinx			bridge_port_set_priority(b_name, bp,
1273164410Ssyrinx			    ctx->scratch->int1);
1274164410Ssyrinx			break;
1275164410Ssyrinx		    case LEAF_begemotBridgeStpPortEnable:
1276164410Ssyrinx			bridge_port_set_stp_enable(b_name, bp,
1277164410Ssyrinx			    ctx->scratch->int1);
1278164410Ssyrinx			break;
1279164410Ssyrinx		    case LEAF_begemotBridgeStpPortPathCost:
1280164410Ssyrinx			bridge_port_set_path_cost(b_name, bp,
1281164410Ssyrinx			    ctx->scratch->int1);
1282164410Ssyrinx			break;
1283164410Ssyrinx		}
1284164410Ssyrinx		return (SNMP_ERR_NOERROR);
1285164410Ssyrinx
1286164410Ssyrinx	    case SNMP_OP_COMMIT:
1287164410Ssyrinx		return (SNMP_ERR_NOERROR);
1288164410Ssyrinx	}
1289165253Ssyrinx	abort();
1290164410Ssyrinx
1291165253Ssyrinxget:
1292164410Ssyrinx	switch (val->var.subs[sub - 1]) {
1293164410Ssyrinx	    case LEAF_begemotBridgeStpPort:
1294164410Ssyrinx		val->v.integer = bp->port_no;
1295165253Ssyrinx		return (SNMP_ERR_NOERROR);
1296165253Ssyrinx
1297164410Ssyrinx	    case LEAF_begemotBridgeStpPortPriority:
1298164410Ssyrinx		val->v.integer = bp->priority;
1299165253Ssyrinx		return (SNMP_ERR_NOERROR);
1300165253Ssyrinx
1301164410Ssyrinx	    case LEAF_begemotBridgeStpPortState:
1302164410Ssyrinx		val->v.integer = bp->state;
1303165253Ssyrinx		return (SNMP_ERR_NOERROR);
1304165253Ssyrinx
1305164410Ssyrinx	    case LEAF_begemotBridgeStpPortEnable:
1306164410Ssyrinx		val->v.integer = bp->enable;
1307165253Ssyrinx		return (SNMP_ERR_NOERROR);
1308165253Ssyrinx
1309164410Ssyrinx	    case LEAF_begemotBridgeStpPortPathCost:
1310164410Ssyrinx		val->v.integer = bp->path_cost;
1311165253Ssyrinx		return (SNMP_ERR_NOERROR);
1312165253Ssyrinx
1313164410Ssyrinx	    case LEAF_begemotBridgeStpPortDesignatedRoot:
1314165253Ssyrinx		return (string_get(val, bp->design_root, SNMP_BRIDGE_ID_LEN));
1315165253Ssyrinx
1316164410Ssyrinx	    case LEAF_begemotBridgeStpPortDesignatedCost:
1317164410Ssyrinx		val->v.integer = bp->design_cost;
1318165253Ssyrinx		return (SNMP_ERR_NOERROR);
1319165253Ssyrinx
1320164410Ssyrinx	    case LEAF_begemotBridgeStpPortDesignatedBridge:
1321165253Ssyrinx		return (string_get(val, bp->design_bridge, SNMP_BRIDGE_ID_LEN));
1322165253Ssyrinx
1323164410Ssyrinx	    case LEAF_begemotBridgeStpPortDesignatedPort:
1324165253Ssyrinx		return (string_get(val, bp->design_port, 2));
1325165253Ssyrinx
1326164410Ssyrinx	    case LEAF_begemotBridgeStpPortForwardTransitions:
1327164410Ssyrinx		val->v.uint32 = bp->fwd_trans;
1328165253Ssyrinx		return (SNMP_ERR_NOERROR);
1329164410Ssyrinx	}
1330164410Ssyrinx
1331165253Ssyrinx	abort();
1332164410Ssyrinx}
1333164410Ssyrinx
1334164410Ssyrinxint
1335164997Ssyrinxop_begemot_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val,
1336164997Ssyrinx    uint sub, uint iidx __unused, enum snmp_op op)
1337164997Ssyrinx{
1338165046Ssyrinx	struct bridge_port *bp;
1339164997Ssyrinx	const char *b_name;
1340164997Ssyrinx
1341164997Ssyrinx	if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1342164997Ssyrinx		bridge_update_all_ports();
1343164997Ssyrinx
1344164997Ssyrinx	switch (op) {
1345164997Ssyrinx	    case SNMP_OP_GET:
1346164997Ssyrinx		if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1347164997Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1348165253Ssyrinx		goto get;
1349164997Ssyrinx
1350164997Ssyrinx	    case SNMP_OP_GETNEXT:
1351164997Ssyrinx		if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1352164997Ssyrinx		    NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1353164997Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
1354165253Ssyrinx		goto get;
1355164997Ssyrinx
1356164997Ssyrinx	    case SNMP_OP_SET:
1357164997Ssyrinx		if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1358164997Ssyrinx			return (SNMP_ERR_NOSUCHNAME);
1359164997Ssyrinx		if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1360164997Ssyrinx			return (SNMP_ERR_GENERR);
1361164997Ssyrinx
1362164997Ssyrinx		switch (val->var.subs[sub - 1]) {
1363164997Ssyrinx		    case LEAF_begemotBridgeStpPortAdminEdgePort:
1364165253Ssyrinx			if (val->v.integer != TruthValue_true &&
1365165253Ssyrinx			    val->v.integer != TruthValue_false)
1366165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1367165253Ssyrinx
1368164997Ssyrinx			ctx->scratch->int1 = bp->admin_edge;
1369165253Ssyrinx			if (bridge_port_set_admin_edge(b_name, bp,
1370165253Ssyrinx			    val->v.integer) < 0)
1371165253Ssyrinx			    return (SNMP_ERR_GENERR);
1372165253Ssyrinx			return (SNMP_ERR_NOERROR);
1373165253Ssyrinx
1374164997Ssyrinx		    case LEAF_begemotBridgeStpPortAdminPointToPoint:
1375165253Ssyrinx			if (val->v.integer < 0 || val->v.integer >
1376165253Ssyrinx			    StpPortAdminPointToPointType_auto)
1377165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1378165253Ssyrinx
1379165416Ssyrinx			ctx->scratch->int1 = bp->admin_ptp;
1380165416Ssyrinx			if (bridge_port_set_admin_ptp(b_name, bp,
1381165253Ssyrinx			    val->v.integer) < 0)
1382165253Ssyrinx			    return (SNMP_ERR_GENERR);
1383165253Ssyrinx			return (SNMP_ERR_NOERROR);
1384165253Ssyrinx
1385164997Ssyrinx		    case LEAF_begemotBridgeStpPortAdminPathCost:
1386165253Ssyrinx			if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
1387165253Ssyrinx			    val->v.integer > SNMP_PORT_MAX_PATHCOST)
1388165253Ssyrinx			    return (SNMP_ERR_WRONG_VALUE);
1389165253Ssyrinx
1390164997Ssyrinx			ctx->scratch->int1 = bp->admin_path_cost;
1391165253Ssyrinx			if (bridge_port_set_path_cost(b_name, bp,
1392165253Ssyrinx			    val->v.integer) < 0)
1393165253Ssyrinx			    return (SNMP_ERR_GENERR);
1394165253Ssyrinx			return (SNMP_ERR_NOERROR);
1395165253Ssyrinx
1396164997Ssyrinx		    case LEAF_begemotBridgeStpPortProtocolMigration:
1397164997Ssyrinx		    case LEAF_begemotBridgeStpPortOperEdgePort:
1398164997Ssyrinx		    case LEAF_begemotBridgeStpPortOperPointToPoint:
1399164997Ssyrinx			return (SNMP_ERR_NOT_WRITEABLE);
1400164997Ssyrinx		}
1401165253Ssyrinx		abort();
1402164997Ssyrinx
1403164997Ssyrinx	    case SNMP_OP_ROLLBACK:
1404164997Ssyrinx		if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
1405164997Ssyrinx		    (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1406164997Ssyrinx			return (SNMP_ERR_GENERR);
1407164997Ssyrinx
1408164997Ssyrinx		switch (val->var.subs[sub - 1]) {
1409164997Ssyrinx		    case LEAF_begemotBridgeStpPortAdminEdgePort:
1410164997Ssyrinx			bridge_port_set_admin_edge(b_name, bp,
1411164997Ssyrinx			    ctx->scratch->int1);
1412164997Ssyrinx			break;
1413164997Ssyrinx		    case LEAF_begemotBridgeStpPortAdminPointToPoint:
1414165416Ssyrinx			bridge_port_set_admin_ptp(b_name, bp,
1415164997Ssyrinx			    ctx->scratch->int1);
1416164997Ssyrinx			break;
1417164997Ssyrinx		    case LEAF_begemotBridgeStpPortAdminPathCost:
1418164997Ssyrinx			bridge_port_set_path_cost(b_name, bp,
1419164997Ssyrinx			    ctx->scratch->int1);
1420164997Ssyrinx			break;
1421164997Ssyrinx		}
1422164997Ssyrinx		return (SNMP_ERR_NOERROR);
1423164997Ssyrinx
1424164997Ssyrinx	    case SNMP_OP_COMMIT:
1425164997Ssyrinx		return (SNMP_ERR_NOERROR);
1426164997Ssyrinx	}
1427165253Ssyrinx	abort();
1428164997Ssyrinx
1429165253Ssyrinxget:
1430164997Ssyrinx	switch (val->var.subs[sub - 1]) {
1431164997Ssyrinx		case LEAF_begemotBridgeStpPortProtocolMigration:
1432164997Ssyrinx			val->v.integer = bp->proto_migr;
1433165253Ssyrinx			return (SNMP_ERR_NOERROR);
1434165253Ssyrinx
1435164997Ssyrinx		case LEAF_begemotBridgeStpPortAdminEdgePort:
1436164997Ssyrinx			val->v.integer = bp->admin_edge;
1437165253Ssyrinx			return (SNMP_ERR_NOERROR);
1438165253Ssyrinx
1439164997Ssyrinx		case LEAF_begemotBridgeStpPortOperEdgePort:
1440164997Ssyrinx			val->v.integer = bp->oper_edge;
1441165253Ssyrinx			return (SNMP_ERR_NOERROR);
1442165253Ssyrinx
1443164997Ssyrinx		case LEAF_begemotBridgeStpPortAdminPointToPoint:
1444165416Ssyrinx			val->v.integer = bp->admin_ptp;
1445165253Ssyrinx			return (SNMP_ERR_NOERROR);
1446165253Ssyrinx
1447164997Ssyrinx		case LEAF_begemotBridgeStpPortOperPointToPoint:
1448165416Ssyrinx			val->v.integer = bp->oper_ptp;
1449165253Ssyrinx			return (SNMP_ERR_NOERROR);
1450165253Ssyrinx
1451164997Ssyrinx		case LEAF_begemotBridgeStpPortAdminPathCost:
1452164997Ssyrinx			val->v.integer = bp->admin_path_cost;
1453165253Ssyrinx			return (SNMP_ERR_NOERROR);
1454164997Ssyrinx	}
1455164997Ssyrinx
1456165253Ssyrinx	abort();
1457164997Ssyrinx}
1458164997Ssyrinx
1459164997Ssyrinxint
1460164410Ssyrinxop_begemot_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
1461164410Ssyrinx	uint sub, uint iidx __unused, enum snmp_op op)
1462164410Ssyrinx{
1463165046Ssyrinx	struct bridge_port *bp;
1464164410Ssyrinx
1465164410Ssyrinx	if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1466164410Ssyrinx		bridge_update_all_ports();
1467164410Ssyrinx
1468164410Ssyrinx	switch (op) {
1469164410Ssyrinx	    case SNMP_OP_GET:
1470164410Ssyrinx		if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1471164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1472165253Ssyrinx		goto get;
1473164410Ssyrinx
1474164410Ssyrinx	    case SNMP_OP_GETNEXT:
1475164410Ssyrinx		if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1476164410Ssyrinx		    NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1477164410Ssyrinx		    return (SNMP_ERR_NOSUCHNAME);
1478165253Ssyrinx		goto get;
1479164410Ssyrinx
1480164410Ssyrinx	    case SNMP_OP_SET:
1481164410Ssyrinx		return (SNMP_ERR_NOT_WRITEABLE);
1482164410Ssyrinx
1483164410Ssyrinx	    case SNMP_OP_ROLLBACK:
1484164410Ssyrinx	    case SNMP_OP_COMMIT:
1485165253Ssyrinx		break;
1486164410Ssyrinx	}
1487165253Ssyrinx	abort();
1488164410Ssyrinx
1489165253Ssyrinxget:
1490164410Ssyrinx	switch (val->var.subs[sub - 1]) {
1491164410Ssyrinx	    case LEAF_begemotBridgeTpPort:
1492164410Ssyrinx		val->v.integer = bp->port_no;
1493165253Ssyrinx		return (SNMP_ERR_NOERROR);
1494165253Ssyrinx
1495164410Ssyrinx	    case LEAF_begemotBridgeTpPortMaxInfo:
1496164410Ssyrinx		val->v.integer = bp->max_info;
1497165253Ssyrinx		return (SNMP_ERR_NOERROR);
1498165253Ssyrinx
1499164410Ssyrinx	    case LEAF_begemotBridgeTpPortInFrames:
1500164410Ssyrinx		val->v.uint32 = bp->in_frames;
1501165253Ssyrinx		return (SNMP_ERR_NOERROR);
1502165253Ssyrinx
1503164410Ssyrinx	    case LEAF_begemotBridgeTpPortOutFrames:
1504164410Ssyrinx		val->v.uint32 = bp->out_frames;
1505165253Ssyrinx		return (SNMP_ERR_NOERROR);
1506165253Ssyrinx
1507164410Ssyrinx	    case LEAF_begemotBridgeTpPortInDiscards:
1508164410Ssyrinx		val->v.uint32 = bp->in_drops;
1509165253Ssyrinx		return (SNMP_ERR_NOERROR);
1510164410Ssyrinx	}
1511164410Ssyrinx
1512165253Ssyrinx	abort();
1513164410Ssyrinx}
1514