1 |
/* $MidnightBSD$ */ |
2 |
/*- |
3 |
* Copyright (c) 2006 Shteryana Shopova <syrinx@FreeBSD.org> |
4 |
* All rights reserved. |
5 |
* |
6 |
* Redistribution and use in source and binary forms, with or without |
7 |
* modification, are permitted provided that the following conditions |
8 |
* are met: |
9 |
* 1. Redistributions of source code must retain the above copyright |
10 |
* notice, this list of conditions and the following disclaimer. |
11 |
* 2. Redistributions in binary form must reproduce the above copyright |
12 |
* notice, this list of conditions and the following disclaimer in the |
13 |
* documentation and/or other materials provided with the distribution. |
14 |
* |
15 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 |
* SUCH DAMAGE. |
26 |
* |
27 |
* Bridge MIB implementation for SNMPd. |
28 |
* Bridge addresses. |
29 |
* |
30 |
* $FreeBSD: stable/10/usr.sbin/bsnmpd/modules/snmp_bridge/bridge_addrs.c 310903 2016-12-31 10:34:09Z ngie $ |
31 |
*/ |
32 |
|
33 |
#include <sys/queue.h> |
34 |
#include <sys/socket.h> |
35 |
#include <sys/types.h> |
36 |
|
37 |
#include <net/ethernet.h> |
38 |
#include <net/if.h> |
39 |
#include <net/if_mib.h> |
40 |
|
41 |
#include <assert.h> |
42 |
#include <errno.h> |
43 |
#include <stdarg.h> |
44 |
#include <string.h> |
45 |
#include <stdlib.h> |
46 |
#include <syslog.h> |
47 |
|
48 |
#include <bsnmp/snmpmod.h> |
49 |
#include <bsnmp/snmp_mibII.h> |
50 |
|
51 |
#include "bridge_tree.h" |
52 |
#include "bridge_snmp.h" |
53 |
|
54 |
TAILQ_HEAD(tp_entries, tp_entry); |
55 |
|
56 |
/* |
57 |
* Free the bridge address list. |
58 |
*/ |
59 |
static void |
60 |
bridge_tpe_free(struct tp_entries *headp) |
61 |
{ |
62 |
struct tp_entry *t; |
63 |
|
64 |
while ((t = TAILQ_FIRST(headp)) != NULL) { |
65 |
TAILQ_REMOVE(headp, t, tp_e); |
66 |
free(t); |
67 |
} |
68 |
} |
69 |
|
70 |
/* |
71 |
* Free the bridge address entries from the address list, |
72 |
* for the specified bridge interface only. |
73 |
*/ |
74 |
static void |
75 |
bridge_tpe_bif_free(struct tp_entries *headp, |
76 |
struct bridge_if *bif) |
77 |
{ |
78 |
struct tp_entry *tp; |
79 |
|
80 |
while (bif->f_tpa != NULL && bif->sysindex == bif->f_tpa->sysindex) { |
81 |
tp = TAILQ_NEXT(bif->f_tpa, tp_e); |
82 |
TAILQ_REMOVE(headp, bif->f_tpa, tp_e); |
83 |
free(bif->f_tpa); |
84 |
bif->f_tpa = tp; |
85 |
} |
86 |
} |
87 |
|
88 |
/* |
89 |
* Compare two mac addresses. |
90 |
* m1 < m2 : -1 |
91 |
* m1 > m2 : +1 |
92 |
* m1 = m2 : 0 |
93 |
*/ |
94 |
static int |
95 |
bridge_compare_macs(const uint8_t *m1, const uint8_t *m2) |
96 |
{ |
97 |
int i; |
98 |
|
99 |
for (i = 0; i < ETHER_ADDR_LEN; i++) { |
100 |
if (m1[i] < m2[i]) |
101 |
return (-1); |
102 |
if (m1[i] > m2[i]) |
103 |
return (1); |
104 |
} |
105 |
|
106 |
return (0); |
107 |
} |
108 |
|
109 |
/* |
110 |
* Insert an address entry in the bridge address TAILQ starting to search |
111 |
* for its place from the position of the first bridge address for the bridge |
112 |
* interface. Update the first bridge address if necessary. |
113 |
*/ |
114 |
static void |
115 |
bridge_addrs_insert_at(struct tp_entries *headp, |
116 |
struct tp_entry *ta, struct tp_entry **f_tpa) |
117 |
{ |
118 |
struct tp_entry *t1; |
119 |
|
120 |
assert(f_tpa != NULL); |
121 |
|
122 |
for (t1 = *f_tpa; |
123 |
t1 != NULL && ta->sysindex == t1->sysindex; |
124 |
t1 = TAILQ_NEXT(t1, tp_e)) { |
125 |
if (bridge_compare_macs(ta->tp_addr, t1->tp_addr) < 0) { |
126 |
TAILQ_INSERT_BEFORE(t1, ta, tp_e); |
127 |
if (*f_tpa == t1) |
128 |
(*f_tpa) = ta; |
129 |
return; |
130 |
} |
131 |
} |
132 |
|
133 |
if (t1 == NULL) |
134 |
TAILQ_INSERT_TAIL(headp, ta, tp_e); |
135 |
else |
136 |
TAILQ_INSERT_BEFORE(t1, ta, tp_e); |
137 |
} |
138 |
|
139 |
/* |
140 |
* Find an address entry's position in the address list |
141 |
* according to bridge interface name. |
142 |
*/ |
143 |
static struct tp_entry * |
144 |
bridge_addrs_find_pos(struct tp_entries *headp, uint32_t b_idx) |
145 |
{ |
146 |
uint32_t t_idx; |
147 |
struct tp_entry *t1; |
148 |
|
149 |
if ((t1 = TAILQ_FIRST(headp)) == NULL || |
150 |
bridge_compare_sysidx(b_idx, t1->sysindex) < 0) |
151 |
return (NULL); |
152 |
|
153 |
t_idx = t1->sysindex; |
154 |
|
155 |
for (t1 = TAILQ_NEXT(t1, tp_e); t1 != NULL; t1 = TAILQ_NEXT(t1, tp_e)) { |
156 |
|
157 |
if (t1->sysindex != t_idx) { |
158 |
if (bridge_compare_sysidx(b_idx, t1->sysindex) < 0) |
159 |
return (TAILQ_PREV(t1, tp_entries, tp_e)); |
160 |
else |
161 |
t_idx = t1->sysindex; |
162 |
} |
163 |
} |
164 |
|
165 |
if (t1 == NULL) |
166 |
t1 = TAILQ_LAST(headp, tp_entries); |
167 |
|
168 |
return (t1); |
169 |
} |
170 |
|
171 |
/* |
172 |
* Insert a bridge address in the bridge addresses list. |
173 |
*/ |
174 |
static void |
175 |
bridge_addrs_bif_insert(struct tp_entries *headp, struct tp_entry *te, |
176 |
struct tp_entry **f_tpa) |
177 |
{ |
178 |
struct tp_entry *temp; |
179 |
|
180 |
if (*f_tpa != NULL) |
181 |
bridge_addrs_insert_at(headp, te, f_tpa); |
182 |
else { |
183 |
temp = bridge_addrs_find_pos(headp, te->sysindex); |
184 |
|
185 |
if (temp == NULL) |
186 |
TAILQ_INSERT_HEAD(headp, te, tp_e); |
187 |
else |
188 |
TAILQ_INSERT_AFTER(headp, temp, te, tp_e); |
189 |
*f_tpa = te; |
190 |
} |
191 |
} |
192 |
|
193 |
static struct tp_entries tp_entries = TAILQ_HEAD_INITIALIZER(tp_entries); |
194 |
static time_t address_list_age; |
195 |
|
196 |
void |
197 |
bridge_addrs_update_listage(void) |
198 |
{ |
199 |
address_list_age = time(NULL); |
200 |
} |
201 |
|
202 |
void |
203 |
bridge_addrs_fini(void) |
204 |
{ |
205 |
bridge_tpe_free(&tp_entries); |
206 |
} |
207 |
|
208 |
void |
209 |
bridge_addrs_free(struct bridge_if *bif) |
210 |
{ |
211 |
bridge_tpe_bif_free(&tp_entries, bif); |
212 |
} |
213 |
|
214 |
/* |
215 |
* Find the first address in the list. |
216 |
*/ |
217 |
static struct tp_entry * |
218 |
bridge_addrs_first(void) |
219 |
{ |
220 |
return (TAILQ_FIRST(&tp_entries)); |
221 |
} |
222 |
|
223 |
/* |
224 |
* Find the next address in the list. |
225 |
*/ |
226 |
static struct tp_entry * |
227 |
bridge_addrs_next(struct tp_entry *te) |
228 |
{ |
229 |
return (TAILQ_NEXT(te, tp_e)); |
230 |
} |
231 |
|
232 |
/* |
233 |
* Find the first address, learnt by the specified bridge interface. |
234 |
*/ |
235 |
struct tp_entry * |
236 |
bridge_addrs_bif_first(struct bridge_if *bif) |
237 |
{ |
238 |
return (bif->f_tpa); |
239 |
} |
240 |
|
241 |
/* |
242 |
* Find the next address, learnt by the specified bridge interface. |
243 |
*/ |
244 |
struct tp_entry * |
245 |
bridge_addrs_bif_next(struct tp_entry *te) |
246 |
{ |
247 |
struct tp_entry *te_next; |
248 |
|
249 |
if ((te_next = TAILQ_NEXT(te, tp_e)) == NULL || |
250 |
te_next->sysindex != te->sysindex) |
251 |
return (NULL); |
252 |
|
253 |
return (te_next); |
254 |
} |
255 |
|
256 |
/* |
257 |
* Remove a bridge address from the list. |
258 |
*/ |
259 |
void |
260 |
bridge_addrs_remove(struct tp_entry *te, struct bridge_if *bif) |
261 |
{ |
262 |
if (bif->f_tpa == te) |
263 |
bif->f_tpa = bridge_addrs_bif_next(te); |
264 |
|
265 |
TAILQ_REMOVE(&tp_entries, te, tp_e); |
266 |
free(te); |
267 |
} |
268 |
|
269 |
/* |
270 |
* Allocate memory for a new bridge address and insert it in the list. |
271 |
*/ |
272 |
struct tp_entry * |
273 |
bridge_new_addrs(uint8_t *mac, struct bridge_if *bif) |
274 |
{ |
275 |
struct tp_entry *te; |
276 |
|
277 |
if ((te = (struct tp_entry *) malloc(sizeof(*te))) == NULL) { |
278 |
syslog(LOG_ERR, "bridge new address: failed: %s", |
279 |
strerror(errno)); |
280 |
return (NULL); |
281 |
} |
282 |
|
283 |
bzero(te, sizeof(*te)); |
284 |
|
285 |
te->sysindex = bif->sysindex; |
286 |
bcopy(mac, te->tp_addr, ETHER_ADDR_LEN); |
287 |
bridge_addrs_bif_insert(&tp_entries, te, &(bif->f_tpa)); |
288 |
|
289 |
return (te); |
290 |
} |
291 |
|
292 |
/* |
293 |
* Given a mac address, learnt on a bridge, |
294 |
* find the corrsponding TP entry for it. |
295 |
*/ |
296 |
struct tp_entry * |
297 |
bridge_addrs_find(uint8_t *mac, struct bridge_if *bif) |
298 |
{ |
299 |
struct tp_entry *te; |
300 |
|
301 |
for (te = bif->f_tpa; te != NULL; te = TAILQ_NEXT(te, tp_e)) { |
302 |
if (te->sysindex != bif->sysindex) { |
303 |
te = NULL; |
304 |
break; |
305 |
} |
306 |
|
307 |
if (bridge_compare_macs(te->tp_addr, mac) == 0) |
308 |
break; |
309 |
} |
310 |
|
311 |
return (te); |
312 |
} |
313 |
|
314 |
void |
315 |
bridge_addrs_dump(struct bridge_if *bif) |
316 |
{ |
317 |
struct tp_entry *te; |
318 |
|
319 |
syslog(LOG_ERR, "Addresses count - %d", bif->num_addrs); |
320 |
for (te = bridge_addrs_bif_first(bif); te != NULL; |
321 |
te = bridge_addrs_bif_next(te)) { |
322 |
syslog(LOG_ERR, "address %x:%x:%x:%x:%x:%x on port %d.%d", |
323 |
te->tp_addr[0], te->tp_addr[1], te->tp_addr[2], |
324 |
te->tp_addr[3], te->tp_addr[4], te->tp_addr[5], |
325 |
te->sysindex, te->port_no); |
326 |
} |
327 |
} |
328 |
|
329 |
/* |
330 |
* RFC4188 specifics. |
331 |
*/ |
332 |
|
333 |
/* |
334 |
* Construct the SNMP index from the address DST Mac. |
335 |
*/ |
336 |
static void |
337 |
bridge_addrs_index_append(struct asn_oid *oid, uint sub, |
338 |
const struct tp_entry *te) |
339 |
{ |
340 |
int i; |
341 |
|
342 |
oid->len = sub + ETHER_ADDR_LEN + 1; |
343 |
oid->subs[sub] = ETHER_ADDR_LEN; |
344 |
|
345 |
for (i = 1; i <= ETHER_ADDR_LEN; i++) |
346 |
oid->subs[sub + i] = te->tp_addr[i - 1]; |
347 |
} |
348 |
|
349 |
/* |
350 |
* Find the address entry for the SNMP index from the default bridge only. |
351 |
*/ |
352 |
static struct tp_entry * |
353 |
bridge_addrs_get(const struct asn_oid *oid, uint sub, |
354 |
struct bridge_if *bif) |
355 |
{ |
356 |
int i; |
357 |
uint8_t tp_addr[ETHER_ADDR_LEN]; |
358 |
|
359 |
if (oid->len - sub != ETHER_ADDR_LEN + 1 || |
360 |
oid->subs[sub] != ETHER_ADDR_LEN) |
361 |
return (NULL); |
362 |
|
363 |
for (i = 0; i < ETHER_ADDR_LEN; i++) |
364 |
tp_addr[i] = oid->subs[sub + i + 1]; |
365 |
|
366 |
return (bridge_addrs_find(tp_addr, bif)); |
367 |
} |
368 |
|
369 |
/* |
370 |
* Find the next address entry for the SNMP index |
371 |
* from the default bridge only. |
372 |
*/ |
373 |
static struct tp_entry * |
374 |
bridge_addrs_getnext(const struct asn_oid *oid, uint sub, |
375 |
struct bridge_if *bif) |
376 |
{ |
377 |
int i; |
378 |
uint8_t tp_addr[ETHER_ADDR_LEN]; |
379 |
static struct tp_entry *te; |
380 |
|
381 |
if (oid->len - sub == 0) |
382 |
return (bridge_addrs_bif_first(bif)); |
383 |
|
384 |
if (oid->len - sub != ETHER_ADDR_LEN + 1 || |
385 |
oid->subs[sub] != ETHER_ADDR_LEN) |
386 |
return (NULL); |
387 |
|
388 |
for (i = 0; i < ETHER_ADDR_LEN; i++) |
389 |
tp_addr[i] = oid->subs[sub + i + 1]; |
390 |
|
391 |
if ((te = bridge_addrs_find(tp_addr, bif)) == NULL) |
392 |
return (NULL); |
393 |
|
394 |
return (bridge_addrs_bif_next(te)); |
395 |
} |
396 |
|
397 |
int |
398 |
op_dot1d_tp_fdb(struct snmp_context *c __unused, struct snmp_value *val, |
399 |
uint sub, uint iidx __unused, enum snmp_op op) |
400 |
{ |
401 |
struct bridge_if *bif; |
402 |
struct tp_entry *te; |
403 |
|
404 |
if ((bif = bridge_get_default()) == NULL) |
405 |
return (SNMP_ERR_NOSUCHNAME); |
406 |
|
407 |
if (time(NULL) - bif->addrs_age > bridge_get_data_maxage() && |
408 |
bridge_update_addrs(bif) <= 0) |
409 |
return (SNMP_ERR_NOSUCHNAME); |
410 |
|
411 |
switch (op) { |
412 |
case SNMP_OP_GET: |
413 |
if ((te = bridge_addrs_get(&val->var, sub, bif)) == NULL) |
414 |
return (SNMP_ERR_NOSUCHNAME); |
415 |
goto get; |
416 |
|
417 |
case SNMP_OP_GETNEXT: |
418 |
if ((te = bridge_addrs_getnext(&val->var, sub, bif)) == NULL) |
419 |
return (SNMP_ERR_NOSUCHNAME); |
420 |
bridge_addrs_index_append(&val->var, sub, te); |
421 |
goto get; |
422 |
|
423 |
case SNMP_OP_SET: |
424 |
return (SNMP_ERR_NOT_WRITEABLE); |
425 |
|
426 |
case SNMP_OP_ROLLBACK: |
427 |
case SNMP_OP_COMMIT: |
428 |
break; |
429 |
} |
430 |
abort(); |
431 |
|
432 |
get: |
433 |
switch (val->var.subs[sub - 1]) { |
434 |
case LEAF_dot1dTpFdbAddress: |
435 |
return (string_get(val, te->tp_addr, ETHER_ADDR_LEN)); |
436 |
case LEAF_dot1dTpFdbPort : |
437 |
val->v.integer = te->port_no; |
438 |
return (SNMP_ERR_NOERROR); |
439 |
case LEAF_dot1dTpFdbStatus: |
440 |
val->v.integer = te->status; |
441 |
return (SNMP_ERR_NOERROR); |
442 |
} |
443 |
|
444 |
abort(); |
445 |
} |
446 |
|
447 |
/* |
448 |
* Private BEGEMOT-BRIDGE-MIB specifics. |
449 |
*/ |
450 |
|
451 |
/* |
452 |
* Construct the SNMP index from the bridge interface name |
453 |
* and the address DST Mac. |
454 |
*/ |
455 |
static int |
456 |
bridge_addrs_begemot_index_append(struct asn_oid *oid, uint sub, |
457 |
const struct tp_entry *te) |
458 |
{ |
459 |
uint i, n_len; |
460 |
const char *b_name; |
461 |
|
462 |
if ((b_name = bridge_if_find_name(te->sysindex)) == NULL) |
463 |
return (-1); |
464 |
|
465 |
n_len = strlen(b_name); |
466 |
oid->len = sub++; |
467 |
oid->subs[oid->len++] = n_len; |
468 |
|
469 |
for (i = 1; i <= n_len; i++) |
470 |
oid->subs[oid->len++] = b_name[i - 1]; |
471 |
|
472 |
oid->subs[oid->len++] = ETHER_ADDR_LEN; |
473 |
for (i = 1 ; i <= ETHER_ADDR_LEN; i++) |
474 |
oid->subs[oid->len++] = te->tp_addr[i - 1]; |
475 |
|
476 |
return (0); |
477 |
} |
478 |
|
479 |
/* |
480 |
* Find a bridge address entry by the bridge interface name |
481 |
* and the address DST Mac. |
482 |
*/ |
483 |
static struct tp_entry * |
484 |
bridge_addrs_begemot_get(const struct asn_oid *oid, uint sub) |
485 |
{ |
486 |
uint i, n_len; |
487 |
uint8_t tp_addr[ETHER_ADDR_LEN]; |
488 |
char bif_name[IFNAMSIZ]; |
489 |
struct bridge_if *bif; |
490 |
|
491 |
n_len = oid->subs[sub]; |
492 |
if (oid->len - sub != n_len + ETHER_ADDR_LEN + 3 || |
493 |
n_len >= IFNAMSIZ || oid->subs[sub + n_len + 1] != ETHER_ADDR_LEN) |
494 |
return (NULL); |
495 |
|
496 |
for (i = 0; i < n_len; i++) |
497 |
bif_name[i] = oid->subs[n_len + i + 1]; |
498 |
bif_name[i] = '\0'; |
499 |
|
500 |
for (i = 1; i <= ETHER_ADDR_LEN; i++) |
501 |
tp_addr[i - 1] = oid->subs[n_len + i + 1]; |
502 |
|
503 |
if ((bif = bridge_if_find_ifname(bif_name)) == NULL) |
504 |
return (NULL); |
505 |
|
506 |
return (bridge_addrs_find(tp_addr, bif)); |
507 |
} |
508 |
|
509 |
/* |
510 |
* Find the next bridge address entry by the bridge interface name |
511 |
* and the address DST Mac. |
512 |
*/ |
513 |
static struct tp_entry * |
514 |
bridge_addrs_begemot_getnext(const struct asn_oid *oid, uint sub) |
515 |
{ |
516 |
uint i, n_len; |
517 |
uint8_t tp_addr[ETHER_ADDR_LEN]; |
518 |
char bif_name[IFNAMSIZ]; |
519 |
struct bridge_if *bif; |
520 |
struct tp_entry *tp; |
521 |
|
522 |
if (oid->len - sub == 0) |
523 |
return (bridge_addrs_first()); |
524 |
|
525 |
n_len = oid->subs[sub]; |
526 |
if (oid->len - sub != n_len + ETHER_ADDR_LEN + 2 || |
527 |
n_len >= IFNAMSIZ || oid->subs[sub + n_len + 1] != ETHER_ADDR_LEN) |
528 |
return (NULL); |
529 |
|
530 |
for (i = 1; i <= n_len; i++) |
531 |
bif_name[i - 1] = oid->subs[sub + i]; |
532 |
|
533 |
bif_name[i - 1] = '\0'; |
534 |
|
535 |
for (i = 1; i <= ETHER_ADDR_LEN; i++) |
536 |
tp_addr[i - 1] = oid->subs[sub + n_len + i + 1]; |
537 |
|
538 |
if ((bif = bridge_if_find_ifname(bif_name)) == NULL || |
539 |
(tp = bridge_addrs_find(tp_addr, bif)) == NULL) |
540 |
return (NULL); |
541 |
|
542 |
return (bridge_addrs_next(tp)); |
543 |
} |
544 |
|
545 |
int |
546 |
op_begemot_tp_fdb(struct snmp_context *c __unused, struct snmp_value *val, |
547 |
uint sub, uint iidx __unused, enum snmp_op op) |
548 |
{ |
549 |
struct tp_entry *te; |
550 |
|
551 |
if (time(NULL) - address_list_age > bridge_get_data_maxage()) |
552 |
bridge_update_all_addrs(); |
553 |
|
554 |
switch (op) { |
555 |
case SNMP_OP_GET: |
556 |
if ((te = bridge_addrs_begemot_get(&val->var, sub)) == NULL) |
557 |
return (SNMP_ERR_NOSUCHNAME); |
558 |
goto get; |
559 |
|
560 |
case SNMP_OP_GETNEXT: |
561 |
if ((te = bridge_addrs_begemot_getnext(&val->var, |
562 |
sub)) == NULL || |
563 |
bridge_addrs_begemot_index_append(&val->var, |
564 |
sub, te) < 0) |
565 |
return (SNMP_ERR_NOSUCHNAME); |
566 |
goto get; |
567 |
|
568 |
case SNMP_OP_SET: |
569 |
return (SNMP_ERR_NOT_WRITEABLE); |
570 |
|
571 |
case SNMP_OP_ROLLBACK: |
572 |
case SNMP_OP_COMMIT: |
573 |
break; |
574 |
} |
575 |
abort(); |
576 |
|
577 |
get: |
578 |
switch (val->var.subs[sub - 1]) { |
579 |
case LEAF_begemotBridgeTpFdbAddress: |
580 |
return (string_get(val, te->tp_addr, ETHER_ADDR_LEN)); |
581 |
case LEAF_begemotBridgeTpFdbPort: |
582 |
val->v.integer = te->port_no; |
583 |
return (SNMP_ERR_NOERROR); |
584 |
case LEAF_begemotBridgeTpFdbStatus: |
585 |
val->v.integer = te->status; |
586 |
return (SNMP_ERR_NOERROR); |
587 |
} |
588 |
|
589 |
abort(); |
590 |
} |