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