]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/agent.c
Ignore unknown ORG TLV. Thanks to Michael Hanig for noticing it.
[thirdparty/lldpd.git] / src / agent.c
CommitLineData
43c02e7b
VB
1/*
2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "lldpd.h"
18
19#include <net-snmp/net-snmp-config.h>
20#include <net-snmp/net-snmp-includes.h>
21#include <net-snmp/agent/net-snmp-agent-includes.h>
22#include <net-snmp/agent/snmp_vars.h>
23#include <net-snmp/agent/util_funcs.h>
24
25static oid lldp_oid[] = {1, 0, 8802, 1, 1, 2};
26
27/* For net-snmp */
28extern int register_sysORTable(oid *, size_t, const char *);
29extern int unregister_sysORTable(oid *, size_t);
30extern struct timeval starttime;
31
32/* Global variable because no way to pass it as argument. Should not be used
33 * elsewhere. */
34struct lldpd *scfg;
35
36static inline uint8_t
37swap_bits(uint8_t n)
38{
39 n = ((n&0xF0) >>4 ) | ( (n&0x0F) <<4);
40 n = ((n&0xCC) >>2 ) | ( (n&0x33) <<2);
41 n = ((n&0xAA) >>1 ) | ( (n&0x55) <<1);
42
43 return n;
44};
45
46struct lldpd_hardware*
47header_portindexed_table(struct variable *vp, oid *name, size_t *length,
48 int exact, size_t *var_len, WriteMethod **write_method)
49{
50 struct lldpd_hardware *hardware, *phardware = NULL;
51 unsigned int port, aport = 0, distance;
52
53 if (header_simple_table(vp, name, length, exact, var_len, write_method, -1))
54 return NULL;
55
56 port = name[*length - 1];
57 distance = -1;
58 TAILQ_FOREACH(hardware, &scfg->g_hardware, h_entries) {
59 if (INTERFACE_OPENED(hardware)) {
60 aport = if_nametoindex(hardware->h_ifname);
61 if (aport == port) {
62 /* Exact match */
63 return hardware;
64 }
65 if (aport < port)
66 continue;
67 if (aport - port < distance) {
68 phardware = hardware;
69 distance = aport - port;
70 }
71 }
72 }
73 if (phardware == NULL)
74 return NULL;
75 if (exact)
76 return NULL;
77 if (distance == -1)
78 return NULL;
79 aport = distance + port;
80 name[*length - 1] = aport;
81 return phardware;
82}
83
84struct lldpd_hardware*
85header_tprindexed_table(struct variable *vp, oid *name, size_t *length,
86 int exact, size_t *var_len, WriteMethod **write_method, int withip)
87{
88 struct lldpd_hardware *hardware, *phardware = NULL;
89 oid *target, current[9], best[9];
90 int result, target_len, oid_len;
91 int i;
92
93 if ((result = snmp_oid_compare(name, *length, vp->name, vp->namelen)) < 0) {
94 memcpy(name, vp->name, sizeof(oid) * vp->namelen);
95 *length = vp->namelen;
96 }
97
98 *write_method = 0;
99 *var_len = sizeof(long);
100
101 oid_len = (withip) ? 9:3;
102 for (i = 0; i < oid_len; i++) best[i] = MAX_SUBID;
103 target = &name[vp->namelen];
104 target_len = *length - vp->namelen;
105 TAILQ_FOREACH(hardware, &scfg->g_hardware, h_entries) {
106 if ((INTERFACE_OPENED(hardware)) && (hardware->h_rchassis != NULL)) {
107 if (withip && (hardware->h_rchassis->c_mgmt.s_addr == INADDR_ANY))
108 continue;
109 current[0] = (hardware->h_rlastchange - starttime.tv_sec)*100;
110 current[1] = if_nametoindex(hardware->h_ifname);
111 current[2] = hardware->h_rid;
112 if (withip) {
113 current[3] = 1;
114 current[4] = 4;
115 current[8] = hardware->h_rchassis->c_mgmt.s_addr >> 24;
116 current[7] = (hardware->h_rchassis->c_mgmt.s_addr & 0xffffff) >> 16;
117 current[6] = (hardware->h_rchassis->c_mgmt.s_addr & 0xffff) >> 8;
118 current[5] = hardware->h_rchassis->c_mgmt.s_addr & 0xff;
119 }
120 if ((result = snmp_oid_compare(current, oid_len, target,
121 target_len)) < 0)
122 continue;
123 if ((result == 0) && !exact)
124 continue;
125 if (result == 0)
126 return hardware;
127 if (snmp_oid_compare(current, oid_len, best, oid_len) < 0) {
128 memcpy(best, current, sizeof(oid) * oid_len);
129 phardware = hardware;
130 }
131 }
132 }
133 if (phardware == NULL)
134 return NULL;
135 if (exact)
136 return NULL;
137 for (i = 0; i < oid_len; i++)
138 if (best[i] != MAX_SUBID) break;
139 if (i == oid_len)
140 return NULL;
141 memcpy(target, best, sizeof(oid) * oid_len);
142 *length = vp->namelen + oid_len;
143
144 return phardware;
145}
146
147struct lldpd_vlan*
148header_pvindexed_table(struct variable *vp, oid *name, size_t *length,
149 int exact, size_t *var_len, WriteMethod **write_method)
150{
151 struct lldpd_hardware *hardware;
152 struct lldpd_vlan *vlan, *pvlan = NULL;
153 oid *target, current[2], best[2];
154 int result, target_len;
155
156 if ((result = snmp_oid_compare(name, *length, vp->name, vp->namelen)) < 0) {
157 memcpy(name, vp->name, sizeof(oid) * vp->namelen);
158 *length = vp->namelen;
159 }
160
161 *write_method = 0;
162 *var_len = sizeof(long);
163
164 best[0] = best[1] = MAX_SUBID;
165 target = &name[vp->namelen];
166 target_len = *length - vp->namelen;
167 TAILQ_FOREACH(hardware, &scfg->g_hardware, h_entries) {
168 if (INTERFACE_OPENED(hardware)) {
169 TAILQ_FOREACH(vlan, &hardware->h_lport.p_vlans, v_entries) {
170 current[0] = if_nametoindex(hardware->h_ifname);
171 current[1] = vlan->v_vid;
172 if ((result = snmp_oid_compare(current, 2, target,
173 target_len)) < 0)
174 continue;
175 if ((result == 0) && !exact)
176 continue;
177 if (result == 0)
178 return vlan;
179 if (snmp_oid_compare(current, 2, best, 2) < 0) {
180 memcpy(best, current, sizeof(oid) * 2);
181 pvlan = vlan;
182 }
183 }
184 }
185 }
186 if (pvlan == NULL)
187 return NULL;
188 if (exact)
189 return NULL;
190 if ((best[0] == best[1]) &&
191 (best[0] == MAX_SUBID))
192 return NULL;
193 memcpy(target, best, sizeof(oid) * 2);
194 *length = vp->namelen + 2;
195
196 return pvlan;
197}
198
199struct lldpd_vlan*
200header_tprvindexed_table(struct variable *vp, oid *name, size_t *length,
201 int exact, size_t *var_len, WriteMethod **write_method)
202{
203 struct lldpd_hardware *hardware;
204 struct lldpd_vlan *vlan, *pvlan = NULL;
205 oid *target, current[4], best[4];
206 int result, target_len;
207
208 if ((result = snmp_oid_compare(name, *length, vp->name, vp->namelen)) < 0) {
209 memcpy(name, vp->name, sizeof(oid) * vp->namelen);
210 *length = vp->namelen;
211 }
212
213 *write_method = 0;
214 *var_len = sizeof(long);
215
216 best[0] = best[1] = best[2] = best[3] = MAX_SUBID;
217 target = &name[vp->namelen];
218 target_len = *length - vp->namelen;
219 TAILQ_FOREACH(hardware, &scfg->g_hardware, h_entries) {
220 if ((INTERFACE_OPENED(hardware)) && (hardware->h_rport != NULL)) {
221 TAILQ_FOREACH(vlan, &hardware->h_rport->p_vlans, v_entries) {
222 current[0] = (hardware->h_rlastchange - starttime.tv_sec)*100;
223 current[1] = if_nametoindex(hardware->h_ifname);
224 current[2] = hardware->h_rid;
225 current[3] = vlan->v_vid;
226 if ((result = snmp_oid_compare(current, 4, target,
227 target_len)) < 0)
228 continue;
229 if ((result == 0) && !exact)
230 continue;
231 if (result == 0)
232 return vlan;
233 if (snmp_oid_compare(current, 4, best, 4) < 0) {
234 memcpy(best, current, sizeof(oid) * 4);
235 pvlan = vlan;
236 }
237 }
238 }
239 }
240 if (pvlan == NULL)
241 return NULL;
242 if (exact)
243 return NULL;
244 if ((best[0] == best[1]) && (best[1] == best[2]) &&
245 (best[2] == best[3]) && (best[0] == MAX_SUBID))
246 return NULL;
247 memcpy(target, best, sizeof(oid) * 4);
248 *length = vp->namelen + 4;
249
250 return pvlan;
251}
252
253/* Scalars */
254#define LLDP_SNMP_TXINTERVAL 1
255#define LLDP_SNMP_TXMULTIPLIER 2
256#define LLDP_SNMP_REINITDELAY 3
257#define LLDP_SNMP_TXDELAY 4
258#define LLDP_SNMP_NOTIFICATION 5
259#define LLDP_SNMP_LASTUPDATE 6
260#define LLDP_SNMP_STATS_INSERTS 7
261#define LLDP_SNMP_STATS_DELETES 8
262#define LLDP_SNMP_STATS_DROPS 9
263#define LLDP_SNMP_STATS_AGEOUTS 10
264/* Local chassis */
265#define LLDP_SNMP_LOCAL_CIDSUBTYPE 1
266#define LLDP_SNMP_LOCAL_CID 2
267#define LLDP_SNMP_LOCAL_SYSNAME 3
268#define LLDP_SNMP_LOCAL_SYSDESCR 4
269#define LLDP_SNMP_LOCAL_SYSCAP_SUP 5
270#define LLDP_SNMP_LOCAL_SYSCAP_ENA 6
271/* Stats */
272#define LLDP_SNMP_STATS_TX_PORTNUM 1
273#define LLDP_SNMP_STATS_TX 2
274#define LLDP_SNMP_STATS_RX_PORTNUM 3
275#define LLDP_SNMP_STATS_RX_DISCARDED 4
276#define LLDP_SNMP_STATS_RX_ERRORS 5
277#define LLDP_SNMP_STATS_RX 6
278#define LLDP_SNMP_STATS_RX_TLVDISCARDED 7
279#define LLDP_SNMP_STATS_RX_TLVUNRECOGNIZED 8
280#define LLDP_SNMP_STATS_RX_AGEOUTS 9
281/* Local ports */
282#define LLDP_SNMP_LOCAL_PORTNUM 1
283#define LLDP_SNMP_LOCAL_PIDSUBTYPE 2
284#define LLDP_SNMP_LOCAL_PID 3
285#define LLDP_SNMP_LOCAL_PORTDESC 4
286#define LLDP_SNMP_LOCAL_DOT3_AUTONEG_SUPPORT 5
287#define LLDP_SNMP_LOCAL_DOT3_AUTONEG_ENABLED 6
288#define LLDP_SNMP_LOCAL_DOT3_AUTONEG_ADVERTISED 7
289#define LLDP_SNMP_LOCAL_DOT3_AUTONEG_MAU 8
290#define LLDP_SNMP_LOCAL_DOT3_AGG_STATUS 9
291#define LLDP_SNMP_LOCAL_DOT3_AGG_ID 10
292/* Remote ports */
293#define LLDP_SNMP_REMOTE_CIDSUBTYPE 1
294#define LLDP_SNMP_REMOTE_CID 2
295#define LLDP_SNMP_REMOTE_PIDSUBTYPE 3
296#define LLDP_SNMP_REMOTE_PID 4
297#define LLDP_SNMP_REMOTE_PORTDESC 5
298#define LLDP_SNMP_REMOTE_SYSNAME 6
299#define LLDP_SNMP_REMOTE_SYSDESC 7
300#define LLDP_SNMP_REMOTE_SYSCAP_SUP 8
301#define LLDP_SNMP_REMOTE_SYSCAP_ENA 9
302#define LLDP_SNMP_REMOTE_DOT3_AUTONEG_SUPPORT 10
303#define LLDP_SNMP_REMOTE_DOT3_AUTONEG_ENABLED 11
304#define LLDP_SNMP_REMOTE_DOT3_AUTONEG_ADVERTISED 12
305#define LLDP_SNMP_REMOTE_DOT3_AUTONEG_MAU 13
306#define LLDP_SNMP_REMOTE_DOT3_AGG_STATUS 14
307#define LLDP_SNMP_REMOTE_DOT3_AGG_ID 15
308/* Local vlans */
309#define LLDP_SNMP_LOCAL_DOT1_VLANNAME 1
310/* Remote vlans */
311#define LLDP_SNMP_REMOTE_DOT1_VLANNAME 1
312/* Management address */
313#define LLDP_SNMP_LOCAL_ADDR_LEN 1
314#define LLDP_SNMP_LOCAL_ADDR_IFSUBTYPE 2
315#define LLDP_SNMP_LOCAL_ADDR_IFID 3
316#define LLDP_SNMP_LOCAL_ADDR_OID 4
317#define LLDP_SNMP_REMOTE_ADDR_IFSUBTYPE 5
318#define LLDP_SNMP_REMOTE_ADDR_IFID 6
319#define LLDP_SNMP_REMOTE_ADDR_OID 7
320
321static u_char*
322agent_h_scalars(struct variable *vp, oid *name, size_t *length,
323 int exact, size_t *var_len, WriteMethod **write_method)
324{
325 static unsigned long long_ret;
326 struct lldpd_hardware *hardware;
327
328 if (header_generic(vp, name, length, exact, var_len, write_method))
329 return NULL;
330
331 switch (vp->magic) {
332 case LLDP_SNMP_TXINTERVAL:
333 long_ret = scfg->g_delay;
334 return (u_char *)&long_ret;
335 case LLDP_SNMP_TXMULTIPLIER:
336 long_ret = scfg->g_lchassis.c_ttl / scfg->g_delay;
337 return (u_char *)&long_ret;
338 case LLDP_SNMP_REINITDELAY:
339 long_ret = 1;
340 return (u_char *)&long_ret;
341 case LLDP_SNMP_TXDELAY:
342 long_ret = LLDPD_TX_MSGDELAY;
343 return (u_char *)&long_ret;
344 case LLDP_SNMP_NOTIFICATION:
345 long_ret = 5;
346 return (u_char *)&long_ret;
347 case LLDP_SNMP_LASTUPDATE:
348 long_ret = 0;
349 TAILQ_FOREACH(hardware, &scfg->g_hardware, h_entries)
350 if (hardware->h_rlastchange > long_ret)
351 long_ret = hardware->h_rlastchange;
352 if (long_ret)
353 long_ret = (long_ret - starttime.tv_sec) * 100;
354 return (u_char *)&long_ret;
355 case LLDP_SNMP_STATS_INSERTS:
356 /* We assume this is equal to valid frames received on all ports */
357 long_ret = 0;
358 TAILQ_FOREACH(hardware, &scfg->g_hardware, h_entries)
359 long_ret += hardware->h_rx_cnt;
360 return (u_char *)&long_ret;
361 case LLDP_SNMP_STATS_AGEOUTS:
362 long_ret = 0;
363 TAILQ_FOREACH(hardware, &scfg->g_hardware, h_entries)
364 long_ret += hardware->h_rx_ageout_cnt;
365 return (u_char *)&long_ret;
366 case LLDP_SNMP_STATS_DELETES:
367 long_ret = 0;
368 TAILQ_FOREACH(hardware, &scfg->g_hardware, h_entries)
369 long_ret += hardware->h_rx_ageout_cnt +
370 hardware->h_rx_cnt?(hardware->h_rx_cnt - 1):0;
371 return (u_char *)&long_ret;
372 case LLDP_SNMP_STATS_DROPS:
373 /* We assume that we never have insufficient resources */
374 long_ret = 0;
375 return (u_char *)&long_ret;
376 default:
377 break;
378 }
379 return NULL;
380}
381
382static u_char*
383agent_h_local_chassis(struct variable *vp, oid *name, size_t *length,
384 int exact, size_t *var_len, WriteMethod **write_method)
385{
386 static uint8_t bit;
387 static unsigned long long_ret;
388
389 if (header_generic(vp, name, length, exact, var_len, write_method))
390 return NULL;
391
392 switch (vp->magic) {
393 case LLDP_SNMP_LOCAL_CIDSUBTYPE:
394 long_ret = scfg->g_lchassis.c_id_subtype;
395 return (u_char *)&long_ret;
396 case LLDP_SNMP_LOCAL_CID:
397 *var_len = scfg->g_lchassis.c_id_len;
398 return (u_char *)scfg->g_lchassis.c_id;
399 case LLDP_SNMP_LOCAL_SYSNAME:
400 *var_len = strlen(scfg->g_lchassis.c_name);
401 return (u_char *)scfg->g_lchassis.c_name;
402 case LLDP_SNMP_LOCAL_SYSDESCR:
403 *var_len = strlen(scfg->g_lchassis.c_descr);
404 return (u_char *)scfg->g_lchassis.c_descr;
405 case LLDP_SNMP_LOCAL_SYSCAP_SUP:
406 *var_len = 1;
407 bit = swap_bits(scfg->g_lchassis.c_cap_available);
408 return (u_char *)&bit;
409 case LLDP_SNMP_LOCAL_SYSCAP_ENA:
410 *var_len = 1;
411 bit = swap_bits(scfg->g_lchassis.c_cap_enabled);
412 return (u_char *)&bit;
413 default:
414 break;
415 }
416 return NULL;
417}
418
419static u_char*
420agent_h_stats(struct variable *vp, oid *name, size_t *length,
421 int exact, size_t *var_len, WriteMethod **write_method)
422{
423 static unsigned long long_ret;
424 struct lldpd_hardware *hardware;
425
426 if ((hardware = header_portindexed_table(vp, name, length,
427 exact, var_len, write_method)) == NULL)
428 return NULL;
429
430 switch (vp->magic) {
431 case LLDP_SNMP_STATS_TX:
432 long_ret = hardware->h_tx_cnt;
433 return (u_char *)&long_ret;
434 case LLDP_SNMP_STATS_RX:
435 long_ret = hardware->h_rx_cnt;
436 return (u_char *)&long_ret;
437 case LLDP_SNMP_STATS_RX_DISCARDED:
438 case LLDP_SNMP_STATS_RX_ERRORS:
439 long_ret = hardware->h_rx_discarded_cnt;
440 return (u_char *)&long_ret;
441 case LLDP_SNMP_STATS_RX_TLVDISCARDED:
442 case LLDP_SNMP_STATS_RX_TLVUNRECOGNIZED:
443 /* Not really handled */
444 long_ret = 0;
445 return (u_char *)&long_ret;
446 case LLDP_SNMP_STATS_RX_AGEOUTS:
447 long_ret = hardware->h_rx_ageout_cnt;
448 return (u_char *)&long_ret;
449 default:
450 break;
451 }
452 return NULL;
453}
454
455static u_char*
456agent_h_local_port(struct variable *vp, oid *name, size_t *length,
457 int exact, size_t *var_len, WriteMethod **write_method)
458{
459 static uint8_t bit;
460 struct lldpd_hardware *hardware;
461 static unsigned long long_ret;
462
463 if ((hardware = header_portindexed_table(vp, name, length,
464 exact, var_len, write_method)) == NULL)
465 return NULL;
466
467 switch (vp->magic) {
468 case LLDP_SNMP_LOCAL_PIDSUBTYPE:
469 long_ret = hardware->h_lport.p_id_subtype;
470 return (u_char *)&long_ret;
471 case LLDP_SNMP_LOCAL_PID:
472 *var_len = hardware->h_lport.p_id_len;
473 return (u_char *)hardware->h_lport.p_id;
474 case LLDP_SNMP_LOCAL_PORTDESC:
475 *var_len = strlen(hardware->h_lport.p_descr);
476 return (u_char *)hardware->h_lport.p_descr;
477 case LLDP_SNMP_LOCAL_DOT3_AUTONEG_SUPPORT:
478 long_ret = 2 - hardware->h_lport.p_autoneg_support;
479 return (u_char *)&long_ret;
480 case LLDP_SNMP_LOCAL_DOT3_AUTONEG_ENABLED:
481 long_ret = 2 - hardware->h_lport.p_autoneg_enabled;
482 return (u_char *)&long_ret;
483 case LLDP_SNMP_LOCAL_DOT3_AUTONEG_ADVERTISED:
484 *var_len = 2;
485 return (u_char *)&hardware->h_lport.p_autoneg_advertised;
486 case LLDP_SNMP_LOCAL_DOT3_AUTONEG_MAU:
487 long_ret = hardware->h_lport.p_mau_type;
488 return (u_char *)&long_ret;
489 case LLDP_SNMP_LOCAL_DOT3_AGG_STATUS:
490 bit = swap_bits((hardware->h_lport.p_aggregid > 0) ? 3 : 0);
491 *var_len = 1;
492 return (u_char *)&bit;
493 case LLDP_SNMP_LOCAL_DOT3_AGG_ID:
494 long_ret = hardware->h_lport.p_aggregid;
495 return (u_char *)&long_ret;
496 default:
497 break;
498 }
499 return NULL;
500}
501
502static u_char*
503agent_h_local_vlan(struct variable *vp, oid *name, size_t *length,
504 int exact, size_t *var_len, WriteMethod **write_method)
505{
506 struct lldpd_vlan *vlan;
507
508 if ((vlan = header_pvindexed_table(vp, name, length,
509 exact, var_len, write_method)) == NULL)
510 return NULL;
511
512 switch (vp->magic) {
513 case LLDP_SNMP_LOCAL_DOT1_VLANNAME:
514 *var_len = strlen(vlan->v_name);
515 return (u_char *)vlan->v_name;
516 default:
517 break;
518 }
519 return NULL;
520}
521
522static u_char*
523agent_h_remote_vlan(struct variable *vp, oid *name, size_t *length,
524 int exact, size_t *var_len, WriteMethod **write_method)
525{
526 struct lldpd_vlan *vlan;
527
528 if ((vlan = header_tprvindexed_table(vp, name, length,
529 exact, var_len, write_method)) == NULL)
530 return NULL;
531
532 switch (vp->magic) {
533 case LLDP_SNMP_REMOTE_DOT1_VLANNAME:
534 *var_len = strlen(vlan->v_name);
535 return (u_char *)vlan->v_name;
536 default:
537 break;
538 }
539 return NULL;
540}
541
542static u_char*
543agent_h_remote_port(struct variable *vp, oid *name, size_t *length,
544 int exact, size_t *var_len, WriteMethod **write_method)
545{
546 struct lldpd_hardware *hardware;
547 static uint8_t bit;
548 static unsigned long long_ret;
549
550 if ((hardware = header_tprindexed_table(vp, name, length,
551 exact, var_len, write_method, 0)) == NULL)
552 return NULL;
553
554 switch (vp->magic) {
555 case LLDP_SNMP_REMOTE_CIDSUBTYPE:
556 long_ret = hardware->h_rchassis->c_id_subtype;
557 return (u_char *)&long_ret;
558 case LLDP_SNMP_REMOTE_CID:
559 *var_len = hardware->h_rchassis->c_id_len;
560 return (u_char *)hardware->h_rchassis->c_id;
561 case LLDP_SNMP_REMOTE_PIDSUBTYPE:
562 long_ret = hardware->h_rport->p_id_subtype;
563 return (u_char *)&long_ret;
564 case LLDP_SNMP_REMOTE_PID:
565 *var_len = hardware->h_rport->p_id_len;
566 return (u_char *)hardware->h_rport->p_id;
567 case LLDP_SNMP_REMOTE_PORTDESC:
568 *var_len = strlen(hardware->h_rport->p_descr);
569 return (u_char *)hardware->h_rport->p_descr;
570 case LLDP_SNMP_REMOTE_SYSNAME:
571 *var_len = strlen(hardware->h_rchassis->c_name);
572 return (u_char *)hardware->h_rchassis->c_name;
573 case LLDP_SNMP_REMOTE_SYSDESC:
574 *var_len = strlen(hardware->h_rchassis->c_descr);
575 return (u_char *)hardware->h_rchassis->c_descr;
576 case LLDP_SNMP_REMOTE_SYSCAP_SUP:
577 *var_len = 1;
578 bit = swap_bits(hardware->h_rchassis->c_cap_available);
579 return (u_char *)&bit;
580 case LLDP_SNMP_REMOTE_SYSCAP_ENA:
581 *var_len = 1;
582 bit = swap_bits(hardware->h_rchassis->c_cap_enabled);
583 return (u_char *)&bit;
584 case LLDP_SNMP_REMOTE_DOT3_AUTONEG_SUPPORT:
585 long_ret = 2 - hardware->h_rport->p_autoneg_support;
586 return (u_char *)&long_ret;
587 case LLDP_SNMP_REMOTE_DOT3_AUTONEG_ENABLED:
588 long_ret = 2 - hardware->h_rport->p_autoneg_enabled;
589 return (u_char *)&long_ret;
590 case LLDP_SNMP_REMOTE_DOT3_AUTONEG_ADVERTISED:
591 *var_len = 2;
592 return (u_char *)&hardware->h_rport->p_autoneg_advertised;
593 case LLDP_SNMP_REMOTE_DOT3_AUTONEG_MAU:
594 long_ret = hardware->h_rport->p_mau_type;
595 return (u_char *)&long_ret;
596 case LLDP_SNMP_REMOTE_DOT3_AGG_STATUS:
597 bit = swap_bits((hardware->h_rport->p_aggregid > 0) ? 3 : 0);
598 *var_len = 1;
599 return (u_char *)&bit;
600 case LLDP_SNMP_REMOTE_DOT3_AGG_ID:
601 long_ret = hardware->h_rport->p_aggregid;
602 return (u_char *)&long_ret;
603 default:
604 break;
605 }
606 return NULL;
607}
608
609static u_char*
610agent_management(struct variable *vp, size_t *var_len, struct lldpd_chassis *chassis)
611{
612 static unsigned long int long_ret;
613 static oid zeroDotZero[2] = {0, 0};
614
615 switch (vp->magic) {
616 case LLDP_SNMP_LOCAL_ADDR_LEN:
617 long_ret = 5;
618 return (u_char*)&long_ret;
619 case LLDP_SNMP_LOCAL_ADDR_IFSUBTYPE:
620 case LLDP_SNMP_REMOTE_ADDR_IFSUBTYPE:
621 if (chassis->c_mgmt_if != 0)
622 long_ret = LLDP_MGMT_IFACE_IFINDEX;
623 else
624 long_ret = 1;
625 return (u_char*)&long_ret;
626 case LLDP_SNMP_LOCAL_ADDR_IFID:
627 case LLDP_SNMP_REMOTE_ADDR_IFID:
628 long_ret = chassis->c_mgmt_if;
629 return (u_char*)&long_ret;
630 case LLDP_SNMP_LOCAL_ADDR_OID:
631 case LLDP_SNMP_REMOTE_ADDR_OID:
632 *var_len = sizeof(zeroDotZero);
633 return (u_char*)zeroDotZero;
634 default:
635 break;
636 }
637 return NULL;
638}
639
640static u_char*
641agent_h_local_management(struct variable *vp, oid *name, size_t *length,
642 int exact, size_t *var_len, WriteMethod **write_method)
643{
644 oid *target, best[6];
645 int result, target_len;
646
647 if (scfg->g_lchassis.c_mgmt.s_addr == INADDR_ANY)
648 return NULL;
649
650 if ((result = snmp_oid_compare(name, *length, vp->name, vp->namelen)) < 0) {
651 memcpy(name, vp->name, sizeof(oid) * vp->namelen);
652 *length = vp->namelen;
653 }
654
655 *write_method = 0;
656 *var_len = sizeof(long);
657
658 target = &name[vp->namelen];
659 target_len = *length - vp->namelen;
660
661 best[0] = 1;
662 best[1] = 4;
663 best[5] = scfg->g_lchassis.c_mgmt.s_addr >> 24;
664 best[4] = (scfg->g_lchassis.c_mgmt.s_addr & 0xffffff) >> 16;
665 best[3] = (scfg->g_lchassis.c_mgmt.s_addr & 0xffff) >> 8;
666 best[2] = scfg->g_lchassis.c_mgmt.s_addr & 0xff;
667
668 if ((result = snmp_oid_compare(target, 6, best, 6)) < 0) {
669 if (exact)
670 return NULL;
671 memcpy(target, best, sizeof(oid) * 6);
672 *length = vp->namelen + 6;
673 } else if (exact && (result != 0))
674 return NULL;
675 else if (!exact && result == 0)
676 return NULL;
677
678 return agent_management(vp, var_len, &scfg->g_lchassis);
679}
680
681static u_char*
682agent_h_remote_management(struct variable *vp, oid *name, size_t *length,
683 int exact, size_t *var_len, WriteMethod **write_method)
684{
685 struct lldpd_hardware *hardware;
686
687 if ((hardware = header_tprindexed_table(vp, name, length,
688 exact, var_len, write_method, 1)) == NULL)
689 return NULL;
690
691 return agent_management(vp, var_len, hardware->h_rchassis);
692}
693
694static struct variable8 lldp_vars[] = {
695 /* Scalars */
696 {LLDP_SNMP_TXINTERVAL, ASN_INTEGER, RONLY, agent_h_scalars, 3, {1, 1, 1}},
697 {LLDP_SNMP_TXMULTIPLIER, ASN_INTEGER, RONLY, agent_h_scalars, 3, {1, 1, 2}},
698 {LLDP_SNMP_REINITDELAY, ASN_INTEGER, RONLY, agent_h_scalars, 3, {1, 1, 3}},
699 {LLDP_SNMP_TXDELAY, ASN_INTEGER, RONLY, agent_h_scalars, 3, {1, 1, 4}},
700 {LLDP_SNMP_NOTIFICATION, ASN_INTEGER, RONLY, agent_h_scalars, 3, {1, 1, 5}},
701 {LLDP_SNMP_LASTUPDATE, ASN_TIMETICKS, RONLY, agent_h_scalars, 3, {1, 2, 1}},
702 {LLDP_SNMP_STATS_INSERTS, ASN_GAUGE, RONLY, agent_h_scalars, 3, {1, 2, 2}},
703 {LLDP_SNMP_STATS_DELETES, ASN_GAUGE, RONLY, agent_h_scalars, 3, {1, 2, 3}},
704 {LLDP_SNMP_STATS_DROPS, ASN_GAUGE, RONLY, agent_h_scalars, 3, {1, 2, 4}},
705 {LLDP_SNMP_STATS_AGEOUTS, ASN_GAUGE, RONLY, agent_h_scalars, 3, {1, 2, 5}},
706 /* Local chassis */
707 {LLDP_SNMP_LOCAL_CIDSUBTYPE, ASN_INTEGER, RONLY, agent_h_local_chassis, 3, {1, 3, 1}},
708 {LLDP_SNMP_LOCAL_CID, ASN_OCTET_STR, RONLY, agent_h_local_chassis, 3, {1, 3, 2}},
709 {LLDP_SNMP_LOCAL_SYSNAME, ASN_OCTET_STR, RONLY, agent_h_local_chassis, 3, {1, 3, 3}},
710 {LLDP_SNMP_LOCAL_SYSDESCR, ASN_OCTET_STR, RONLY, agent_h_local_chassis, 3, {1, 3, 4}},
711 {LLDP_SNMP_LOCAL_SYSCAP_SUP, ASN_OCTET_STR, RONLY, agent_h_local_chassis, 3, {1, 3, 5}},
712 {LLDP_SNMP_LOCAL_SYSCAP_ENA, ASN_OCTET_STR, RONLY, agent_h_local_chassis, 3, {1, 3, 6}},
713 /* Stats */
714 {LLDP_SNMP_STATS_TX, ASN_COUNTER, RONLY, agent_h_stats, 5, {1, 2, 6, 1, 2}},
715 {LLDP_SNMP_STATS_RX_DISCARDED, ASN_COUNTER, RONLY, agent_h_stats, 5, {1, 2, 7, 1, 2}},
716 {LLDP_SNMP_STATS_RX_ERRORS, ASN_COUNTER, RONLY, agent_h_stats, 5, {1, 2, 7, 1, 3}},
717 {LLDP_SNMP_STATS_RX, ASN_COUNTER, RONLY, agent_h_stats, 5, {1, 2, 7, 1, 4}},
718 {LLDP_SNMP_STATS_RX_TLVDISCARDED, ASN_COUNTER, RONLY, agent_h_stats, 5, {1, 2, 7, 1, 5}},
719 {LLDP_SNMP_STATS_RX_TLVUNRECOGNIZED, ASN_COUNTER, RONLY, agent_h_stats, 5, {1, 2, 7, 1, 6}},
720 {LLDP_SNMP_STATS_RX_AGEOUTS, ASN_GAUGE, RONLY, agent_h_stats, 5, {1, 2, 7, 1, 7}},
721 /* Local ports */
722 {LLDP_SNMP_LOCAL_PIDSUBTYPE, ASN_INTEGER, RONLY, agent_h_local_port, 5, {1, 3, 7, 1, 2}},
723 {LLDP_SNMP_LOCAL_PID, ASN_OCTET_STR, RONLY, agent_h_local_port, 5, {1, 3, 7, 1, 3}},
724 {LLDP_SNMP_LOCAL_PORTDESC, ASN_OCTET_STR, RONLY, agent_h_local_port, 5, {1, 3, 7, 1, 4}},
725 {LLDP_SNMP_LOCAL_DOT3_AUTONEG_SUPPORT, ASN_INTEGER, RONLY, agent_h_local_port, 8,
726 {1, 5, 4623, 1, 2, 1, 1, 1}},
727 {LLDP_SNMP_LOCAL_DOT3_AUTONEG_ENABLED, ASN_INTEGER, RONLY, agent_h_local_port, 8,
728 {1, 5, 4623, 1, 2, 1, 1, 2}},
729 {LLDP_SNMP_LOCAL_DOT3_AUTONEG_ADVERTISED, ASN_OCTET_STR, RONLY, agent_h_local_port, 8,
730 {1, 5, 4623, 1, 2, 1, 1, 3}},
731 {LLDP_SNMP_LOCAL_DOT3_AUTONEG_MAU, ASN_INTEGER, RONLY, agent_h_local_port, 8,
732 {1, 5, 4623, 1, 2, 1, 1, 4}},
733 {LLDP_SNMP_LOCAL_DOT3_AGG_STATUS, ASN_OCTET_STR, RONLY, agent_h_local_port, 8,
734 {1, 5, 4623, 1, 2, 3, 1, 1}},
735 {LLDP_SNMP_LOCAL_DOT3_AGG_ID, ASN_INTEGER, RONLY, agent_h_local_port, 8,
736 {1, 5, 4623, 1, 2, 3, 1, 2}},
737 /* Remote ports */
738 {LLDP_SNMP_REMOTE_CIDSUBTYPE, ASN_INTEGER, RONLY, agent_h_remote_port, 5, {1, 4, 1, 1, 4}},
739 {LLDP_SNMP_REMOTE_CID, ASN_OCTET_STR, RONLY, agent_h_remote_port, 5, {1, 4, 1, 1, 5}},
740 {LLDP_SNMP_REMOTE_PIDSUBTYPE, ASN_INTEGER, RONLY, agent_h_remote_port, 5, {1, 4, 1, 1, 6}},
741 {LLDP_SNMP_REMOTE_PID, ASN_OCTET_STR, RONLY, agent_h_remote_port, 5, {1, 4, 1, 1, 7}},
742 {LLDP_SNMP_REMOTE_PORTDESC, ASN_OCTET_STR, RONLY, agent_h_remote_port, 5, {1, 4, 1, 1, 8}},
743 {LLDP_SNMP_REMOTE_SYSNAME, ASN_OCTET_STR, RONLY, agent_h_remote_port, 5, {1, 4, 1, 1, 9}},
744 {LLDP_SNMP_REMOTE_SYSDESC, ASN_OCTET_STR, RONLY, agent_h_remote_port, 5, {1, 4, 1, 1, 10}},
745 {LLDP_SNMP_REMOTE_SYSCAP_SUP, ASN_OCTET_STR, RONLY, agent_h_remote_port, 5, {1, 4, 1, 1, 11}},
746 {LLDP_SNMP_REMOTE_SYSCAP_ENA, ASN_OCTET_STR, RONLY, agent_h_remote_port, 5, {1, 4, 1, 1, 12}},
747 {LLDP_SNMP_REMOTE_DOT3_AUTONEG_SUPPORT, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
748 {1, 5, 4623, 1, 3, 1, 1, 1}},
749 {LLDP_SNMP_REMOTE_DOT3_AUTONEG_ENABLED, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
750 {1, 5, 4623, 1, 3, 1, 1, 2}},
751 {LLDP_SNMP_REMOTE_DOT3_AUTONEG_ADVERTISED, ASN_OCTET_STR, RONLY, agent_h_remote_port, 8,
752 {1, 5, 4623, 1, 3, 1, 1, 3}},
753 {LLDP_SNMP_REMOTE_DOT3_AUTONEG_MAU, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
754 {1, 5, 4623, 1, 3, 1, 1, 4}},
755 {LLDP_SNMP_REMOTE_DOT3_AGG_STATUS, ASN_OCTET_STR, RONLY, agent_h_remote_port, 8,
756 {1, 5, 4623, 1, 3, 3, 1, 1}},
757 {LLDP_SNMP_REMOTE_DOT3_AGG_ID, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
758 {1, 5, 4623, 1, 3, 3, 1, 2}},
759 /* Local vlans */
760 {LLDP_SNMP_LOCAL_DOT1_VLANNAME, ASN_OCTET_STR, RONLY, agent_h_local_vlan, 8,
761 {1, 5, 32962, 1, 2, 3, 1, 2}},
762 /* Remote vlans */
763 {LLDP_SNMP_REMOTE_DOT1_VLANNAME, ASN_OCTET_STR, RONLY, agent_h_remote_vlan, 8,
764 {1, 5, 32962, 1, 3, 3, 1, 2}},
765 /* Management address */
766 {LLDP_SNMP_LOCAL_ADDR_LEN, ASN_INTEGER, RONLY, agent_h_local_management, 5,
767 {1, 3, 8, 1, 3}},
768 {LLDP_SNMP_LOCAL_ADDR_IFSUBTYPE, ASN_INTEGER, RONLY, agent_h_local_management, 5,
769 {1, 3, 8, 1, 4}},
770 {LLDP_SNMP_LOCAL_ADDR_IFID, ASN_INTEGER, RONLY, agent_h_local_management, 5,
771 {1, 3, 8, 1, 5}},
772 {LLDP_SNMP_LOCAL_ADDR_OID, ASN_OBJECT_ID, RONLY, agent_h_local_management, 5,
773 {1, 3, 8, 1, 6}},
774 {LLDP_SNMP_REMOTE_ADDR_IFSUBTYPE, ASN_INTEGER, RONLY, agent_h_remote_management, 5,
775 {1, 4, 2, 1, 3}},
776 {LLDP_SNMP_REMOTE_ADDR_IFID, ASN_INTEGER, RONLY, agent_h_remote_management, 5,
777 {1, 4, 2, 1, 4}},
778 {LLDP_SNMP_REMOTE_ADDR_OID, ASN_OBJECT_ID, RONLY, agent_h_remote_management, 5,
779 {1, 4, 2, 1, 5}},
780};
781
782void
783agent_init(struct lldpd *cfg, int debug)
784{
785 int rc;
786 extern char *__progname;
787
788 LLOG_INFO("Enable SNMP subagent");
789 netsnmp_enable_subagent();
790 snmp_disable_log();
791 if (debug)
792 snmp_enable_stderrlog();
793 else
794 snmp_enable_syslog_ident(__progname, LOG_DAEMON);
795
796 scfg = cfg;
797
798 init_agent("lldpAgent");
799
800 REGISTER_MIB("lldp", lldp_vars, variable8, lldp_oid);
801
802 init_snmp("lldpAgent");
803
804 if ((rc = register_sysORTable(lldp_oid, OID_LENGTH(lldp_oid),
805 "lldpMIB implementation by lldpd")) != 0)
806 LLOG_WARNX("Unable to register to sysORTable (%d)", rc);
807}
808
809void
810agent_shutdown()
811{
812 unregister_sysORTable(lldp_oid, OID_LENGTH(lldp_oid));
813 snmp_shutdown("lldpAgent");
814}