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
bridge_ports_free(struct bridge_ports * headp)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
bridge_port_memif_free(struct bridge_ports * headp,struct bridge_if * bif)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
bridge_port_insert_at(struct bridge_ports * headp,struct bridge_port * bp,struct bridge_port ** f_bp)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 *
bridge_port_find_pos(struct bridge_ports * headp,uint32_t b_idx)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
bridge_port_memif_insert(struct bridge_ports * headp,struct bridge_port * bp,struct bridge_port ** f_bp)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
bridge_ports_update_listage(void)181 bridge_ports_update_listage(void)
182 {
183 ports_list_age = time(NULL);
184 }
185
186 void
bridge_ports_fini(void)187 bridge_ports_fini(void)
188 {
189 bridge_ports_free(&bridge_ports);
190 }
191
192 void
bridge_members_free(struct bridge_if * bif)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 *
bridge_port_first(void)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 *
bridge_port_next(struct bridge_port * bp)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 *
bridge_port_bif_first(struct bridge_if * bif)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 *
bridge_port_bif_next(struct bridge_port * bp)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
bridge_port_remove(struct bridge_port * bp,struct bridge_if * bif)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 *
bridge_new_port(struct mibif * mif,struct bridge_if * bif)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
bridge_port_getinfo_mibif(struct mibif * m_if,struct bridge_port * bp)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 *
bridge_port_find(int32_t if_idx,struct bridge_if * bif)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
bridge_ports_dump(struct bridge_if * bif)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
op_dot1d_base_port(struct snmp_context * c __unused,struct snmp_value * val,uint sub,uint iidx __unused,enum snmp_op op)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
op_dot1d_stp_port(struct snmp_context * ctx,struct snmp_value * val,uint sub,uint iidx __unused,enum snmp_op op)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
op_dot1d_stp_ext_port(struct snmp_context * ctx,struct snmp_value * val,uint sub,uint iidx __unused,enum snmp_op op)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
op_dot1d_tp_port(struct snmp_context * c __unused,struct snmp_value * val,uint sub,uint iidx __unused,enum snmp_op op)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
bridge_port_index_append(struct asn_oid * oid,uint sub,const struct bridge_port * bp)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 *
bridge_port_index_get(const struct asn_oid * oid,uint sub,int8_t status)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 *
bridge_port_index_getnext(const struct asn_oid * oid,uint sub,int8_t status)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
bridge_port_index_decode(const struct asn_oid * oid,uint sub,char * b_name,int32_t * idx)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
bridge_port_set_status(struct snmp_context * ctx,struct snmp_value * val,uint sub)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
bridge_port_rollback_status(struct snmp_context * ctx,struct snmp_value * val,uint sub)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
bridge_port_commit_status(struct snmp_value * val,uint sub)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
bridge_port_set_span_enable(struct snmp_context * ctx,struct snmp_value * val,uint sub)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
op_begemot_base_port(struct snmp_context * ctx,struct snmp_value * val,uint sub,uint iidx __unused,enum snmp_op op)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
op_begemot_stp_port(struct snmp_context * ctx,struct snmp_value * val,uint sub,uint iidx __unused,enum snmp_op op)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 begemotBridgeStpPortEnable_enabled ||
1233 val->v.integer !=
1234 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
op_begemot_stp_ext_port(struct snmp_context * ctx,struct snmp_value * val,uint sub,uint iidx __unused,enum snmp_op op)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
op_begemot_tp_port(struct snmp_context * c __unused,struct snmp_value * val,uint sub,uint iidx __unused,enum snmp_op op)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 }
1514