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