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