]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bsnmpd/modules/snmp_bridge/bridge_port.c
MFV r361322:
[FreeBSD/FreeBSD.git] / usr.sbin / bsnmpd / modules / snmp_bridge / bridge_port.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * Bridge MIB implementation for SNMPd.
29  * Bridge ports.
30  *
31  * $FreeBSD$
32  */
33
34 #include <sys/queue.h>
35 #include <sys/socket.h>
36 #include <sys/types.h>
37
38 #include <net/ethernet.h>
39 #include <net/if.h>
40 #include <net/if_mib.h>
41
42 #include <assert.h>
43 #include <errno.h>
44 #include <stdarg.h>
45 #include <string.h>
46 #include <stdlib.h>
47 #include <syslog.h>
48
49 #include <bsnmp/snmpmod.h>
50 #include <bsnmp/snmp_mibII.h>
51
52 #define SNMPTREE_TYPES
53 #include "bridge_tree.h"
54 #include "bridge_snmp.h"
55
56 TAILQ_HEAD(bridge_ports, bridge_port);
57
58 /*
59  * Free the bridge base ports list.
60  */
61 static void
62 bridge_ports_free(struct bridge_ports *headp)
63 {
64         struct bridge_port *bp;
65
66         while ((bp = TAILQ_FIRST(headp)) != NULL) {
67                 TAILQ_REMOVE(headp, bp, b_p);
68                 free(bp);
69         }
70 }
71
72 /*
73  * Free the bridge base ports from the base ports list,
74  * members of a specified bridge interface only.
75  */
76 static void
77 bridge_port_memif_free(struct bridge_ports *headp,
78         struct bridge_if *bif)
79 {
80         struct bridge_port *bp;
81
82         while (bif->f_bp != NULL && bif->sysindex == bif->f_bp->sysindex) {
83                 bp = TAILQ_NEXT(bif->f_bp, b_p);
84                 TAILQ_REMOVE(headp, bif->f_bp, b_p);
85                 free(bif->f_bp);
86                 bif->f_bp = bp;
87         }
88 }
89
90 /*
91  * Insert a port entry in the base port TAILQ starting to search
92  * for its place from the position of the first bridge port for the bridge
93  * interface. Update the first bridge port if necessary.
94  */
95 static void
96 bridge_port_insert_at(struct bridge_ports *headp,
97         struct bridge_port *bp, struct bridge_port **f_bp)
98 {
99         struct bridge_port *t1;
100
101         assert(f_bp != NULL);
102
103         for (t1 = *f_bp;
104             t1 != NULL && bp->sysindex == t1->sysindex;
105             t1 = TAILQ_NEXT(t1, b_p)) {
106                 if (bp->if_idx < t1->if_idx) {
107                         TAILQ_INSERT_BEFORE(t1, bp, b_p);
108                         if (*f_bp == t1)
109                                 *f_bp = bp;
110                         return;
111                 }
112         }
113
114         /*
115          * Handle the case when our first port was actually the
116          * last element of the TAILQ.
117          */
118         if (t1 == NULL)
119                 TAILQ_INSERT_TAIL(headp, bp, b_p);
120         else
121                 TAILQ_INSERT_BEFORE(t1, bp, b_p);
122 }
123
124 /*
125  * Find a port entry's position in the ports list according
126  * to it's parent bridge interface name. Returns a NULL if
127  * we should be at the TAILQ head, otherwise the entry after
128  * which we should be inserted.
129  */
130 static struct bridge_port *
131 bridge_port_find_pos(struct bridge_ports *headp, uint32_t b_idx)
132 {
133         uint32_t t_idx;
134         struct bridge_port *t1;
135
136         if ((t1 = TAILQ_FIRST(headp)) == NULL ||
137             bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
138                 return (NULL);
139
140         t_idx = t1->sysindex;
141
142         for (t1 = TAILQ_NEXT(t1, b_p); t1 != NULL; t1 = TAILQ_NEXT(t1, b_p)) {
143                 if (t1->sysindex != t_idx) {
144                         if (bridge_compare_sysidx(b_idx, t1->sysindex) < 0)
145                                 return (TAILQ_PREV(t1, bridge_ports, b_p));
146                         else
147                                 t_idx = t1->sysindex;
148                 }
149         }
150
151         if (t1 == NULL)
152                 t1 = TAILQ_LAST(headp, bridge_ports);
153
154         return (t1);
155 }
156
157 /*
158  * Insert a bridge member interface in the ports TAILQ.
159  */
160 static void
161 bridge_port_memif_insert(struct bridge_ports *headp,
162         struct bridge_port *bp, struct bridge_port **f_bp)
163 {
164         struct bridge_port *temp;
165
166         if (*f_bp != NULL)
167                 bridge_port_insert_at(headp, bp, f_bp);
168         else {
169                 temp = bridge_port_find_pos(headp, bp->sysindex);
170
171                 if (temp == NULL)
172                         TAILQ_INSERT_HEAD(headp, bp, b_p);
173                 else
174                         TAILQ_INSERT_AFTER(headp, temp, bp, b_p);
175                 *f_bp = bp;
176         }
177 }
178
179 /* The global ports list. */
180 static struct bridge_ports bridge_ports = TAILQ_HEAD_INITIALIZER(bridge_ports);
181 static time_t ports_list_age;
182
183 void
184 bridge_ports_update_listage(void)
185 {
186         ports_list_age = time(NULL);
187 }
188
189 void
190 bridge_ports_fini(void)
191 {
192         bridge_ports_free(&bridge_ports);
193 }
194
195 void
196 bridge_members_free(struct bridge_if *bif)
197 {
198         bridge_port_memif_free(&bridge_ports, bif);
199 }
200
201 /*
202  * Find the first port in the ports list.
203  */
204 static struct bridge_port *
205 bridge_port_first(void)
206 {
207         return (TAILQ_FIRST(&bridge_ports));
208 }
209
210 /*
211  * Find the next port in the ports list.
212  */
213 static struct bridge_port *
214 bridge_port_next(struct bridge_port *bp)
215 {
216         return (TAILQ_NEXT(bp, b_p));
217 }
218
219 /*
220  * Find the first member of the specified bridge interface.
221  */
222 struct bridge_port *
223 bridge_port_bif_first(struct bridge_if *bif)
224 {
225         return (bif->f_bp);
226 }
227
228 /*
229  * Find the next member of the specified bridge interface.
230  */
231 struct bridge_port *
232 bridge_port_bif_next(struct bridge_port *bp)
233 {
234         struct bridge_port *bp_next;
235
236         if ((bp_next = TAILQ_NEXT(bp, b_p)) == NULL ||
237             bp_next->sysindex != bp->sysindex)
238                 return (NULL);
239
240         return (bp_next);
241 }
242
243 /*
244  * Remove a bridge port from the ports list.
245  */
246 void
247 bridge_port_remove(struct bridge_port *bp, struct bridge_if *bif)
248 {
249         if (bif->f_bp == bp)
250                 bif->f_bp = bridge_port_bif_next(bp);
251
252         TAILQ_REMOVE(&bridge_ports, bp, b_p);
253         free(bp);
254 }
255
256 /*
257  * Allocate memory for a new bridge port and insert it
258  * in the base ports list. Return a pointer to the port's
259  * structure in case we want to do anything else with it.
260  */
261 struct bridge_port *
262 bridge_new_port(struct mibif *mif, struct bridge_if *bif)
263 {
264         struct bridge_port *bp;
265
266         if ((bp = (struct bridge_port *) malloc(sizeof(*bp))) == NULL) {
267                 syslog(LOG_ERR, "bridge new member: failed: %s",
268                         strerror(errno));
269                 return (NULL);
270         }
271
272         bzero(bp, sizeof(*bp));
273
274         bp->sysindex = bif->sysindex;
275         bp->if_idx = mif->index;
276         bp->port_no = mif->sysindex;
277         strlcpy(bp->p_name, mif->name, IFNAMSIZ);
278         bp->circuit = oid_zeroDotZero;
279
280         /*
281          * Initialize all rstpMib specific values to false/default.
282          * These will be set to their true values later if the bridge
283          * supports RSTP.
284          */
285         bp->proto_migr = TruthValue_false;
286         bp->admin_edge = TruthValue_false;
287         bp->oper_edge = TruthValue_false;
288         bp->oper_ptp = TruthValue_false;
289         bp->admin_ptp = StpPortAdminPointToPointType_auto;
290
291         bridge_port_memif_insert(&bridge_ports, bp, &(bif->f_bp));
292
293         return (bp);
294 }
295
296 /*
297  * Update our info from the corresponding mibII interface info.
298  */
299 void
300 bridge_port_getinfo_mibif(struct mibif *m_if, struct bridge_port *bp)
301 {
302         bp->max_info = m_if->mib.ifmd_data.ifi_mtu;
303         bp->in_frames = m_if->mib.ifmd_data.ifi_ipackets;
304         bp->out_frames = m_if->mib.ifmd_data.ifi_opackets;
305         bp->in_drops = m_if->mib.ifmd_data.ifi_iqdrops;
306 }
307
308 /*
309  * Find a port, whose SNMP's mibII ifIndex matches one of the ports,
310  * members of the specified bridge interface.
311  */
312 struct bridge_port *
313 bridge_port_find(int32_t if_idx, struct bridge_if *bif)
314 {
315         struct bridge_port *bp;
316
317         for (bp = bif->f_bp; bp != NULL; bp = TAILQ_NEXT(bp, b_p)) {
318                 if (bp->sysindex != bif->sysindex) {
319                         bp = NULL;
320                         break;
321                 }
322
323                 if (bp->if_idx == if_idx)
324                         break;
325         }
326
327         return (bp);
328 }
329
330 void
331 bridge_ports_dump(struct bridge_if *bif)
332 {
333         struct bridge_port *bp;
334
335         for (bp = bridge_port_bif_first(bif); bp != NULL;
336             bp = bridge_port_bif_next(bp)) {
337                 syslog(LOG_ERR, "memif - %s, index - %d",
338                 bp->p_name, bp->port_no);
339         }
340 }
341
342 /*
343  * RFC4188 specifics.
344  */
345 int
346 op_dot1d_base_port(struct snmp_context *c __unused, struct snmp_value *val,
347         uint sub, uint iidx __unused, enum snmp_op op)
348 {
349         struct bridge_if *bif;
350         struct bridge_port *bp;
351
352         if ((bif = bridge_get_default()) == NULL)
353                 return (SNMP_ERR_NOSUCHNAME);
354
355         if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
356             bridge_update_memif(bif) <= 0)
357                 return (SNMP_ERR_NOSUCHNAME);
358
359         switch (op) {
360                 case SNMP_OP_GET:
361                     if (val->var.len - sub != 1)
362                         return (SNMP_ERR_NOSUCHNAME);
363                     if ((bp = bridge_port_find(val->var.subs[sub],
364                         bif)) == NULL)
365                             return (SNMP_ERR_NOSUCHNAME);
366                     goto get;
367
368                 case SNMP_OP_GETNEXT:
369                     if (val->var.len - sub == 0) {
370                         if ((bp = bridge_port_bif_first(bif)) == NULL)
371                             return (SNMP_ERR_NOSUCHNAME);
372                     } else {
373                         if ((bp = bridge_port_find(val->var.subs[sub],
374                             bif)) == NULL ||
375                             (bp = bridge_port_bif_next(bp)) == NULL)
376                                 return (SNMP_ERR_NOSUCHNAME);
377                     }
378                     val->var.len = sub + 1;
379                     val->var.subs[sub] = bp->port_no;
380                     goto get;
381
382                 case SNMP_OP_SET:
383                     return (SNMP_ERR_NOT_WRITEABLE);
384
385                 case SNMP_OP_ROLLBACK:
386                 case SNMP_OP_COMMIT:
387                     break;
388         }
389         abort();
390
391 get:
392         switch (val->var.subs[sub - 1]) {
393             case LEAF_dot1dBasePort:
394                 val->v.integer = bp->port_no;
395                 return (SNMP_ERR_NOERROR);
396
397             case LEAF_dot1dBasePortIfIndex:
398                 val->v.integer = bp->if_idx;
399                 return (SNMP_ERR_NOERROR);
400
401             case LEAF_dot1dBasePortCircuit:
402                 val->v.oid = bp->circuit;
403                 return (SNMP_ERR_NOERROR);
404
405             case LEAF_dot1dBasePortDelayExceededDiscards:
406                 val->v.uint32 = bp->dly_ex_drops;
407                 return (SNMP_ERR_NOERROR);
408
409             case LEAF_dot1dBasePortMtuExceededDiscards:
410                 val->v.uint32 = bp->dly_mtu_drops;
411                 return (SNMP_ERR_NOERROR);
412         }
413
414         abort();
415 }
416
417 int
418 op_dot1d_stp_port(struct snmp_context *ctx, struct snmp_value *val,
419          uint sub, uint iidx __unused, enum snmp_op op)
420 {
421         struct bridge_if *bif;
422         struct bridge_port *bp;
423
424         if ((bif = bridge_get_default()) == NULL)
425                 return (SNMP_ERR_NOSUCHNAME);
426
427         if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
428             bridge_update_memif(bif) <= 0)
429                 return (SNMP_ERR_NOSUCHNAME);
430
431         switch (op) {
432                 case SNMP_OP_GET:
433                     if (val->var.len - sub != 1)
434                         return (SNMP_ERR_NOSUCHNAME);
435                     if ((bp = bridge_port_find(val->var.subs[sub],
436                         bif)) == NULL)
437                             return (SNMP_ERR_NOSUCHNAME);
438                     goto get;
439
440                 case SNMP_OP_GETNEXT:
441                     if (val->var.len - sub == 0) {
442                         if ((bp = bridge_port_bif_first(bif)) == NULL)
443                             return (SNMP_ERR_NOSUCHNAME);
444                     } else {
445                         if ((bp = bridge_port_find(val->var.subs[sub],
446                             bif)) == NULL ||
447                             (bp = bridge_port_bif_next(bp)) == NULL)
448                                 return (SNMP_ERR_NOSUCHNAME);
449                     }
450                     val->var.len = sub + 1;
451                     val->var.subs[sub] = bp->port_no;
452                     goto get;
453
454                 case SNMP_OP_SET:
455                     if (val->var.len - sub != 1)
456                         return (SNMP_ERR_NOSUCHNAME);
457                     if ((bp = bridge_port_find(val->var.subs[sub],
458                         bif)) == NULL)
459                             return (SNMP_ERR_NOSUCHNAME);
460
461                     switch (val->var.subs[sub - 1]) {
462                         case LEAF_dot1dStpPortPriority:
463                             if (val->v.integer < 0 || val->v.integer > 255)
464                                 return (SNMP_ERR_WRONG_VALUE);
465
466                             ctx->scratch->int1 = bp->priority;
467                             if (bridge_port_set_priority(bif->bif_name, bp,
468                                 val->v.integer) < 0)
469                                 return (SNMP_ERR_GENERR);
470                             return (SNMP_ERR_NOERROR);
471
472                         case LEAF_dot1dStpPortEnable:
473                             if (val->v.integer != dot1dStpPortEnable_enabled &&
474                                 val->v.integer != dot1dStpPortEnable_disabled)
475                                 return (SNMP_ERR_WRONG_VALUE);
476
477                             ctx->scratch->int1 = bp->enable;
478                             if (bridge_port_set_stp_enable(bif->bif_name,
479                                 bp, val->v.integer) < 0)
480                                 return (SNMP_ERR_GENERR);
481                             return (SNMP_ERR_NOERROR);
482
483                         case LEAF_dot1dStpPortPathCost:
484                             if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
485                                 val->v.integer > SNMP_PORT_MAX_PATHCOST)
486                                 return (SNMP_ERR_WRONG_VALUE);
487
488                             ctx->scratch->int1 = bp->path_cost;
489                             if (bridge_port_set_path_cost(bif->bif_name, bp,
490                                 val->v.integer) < 0)
491                                 return (SNMP_ERR_GENERR);
492                             return (SNMP_ERR_NOERROR);
493
494                         case LEAF_dot1dStpPort:
495                         case LEAF_dot1dStpPortState:
496                         case LEAF_dot1dStpPortDesignatedRoot:
497                         case LEAF_dot1dStpPortDesignatedCost:
498                         case LEAF_dot1dStpPortDesignatedBridge:
499                         case LEAF_dot1dStpPortDesignatedPort:
500                         case LEAF_dot1dStpPortForwardTransitions:
501                             return (SNMP_ERR_NOT_WRITEABLE);
502                     }
503                     abort();
504
505                 case SNMP_OP_ROLLBACK:
506                     if ((bp = bridge_port_find(val->var.subs[sub],
507                         bif)) == NULL)
508                             return (SNMP_ERR_GENERR);
509                     switch (val->var.subs[sub - 1]) {
510                         case LEAF_dot1dStpPortPriority:
511                             bridge_port_set_priority(bif->bif_name, bp,
512                                 ctx->scratch->int1);
513                             break;
514                         case LEAF_dot1dStpPortEnable:
515                             bridge_port_set_stp_enable(bif->bif_name, bp,
516                                 ctx->scratch->int1);
517                             break;
518                         case LEAF_dot1dStpPortPathCost:
519                             bridge_port_set_path_cost(bif->bif_name, bp,
520                                 ctx->scratch->int1);
521                             break;
522                     }
523                     return (SNMP_ERR_NOERROR);
524
525                 case SNMP_OP_COMMIT:
526                     return (SNMP_ERR_NOERROR);
527         }
528         abort();
529
530 get:
531         switch (val->var.subs[sub - 1]) {
532                 case LEAF_dot1dStpPort:
533                         val->v.integer = bp->port_no;
534                         return (SNMP_ERR_NOERROR);
535
536                 case LEAF_dot1dStpPortPriority:
537                         val->v.integer = bp->priority;
538                         return (SNMP_ERR_NOERROR);
539
540                 case LEAF_dot1dStpPortState:
541                         val->v.integer = bp->state;
542                         return (SNMP_ERR_NOERROR);
543
544                 case LEAF_dot1dStpPortEnable:
545                         val->v.integer = bp->enable;
546                         return (SNMP_ERR_NOERROR);
547
548                 case LEAF_dot1dStpPortPathCost:
549                         val->v.integer = bp->path_cost;
550                         return (SNMP_ERR_NOERROR);
551
552                 case LEAF_dot1dStpPortDesignatedRoot:
553                         return (string_get(val, bp->design_root,
554                             SNMP_BRIDGE_ID_LEN));
555
556                 case LEAF_dot1dStpPortDesignatedCost:
557                         val->v.integer = bp->design_cost;
558                         return (SNMP_ERR_NOERROR);
559
560                 case LEAF_dot1dStpPortDesignatedBridge:
561                         return (string_get(val, bp->design_bridge,
562                             SNMP_BRIDGE_ID_LEN));
563
564                 case LEAF_dot1dStpPortDesignatedPort:
565                         return (string_get(val, bp->design_port, 2));
566
567                 case LEAF_dot1dStpPortForwardTransitions:
568                         val->v.uint32 = bp->fwd_trans;
569                         return (SNMP_ERR_NOERROR);
570         }
571
572         abort();
573 }
574
575 int
576 op_dot1d_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val,
577     uint sub, uint iidx __unused, enum snmp_op op)
578 {
579         struct bridge_if *bif;
580         struct bridge_port *bp;
581
582         if ((bif = bridge_get_default()) == NULL)
583                 return (SNMP_ERR_NOSUCHNAME);
584
585         if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
586             bridge_update_memif(bif) <= 0)
587                 return (SNMP_ERR_NOSUCHNAME);
588
589         switch (op) {
590                 case SNMP_OP_GET:
591                     if (val->var.len - sub != 1)
592                         return (SNMP_ERR_NOSUCHNAME);
593                     if ((bp = bridge_port_find(val->var.subs[sub],
594                         bif)) == NULL)
595                             return (SNMP_ERR_NOSUCHNAME);
596                     goto get;
597
598                 case SNMP_OP_GETNEXT:
599                     if (val->var.len - sub == 0) {
600                         if ((bp = bridge_port_bif_first(bif)) == NULL)
601                             return (SNMP_ERR_NOSUCHNAME);
602                     } else {
603                         if ((bp = bridge_port_find(val->var.subs[sub],
604                             bif)) == NULL ||
605                             (bp = bridge_port_bif_next(bp)) == NULL)
606                                 return (SNMP_ERR_NOSUCHNAME);
607                     }
608                     val->var.len = sub + 1;
609                     val->var.subs[sub] = bp->port_no;
610                     goto get;
611
612                 case SNMP_OP_SET:
613                     if (val->var.len - sub != 1)
614                         return (SNMP_ERR_NOSUCHNAME);
615                     if ((bp = bridge_port_find(val->var.subs[sub],
616                         bif)) == NULL)
617                             return (SNMP_ERR_NOSUCHNAME);
618
619                     switch (val->var.subs[sub - 1]) {
620                         case LEAF_dot1dStpPortAdminEdgePort:
621                             if (val->v.integer != TruthValue_true &&
622                                 val->v.integer != TruthValue_false)
623                                 return (SNMP_ERR_WRONG_VALUE);
624
625                             ctx->scratch->int1 = bp->admin_edge;
626                             if (bridge_port_set_admin_edge(bif->bif_name, bp,
627                                 val->v.integer) < 0)
628                                 return (SNMP_ERR_GENERR);
629                             return (SNMP_ERR_NOERROR);
630
631                         case LEAF_dot1dStpPortAdminPointToPoint:
632                             if (val->v.integer < 0 || val->v.integer >
633                                 StpPortAdminPointToPointType_auto)
634                                 return (SNMP_ERR_WRONG_VALUE);
635
636                             ctx->scratch->int1 = bp->admin_ptp;
637                             if (bridge_port_set_admin_ptp(bif->bif_name, bp,
638                                 val->v.integer) < 0)
639                                 return (SNMP_ERR_GENERR);
640                             return (SNMP_ERR_NOERROR);
641
642                         case LEAF_dot1dStpPortAdminPathCost:
643                             if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
644                                 val->v.integer > SNMP_PORT_MAX_PATHCOST)
645                                 return (SNMP_ERR_WRONG_VALUE);
646
647                             ctx->scratch->int1 = bp->admin_path_cost;
648                             if (bridge_port_set_path_cost(bif->bif_name, bp,
649                                 val->v.integer) < 0)
650                                 return (SNMP_ERR_GENERR);
651                             return (SNMP_ERR_NOERROR);
652
653                         case LEAF_dot1dStpPortProtocolMigration:
654                         case LEAF_dot1dStpPortOperEdgePort:
655                         case LEAF_dot1dStpPortOperPointToPoint:
656                             return (SNMP_ERR_NOT_WRITEABLE);
657                     }
658                     abort();
659
660                 case SNMP_OP_ROLLBACK:
661                     if ((bp = bridge_port_find(val->var.subs[sub],
662                         bif)) == NULL)
663                             return (SNMP_ERR_GENERR);
664
665                     switch (val->var.subs[sub - 1]) {
666                         case LEAF_dot1dStpPortAdminEdgePort:
667                             bridge_port_set_admin_edge(bif->bif_name, bp,
668                                 ctx->scratch->int1);
669                             break;
670                         case LEAF_dot1dStpPortAdminPointToPoint:
671                             bridge_port_set_admin_ptp(bif->bif_name, bp,
672                                 ctx->scratch->int1);
673                             break;
674                         case LEAF_dot1dStpPortAdminPathCost:
675                             bridge_port_set_path_cost(bif->bif_name, bp,
676                                 ctx->scratch->int1);
677                             break;
678                     }
679                     return (SNMP_ERR_NOERROR);
680
681                 case SNMP_OP_COMMIT:
682                     return (SNMP_ERR_NOERROR);
683         }
684         abort();
685
686 get:
687         switch (val->var.subs[sub - 1]) {
688                 case LEAF_dot1dStpPortProtocolMigration:
689                         val->v.integer = bp->proto_migr;
690                         return (SNMP_ERR_NOERROR);
691
692                 case LEAF_dot1dStpPortAdminEdgePort:
693                         val->v.integer = bp->admin_edge;
694                         return (SNMP_ERR_NOERROR);
695
696                 case LEAF_dot1dStpPortOperEdgePort:
697                         val->v.integer = bp->oper_edge;
698                         return (SNMP_ERR_NOERROR);
699
700                 case LEAF_dot1dStpPortAdminPointToPoint:
701                         val->v.integer = bp->admin_ptp;
702                         return (SNMP_ERR_NOERROR);
703
704                 case LEAF_dot1dStpPortOperPointToPoint:
705                         val->v.integer = bp->oper_ptp;
706                         return (SNMP_ERR_NOERROR);
707
708                 case LEAF_dot1dStpPortAdminPathCost:
709                         val->v.integer = bp->admin_path_cost;
710                         return (SNMP_ERR_NOERROR);
711         }
712
713         abort();
714 }
715
716 int
717 op_dot1d_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
718     uint sub, uint iidx __unused, enum snmp_op op)
719 {
720         struct bridge_if *bif;
721         struct bridge_port *bp;
722
723         if ((bif = bridge_get_default()) == NULL)
724                 return (SNMP_ERR_NOSUCHNAME);
725
726         if (time(NULL) - bif->ports_age > bridge_get_data_maxage() &&
727             bridge_update_memif(bif) <= 0)
728                 return (SNMP_ERR_NOSUCHNAME);
729
730         switch (op) {
731                 case SNMP_OP_GET:
732                     if (val->var.len - sub != 1)
733                         return (SNMP_ERR_NOSUCHNAME);
734                     if ((bp = bridge_port_find(val->var.subs[sub],
735                         bif)) == NULL)
736                             return (SNMP_ERR_NOSUCHNAME);
737                     goto get;
738
739                 case SNMP_OP_GETNEXT:
740                     if (val->var.len - sub == 0) {
741                         if ((bp = bridge_port_bif_first(bif)) == NULL)
742                             return (SNMP_ERR_NOSUCHNAME);
743                     } else {
744                         if ((bp = bridge_port_find(val->var.subs[sub],
745                             bif)) == NULL ||
746                             (bp = bridge_port_bif_next(bp)) == NULL)
747                                 return (SNMP_ERR_NOSUCHNAME);
748                     }
749                     val->var.len = sub + 1;
750                     val->var.subs[sub] = bp->port_no;
751                     goto get;
752
753                 case SNMP_OP_SET:
754                     return (SNMP_ERR_NOT_WRITEABLE);
755
756                 case SNMP_OP_ROLLBACK:
757                 case SNMP_OP_COMMIT:
758                     break;
759         }
760         abort();
761
762 get:
763         switch (val->var.subs[sub - 1]) {
764                 case LEAF_dot1dTpPort:
765                         val->v.integer = bp->port_no;
766                         return (SNMP_ERR_NOERROR);
767
768                 case LEAF_dot1dTpPortMaxInfo:
769                         val->v.integer = bp->max_info;
770                         return (SNMP_ERR_NOERROR);
771
772                 case LEAF_dot1dTpPortInFrames:
773                         val->v.uint32 = bp->in_frames;
774                         return (SNMP_ERR_NOERROR);
775
776                 case LEAF_dot1dTpPortOutFrames:
777                         val->v.uint32 = bp->out_frames;
778                         return (SNMP_ERR_NOERROR);
779
780                 case LEAF_dot1dTpPortInDiscards:
781                         val->v.uint32 = bp->in_drops;
782                         return (SNMP_ERR_NOERROR);
783         }
784
785         abort();
786 }
787
788 /*
789  * Private BEGEMOT-BRIDGE-MIB specifics.
790  */
791
792 /*
793  * Construct a bridge port entry index.
794  */
795 static int
796 bridge_port_index_append(struct asn_oid *oid, uint sub,
797         const struct bridge_port *bp)
798 {
799         uint i;
800         const char *b_name;
801
802         if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
803                 return (-1);
804
805         oid->len = sub + strlen(b_name) + 1 + 1;
806         oid->subs[sub] = strlen(b_name);
807
808         for (i = 1; i <= strlen(b_name); i++)
809                 oid->subs[sub + i] = b_name[i - 1];
810
811         oid->subs[sub + i] = bp->port_no;
812
813         return (0);
814 }
815
816 /*
817  * Get the port entry from an entry's index.
818  */
819 static struct bridge_port *
820 bridge_port_index_get(const struct asn_oid *oid, uint sub, int8_t status)
821 {
822         uint i;
823         int32_t port_no;
824         char bif_name[IFNAMSIZ];
825         struct bridge_if *bif;
826         struct bridge_port *bp;
827
828         if (oid->len - sub != oid->subs[sub] + 2 ||
829             oid->subs[sub] >= IFNAMSIZ)
830                 return (NULL);
831
832         for (i = 0; i < oid->subs[sub]; i++)
833                 bif_name[i] = oid->subs[sub + i + 1];
834         bif_name[i] = '\0';
835
836         port_no = oid->subs[sub + i + 1];
837
838         if ((bif = bridge_if_find_ifname(bif_name)) == NULL)
839                 return (NULL);
840
841         if ((bp = bridge_port_find(port_no, bif)) == NULL ||
842             (status == 0 && bp->status != RowStatus_active))
843                 return (NULL);
844
845         return (bp);
846 }
847
848 /*
849  * Get the next port entry from an entry's index.
850  */
851 static struct bridge_port *
852 bridge_port_index_getnext(const struct asn_oid *oid, uint sub, int8_t status)
853 {
854         uint i;
855         int32_t port_no;
856         char bif_name[IFNAMSIZ];
857         struct bridge_if *bif;
858         struct bridge_port *bp;
859
860         if (oid->len - sub == 0)
861                 bp = bridge_port_first();
862         else {
863                 if (oid->len - sub != oid->subs[sub] + 2 ||
864                     oid->subs[sub] >= IFNAMSIZ)
865                         return (NULL);
866
867                 for (i = 0; i < oid->subs[sub]; i++)
868                         bif_name[i] = oid->subs[sub + i + 1];
869                 bif_name[i] = '\0';
870
871                 port_no = oid->subs[sub + i + 1];
872
873                 if ((bif = bridge_if_find_ifname(bif_name)) == NULL ||
874                     (bp = bridge_port_find(port_no, bif)) == NULL)
875                         return (NULL);
876
877                 bp = bridge_port_next(bp);
878         }
879
880         if (status == 1)
881                 return (bp);
882
883         while (bp != NULL) {
884                 if (bp->status == RowStatus_active)
885                         break;
886                 bp = bridge_port_next(bp);
887         }
888
889         return (bp);
890 }
891
892 /*
893  * Read the bridge name and port index from a ASN OID structure.
894  */
895 static int
896 bridge_port_index_decode(const struct asn_oid *oid, uint sub,
897         char *b_name, int32_t *idx)
898 {
899         uint i;
900
901         if (oid->len - sub != oid->subs[sub] + 2 ||
902             oid->subs[sub] >= IFNAMSIZ)
903                 return (-1);
904
905         for (i = 0; i < oid->subs[sub]; i++)
906                 b_name[i] = oid->subs[sub + i + 1];
907         b_name[i] = '\0';
908
909         *idx = oid->subs[sub + i + 1];
910         return (0);
911 }
912
913 static int
914 bridge_port_set_status(struct snmp_context *ctx,
915         struct snmp_value *val, uint sub)
916 {
917         int32_t if_idx;
918         char b_name[IFNAMSIZ];
919         struct bridge_if *bif;
920         struct bridge_port *bp;
921         struct mibif *mif;
922
923         if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
924                 return (SNMP_ERR_INCONS_VALUE);
925
926         if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
927             (mif = mib_find_if(if_idx)) == NULL)
928                 return (SNMP_ERR_INCONS_VALUE);
929
930         bp = bridge_port_find(if_idx, bif);
931
932         switch (val->v.integer) {
933             case RowStatus_active:
934                 if (bp == NULL)
935                     return (SNMP_ERR_INCONS_VALUE);
936
937                 if (bp->span_enable == 0)
938                     return (SNMP_ERR_INCONS_VALUE);
939
940                 ctx->scratch->int1 = bp->status;
941                 bp->status = RowStatus_active;
942                 break;
943
944             case RowStatus_notInService:
945                 if (bp == NULL || bp->span_enable == 0 ||
946                     bp->status == RowStatus_active)
947                         return (SNMP_ERR_INCONS_VALUE);
948
949                 ctx->scratch->int1 = bp->status;
950                 bp->status = RowStatus_notInService;
951
952             case RowStatus_notReady:
953                 /* FALLTHROUGH */
954             case RowStatus_createAndGo:
955                 return (SNMP_ERR_INCONS_VALUE);
956
957             case RowStatus_createAndWait:
958                 if (bp != NULL)
959                     return (SNMP_ERR_INCONS_VALUE);
960
961                 if ((bp = bridge_new_port(mif, bif)) == NULL)
962                         return (SNMP_ERR_GENERR);
963
964                 ctx->scratch->int1 = RowStatus_destroy;
965                 bp->status = RowStatus_notReady;
966                 break;
967
968             case RowStatus_destroy:
969                 if (bp == NULL)
970                     return (SNMP_ERR_INCONS_VALUE);
971
972                 ctx->scratch->int1 = bp->status;
973                 bp->status = RowStatus_destroy;
974                 break;
975         }
976
977         return (SNMP_ERR_NOERROR);
978 }
979
980 static int
981 bridge_port_rollback_status(struct snmp_context *ctx,
982         struct snmp_value *val, uint sub)
983 {
984         int32_t if_idx;
985         char b_name[IFNAMSIZ];
986         struct bridge_if *bif;
987         struct bridge_port *bp;
988
989         if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
990                 return (SNMP_ERR_GENERR);
991
992         if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
993             (bp = bridge_port_find(if_idx, bif)) == NULL)
994                 return (SNMP_ERR_GENERR);
995
996         if (ctx->scratch->int1 == RowStatus_destroy)
997                 bridge_port_remove(bp, bif);
998         else
999                 bp->status = ctx->scratch->int1;
1000
1001         return (SNMP_ERR_NOERROR);
1002 }
1003
1004 static int
1005 bridge_port_commit_status(struct snmp_value *val, uint sub)
1006 {
1007         int32_t if_idx;
1008         char b_name[IFNAMSIZ];
1009         struct bridge_if *bif;
1010         struct bridge_port *bp;
1011
1012         if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
1013                 return (SNMP_ERR_GENERR);
1014
1015         if ((bif = bridge_if_find_ifname(b_name)) == NULL ||
1016             (bp = bridge_port_find(if_idx, bif)) == NULL)
1017                 return (SNMP_ERR_GENERR);
1018
1019         switch (bp->status) {
1020                 case RowStatus_active:
1021                         if (bridge_port_addm(bp, b_name) < 0)
1022                                 return (SNMP_ERR_COMMIT_FAILED);
1023                         break;
1024
1025                 case RowStatus_destroy:
1026                         if (bridge_port_delm(bp, b_name) < 0)
1027                                 return (SNMP_ERR_COMMIT_FAILED);
1028                         bridge_port_remove(bp, bif);
1029                         break;
1030         }
1031
1032         return (SNMP_ERR_NOERROR);
1033 }
1034
1035 static int
1036 bridge_port_set_span_enable(struct snmp_context *ctx,
1037                 struct snmp_value *val, uint sub)
1038 {
1039         int32_t if_idx;
1040         char b_name[IFNAMSIZ];
1041         struct bridge_if *bif;
1042         struct bridge_port *bp;
1043         struct mibif *mif;
1044
1045         if (val->v.integer != begemotBridgeBaseSpanEnabled_enabled &&
1046             val->v.integer != begemotBridgeBaseSpanEnabled_disabled)
1047                 return (SNMP_ERR_BADVALUE);
1048
1049         if (bridge_port_index_decode(&val->var, sub, b_name, &if_idx) < 0)
1050                 return (SNMP_ERR_INCONS_VALUE);
1051
1052         if ((bif = bridge_if_find_ifname(b_name)) == NULL)
1053                 return (SNMP_ERR_INCONS_VALUE);
1054
1055         if ((bp = bridge_port_find(if_idx, bif)) == NULL) {
1056                 if ((mif = mib_find_if(if_idx)) == NULL)
1057                         return (SNMP_ERR_INCONS_VALUE);
1058
1059                 if ((bp = bridge_new_port(mif, bif)) == NULL)
1060                         return (SNMP_ERR_GENERR);
1061
1062                 ctx->scratch->int1 = RowStatus_destroy;
1063         } else if (bp->status == RowStatus_active) {
1064                 return (SNMP_ERR_INCONS_VALUE);
1065         } else {
1066                 ctx->scratch->int1 = bp->status;
1067         }
1068
1069         bp->span_enable = val->v.integer;
1070         bp->status = RowStatus_notInService;
1071
1072         return (SNMP_ERR_NOERROR);
1073 }
1074
1075 int
1076 op_begemot_base_port(struct snmp_context *ctx, struct snmp_value *val,
1077         uint sub, uint iidx __unused, enum snmp_op op)
1078 {
1079         int8_t status, which;
1080         const char *bname;
1081         struct bridge_port *bp;
1082
1083         if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1084                 bridge_update_all_ports();
1085
1086         which = val->var.subs[sub - 1];
1087         status = 0;
1088
1089         switch (op) {
1090             case SNMP_OP_GET:
1091                 if (which == LEAF_begemotBridgeBaseSpanEnabled ||
1092                     which == LEAF_begemotBridgeBasePortStatus)
1093                         status = 1;
1094                 if ((bp = bridge_port_index_get(&val->var, sub,
1095                     status)) == NULL)
1096                         return (SNMP_ERR_NOSUCHNAME);
1097                 goto get;
1098
1099             case SNMP_OP_GETNEXT:
1100                 if (which == LEAF_begemotBridgeBaseSpanEnabled ||
1101                     which == LEAF_begemotBridgeBasePortStatus)
1102                         status = 1;
1103                 if ((bp = bridge_port_index_getnext(&val->var, sub,
1104                     status)) == NULL ||
1105                     bridge_port_index_append(&val->var, sub, bp) < 0)
1106                         return (SNMP_ERR_NOSUCHNAME);
1107                 goto get;
1108
1109             case SNMP_OP_SET:
1110                 switch (which) {
1111                     case LEAF_begemotBridgeBaseSpanEnabled:
1112                         return (bridge_port_set_span_enable(ctx, val, sub));
1113
1114                     case LEAF_begemotBridgeBasePortStatus:
1115                         return (bridge_port_set_status(ctx, val, sub));
1116
1117                     case LEAF_begemotBridgeBasePortPrivate:
1118                         if ((bp = bridge_port_index_get(&val->var, sub,
1119                             status)) == NULL)
1120                                 return (SNMP_ERR_NOSUCHNAME);
1121                         if ((bname = bridge_if_find_name(bp->sysindex)) == NULL)
1122                                 return (SNMP_ERR_GENERR);
1123                         ctx->scratch->int1 = bp->priv_set;
1124                         return (bridge_port_set_private(bname, bp,
1125                             val->v.integer));
1126
1127                     case LEAF_begemotBridgeBasePort:
1128                     case LEAF_begemotBridgeBasePortIfIndex:
1129                     case LEAF_begemotBridgeBasePortDelayExceededDiscards:
1130                     case LEAF_begemotBridgeBasePortMtuExceededDiscards:
1131                         return (SNMP_ERR_NOT_WRITEABLE);
1132                 }
1133                 abort();
1134
1135             case SNMP_OP_ROLLBACK:
1136                 switch (which) {
1137                     case LEAF_begemotBridgeBaseSpanEnabled:
1138                         /* FALLTHROUGH */
1139                     case LEAF_begemotBridgeBasePortStatus:
1140                         return (bridge_port_rollback_status(ctx, val, sub));
1141                     case LEAF_begemotBridgeBasePortPrivate:
1142                         if ((bp = bridge_port_index_get(&val->var, sub,
1143                             status)) == NULL)
1144                                 return (SNMP_ERR_GENERR);
1145                         if ((bname = bridge_if_find_name(bp->sysindex)) == NULL)
1146                                 return (SNMP_ERR_GENERR);
1147                         return (bridge_port_set_private(bname, bp,
1148                             ctx->scratch->int1));
1149                 }
1150                 return (SNMP_ERR_NOERROR);
1151
1152             case SNMP_OP_COMMIT:
1153                 if (which == LEAF_begemotBridgeBasePortStatus)
1154                         return (bridge_port_commit_status(val, sub));
1155
1156                 return (SNMP_ERR_NOERROR);
1157         }
1158         abort();
1159
1160 get:
1161         switch (which) {
1162             case LEAF_begemotBridgeBasePort:
1163                 val->v.integer = bp->port_no;
1164                 return (SNMP_ERR_NOERROR);
1165
1166             case LEAF_begemotBridgeBasePortIfIndex:
1167                 val->v.integer = bp->if_idx;
1168                 return (SNMP_ERR_NOERROR);
1169
1170             case LEAF_begemotBridgeBaseSpanEnabled:
1171                 val->v.integer = bp->span_enable;
1172                 return (SNMP_ERR_NOERROR);
1173
1174             case LEAF_begemotBridgeBasePortDelayExceededDiscards:
1175                 val->v.uint32 = bp->dly_ex_drops;
1176                 return (SNMP_ERR_NOERROR);
1177
1178             case LEAF_begemotBridgeBasePortMtuExceededDiscards:
1179                 val->v.uint32 = bp->dly_mtu_drops;
1180                 return (SNMP_ERR_NOERROR);
1181
1182             case LEAF_begemotBridgeBasePortStatus:
1183                 val->v.integer = bp->status;
1184                 return (SNMP_ERR_NOERROR);
1185
1186             case LEAF_begemotBridgeBasePortPrivate:
1187                 val->v.integer = bp->priv_set;
1188                 return (SNMP_ERR_NOERROR);
1189         }
1190
1191         abort();
1192 }
1193
1194 int
1195 op_begemot_stp_port(struct snmp_context *ctx, struct snmp_value *val,
1196         uint sub, uint iidx __unused, enum snmp_op op)
1197 {
1198         struct bridge_port *bp;
1199         const char *b_name;
1200
1201         if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1202                 bridge_update_all_ports();
1203
1204         switch (op) {
1205             case SNMP_OP_GET:
1206                 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1207                     return (SNMP_ERR_NOSUCHNAME);
1208                 goto get;
1209
1210             case SNMP_OP_GETNEXT:
1211                 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1212                     NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1213                         return (SNMP_ERR_NOSUCHNAME);
1214                 goto get;
1215
1216             case SNMP_OP_SET:
1217                 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1218                         return (SNMP_ERR_NOSUCHNAME);
1219                 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1220                         return (SNMP_ERR_GENERR);
1221
1222                 switch (val->var.subs[sub - 1]) {
1223                     case LEAF_begemotBridgeStpPortPriority:
1224                         if (val->v.integer < 0 || val->v.integer > 255)
1225                             return (SNMP_ERR_WRONG_VALUE);
1226
1227                         ctx->scratch->int1 = bp->priority;
1228                         if (bridge_port_set_priority(b_name, bp,
1229                             val->v.integer) < 0)
1230                             return (SNMP_ERR_GENERR);
1231                         return (SNMP_ERR_NOERROR);
1232
1233                     case LEAF_begemotBridgeStpPortEnable:
1234                         if (val->v.integer !=
1235                             (int32_t)begemotBridgeStpPortEnable_enabled ||
1236                             val->v.integer !=
1237                             (int32_t)begemotBridgeStpPortEnable_disabled)
1238                             return (SNMP_ERR_WRONG_VALUE);
1239
1240                         ctx->scratch->int1 = bp->enable;
1241                         if (bridge_port_set_stp_enable(b_name, bp,
1242                             val->v.integer) < 0)
1243                             return (SNMP_ERR_GENERR);
1244                         return (SNMP_ERR_NOERROR);
1245
1246                     case LEAF_begemotBridgeStpPortPathCost:
1247                         if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
1248                             val->v.integer > SNMP_PORT_MAX_PATHCOST)
1249                             return (SNMP_ERR_WRONG_VALUE);
1250
1251                         ctx->scratch->int1 = bp->path_cost;
1252                         if (bridge_port_set_path_cost(b_name, bp,
1253                             val->v.integer) < 0)
1254                             return (SNMP_ERR_GENERR);
1255                         return (SNMP_ERR_NOERROR);
1256
1257                     case LEAF_begemotBridgeStpPort:
1258                     case LEAF_begemotBridgeStpPortState:
1259                     case LEAF_begemotBridgeStpPortDesignatedRoot:
1260                     case LEAF_begemotBridgeStpPortDesignatedCost:
1261                     case LEAF_begemotBridgeStpPortDesignatedBridge:
1262                     case LEAF_begemotBridgeStpPortDesignatedPort:
1263                     case LEAF_begemotBridgeStpPortForwardTransitions:
1264                         return (SNMP_ERR_NOT_WRITEABLE);
1265                 }
1266                 abort();
1267
1268             case SNMP_OP_ROLLBACK:
1269                 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
1270                     (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1271                         return (SNMP_ERR_GENERR);
1272
1273                 switch (val->var.subs[sub - 1]) {
1274                     case LEAF_begemotBridgeStpPortPriority:
1275                         bridge_port_set_priority(b_name, bp,
1276                             ctx->scratch->int1);
1277                         break;
1278                     case LEAF_begemotBridgeStpPortEnable:
1279                         bridge_port_set_stp_enable(b_name, bp,
1280                             ctx->scratch->int1);
1281                         break;
1282                     case LEAF_begemotBridgeStpPortPathCost:
1283                         bridge_port_set_path_cost(b_name, bp,
1284                             ctx->scratch->int1);
1285                         break;
1286                 }
1287                 return (SNMP_ERR_NOERROR);
1288
1289             case SNMP_OP_COMMIT:
1290                 return (SNMP_ERR_NOERROR);
1291         }
1292         abort();
1293
1294 get:
1295         switch (val->var.subs[sub - 1]) {
1296             case LEAF_begemotBridgeStpPort:
1297                 val->v.integer = bp->port_no;
1298                 return (SNMP_ERR_NOERROR);
1299
1300             case LEAF_begemotBridgeStpPortPriority:
1301                 val->v.integer = bp->priority;
1302                 return (SNMP_ERR_NOERROR);
1303
1304             case LEAF_begemotBridgeStpPortState:
1305                 val->v.integer = bp->state;
1306                 return (SNMP_ERR_NOERROR);
1307
1308             case LEAF_begemotBridgeStpPortEnable:
1309                 val->v.integer = bp->enable;
1310                 return (SNMP_ERR_NOERROR);
1311
1312             case LEAF_begemotBridgeStpPortPathCost:
1313                 val->v.integer = bp->path_cost;
1314                 return (SNMP_ERR_NOERROR);
1315
1316             case LEAF_begemotBridgeStpPortDesignatedRoot:
1317                 return (string_get(val, bp->design_root, SNMP_BRIDGE_ID_LEN));
1318
1319             case LEAF_begemotBridgeStpPortDesignatedCost:
1320                 val->v.integer = bp->design_cost;
1321                 return (SNMP_ERR_NOERROR);
1322
1323             case LEAF_begemotBridgeStpPortDesignatedBridge:
1324                 return (string_get(val, bp->design_bridge, SNMP_BRIDGE_ID_LEN));
1325
1326             case LEAF_begemotBridgeStpPortDesignatedPort:
1327                 return (string_get(val, bp->design_port, 2));
1328
1329             case LEAF_begemotBridgeStpPortForwardTransitions:
1330                 val->v.uint32 = bp->fwd_trans;
1331                 return (SNMP_ERR_NOERROR);
1332         }
1333
1334         abort();
1335 }
1336
1337 int
1338 op_begemot_stp_ext_port(struct snmp_context *ctx, struct snmp_value *val,
1339     uint sub, uint iidx __unused, enum snmp_op op)
1340 {
1341         struct bridge_port *bp;
1342         const char *b_name;
1343
1344         if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1345                 bridge_update_all_ports();
1346
1347         switch (op) {
1348             case SNMP_OP_GET:
1349                 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1350                     return (SNMP_ERR_NOSUCHNAME);
1351                 goto get;
1352
1353             case SNMP_OP_GETNEXT:
1354                 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1355                     NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1356                         return (SNMP_ERR_NOSUCHNAME);
1357                 goto get;
1358
1359             case SNMP_OP_SET:
1360                 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1361                         return (SNMP_ERR_NOSUCHNAME);
1362                 if ((b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1363                         return (SNMP_ERR_GENERR);
1364
1365                 switch (val->var.subs[sub - 1]) {
1366                     case LEAF_begemotBridgeStpPortAdminEdgePort:
1367                         if (val->v.integer != TruthValue_true &&
1368                             val->v.integer != TruthValue_false)
1369                             return (SNMP_ERR_WRONG_VALUE);
1370
1371                         ctx->scratch->int1 = bp->admin_edge;
1372                         if (bridge_port_set_admin_edge(b_name, bp,
1373                             val->v.integer) < 0)
1374                             return (SNMP_ERR_GENERR);
1375                         return (SNMP_ERR_NOERROR);
1376
1377                     case LEAF_begemotBridgeStpPortAdminPointToPoint:
1378                         if (val->v.integer < 0 || val->v.integer >
1379                             StpPortAdminPointToPointType_auto)
1380                             return (SNMP_ERR_WRONG_VALUE);
1381
1382                         ctx->scratch->int1 = bp->admin_ptp;
1383                         if (bridge_port_set_admin_ptp(b_name, bp,
1384                             val->v.integer) < 0)
1385                             return (SNMP_ERR_GENERR);
1386                         return (SNMP_ERR_NOERROR);
1387
1388                     case LEAF_begemotBridgeStpPortAdminPathCost:
1389                         if (val->v.integer < SNMP_PORT_MIN_PATHCOST ||
1390                             val->v.integer > SNMP_PORT_MAX_PATHCOST)
1391                             return (SNMP_ERR_WRONG_VALUE);
1392
1393                         ctx->scratch->int1 = bp->admin_path_cost;
1394                         if (bridge_port_set_path_cost(b_name, bp,
1395                             val->v.integer) < 0)
1396                             return (SNMP_ERR_GENERR);
1397                         return (SNMP_ERR_NOERROR);
1398
1399                     case LEAF_begemotBridgeStpPortProtocolMigration:
1400                     case LEAF_begemotBridgeStpPortOperEdgePort:
1401                     case LEAF_begemotBridgeStpPortOperPointToPoint:
1402                         return (SNMP_ERR_NOT_WRITEABLE);
1403                 }
1404                 abort();
1405
1406             case SNMP_OP_ROLLBACK:
1407                 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL ||
1408                     (b_name = bridge_if_find_name(bp->sysindex)) == NULL)
1409                         return (SNMP_ERR_GENERR);
1410
1411                 switch (val->var.subs[sub - 1]) {
1412                     case LEAF_begemotBridgeStpPortAdminEdgePort:
1413                         bridge_port_set_admin_edge(b_name, bp,
1414                             ctx->scratch->int1);
1415                         break;
1416                     case LEAF_begemotBridgeStpPortAdminPointToPoint:
1417                         bridge_port_set_admin_ptp(b_name, bp,
1418                             ctx->scratch->int1);
1419                         break;
1420                     case LEAF_begemotBridgeStpPortAdminPathCost:
1421                         bridge_port_set_path_cost(b_name, bp,
1422                             ctx->scratch->int1);
1423                         break;
1424                 }
1425                 return (SNMP_ERR_NOERROR);
1426
1427             case SNMP_OP_COMMIT:
1428                 return (SNMP_ERR_NOERROR);
1429         }
1430         abort();
1431
1432 get:
1433         switch (val->var.subs[sub - 1]) {
1434                 case LEAF_begemotBridgeStpPortProtocolMigration:
1435                         val->v.integer = bp->proto_migr;
1436                         return (SNMP_ERR_NOERROR);
1437
1438                 case LEAF_begemotBridgeStpPortAdminEdgePort:
1439                         val->v.integer = bp->admin_edge;
1440                         return (SNMP_ERR_NOERROR);
1441
1442                 case LEAF_begemotBridgeStpPortOperEdgePort:
1443                         val->v.integer = bp->oper_edge;
1444                         return (SNMP_ERR_NOERROR);
1445
1446                 case LEAF_begemotBridgeStpPortAdminPointToPoint:
1447                         val->v.integer = bp->admin_ptp;
1448                         return (SNMP_ERR_NOERROR);
1449
1450                 case LEAF_begemotBridgeStpPortOperPointToPoint:
1451                         val->v.integer = bp->oper_ptp;
1452                         return (SNMP_ERR_NOERROR);
1453
1454                 case LEAF_begemotBridgeStpPortAdminPathCost:
1455                         val->v.integer = bp->admin_path_cost;
1456                         return (SNMP_ERR_NOERROR);
1457         }
1458
1459         abort();
1460 }
1461
1462 int
1463 op_begemot_tp_port(struct snmp_context *c __unused, struct snmp_value *val,
1464         uint sub, uint iidx __unused, enum snmp_op op)
1465 {
1466         struct bridge_port *bp;
1467
1468         if (time(NULL) - ports_list_age > bridge_get_data_maxage())
1469                 bridge_update_all_ports();
1470
1471         switch (op) {
1472             case SNMP_OP_GET:
1473                 if ((bp = bridge_port_index_get(&val->var, sub, 0)) == NULL)
1474                     return (SNMP_ERR_NOSUCHNAME);
1475                 goto get;
1476
1477             case SNMP_OP_GETNEXT:
1478                 if ((bp = bridge_port_index_getnext(&val->var, sub, 0)) ==
1479                     NULL || bridge_port_index_append(&val->var, sub, bp) < 0)
1480                     return (SNMP_ERR_NOSUCHNAME);
1481                 goto get;
1482
1483             case SNMP_OP_SET:
1484                 return (SNMP_ERR_NOT_WRITEABLE);
1485
1486             case SNMP_OP_ROLLBACK:
1487             case SNMP_OP_COMMIT:
1488                 break;
1489         }
1490         abort();
1491
1492 get:
1493         switch (val->var.subs[sub - 1]) {
1494             case LEAF_begemotBridgeTpPort:
1495                 val->v.integer = bp->port_no;
1496                 return (SNMP_ERR_NOERROR);
1497
1498             case LEAF_begemotBridgeTpPortMaxInfo:
1499                 val->v.integer = bp->max_info;
1500                 return (SNMP_ERR_NOERROR);
1501
1502             case LEAF_begemotBridgeTpPortInFrames:
1503                 val->v.uint32 = bp->in_frames;
1504                 return (SNMP_ERR_NOERROR);
1505
1506             case LEAF_begemotBridgeTpPortOutFrames:
1507                 val->v.uint32 = bp->out_frames;
1508                 return (SNMP_ERR_NOERROR);
1509
1510             case LEAF_begemotBridgeTpPortInDiscards:
1511                 val->v.uint32 = bp->in_drops;
1512                 return (SNMP_ERR_NOERROR);
1513         }
1514
1515         abort();
1516 }