]> git.ipfire.org Git - thirdparty/lldpd.git/blame_incremental - src/daemon/agent.c
build: bump cross-platform-actions/action from 0.27.0 to 0.28.0
[thirdparty/lldpd.git] / src / daemon / agent.c
... / ...
CommitLineData
1/* -*- mode: c; c-file-style: "openbsd" -*- */
2/*
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include "lldpd.h"
19
20#include <assert.h>
21
22#include "agent.h"
23
24#if HAVE_NET_SNMP_AGENT_UTIL_FUNCS_H
25# include <net-snmp/agent/util_funcs.h>
26#else
27/* The above header may be buggy. We just need this function. */
28int header_generic(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **);
29#endif
30
31/* For net-snmp */
32extern int register_sysORTable(oid *, size_t, const char *);
33extern int unregister_sysORTable(oid *, size_t);
34
35/* Global variable because no way to pass it as argument. Should not be used
36 * elsewhere. */
37#define scfg agent_scfg
38struct lldpd *agent_scfg;
39
40static uint8_t
41swap_bits(uint8_t n)
42{
43 n = ((n & 0xF0) >> 4) | ((n & 0x0F) << 4);
44 n = ((n & 0xCC) >> 2) | ((n & 0x33) << 2);
45 n = ((n & 0xAA) >> 1) | ((n & 0x55) << 1);
46
47 return n;
48};
49
50extern struct timeval starttime;
51static long int
52lastchange(struct lldpd_port *port)
53{
54 if (port->p_lastchange > starttime.tv_sec)
55 return (port->p_lastchange - starttime.tv_sec) * 100;
56 return 0;
57}
58
59/* -------------
60 Helper functions to build header_*indexed_table() functions.
61 Those functions keep an internal state. They are not reentrant!
62*/
63struct header_index {
64 struct variable *vp;
65 oid *name; /* Requested/returned OID */
66 size_t *length; /* Length of above OID */
67 int exact;
68 oid best[MAX_OID_LEN]; /* Best OID */
69 size_t best_len; /* Best OID length */
70 void *entity; /* Best entity */
71};
72static struct header_index header_idx;
73
74static int
75header_index_init(struct variable *vp, oid *name, size_t *length, int exact,
76 size_t *var_len, WriteMethod **write_method)
77{
78 /* If the requested OID name is less than OID prefix we
79 handle, adjust it to our prefix. */
80 if ((snmp_oid_compare(name, *length, vp->name, vp->namelen)) < 0) {
81 memcpy(name, vp->name, sizeof(oid) * vp->namelen);
82 *length = vp->namelen;
83 }
84 /* Now, we can only handle OID matching our prefix. Those two
85 tests are not really necessary since NetSNMP won't give us
86 OID "above" our prefix. But this makes unit tests
87 easier. */
88 if (*length < vp->namelen) return 0;
89 if (memcmp(name, vp->name, vp->namelen * sizeof(oid))) return 0;
90
91 if (write_method != NULL) *write_method = 0;
92 *var_len = sizeof(long);
93
94 /* Initialize our header index structure */
95 header_idx.vp = vp;
96 header_idx.name = name;
97 header_idx.length = length;
98 header_idx.exact = exact;
99 header_idx.best_len = 0;
100 header_idx.entity = NULL;
101 return 1;
102}
103
104static int
105header_index_add(oid *index, size_t len, void *entity)
106{
107 int result;
108 oid *target;
109 size_t target_len;
110
111 target = header_idx.name + header_idx.vp->namelen;
112 target_len = *header_idx.length - header_idx.vp->namelen;
113 if ((result = snmp_oid_compare(index, len, target, target_len)) < 0)
114 return 0; /* Too small. */
115 if (result == 0) return header_idx.exact;
116 if (header_idx.best_len == 0 ||
117 (snmp_oid_compare(index, len, header_idx.best, header_idx.best_len) < 0)) {
118 memcpy(header_idx.best, index, sizeof(oid) * len);
119 header_idx.best_len = len;
120 header_idx.entity = entity;
121 }
122 return 0; /* No best match yet. */
123}
124
125static void *
126header_index_best()
127{
128 if (header_idx.entity == NULL) return NULL;
129 if (header_idx.exact) return NULL;
130 memcpy(header_idx.name + header_idx.vp->namelen, header_idx.best,
131 sizeof(oid) * header_idx.best_len);
132 *header_idx.length = header_idx.vp->namelen + header_idx.best_len;
133 return header_idx.entity;
134}
135/* ----------------------------- */
136
137static struct lldpd_hardware *
138header_portindexed_table(struct variable *vp, oid *name, size_t *length, int exact,
139 size_t *var_len, WriteMethod **write_method)
140{
141 struct lldpd_hardware *hardware;
142
143 if (!header_index_init(vp, name, length, exact, var_len, write_method))
144 return NULL;
145 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries) {
146 oid index[1] = { hardware->h_ifindex };
147 if (header_index_add(index, 1, hardware)) return hardware;
148 }
149 return header_index_best();
150}
151
152#ifdef ENABLE_LLDPMED
153static struct lldpd_med_policy *
154header_pmedindexed_policy_table(struct variable *vp, oid *name, size_t *length,
155 int exact, size_t *var_len, WriteMethod **write_method)
156{
157 struct lldpd_hardware *hardware;
158 int i;
159 oid index[2];
160
161 if (!header_index_init(vp, name, length, exact, var_len, write_method))
162 return NULL;
163 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries) {
164 for (i = 0; i < LLDP_MED_APPTYPE_LAST; i++) {
165 if (hardware->h_lport.p_med_policy[i].type != i + 1) continue;
166 index[0] = hardware->h_ifindex;
167 index[1] = i + 1;
168 if (header_index_add(index, 2,
169 &hardware->h_lport.p_med_policy[i]))
170 return &hardware->h_lport.p_med_policy[i];
171 }
172 }
173 return header_index_best();
174}
175
176static struct lldpd_med_loc *
177header_pmedindexed_location_table(struct variable *vp, oid *name, size_t *length,
178 int exact, size_t *var_len, WriteMethod **write_method)
179{
180 struct lldpd_hardware *hardware;
181 int i;
182 oid index[2];
183
184 if (!header_index_init(vp, name, length, exact, var_len, write_method))
185 return NULL;
186 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries) {
187 for (i = 0; i < LLDP_MED_LOCFORMAT_LAST; i++) {
188 if (hardware->h_lport.p_med_location[i].format != i + 1)
189 continue;
190 index[0] = hardware->h_ifindex;
191 index[1] = i + 2;
192 if (header_index_add(index, 2,
193 &hardware->h_lport.p_med_location[i]))
194 return &hardware->h_lport.p_med_location[i];
195 }
196 }
197 return header_index_best();
198}
199#endif
200
201static struct lldpd_port *
202header_tprindexed_table(struct variable *vp, oid *name, size_t *length, int exact,
203 size_t *var_len, WriteMethod **write_method, int withmed)
204{
205 struct lldpd_hardware *hardware;
206 struct lldpd_port *port;
207 oid index[3];
208
209 if (!header_index_init(vp, name, length, exact, var_len, write_method))
210 return NULL;
211 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries) {
212 TAILQ_FOREACH (port, &hardware->h_rports, p_entries) {
213 if (SMART_HIDDEN(port)) continue;
214#ifdef ENABLE_LLDPMED
215 if (withmed && !port->p_chassis->c_med_cap_available) continue;
216#endif
217 index[0] = lastchange(port);
218 index[1] = hardware->h_ifindex;
219 index[2] = port->p_chassis->c_index;
220 if (header_index_add(index, 3, port)) return port;
221 }
222 }
223 return header_index_best();
224}
225
226static struct lldpd_mgmt *
227header_ipindexed_table(struct variable *vp, oid *name, size_t *length, int exact,
228 size_t *var_len, WriteMethod **write_method)
229{
230 struct lldpd_chassis *chassis = LOCAL_CHASSIS(scfg);
231 struct lldpd_mgmt *mgmt;
232 oid index[2 + 16];
233
234 if (!header_index_init(vp, name, length, exact, var_len, write_method))
235 return NULL;
236 TAILQ_FOREACH (mgmt, &chassis->c_mgmt, m_entries) {
237 int i;
238 switch (mgmt->m_family) {
239 case LLDPD_AF_IPV4:
240 index[0] = 1;
241 break;
242 case LLDPD_AF_IPV6:
243 index[0] = 2;
244 break;
245 default:
246 assert(0);
247 }
248 index[1] = mgmt->m_addrsize;
249 if (index[1] > sizeof(index) - 2) continue; /* Odd... */
250 for (i = 0; i < index[1]; i++)
251 index[i + 2] = mgmt->m_addr.octets[i];
252 if (header_index_add(index, 2 + index[1], mgmt)) return mgmt;
253 }
254
255 return header_index_best();
256}
257
258static struct lldpd_mgmt *
259header_tpripindexed_table(struct variable *vp, oid *name, size_t *length, int exact,
260 size_t *var_len, WriteMethod **write_method)
261{
262 struct lldpd_hardware *hardware;
263 struct lldpd_port *port;
264 struct lldpd_mgmt *mgmt;
265 oid index[5 + 16];
266
267 if (!header_index_init(vp, name, length, exact, var_len, write_method))
268 return NULL;
269 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries) {
270 TAILQ_FOREACH (port, &hardware->h_rports, p_entries) {
271 if (SMART_HIDDEN(port)) continue;
272 TAILQ_FOREACH (mgmt, &port->p_chassis->c_mgmt, m_entries) {
273 int i;
274 index[0] = lastchange(port);
275 index[1] = hardware->h_ifindex;
276 index[2] = port->p_chassis->c_index;
277 switch (mgmt->m_family) {
278 case LLDPD_AF_IPV4:
279 index[3] = 1;
280 break;
281 case LLDPD_AF_IPV6:
282 index[3] = 2;
283 break;
284 default:
285 assert(0);
286 }
287 index[4] = mgmt->m_addrsize;
288 if (index[4] > sizeof(index) - 5) continue; /* Odd... */
289 for (i = 0; i < index[4]; i++)
290 index[i + 5] = mgmt->m_addr.octets[i];
291 if (header_index_add(index, 5 + index[4], mgmt))
292 return mgmt;
293 }
294 }
295 }
296 return header_index_best();
297}
298
299#ifdef ENABLE_CUSTOM
300static struct lldpd_custom *
301header_tprcustomindexed_table(struct variable *vp, oid *name, size_t *length, int exact,
302 size_t *var_len, WriteMethod **write_method)
303{
304 struct lldpd_hardware *hardware;
305 struct lldpd_port *port;
306 struct lldpd_custom *custom;
307 oid index[8];
308 oid idx;
309
310 if (!header_index_init(vp, name, length, exact, var_len, write_method))
311 return NULL;
312 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries) {
313 TAILQ_FOREACH (port, &hardware->h_rports, p_entries) {
314 if (SMART_HIDDEN(port)) continue;
315 idx = 1;
316 TAILQ_FOREACH (custom, &port->p_custom_list, next) {
317 index[0] = lastchange(port);
318 index[1] = hardware->h_ifindex;
319 index[2] = port->p_chassis->c_index;
320 index[3] = custom->oui[0];
321 index[4] = custom->oui[1];
322 index[5] = custom->oui[2];
323 index[6] = custom->subtype;
324 index[7] = idx++;
325 if (header_index_add(index, 8, custom)) return custom;
326 }
327 }
328 }
329 return header_index_best();
330}
331#endif
332
333#ifdef ENABLE_LLDPMED
334# define TPR_VARIANT_MED_POLICY 2
335# define TPR_VARIANT_MED_LOCATION 3
336static void *
337header_tprmedindexed_table(struct variable *vp, oid *name, size_t *length, int exact,
338 size_t *var_len, WriteMethod **write_method, int variant)
339{
340 struct lldpd_hardware *hardware;
341 struct lldpd_port *port;
342 int j;
343 oid index[4];
344
345 if (!header_index_init(vp, name, length, exact, var_len, write_method))
346 return NULL;
347 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries) {
348 TAILQ_FOREACH (port, &hardware->h_rports, p_entries) {
349 if (SMART_HIDDEN(port)) continue;
350 if (!port->p_chassis->c_med_cap_available) continue;
351 switch (variant) {
352 case TPR_VARIANT_MED_POLICY:
353 for (j = 0; j < LLDP_MED_APPTYPE_LAST; j++) {
354 if (port->p_med_policy[j].type != j + 1)
355 continue;
356 index[0] = lastchange(port);
357 index[1] = hardware->h_ifindex;
358 index[2] = port->p_chassis->c_index;
359 index[3] = j + 1;
360 if (header_index_add(index, 4,
361 &port->p_med_policy[j]))
362 return &port->p_med_policy[j];
363 }
364 break;
365 case TPR_VARIANT_MED_LOCATION:
366 for (j = 0; j < LLDP_MED_LOCFORMAT_LAST; j++) {
367 if (port->p_med_location[j].format != j + 1)
368 continue;
369 index[0] = lastchange(port);
370 index[1] = hardware->h_ifindex;
371 index[2] = port->p_chassis->c_index;
372 index[3] = j + 2;
373 if (header_index_add(index, 4,
374 &port->p_med_location[j]))
375 return &port->p_med_location[j];
376 }
377 break;
378 }
379 }
380 }
381 return header_index_best();
382}
383#endif
384
385#ifdef ENABLE_DOT1
386static struct lldpd_vlan *
387header_pvindexed_table(struct variable *vp, oid *name, size_t *length, int exact,
388 size_t *var_len, WriteMethod **write_method)
389{
390 struct lldpd_hardware *hardware;
391 struct lldpd_vlan *vlan;
392
393 if (!header_index_init(vp, name, length, exact, var_len, write_method))
394 return NULL;
395 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries) {
396 TAILQ_FOREACH (vlan, &hardware->h_lport.p_vlans, v_entries) {
397 oid index[2] = { hardware->h_ifindex, vlan->v_vid };
398 if (header_index_add(index, 2, vlan)) return vlan;
399 }
400 }
401 return header_index_best();
402}
403
404static struct lldpd_vlan *
405header_tprvindexed_table(struct variable *vp, oid *name, size_t *length, int exact,
406 size_t *var_len, WriteMethod **write_method)
407{
408 struct lldpd_hardware *hardware;
409 struct lldpd_port *port;
410 struct lldpd_vlan *vlan;
411
412 if (!header_index_init(vp, name, length, exact, var_len, write_method))
413 return NULL;
414 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries) {
415 TAILQ_FOREACH (port, &hardware->h_rports, p_entries) {
416 if (SMART_HIDDEN(port)) continue;
417 TAILQ_FOREACH (vlan, &port->p_vlans, v_entries) {
418 oid index[4] = { lastchange(port), hardware->h_ifindex,
419 port->p_chassis->c_index, vlan->v_vid };
420 if (header_index_add(index, 4, vlan)) return vlan;
421 }
422 }
423 }
424 return header_index_best();
425}
426
427static struct lldpd_ppvid *
428header_pppvidindexed_table(struct variable *vp, oid *name, size_t *length, int exact,
429 size_t *var_len, WriteMethod **write_method)
430{
431 struct lldpd_hardware *hardware;
432 struct lldpd_ppvid *ppvid;
433
434 if (!header_index_init(vp, name, length, exact, var_len, write_method))
435 return NULL;
436 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries) {
437 TAILQ_FOREACH (ppvid, &hardware->h_lport.p_ppvids, p_entries) {
438 oid index[2] = { hardware->h_ifindex, ppvid->p_ppvid };
439 if (header_index_add(index, 2, ppvid)) return ppvid;
440 }
441 }
442 return header_index_best();
443}
444
445static struct lldpd_ppvid *
446header_tprppvidindexed_table(struct variable *vp, oid *name, size_t *length, int exact,
447 size_t *var_len, WriteMethod **write_method)
448{
449 struct lldpd_hardware *hardware;
450 struct lldpd_port *port;
451 struct lldpd_ppvid *ppvid;
452
453 if (!header_index_init(vp, name, length, exact, var_len, write_method))
454 return NULL;
455 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries) {
456 TAILQ_FOREACH (port, &hardware->h_rports, p_entries) {
457 if (SMART_HIDDEN(port)) continue;
458 TAILQ_FOREACH (ppvid, &port->p_ppvids, p_entries) {
459 oid index[4] = { lastchange(port), hardware->h_ifindex,
460 port->p_chassis->c_index, ppvid->p_ppvid };
461 if (header_index_add(index, 4, ppvid)) return ppvid;
462 }
463 }
464 }
465 return header_index_best();
466}
467
468static struct lldpd_pi *
469header_ppiindexed_table(struct variable *vp, oid *name, size_t *length, int exact,
470 size_t *var_len, WriteMethod **write_method)
471{
472 struct lldpd_hardware *hardware;
473 struct lldpd_pi *pi;
474
475 if (!header_index_init(vp, name, length, exact, var_len, write_method))
476 return NULL;
477 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries) {
478 TAILQ_FOREACH (pi, &hardware->h_lport.p_pids, p_entries) {
479 oid index[2] = { hardware->h_ifindex,
480 frame_checksum((const u_char *)pi->p_pi, pi->p_pi_len,
481 0) };
482 if (header_index_add(index, 2, pi)) return pi;
483 }
484 }
485 return header_index_best();
486}
487
488static struct lldpd_pi *
489header_tprpiindexed_table(struct variable *vp, oid *name, size_t *length, int exact,
490 size_t *var_len, WriteMethod **write_method)
491{
492 struct lldpd_hardware *hardware;
493 struct lldpd_port *port;
494 struct lldpd_pi *pi;
495
496 if (!header_index_init(vp, name, length, exact, var_len, write_method))
497 return NULL;
498 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries) {
499 TAILQ_FOREACH (port, &hardware->h_rports, p_entries) {
500 if (SMART_HIDDEN(port)) continue;
501 TAILQ_FOREACH (pi, &port->p_pids, p_entries) {
502 oid index[4] = { lastchange(port), hardware->h_ifindex,
503 port->p_chassis->c_index,
504 frame_checksum((const u_char *)pi->p_pi,
505 pi->p_pi_len, 0) };
506 if (header_index_add(index, 4, pi)) return pi;
507 }
508 }
509 }
510 return header_index_best();
511}
512#endif
513
514/* Scalars */
515#define LLDP_SNMP_TXINTERVAL 1
516#define LLDP_SNMP_TXMULTIPLIER 2
517#define LLDP_SNMP_REINITDELAY 3
518#define LLDP_SNMP_TXDELAY 4
519#define LLDP_SNMP_NOTIFICATION 5
520#define LLDP_SNMP_LASTUPDATE 6
521#define LLDP_SNMP_STATS_INSERTS 7
522#define LLDP_SNMP_STATS_DELETES 8
523#define LLDP_SNMP_STATS_DROPS 9
524#define LLDP_SNMP_STATS_AGEOUTS 10
525/* Chassis */
526#define LLDP_SNMP_CIDSUBTYPE 1
527#define LLDP_SNMP_CID 2
528#define LLDP_SNMP_SYSNAME 3
529#define LLDP_SNMP_SYSDESCR 4
530#define LLDP_SNMP_SYSCAP_SUP 5
531#define LLDP_SNMP_SYSCAP_ENA 6
532/* Stats */
533#define LLDP_SNMP_STATS_TX 2
534#define LLDP_SNMP_STATS_RX_DISCARDED 4
535#define LLDP_SNMP_STATS_RX_ERRORS 5
536#define LLDP_SNMP_STATS_RX 6
537#define LLDP_SNMP_STATS_RX_TLVDISCARDED 7
538#define LLDP_SNMP_STATS_RX_TLVUNRECOGNIZED 8
539#define LLDP_SNMP_STATS_RX_AGEOUTS 9
540/* Ports */
541#define LLDP_SNMP_PIDSUBTYPE 2
542#define LLDP_SNMP_PID 3
543#define LLDP_SNMP_PORTDESC 4
544#define LLDP_SNMP_DOT3_AUTONEG_SUPPORT 5
545#define LLDP_SNMP_DOT3_AUTONEG_ENABLED 6
546#define LLDP_SNMP_DOT3_AUTONEG_ADVERTISED 7
547#define LLDP_SNMP_DOT3_AUTONEG_MAU 8
548#define LLDP_SNMP_DOT3_AGG_STATUS 9
549#define LLDP_SNMP_DOT3_AGG_ID 10
550#define LLDP_SNMP_DOT3_MFS 11
551#define LLDP_SNMP_DOT3_POWER_DEVICETYPE 12
552#define LLDP_SNMP_DOT3_POWER_SUPPORT 13
553#define LLDP_SNMP_DOT3_POWER_ENABLED 14
554#define LLDP_SNMP_DOT3_POWER_PAIRCONTROL 15
555#define LLDP_SNMP_DOT3_POWER_PAIRS 16
556#define LLDP_SNMP_DOT3_POWER_CLASS 17
557#define LLDP_SNMP_DOT3_POWER_TYPE 18
558#define LLDP_SNMP_DOT3_POWER_SOURCE 19
559#define LLDP_SNMP_DOT3_POWER_PRIORITY 20
560#define LLDP_SNMP_DOT3_POWER_REQUESTED 21
561#define LLDP_SNMP_DOT3_POWER_ALLOCATED 22
562#define LLDP_SNMP_DOT1_PVID 23
563/* Vlans */
564#define LLDP_SNMP_DOT1_VLANNAME 1
565/* Protocol VLAN IDs */
566#define LLDP_SNMP_DOT1_PPVLAN_SUPPORTED 2
567#define LLDP_SNMP_DOT1_PPVLAN_ENABLED 3
568/* Protocol Identity */
569#define LLDP_SNMP_DOT1_PI 1
570/* Management address */
571#define LLDP_SNMP_ADDR_LEN 1
572#define LLDP_SNMP_ADDR_IFSUBTYPE 2
573#define LLDP_SNMP_ADDR_IFID 3
574#define LLDP_SNMP_ADDR_OID 4
575/* Custom TLVs */
576#define LLDP_SNMP_ORG_DEF_INFO 1
577/* LLDP-MED */
578#define LLDP_SNMP_MED_CAP_AVAILABLE 1
579#define LLDP_SNMP_MED_CAP_ENABLED 2
580#define LLDP_SNMP_MED_CLASS 3
581#define LLDP_SNMP_MED_HW 4
582#define LLDP_SNMP_MED_FW 5
583#define LLDP_SNMP_MED_SW 6
584#define LLDP_SNMP_MED_SN 7
585#define LLDP_SNMP_MED_MANUF 8
586#define LLDP_SNMP_MED_MODEL 9
587#define LLDP_SNMP_MED_ASSET 10
588#define LLDP_SNMP_MED_POLICY_VID 11
589#define LLDP_SNMP_MED_POLICY_PRIO 12
590#define LLDP_SNMP_MED_POLICY_DSCP 13
591#define LLDP_SNMP_MED_POLICY_UNKNOWN 14
592#define LLDP_SNMP_MED_POLICY_TAGGED 15
593#define LLDP_SNMP_MED_LOCATION 16
594#define LLDP_SNMP_MED_POE_DEVICETYPE 17
595#define LLDP_SNMP_MED_POE_PSE_POWERVAL 19
596#define LLDP_SNMP_MED_POE_PSE_POWERSOURCE 20
597#define LLDP_SNMP_MED_POE_PSE_POWERPRIORITY 21
598#define LLDP_SNMP_MED_POE_PD_POWERVAL 22
599#define LLDP_SNMP_MED_POE_PD_POWERSOURCE 23
600#define LLDP_SNMP_MED_POE_PD_POWERPRIORITY 24
601
602/* The following macro should be used anytime where the selected OID
603 is finally not returned (for example, when the associated data is
604 not available). In this case, we retry the function with the next
605 OID. */
606#define TRYNEXT(X) \
607 do { \
608 if (!exact && (name[*length - 1] < MAX_SUBID)) \
609 return X(vp, name, length, exact, var_len, write_method); \
610 return NULL; \
611 } while (0)
612
613static u_char *
614agent_h_scalars(struct variable *vp, oid *name, size_t *length, int exact,
615 size_t *var_len, WriteMethod **write_method)
616{
617 static unsigned long long_ret;
618 struct lldpd_hardware *hardware;
619 struct lldpd_port *port;
620
621 if (header_generic(vp, name, length, exact, var_len, write_method)) return NULL;
622
623 switch (vp->magic) {
624 case LLDP_SNMP_TXINTERVAL:
625 long_ret = (scfg->g_config.c_tx_interval + 999) / 1000;
626 return (u_char *)&long_ret;
627 case LLDP_SNMP_TXMULTIPLIER:
628 long_ret = scfg->g_config.c_tx_hold;
629 return (u_char *)&long_ret;
630 case LLDP_SNMP_REINITDELAY:
631 long_ret = 1;
632 return (u_char *)&long_ret;
633 case LLDP_SNMP_TXDELAY:
634 long_ret = LLDPD_TX_MSGDELAY;
635 return (u_char *)&long_ret;
636 case LLDP_SNMP_NOTIFICATION:
637 long_ret = 5;
638 return (u_char *)&long_ret;
639 case LLDP_SNMP_LASTUPDATE:
640 long_ret = 0;
641 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries) {
642 /* Check if the last removal of a remote port on this local port
643 * was the last change. */
644 if (hardware->h_lport.p_lastremove > long_ret)
645 long_ret = hardware->h_lport.p_lastremove;
646 /* Check if any change on the existing remote ports was the last
647 * change. */
648 TAILQ_FOREACH (port, &hardware->h_rports, p_entries) {
649 if (SMART_HIDDEN(port)) continue;
650 if (port->p_lastchange > long_ret)
651 long_ret = port->p_lastchange;
652 }
653 }
654 if (long_ret) long_ret = (long_ret - starttime.tv_sec) * 100;
655 return (u_char *)&long_ret;
656 case LLDP_SNMP_STATS_INSERTS:
657 /* We assume this is equal to valid frames received on all ports */
658 long_ret = 0;
659 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries)
660 long_ret += hardware->h_insert_cnt;
661 return (u_char *)&long_ret;
662 case LLDP_SNMP_STATS_AGEOUTS:
663 long_ret = 0;
664 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries)
665 long_ret += hardware->h_ageout_cnt;
666 return (u_char *)&long_ret;
667 case LLDP_SNMP_STATS_DELETES:
668 long_ret = 0;
669 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries)
670 long_ret += hardware->h_delete_cnt;
671 return (u_char *)&long_ret;
672 case LLDP_SNMP_STATS_DROPS:
673 long_ret = 0;
674 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries)
675 long_ret += hardware->h_drop_cnt;
676 return (u_char *)&long_ret;
677 default:
678 break;
679 }
680 return NULL;
681}
682
683#ifdef ENABLE_LLDPMED
684static u_char *
685agent_v_med_power(struct variable *vp, size_t *var_len, struct lldpd_med_power *power)
686{
687 static unsigned long long_ret;
688
689 switch (vp->magic) {
690 case LLDP_SNMP_MED_POE_DEVICETYPE:
691 switch (power->devicetype) {
692 case LLDP_MED_POW_TYPE_PSE:
693 long_ret = 2;
694 break;
695 case LLDP_MED_POW_TYPE_PD:
696 long_ret = 3;
697 break;
698 case 0:
699 long_ret = 4;
700 break;
701 default:
702 long_ret = 1;
703 }
704 return (u_char *)&long_ret;
705 case LLDP_SNMP_MED_POE_PSE_POWERVAL:
706 case LLDP_SNMP_MED_POE_PD_POWERVAL:
707 if (((vp->magic == LLDP_SNMP_MED_POE_PSE_POWERVAL) &&
708 (power->devicetype == LLDP_MED_POW_TYPE_PSE)) ||
709 ((vp->magic == LLDP_SNMP_MED_POE_PD_POWERVAL) &&
710 (power->devicetype == LLDP_MED_POW_TYPE_PD))) {
711 long_ret = power->val;
712 return (u_char *)&long_ret;
713 }
714 break;
715 case LLDP_SNMP_MED_POE_PSE_POWERSOURCE:
716 if (power->devicetype == LLDP_MED_POW_TYPE_PSE) {
717 switch (power->source) {
718 case LLDP_MED_POW_SOURCE_PRIMARY:
719 long_ret = 2;
720 break;
721 case LLDP_MED_POW_SOURCE_BACKUP:
722 long_ret = 3;
723 break;
724 default:
725 long_ret = 1;
726 }
727 return (u_char *)&long_ret;
728 }
729 break;
730 case LLDP_SNMP_MED_POE_PD_POWERSOURCE:
731 if (power->devicetype == LLDP_MED_POW_TYPE_PD) {
732 switch (power->source) {
733 case LLDP_MED_POW_SOURCE_PSE:
734 long_ret = 2;
735 break;
736 case LLDP_MED_POW_SOURCE_LOCAL:
737 long_ret = 3;
738 break;
739 case LLDP_MED_POW_SOURCE_BOTH:
740 long_ret = 4;
741 break;
742 default:
743 long_ret = 1;
744 }
745 return (u_char *)&long_ret;
746 }
747 break;
748 case LLDP_SNMP_MED_POE_PSE_POWERPRIORITY:
749 case LLDP_SNMP_MED_POE_PD_POWERPRIORITY:
750 if (((vp->magic == LLDP_SNMP_MED_POE_PSE_POWERPRIORITY) &&
751 (power->devicetype == LLDP_MED_POW_TYPE_PSE)) ||
752 ((vp->magic == LLDP_SNMP_MED_POE_PD_POWERPRIORITY) &&
753 (power->devicetype == LLDP_MED_POW_TYPE_PD))) {
754 switch (power->priority) {
755 case LLDP_MED_POW_PRIO_CRITICAL:
756 long_ret = 2;
757 break;
758 case LLDP_MED_POW_PRIO_HIGH:
759 long_ret = 3;
760 break;
761 case LLDP_MED_POW_PRIO_LOW:
762 long_ret = 4;
763 break;
764 default:
765 long_ret = 1;
766 }
767 return (u_char *)&long_ret;
768 }
769 break;
770 }
771
772 return NULL;
773}
774static u_char *
775agent_h_local_med_power(struct variable *vp, oid *name, size_t *length, int exact,
776 size_t *var_len, WriteMethod **write_method)
777{
778 struct lldpd_med_power *power = NULL;
779 struct lldpd_hardware *hardware;
780 int pse = 0;
781
782 if (!LOCAL_CHASSIS(scfg)->c_med_cap_available) return NULL;
783 if (header_generic(vp, name, length, exact, var_len, write_method)) return NULL;
784
785 /* LLDP-MED requires only one device type for all
786 ports. Moreover, a PSE can only have one power source. At
787 least, all PD values are global and not per-port. We try to
788 do our best. For device type, we decide on the number of
789 PD/PSE ports. */
790 TAILQ_FOREACH (hardware, &scfg->g_hardware, h_entries) {
791 if (hardware->h_lport.p_med_power.devicetype == LLDP_MED_POW_TYPE_PSE) {
792 pse++;
793 if (pse == 1) /* Take this port as a reference */
794 power = &hardware->h_lport.p_med_power;
795 } else if (hardware->h_lport.p_med_power.devicetype ==
796 LLDP_MED_POW_TYPE_PD) {
797 pse--;
798 if (pse == -1) /* Take this one instead */
799 power = &hardware->h_lport.p_med_power;
800 }
801 }
802 if (power) {
803 u_char *a;
804 if ((a = agent_v_med_power(vp, var_len, power)) != NULL) return a;
805 }
806 TRYNEXT(agent_h_local_med_power);
807}
808static u_char *
809agent_h_remote_med_power(struct variable *vp, oid *name, size_t *length, int exact,
810 size_t *var_len, WriteMethod **write_method)
811{
812 struct lldpd_port *port;
813 u_char *a;
814
815 if ((port = header_tprindexed_table(vp, name, length, exact, var_len,
816 write_method, 1)) == NULL)
817 return NULL;
818
819 if ((a = agent_v_med_power(vp, var_len, &port->p_med_power)) != NULL) return a;
820 TRYNEXT(agent_h_remote_med_power);
821}
822
823static u_char *
824agent_v_med(struct variable *vp, size_t *var_len, struct lldpd_chassis *chassis,
825 struct lldpd_port *port)
826{
827 static unsigned long long_ret;
828 static uint8_t bit;
829
830 switch (vp->magic) {
831 case LLDP_SNMP_MED_CLASS:
832 long_ret = chassis->c_med_type;
833 return (u_char *)&long_ret;
834 case LLDP_SNMP_MED_CAP_AVAILABLE:
835 *var_len = 1;
836 bit = swap_bits(chassis->c_med_cap_available);
837 return (u_char *)&bit;
838 case LLDP_SNMP_MED_CAP_ENABLED:
839 if (!port) break;
840 *var_len = 1;
841 bit = swap_bits(port->p_med_cap_enabled);
842 return (u_char *)&bit;
843
844# define LLDP_H_MED(magic, variable) \
845 case magic: \
846 if (chassis->variable) { \
847 *var_len = strlen(chassis->variable); \
848 return (u_char *)chassis->variable; \
849 } \
850 break
851
852 LLDP_H_MED(LLDP_SNMP_MED_HW, c_med_hw);
853 LLDP_H_MED(LLDP_SNMP_MED_SW, c_med_sw);
854 LLDP_H_MED(LLDP_SNMP_MED_FW, c_med_fw);
855 LLDP_H_MED(LLDP_SNMP_MED_SN, c_med_sn);
856 LLDP_H_MED(LLDP_SNMP_MED_MANUF, c_med_manuf);
857 LLDP_H_MED(LLDP_SNMP_MED_MODEL, c_med_model);
858 LLDP_H_MED(LLDP_SNMP_MED_ASSET, c_med_asset);
859 }
860 return NULL;
861}
862static u_char *
863agent_h_local_med(struct variable *vp, oid *name, size_t *length, int exact,
864 size_t *var_len, WriteMethod **write_method)
865{
866 u_char *a;
867
868 if (!LOCAL_CHASSIS(scfg)->c_med_cap_available) return NULL;
869 if (header_generic(vp, name, length, exact, var_len, write_method)) return NULL;
870
871 if ((a = agent_v_med(vp, var_len, LOCAL_CHASSIS(scfg), NULL)) != NULL) return a;
872 TRYNEXT(agent_h_local_med);
873}
874
875static u_char *
876agent_h_remote_med(struct variable *vp, oid *name, size_t *length, int exact,
877 size_t *var_len, WriteMethod **write_method)
878{
879 struct lldpd_port *port;
880 u_char *a;
881
882 if ((port = header_tprindexed_table(vp, name, length, exact, var_len,
883 write_method, 1)) == NULL)
884 return NULL;
885
886 if ((a = agent_v_med(vp, var_len, port->p_chassis, port)) != NULL) return a;
887 TRYNEXT(agent_h_remote_med);
888}
889
890static u_char *
891agent_v_med_policy(struct variable *vp, size_t *var_len,
892 struct lldpd_med_policy *policy)
893{
894 static unsigned long long_ret;
895
896 switch (vp->magic) {
897 case LLDP_SNMP_MED_POLICY_VID:
898 long_ret = policy->vid;
899 return (u_char *)&long_ret;
900 case LLDP_SNMP_MED_POLICY_PRIO:
901 long_ret = policy->priority;
902 return (u_char *)&long_ret;
903 case LLDP_SNMP_MED_POLICY_DSCP:
904 long_ret = policy->dscp;
905 return (u_char *)&long_ret;
906 case LLDP_SNMP_MED_POLICY_UNKNOWN:
907 long_ret = policy->unknown ? 1 : 2;
908 return (u_char *)&long_ret;
909 case LLDP_SNMP_MED_POLICY_TAGGED:
910 long_ret = policy->tagged ? 1 : 2;
911 return (u_char *)&long_ret;
912 default:
913 return NULL;
914 }
915}
916static u_char *
917agent_h_remote_med_policy(struct variable *vp, oid *name, size_t *length, int exact,
918 size_t *var_len, WriteMethod **write_method)
919{
920 struct lldpd_med_policy *policy;
921
922 if ((policy = (struct lldpd_med_policy *)header_tprmedindexed_table(vp, name,
923 length, exact, var_len, write_method, TPR_VARIANT_MED_POLICY)) == NULL)
924 return NULL;
925
926 return agent_v_med_policy(vp, var_len, policy);
927}
928static u_char *
929agent_h_local_med_policy(struct variable *vp, oid *name, size_t *length, int exact,
930 size_t *var_len, WriteMethod **write_method)
931{
932 struct lldpd_med_policy *policy;
933
934 if ((policy = (struct lldpd_med_policy *)header_pmedindexed_policy_table(vp,
935 name, length, exact, var_len, write_method)) == NULL)
936 return NULL;
937
938 return agent_v_med_policy(vp, var_len, policy);
939}
940
941static u_char *
942agent_v_med_location(struct variable *vp, size_t *var_len,
943 struct lldpd_med_loc *location)
944{
945 switch (vp->magic) {
946 case LLDP_SNMP_MED_LOCATION:
947 *var_len = location->data_len;
948 return (u_char *)location->data;
949 default:
950 return NULL;
951 }
952}
953static u_char *
954agent_h_remote_med_location(struct variable *vp, oid *name, size_t *length, int exact,
955 size_t *var_len, WriteMethod **write_method)
956{
957 struct lldpd_med_loc *location;
958
959 if ((location = (struct lldpd_med_loc *)header_tprmedindexed_table(vp, name,
960 length, exact, var_len, write_method, TPR_VARIANT_MED_LOCATION)) ==
961 NULL)
962 return NULL;
963
964 return agent_v_med_location(vp, var_len, location);
965}
966static u_char *
967agent_h_local_med_location(struct variable *vp, oid *name, size_t *length, int exact,
968 size_t *var_len, WriteMethod **write_method)
969{
970 struct lldpd_med_loc *location;
971
972 if ((location = (struct lldpd_med_loc *)header_pmedindexed_location_table(vp,
973 name, length, exact, var_len, write_method)) == NULL)
974 return NULL;
975
976 return agent_v_med_location(vp, var_len, location);
977}
978#endif
979
980static u_char *
981agent_v_chassis(struct variable *vp, size_t *var_len, struct lldpd_chassis *chassis)
982{
983 static uint8_t bit;
984 static unsigned long long_ret;
985
986 switch (vp->magic) {
987 case LLDP_SNMP_CIDSUBTYPE:
988 long_ret = chassis->c_id_subtype;
989 return (u_char *)&long_ret;
990 case LLDP_SNMP_CID:
991 *var_len = chassis->c_id_len;
992 return (u_char *)chassis->c_id;
993 case LLDP_SNMP_SYSNAME:
994 if (!chassis->c_name || *chassis->c_name == '\0') break;
995 *var_len = strlen(chassis->c_name);
996 return (u_char *)chassis->c_name;
997 case LLDP_SNMP_SYSDESCR:
998 if (!chassis->c_descr || *chassis->c_descr == '\0') break;
999 *var_len = strlen(chassis->c_descr);
1000 return (u_char *)chassis->c_descr;
1001 case LLDP_SNMP_SYSCAP_SUP:
1002 *var_len = 1;
1003 bit = swap_bits(chassis->c_cap_available);
1004 return (u_char *)&bit;
1005 case LLDP_SNMP_SYSCAP_ENA:
1006 *var_len = 1;
1007 bit = swap_bits(chassis->c_cap_enabled);
1008 return (u_char *)&bit;
1009 default:
1010 break;
1011 }
1012 return NULL;
1013}
1014static u_char *
1015agent_h_local_chassis(struct variable *vp, oid *name, size_t *length, int exact,
1016 size_t *var_len, WriteMethod **write_method)
1017{
1018 u_char *a;
1019
1020 if (header_generic(vp, name, length, exact, var_len, write_method)) return NULL;
1021
1022 if ((a = agent_v_chassis(vp, var_len, LOCAL_CHASSIS(scfg))) != NULL) return a;
1023 TRYNEXT(agent_h_local_chassis);
1024}
1025static u_char *
1026agent_h_remote_chassis(struct variable *vp, oid *name, size_t *length, int exact,
1027 size_t *var_len, WriteMethod **write_method)
1028{
1029 struct lldpd_port *port;
1030 u_char *a;
1031
1032 if ((port = header_tprindexed_table(vp, name, length, exact, var_len,
1033 write_method, 0)) == NULL)
1034 return NULL;
1035
1036 if ((a = agent_v_chassis(vp, var_len, port->p_chassis)) != NULL) return a;
1037 TRYNEXT(agent_h_remote_chassis);
1038}
1039
1040static u_char *
1041agent_h_stats(struct variable *vp, oid *name, size_t *length, int exact,
1042 size_t *var_len, WriteMethod **write_method)
1043{
1044 static unsigned long long_ret;
1045 struct lldpd_hardware *hardware;
1046
1047 if ((hardware = header_portindexed_table(vp, name, length, exact, var_len,
1048 write_method)) == NULL)
1049 return NULL;
1050
1051 switch (vp->magic) {
1052 case LLDP_SNMP_STATS_TX:
1053 long_ret = hardware->h_tx_cnt;
1054 return (u_char *)&long_ret;
1055 case LLDP_SNMP_STATS_RX:
1056 long_ret = hardware->h_rx_cnt;
1057 return (u_char *)&long_ret;
1058 case LLDP_SNMP_STATS_RX_DISCARDED:
1059 case LLDP_SNMP_STATS_RX_ERRORS:
1060 /* We discard only frame with errors. Therefore, the two values
1061 * are equal */
1062 long_ret = hardware->h_rx_discarded_cnt;
1063 return (u_char *)&long_ret;
1064 case LLDP_SNMP_STATS_RX_TLVDISCARDED:
1065 case LLDP_SNMP_STATS_RX_TLVUNRECOGNIZED:
1066 /* We discard only unrecognized TLV. Malformed TLV
1067 implies dropping the whole frame */
1068 long_ret = hardware->h_rx_unrecognized_cnt;
1069 return (u_char *)&long_ret;
1070 case LLDP_SNMP_STATS_RX_AGEOUTS:
1071 long_ret = hardware->h_ageout_cnt;
1072 return (u_char *)&long_ret;
1073 default:
1074 return NULL;
1075 }
1076}
1077
1078#ifdef ENABLE_DOT1
1079static u_char *
1080agent_v_vlan(struct variable *vp, size_t *var_len, struct lldpd_vlan *vlan)
1081{
1082 switch (vp->magic) {
1083 case LLDP_SNMP_DOT1_VLANNAME:
1084 *var_len = strlen(vlan->v_name);
1085 return (u_char *)vlan->v_name;
1086 default:
1087 return NULL;
1088 }
1089}
1090static u_char *
1091agent_h_local_vlan(struct variable *vp, oid *name, size_t *length, int exact,
1092 size_t *var_len, WriteMethod **write_method)
1093{
1094 struct lldpd_vlan *vlan;
1095
1096 if ((vlan = header_pvindexed_table(vp, name, length, exact, var_len,
1097 write_method)) == NULL)
1098 return NULL;
1099
1100 return agent_v_vlan(vp, var_len, vlan);
1101}
1102static u_char *
1103agent_h_remote_vlan(struct variable *vp, oid *name, size_t *length, int exact,
1104 size_t *var_len, WriteMethod **write_method)
1105{
1106 struct lldpd_vlan *vlan;
1107
1108 if ((vlan = header_tprvindexed_table(vp, name, length, exact, var_len,
1109 write_method)) == NULL)
1110 return NULL;
1111
1112 return agent_v_vlan(vp, var_len, vlan);
1113}
1114
1115static u_char *
1116agent_v_ppvid(struct variable *vp, size_t *var_len, struct lldpd_ppvid *ppvid)
1117{
1118 static unsigned long long_ret;
1119
1120 switch (vp->magic) {
1121 case LLDP_SNMP_DOT1_PPVLAN_SUPPORTED:
1122 long_ret = (ppvid->p_cap_status & LLDP_PPVID_CAP_SUPPORTED) ? 1 : 2;
1123 return (u_char *)&long_ret;
1124 case LLDP_SNMP_DOT1_PPVLAN_ENABLED:
1125 long_ret = (ppvid->p_cap_status & LLDP_PPVID_CAP_ENABLED) ? 1 : 2;
1126 return (u_char *)&long_ret;
1127 default:
1128 return NULL;
1129 }
1130}
1131static u_char *
1132agent_h_local_ppvid(struct variable *vp, oid *name, size_t *length, int exact,
1133 size_t *var_len, WriteMethod **write_method)
1134{
1135 struct lldpd_ppvid *ppvid;
1136
1137 if ((ppvid = header_pppvidindexed_table(vp, name, length, exact, var_len,
1138 write_method)) == NULL)
1139 return NULL;
1140
1141 return agent_v_ppvid(vp, var_len, ppvid);
1142}
1143
1144static u_char *
1145agent_h_remote_ppvid(struct variable *vp, oid *name, size_t *length, int exact,
1146 size_t *var_len, WriteMethod **write_method)
1147{
1148 struct lldpd_ppvid *ppvid;
1149
1150 if ((ppvid = header_tprppvidindexed_table(vp, name, length, exact, var_len,
1151 write_method)) == NULL)
1152 return NULL;
1153
1154 return agent_v_ppvid(vp, var_len, ppvid);
1155}
1156
1157static u_char *
1158agent_v_pi(struct variable *vp, size_t *var_len, struct lldpd_pi *pi)
1159{
1160 switch (vp->magic) {
1161 case LLDP_SNMP_DOT1_PI:
1162 *var_len = pi->p_pi_len;
1163 return (u_char *)pi->p_pi;
1164 default:
1165 return NULL;
1166 }
1167}
1168static u_char *
1169agent_h_local_pi(struct variable *vp, oid *name, size_t *length, int exact,
1170 size_t *var_len, WriteMethod **write_method)
1171{
1172 struct lldpd_pi *pi;
1173
1174 if ((pi = header_ppiindexed_table(vp, name, length, exact, var_len,
1175 write_method)) == NULL)
1176 return NULL;
1177
1178 return agent_v_pi(vp, var_len, pi);
1179}
1180static u_char *
1181agent_h_remote_pi(struct variable *vp, oid *name, size_t *length, int exact,
1182 size_t *var_len, WriteMethod **write_method)
1183{
1184 struct lldpd_pi *pi;
1185
1186 if ((pi = header_tprpiindexed_table(vp, name, length, exact, var_len,
1187 write_method)) == NULL)
1188 return NULL;
1189
1190 return agent_v_pi(vp, var_len, pi);
1191}
1192#endif
1193
1194static u_char *
1195agent_v_port(struct variable *vp, size_t *var_len, struct lldpd_port *port)
1196{
1197#ifdef ENABLE_DOT3
1198 static uint16_t short_ret;
1199 static uint8_t bit;
1200#endif
1201 static unsigned long long_ret;
1202
1203 switch (vp->magic) {
1204 case LLDP_SNMP_PIDSUBTYPE:
1205 long_ret = port->p_id_subtype;
1206 return (u_char *)&long_ret;
1207 case LLDP_SNMP_PID:
1208 *var_len = port->p_id_len;
1209 return (u_char *)port->p_id;
1210 case LLDP_SNMP_PORTDESC:
1211 if (!port->p_descr || *port->p_descr == '\0') break;
1212 *var_len = strlen(port->p_descr);
1213 return (u_char *)port->p_descr;
1214#ifdef ENABLE_DOT3
1215 case LLDP_SNMP_DOT3_AUTONEG_SUPPORT:
1216 long_ret = 2 - port->p_macphy.autoneg_support;
1217 return (u_char *)&long_ret;
1218 case LLDP_SNMP_DOT3_AUTONEG_ENABLED:
1219 long_ret = 2 - port->p_macphy.autoneg_enabled;
1220 return (u_char *)&long_ret;
1221 case LLDP_SNMP_DOT3_AUTONEG_ADVERTISED:
1222 *var_len = 2;
1223 short_ret = htons(port->p_macphy.autoneg_advertised);
1224 return (u_char *)&short_ret;
1225 case LLDP_SNMP_DOT3_AUTONEG_MAU:
1226 long_ret = port->p_macphy.mau_type;
1227 return (u_char *)&long_ret;
1228 case LLDP_SNMP_DOT3_AGG_STATUS:
1229 bit = swap_bits((port->p_aggregid > 0) ? 3 : 0);
1230 *var_len = 1;
1231 return (u_char *)&bit;
1232 case LLDP_SNMP_DOT3_AGG_ID:
1233 long_ret = port->p_aggregid;
1234 return (u_char *)&long_ret;
1235 case LLDP_SNMP_DOT3_MFS:
1236 if (port->p_mfs) {
1237 long_ret = port->p_mfs;
1238 return (u_char *)&long_ret;
1239 }
1240 break;
1241 case LLDP_SNMP_DOT3_POWER_DEVICETYPE:
1242 if (port->p_power.devicetype) {
1243 long_ret =
1244 (port->p_power.devicetype == LLDP_DOT3_POWER_PSE) ? 1 : 2;
1245 return (u_char *)&long_ret;
1246 }
1247 break;
1248 case LLDP_SNMP_DOT3_POWER_SUPPORT:
1249 if (port->p_power.devicetype) {
1250 long_ret = (port->p_power.supported) ? 1 : 2;
1251 return (u_char *)&long_ret;
1252 }
1253 break;
1254 case LLDP_SNMP_DOT3_POWER_ENABLED:
1255 if (port->p_power.devicetype) {
1256 long_ret = (port->p_power.enabled) ? 1 : 2;
1257 return (u_char *)&long_ret;
1258 }
1259 break;
1260 case LLDP_SNMP_DOT3_POWER_PAIRCONTROL:
1261 if (port->p_power.devicetype) {
1262 long_ret = (port->p_power.paircontrol) ? 1 : 2;
1263 return (u_char *)&long_ret;
1264 }
1265 break;
1266 case LLDP_SNMP_DOT3_POWER_PAIRS:
1267 if (port->p_power.devicetype) {
1268 long_ret = port->p_power.pairs;
1269 return (u_char *)&long_ret;
1270 }
1271 break;
1272 case LLDP_SNMP_DOT3_POWER_CLASS:
1273 if (port->p_power.devicetype && port->p_power.class) {
1274 long_ret = port->p_power.class;
1275 return (u_char *)&long_ret;
1276 }
1277 break;
1278 case LLDP_SNMP_DOT3_POWER_TYPE:
1279 if (port->p_power.devicetype &&
1280 port->p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
1281 *var_len = 1;
1282 bit = (((port->p_power.powertype ==
1283 LLDP_DOT3_POWER_8023AT_TYPE1) ?
1284 0 :
1285 1)
1286 << 7) |
1287 (((port->p_power.devicetype == LLDP_DOT3_POWER_PSE) ? 0 : 1)
1288 << 6);
1289 return (u_char *)&bit;
1290 }
1291 break;
1292 case LLDP_SNMP_DOT3_POWER_SOURCE:
1293 if (port->p_power.devicetype &&
1294 port->p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
1295 *var_len = 1;
1296 bit = swap_bits(port->p_power.source % (1 << 2));
1297 return (u_char *)&bit;
1298 }
1299 break;
1300 case LLDP_SNMP_DOT3_POWER_PRIORITY:
1301 if (port->p_power.devicetype &&
1302 port->p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
1303 /* See 30.12.2.1.16. This seems defined in reverse order... */
1304 long_ret = 4 - port->p_power.priority;
1305 return (u_char *)&long_ret;
1306 }
1307 break;
1308 case LLDP_SNMP_DOT3_POWER_REQUESTED:
1309 if (port->p_power.devicetype &&
1310 port->p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
1311 long_ret = port->p_power.requested;
1312 return (u_char *)&long_ret;
1313 }
1314 break;
1315 case LLDP_SNMP_DOT3_POWER_ALLOCATED:
1316 if (port->p_power.devicetype &&
1317 port->p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
1318 long_ret = port->p_power.allocated;
1319 return (u_char *)&long_ret;
1320 }
1321 break;
1322#endif
1323#ifdef ENABLE_DOT1
1324 case LLDP_SNMP_DOT1_PVID:
1325 long_ret = port->p_pvid;
1326 return (u_char *)&long_ret;
1327#endif
1328 default:
1329 break;
1330 }
1331 return NULL;
1332}
1333static u_char *
1334agent_h_remote_port(struct variable *vp, oid *name, size_t *length, int exact,
1335 size_t *var_len, WriteMethod **write_method)
1336{
1337 struct lldpd_port *port;
1338 u_char *a;
1339
1340 if ((port = header_tprindexed_table(vp, name, length, exact, var_len,
1341 write_method, 0)) == NULL)
1342 return NULL;
1343
1344 if ((a = agent_v_port(vp, var_len, port)) != NULL) return a;
1345 TRYNEXT(agent_h_remote_port);
1346}
1347static u_char *
1348agent_h_local_port(struct variable *vp, oid *name, size_t *length, int exact,
1349 size_t *var_len, WriteMethod **write_method)
1350{
1351 struct lldpd_hardware *hardware;
1352 u_char *a;
1353
1354 if ((hardware = header_portindexed_table(vp, name, length, exact, var_len,
1355 write_method)) == NULL)
1356 return NULL;
1357
1358 if ((a = agent_v_port(vp, var_len, &hardware->h_lport)) != NULL) return a;
1359 TRYNEXT(agent_h_local_port);
1360}
1361
1362static u_char *
1363agent_v_management(struct variable *vp, size_t *var_len, struct lldpd_mgmt *mgmt)
1364{
1365 static unsigned long int long_ret;
1366 static oid zeroDotZero[2] = { 0, 0 };
1367
1368 switch (vp->magic) {
1369 case LLDP_SNMP_ADDR_LEN:
1370 long_ret = mgmt->m_addrsize + 1;
1371 return (u_char *)&long_ret;
1372 case LLDP_SNMP_ADDR_IFSUBTYPE:
1373 if (mgmt->m_iface != 0)
1374 long_ret = LLDP_MGMT_IFACE_IFINDEX;
1375 else
1376 long_ret = 1;
1377 return (u_char *)&long_ret;
1378 case LLDP_SNMP_ADDR_IFID:
1379 long_ret = mgmt->m_iface;
1380 return (u_char *)&long_ret;
1381 case LLDP_SNMP_ADDR_OID:
1382 *var_len = sizeof(zeroDotZero);
1383 return (u_char *)zeroDotZero;
1384 default:
1385 return NULL;
1386 }
1387}
1388static u_char *
1389agent_h_local_management(struct variable *vp, oid *name, size_t *length, int exact,
1390 size_t *var_len, WriteMethod **write_method)
1391{
1392
1393 struct lldpd_mgmt *mgmt;
1394
1395 if ((mgmt = header_ipindexed_table(vp, name, length, exact, var_len,
1396 write_method)) == NULL)
1397 return NULL;
1398
1399 return agent_v_management(vp, var_len, mgmt);
1400}
1401static u_char *
1402agent_h_remote_management(struct variable *vp, oid *name, size_t *length, int exact,
1403 size_t *var_len, WriteMethod **write_method)
1404{
1405 struct lldpd_mgmt *mgmt;
1406
1407 if ((mgmt = header_tpripindexed_table(vp, name, length, exact, var_len,
1408 write_method)) == NULL)
1409 return NULL;
1410
1411 return agent_v_management(vp, var_len, mgmt);
1412}
1413
1414#ifdef ENABLE_CUSTOM
1415static u_char *
1416agent_v_custom(struct variable *vp, size_t *var_len, struct lldpd_custom *custom)
1417{
1418 switch (vp->magic) {
1419 case LLDP_SNMP_ORG_DEF_INFO:
1420 *var_len = custom->oui_info_len;
1421 return (u_char *)custom->oui_info;
1422 default:
1423 return NULL;
1424 }
1425}
1426static u_char *
1427agent_h_remote_custom(struct variable *vp, oid *name, size_t *length, int exact,
1428 size_t *var_len, WriteMethod **write_method)
1429{
1430 struct lldpd_custom *custom;
1431
1432 if ((custom = header_tprcustomindexed_table(vp, name, length, exact, var_len,
1433 write_method)) == NULL)
1434 return NULL;
1435
1436 return agent_v_custom(vp, var_len, custom);
1437}
1438#endif
1439
1440/*
1441 Here is how it works: a agent_h_*() function will handle incoming
1442 requests. It will use an appropriate header_*indexed_table()
1443 function to grab the appropriate structure that was queried (a port,
1444 a chassis, ...). It will then delegate to a agent_v_*() function the
1445 responsability to extract the appropriate answer.
1446
1447 agent_h_*() functions and header_*indexed_table() are not shared
1448 between remote and not remote version while agent_v_*() functions
1449 are the same for both version.
1450*/
1451
1452/* For testing purposes, keep this structure ordered by increasing OID! */
1453struct variable8 agent_lldp_vars[] = {
1454 /* Scalars */
1455 { LLDP_SNMP_TXINTERVAL, ASN_INTEGER, RONLY, agent_h_scalars, 3, { 1, 1, 1 } },
1456 { LLDP_SNMP_TXMULTIPLIER, ASN_INTEGER, RONLY, agent_h_scalars, 3, { 1, 1, 2 } },
1457 { LLDP_SNMP_REINITDELAY, ASN_INTEGER, RONLY, agent_h_scalars, 3, { 1, 1, 3 } },
1458 { LLDP_SNMP_TXDELAY, ASN_INTEGER, RONLY, agent_h_scalars, 3, { 1, 1, 4 } },
1459 { LLDP_SNMP_NOTIFICATION, ASN_INTEGER, RONLY, agent_h_scalars, 3, { 1, 1, 5 } },
1460 { LLDP_SNMP_LASTUPDATE, ASN_TIMETICKS, RONLY, agent_h_scalars, 3, { 1, 2, 1 } },
1461 { LLDP_SNMP_STATS_INSERTS, ASN_GAUGE, RONLY, agent_h_scalars, 3, { 1, 2, 2 } },
1462 { LLDP_SNMP_STATS_DELETES, ASN_GAUGE, RONLY, agent_h_scalars, 3, { 1, 2, 3 } },
1463 { LLDP_SNMP_STATS_DROPS, ASN_GAUGE, RONLY, agent_h_scalars, 3, { 1, 2, 4 } },
1464 { LLDP_SNMP_STATS_AGEOUTS, ASN_GAUGE, RONLY, agent_h_scalars, 3, { 1, 2, 5 } },
1465 /* Stats */
1466 { LLDP_SNMP_STATS_TX, ASN_COUNTER, RONLY, agent_h_stats, 5, { 1, 2, 6, 1, 2 } },
1467 { LLDP_SNMP_STATS_RX_DISCARDED, ASN_COUNTER, RONLY, agent_h_stats, 5,
1468 { 1, 2, 7, 1, 2 } },
1469 { LLDP_SNMP_STATS_RX_ERRORS, ASN_COUNTER, RONLY, agent_h_stats, 5,
1470 { 1, 2, 7, 1, 3 } },
1471 { LLDP_SNMP_STATS_RX, ASN_COUNTER, RONLY, agent_h_stats, 5, { 1, 2, 7, 1, 4 } },
1472 { LLDP_SNMP_STATS_RX_TLVDISCARDED, ASN_COUNTER, RONLY, agent_h_stats, 5,
1473 { 1, 2, 7, 1, 5 } },
1474 { LLDP_SNMP_STATS_RX_TLVUNRECOGNIZED, ASN_COUNTER, RONLY, agent_h_stats, 5,
1475 { 1, 2, 7, 1, 6 } },
1476 { LLDP_SNMP_STATS_RX_AGEOUTS, ASN_GAUGE, RONLY, agent_h_stats, 5,
1477 { 1, 2, 7, 1, 7 } },
1478 /* Local chassis */
1479 { LLDP_SNMP_CIDSUBTYPE, ASN_INTEGER, RONLY, agent_h_local_chassis, 3,
1480 { 1, 3, 1 } },
1481 { LLDP_SNMP_CID, ASN_OCTET_STR, RONLY, agent_h_local_chassis, 3, { 1, 3, 2 } },
1482 { LLDP_SNMP_SYSNAME, ASN_OCTET_STR, RONLY, agent_h_local_chassis, 3,
1483 { 1, 3, 3 } },
1484 { LLDP_SNMP_SYSDESCR, ASN_OCTET_STR, RONLY, agent_h_local_chassis, 3,
1485 { 1, 3, 4 } },
1486 { LLDP_SNMP_SYSCAP_SUP, ASN_OCTET_STR, RONLY, agent_h_local_chassis, 3,
1487 { 1, 3, 5 } },
1488 { LLDP_SNMP_SYSCAP_ENA, ASN_OCTET_STR, RONLY, agent_h_local_chassis, 3,
1489 { 1, 3, 6 } },
1490 /* Local ports */
1491 { LLDP_SNMP_PIDSUBTYPE, ASN_INTEGER, RONLY, agent_h_local_port, 5,
1492 { 1, 3, 7, 1, 2 } },
1493 { LLDP_SNMP_PID, ASN_OCTET_STR, RONLY, agent_h_local_port, 5,
1494 { 1, 3, 7, 1, 3 } },
1495 { LLDP_SNMP_PORTDESC, ASN_OCTET_STR, RONLY, agent_h_local_port, 5,
1496 { 1, 3, 7, 1, 4 } },
1497 /* Local management address */
1498 { LLDP_SNMP_ADDR_LEN, ASN_INTEGER, RONLY, agent_h_local_management, 5,
1499 { 1, 3, 8, 1, 3 } },
1500 { LLDP_SNMP_ADDR_IFSUBTYPE, ASN_INTEGER, RONLY, agent_h_local_management, 5,
1501 { 1, 3, 8, 1, 4 } },
1502 { LLDP_SNMP_ADDR_IFID, ASN_INTEGER, RONLY, agent_h_local_management, 5,
1503 { 1, 3, 8, 1, 5 } },
1504 { LLDP_SNMP_ADDR_OID, ASN_OBJECT_ID, RONLY, agent_h_local_management, 5,
1505 { 1, 3, 8, 1, 6 } },
1506 /* Remote ports */
1507 { LLDP_SNMP_CIDSUBTYPE, ASN_INTEGER, RONLY, agent_h_remote_chassis, 5,
1508 { 1, 4, 1, 1, 4 } },
1509 { LLDP_SNMP_CID, ASN_OCTET_STR, RONLY, agent_h_remote_chassis, 5,
1510 { 1, 4, 1, 1, 5 } },
1511 { LLDP_SNMP_PIDSUBTYPE, ASN_INTEGER, RONLY, agent_h_remote_port, 5,
1512 { 1, 4, 1, 1, 6 } },
1513 { LLDP_SNMP_PID, ASN_OCTET_STR, RONLY, agent_h_remote_port, 5,
1514 { 1, 4, 1, 1, 7 } },
1515 { LLDP_SNMP_PORTDESC, ASN_OCTET_STR, RONLY, agent_h_remote_port, 5,
1516 { 1, 4, 1, 1, 8 } },
1517 { LLDP_SNMP_SYSNAME, ASN_OCTET_STR, RONLY, agent_h_remote_chassis, 5,
1518 { 1, 4, 1, 1, 9 } },
1519 { LLDP_SNMP_SYSDESCR, ASN_OCTET_STR, RONLY, agent_h_remote_chassis, 5,
1520 { 1, 4, 1, 1, 10 } },
1521 { LLDP_SNMP_SYSCAP_SUP, ASN_OCTET_STR, RONLY, agent_h_remote_chassis, 5,
1522 { 1, 4, 1, 1, 11 } },
1523 { LLDP_SNMP_SYSCAP_ENA, ASN_OCTET_STR, RONLY, agent_h_remote_chassis, 5,
1524 { 1, 4, 1, 1, 12 } },
1525 /* Remote management address */
1526 { LLDP_SNMP_ADDR_IFSUBTYPE, ASN_INTEGER, RONLY, agent_h_remote_management, 5,
1527 { 1, 4, 2, 1, 3 } },
1528 { LLDP_SNMP_ADDR_IFID, ASN_INTEGER, RONLY, agent_h_remote_management, 5,
1529 { 1, 4, 2, 1, 4 } },
1530 { LLDP_SNMP_ADDR_OID, ASN_OBJECT_ID, RONLY, agent_h_remote_management, 5,
1531 { 1, 4, 2, 1, 5 } },
1532#ifdef ENABLE_CUSTOM
1533 /* Custom TLVs */
1534 { LLDP_SNMP_ORG_DEF_INFO, ASN_OCTET_STR, RONLY, agent_h_remote_custom, 5,
1535 { 1, 4, 4, 1, 4 } },
1536#endif
1537#ifdef ENABLE_DOT3
1538 /* Dot3, local ports */
1539 { LLDP_SNMP_DOT3_AUTONEG_SUPPORT, ASN_INTEGER, RONLY, agent_h_local_port, 8,
1540 { 1, 5, 4623, 1, 2, 1, 1, 1 } },
1541 { LLDP_SNMP_DOT3_AUTONEG_ENABLED, ASN_INTEGER, RONLY, agent_h_local_port, 8,
1542 { 1, 5, 4623, 1, 2, 1, 1, 2 } },
1543 { LLDP_SNMP_DOT3_AUTONEG_ADVERTISED, ASN_OCTET_STR, RONLY, agent_h_local_port,
1544 8, { 1, 5, 4623, 1, 2, 1, 1, 3 } },
1545 { LLDP_SNMP_DOT3_AUTONEG_MAU, ASN_INTEGER, RONLY, agent_h_local_port, 8,
1546 { 1, 5, 4623, 1, 2, 1, 1, 4 } },
1547 { LLDP_SNMP_DOT3_POWER_DEVICETYPE, ASN_INTEGER, RONLY, agent_h_local_port, 8,
1548 { 1, 5, 4623, 1, 2, 2, 1, 1 } },
1549 { LLDP_SNMP_DOT3_POWER_SUPPORT, ASN_INTEGER, RONLY, agent_h_local_port, 8,
1550 { 1, 5, 4623, 1, 2, 2, 1, 2 } },
1551 { LLDP_SNMP_DOT3_POWER_ENABLED, ASN_INTEGER, RONLY, agent_h_local_port, 8,
1552 { 1, 5, 4623, 1, 2, 2, 1, 3 } },
1553 { LLDP_SNMP_DOT3_POWER_PAIRCONTROL, ASN_INTEGER, RONLY, agent_h_local_port, 8,
1554 { 1, 5, 4623, 1, 2, 2, 1, 4 } },
1555 { LLDP_SNMP_DOT3_POWER_PAIRS, ASN_INTEGER, RONLY, agent_h_local_port, 8,
1556 { 1, 5, 4623, 1, 2, 2, 1, 5 } },
1557 { LLDP_SNMP_DOT3_POWER_CLASS, ASN_INTEGER, RONLY, agent_h_local_port, 8,
1558 { 1, 5, 4623, 1, 2, 2, 1, 6 } },
1559 { LLDP_SNMP_DOT3_POWER_TYPE, ASN_OCTET_STR, RONLY, agent_h_local_port, 8,
1560 { 1, 5, 4623, 1, 2, 2, 1, 7 } },
1561 { LLDP_SNMP_DOT3_POWER_SOURCE, ASN_OCTET_STR, RONLY, agent_h_local_port, 8,
1562 { 1, 5, 4623, 1, 2, 2, 1, 8 } },
1563 { LLDP_SNMP_DOT3_POWER_PRIORITY, ASN_INTEGER, RONLY, agent_h_local_port, 8,
1564 { 1, 5, 4623, 1, 2, 2, 1, 9 } },
1565 { LLDP_SNMP_DOT3_POWER_REQUESTED, ASN_INTEGER, RONLY, agent_h_local_port, 8,
1566 { 1, 5, 4623, 1, 2, 2, 1, 10 } },
1567 { LLDP_SNMP_DOT3_POWER_ALLOCATED, ASN_INTEGER, RONLY, agent_h_local_port, 8,
1568 { 1, 5, 4623, 1, 2, 2, 1, 11 } },
1569 { LLDP_SNMP_DOT3_AGG_STATUS, ASN_OCTET_STR, RONLY, agent_h_local_port, 8,
1570 { 1, 5, 4623, 1, 2, 3, 1, 1 } },
1571 { LLDP_SNMP_DOT3_AGG_ID, ASN_INTEGER, RONLY, agent_h_local_port, 8,
1572 { 1, 5, 4623, 1, 2, 3, 1, 2 } },
1573 { LLDP_SNMP_DOT3_MFS, ASN_INTEGER, RONLY, agent_h_local_port, 8,
1574 { 1, 5, 4623, 1, 2, 4, 1, 1 } },
1575#endif
1576/* Dot3, remote ports */
1577#ifdef ENABLE_DOT3
1578 { LLDP_SNMP_DOT3_AUTONEG_SUPPORT, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
1579 { 1, 5, 4623, 1, 3, 1, 1, 1 } },
1580 { LLDP_SNMP_DOT3_AUTONEG_ENABLED, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
1581 { 1, 5, 4623, 1, 3, 1, 1, 2 } },
1582 { LLDP_SNMP_DOT3_AUTONEG_ADVERTISED, ASN_OCTET_STR, RONLY, agent_h_remote_port,
1583 8, { 1, 5, 4623, 1, 3, 1, 1, 3 } },
1584 { LLDP_SNMP_DOT3_AUTONEG_MAU, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
1585 { 1, 5, 4623, 1, 3, 1, 1, 4 } },
1586 { LLDP_SNMP_DOT3_POWER_DEVICETYPE, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
1587 { 1, 5, 4623, 1, 3, 2, 1, 1 } },
1588 { LLDP_SNMP_DOT3_POWER_SUPPORT, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
1589 { 1, 5, 4623, 1, 3, 2, 1, 2 } },
1590 { LLDP_SNMP_DOT3_POWER_ENABLED, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
1591 { 1, 5, 4623, 1, 3, 2, 1, 3 } },
1592 { LLDP_SNMP_DOT3_POWER_PAIRCONTROL, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
1593 { 1, 5, 4623, 1, 3, 2, 1, 4 } },
1594 { LLDP_SNMP_DOT3_POWER_PAIRS, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
1595 { 1, 5, 4623, 1, 3, 2, 1, 5 } },
1596 { LLDP_SNMP_DOT3_POWER_CLASS, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
1597 { 1, 5, 4623, 1, 3, 2, 1, 6 } },
1598 { LLDP_SNMP_DOT3_POWER_TYPE, ASN_OCTET_STR, RONLY, agent_h_remote_port, 8,
1599 { 1, 5, 4623, 1, 3, 2, 1, 7 } },
1600 { LLDP_SNMP_DOT3_POWER_SOURCE, ASN_OCTET_STR, RONLY, agent_h_remote_port, 8,
1601 { 1, 5, 4623, 1, 3, 2, 1, 8 } },
1602 { LLDP_SNMP_DOT3_POWER_PRIORITY, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
1603 { 1, 5, 4623, 1, 3, 2, 1, 9 } },
1604 { LLDP_SNMP_DOT3_POWER_REQUESTED, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
1605 { 1, 5, 4623, 1, 3, 2, 1, 10 } },
1606 { LLDP_SNMP_DOT3_POWER_ALLOCATED, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
1607 { 1, 5, 4623, 1, 3, 2, 1, 11 } },
1608 { LLDP_SNMP_DOT3_AGG_STATUS, ASN_OCTET_STR, RONLY, agent_h_remote_port, 8,
1609 { 1, 5, 4623, 1, 3, 3, 1, 1 } },
1610 { LLDP_SNMP_DOT3_AGG_ID, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
1611 { 1, 5, 4623, 1, 3, 3, 1, 2 } },
1612 { LLDP_SNMP_DOT3_MFS, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
1613 { 1, 5, 4623, 1, 3, 4, 1, 1 } },
1614#endif
1615#ifdef ENABLE_LLDPMED
1616 /* LLDP-MED local */
1617 { LLDP_SNMP_MED_CLASS, ASN_INTEGER, RONLY, agent_h_local_med, 6,
1618 { 1, 5, 4795, 1, 1, 1 } },
1619 { LLDP_SNMP_MED_POLICY_VID, ASN_INTEGER, RONLY, agent_h_local_med_policy, 8,
1620 { 1, 5, 4795, 1, 2, 1, 1, 2 } },
1621 { LLDP_SNMP_MED_POLICY_PRIO, ASN_INTEGER, RONLY, agent_h_local_med_policy, 8,
1622 { 1, 5, 4795, 1, 2, 1, 1, 3 } },
1623 { LLDP_SNMP_MED_POLICY_DSCP, ASN_INTEGER, RONLY, agent_h_local_med_policy, 8,
1624 { 1, 5, 4795, 1, 2, 1, 1, 4 } },
1625 { LLDP_SNMP_MED_POLICY_UNKNOWN, ASN_INTEGER, RONLY, agent_h_local_med_policy, 8,
1626 { 1, 5, 4795, 1, 2, 1, 1, 5 } },
1627 { LLDP_SNMP_MED_POLICY_TAGGED, ASN_INTEGER, RONLY, agent_h_local_med_policy, 8,
1628 { 1, 5, 4795, 1, 2, 1, 1, 6 } },
1629 { LLDP_SNMP_MED_HW, ASN_OCTET_STR, RONLY, agent_h_local_med, 6,
1630 { 1, 5, 4795, 1, 2, 2 } },
1631 { LLDP_SNMP_MED_FW, ASN_OCTET_STR, RONLY, agent_h_local_med, 6,
1632 { 1, 5, 4795, 1, 2, 3 } },
1633 { LLDP_SNMP_MED_SW, ASN_OCTET_STR, RONLY, agent_h_local_med, 6,
1634 { 1, 5, 4795, 1, 2, 4 } },
1635 { LLDP_SNMP_MED_SN, ASN_OCTET_STR, RONLY, agent_h_local_med, 6,
1636 { 1, 5, 4795, 1, 2, 5 } },
1637 { LLDP_SNMP_MED_MANUF, ASN_OCTET_STR, RONLY, agent_h_local_med, 6,
1638 { 1, 5, 4795, 1, 2, 6 } },
1639 { LLDP_SNMP_MED_MODEL, ASN_OCTET_STR, RONLY, agent_h_local_med, 6,
1640 { 1, 5, 4795, 1, 2, 7 } },
1641 { LLDP_SNMP_MED_ASSET, ASN_OCTET_STR, RONLY, agent_h_local_med, 6,
1642 { 1, 5, 4795, 1, 2, 8 } },
1643 { LLDP_SNMP_MED_LOCATION, ASN_OCTET_STR, RONLY, agent_h_local_med_location, 8,
1644 { 1, 5, 4795, 1, 2, 9, 1, 2 } },
1645 { LLDP_SNMP_MED_POE_DEVICETYPE, ASN_INTEGER, RONLY, agent_h_local_med_power, 6,
1646 { 1, 5, 4795, 1, 2, 10 } },
1647 { LLDP_SNMP_MED_POE_PSE_POWERVAL, ASN_GAUGE, RONLY, agent_h_local_med_power, 8,
1648 { 1, 5, 4795, 1, 2, 11, 1, 1 } },
1649 { LLDP_SNMP_MED_POE_PSE_POWERPRIORITY, ASN_INTEGER, RONLY,
1650 agent_h_local_med_power, 8, { 1, 5, 4795, 1, 2, 11, 1, 2 } },
1651 { LLDP_SNMP_MED_POE_PSE_POWERSOURCE, ASN_INTEGER, RONLY,
1652 agent_h_local_med_power, 6, { 1, 5, 4795, 1, 2, 12 } },
1653 { LLDP_SNMP_MED_POE_PD_POWERVAL, ASN_GAUGE, RONLY, agent_h_local_med_power, 6,
1654 { 1, 5, 4795, 1, 2, 13 } },
1655 { LLDP_SNMP_MED_POE_PD_POWERSOURCE, ASN_INTEGER, RONLY, agent_h_local_med_power,
1656 6, { 1, 5, 4795, 1, 2, 14 } },
1657 { LLDP_SNMP_MED_POE_PD_POWERPRIORITY, ASN_INTEGER, RONLY,
1658 agent_h_local_med_power, 6, { 1, 5, 4795, 1, 2, 15 } },
1659 /* LLDP-MED remote */
1660 { LLDP_SNMP_MED_CAP_AVAILABLE, ASN_OCTET_STR, RONLY, agent_h_remote_med, 8,
1661 { 1, 5, 4795, 1, 3, 1, 1, 1 } },
1662 { LLDP_SNMP_MED_CAP_ENABLED, ASN_OCTET_STR, RONLY, agent_h_remote_med, 8,
1663 { 1, 5, 4795, 1, 3, 1, 1, 2 } },
1664 { LLDP_SNMP_MED_CLASS, ASN_INTEGER, RONLY, agent_h_remote_med, 8,
1665 { 1, 5, 4795, 1, 3, 1, 1, 3 } },
1666 { LLDP_SNMP_MED_POLICY_VID, ASN_INTEGER, RONLY, agent_h_remote_med_policy, 8,
1667 { 1, 5, 4795, 1, 3, 2, 1, 2 } },
1668 { LLDP_SNMP_MED_POLICY_PRIO, ASN_INTEGER, RONLY, agent_h_remote_med_policy, 8,
1669 { 1, 5, 4795, 1, 3, 2, 1, 3 } },
1670 { LLDP_SNMP_MED_POLICY_DSCP, ASN_INTEGER, RONLY, agent_h_remote_med_policy, 8,
1671 { 1, 5, 4795, 1, 3, 2, 1, 4 } },
1672 { LLDP_SNMP_MED_POLICY_UNKNOWN, ASN_INTEGER, RONLY, agent_h_remote_med_policy,
1673 8, { 1, 5, 4795, 1, 3, 2, 1, 5 } },
1674 { LLDP_SNMP_MED_POLICY_TAGGED, ASN_INTEGER, RONLY, agent_h_remote_med_policy, 8,
1675 { 1, 5, 4795, 1, 3, 2, 1, 6 } },
1676 { LLDP_SNMP_MED_HW, ASN_OCTET_STR, RONLY, agent_h_remote_med, 8,
1677 { 1, 5, 4795, 1, 3, 3, 1, 1 } },
1678 { LLDP_SNMP_MED_FW, ASN_OCTET_STR, RONLY, agent_h_remote_med, 8,
1679 { 1, 5, 4795, 1, 3, 3, 1, 2 } },
1680 { LLDP_SNMP_MED_SW, ASN_OCTET_STR, RONLY, agent_h_remote_med, 8,
1681 { 1, 5, 4795, 1, 3, 3, 1, 3 } },
1682 { LLDP_SNMP_MED_SN, ASN_OCTET_STR, RONLY, agent_h_remote_med, 8,
1683 { 1, 5, 4795, 1, 3, 3, 1, 4 } },
1684 { LLDP_SNMP_MED_MANUF, ASN_OCTET_STR, RONLY, agent_h_remote_med, 8,
1685 { 1, 5, 4795, 1, 3, 3, 1, 5 } },
1686 { LLDP_SNMP_MED_MODEL, ASN_OCTET_STR, RONLY, agent_h_remote_med, 8,
1687 { 1, 5, 4795, 1, 3, 3, 1, 6 } },
1688 { LLDP_SNMP_MED_ASSET, ASN_OCTET_STR, RONLY, agent_h_remote_med, 8,
1689 { 1, 5, 4795, 1, 3, 3, 1, 7 } },
1690 { LLDP_SNMP_MED_LOCATION, ASN_OCTET_STR, RONLY, agent_h_remote_med_location, 8,
1691 { 1, 5, 4795, 1, 3, 4, 1, 2 } },
1692 { LLDP_SNMP_MED_POE_DEVICETYPE, ASN_INTEGER, RONLY, agent_h_remote_med_power, 8,
1693 { 1, 5, 4795, 1, 3, 5, 1, 1 } },
1694 { LLDP_SNMP_MED_POE_PSE_POWERVAL, ASN_GAUGE, RONLY, agent_h_remote_med_power, 8,
1695 { 1, 5, 4795, 1, 3, 6, 1, 1 } },
1696 { LLDP_SNMP_MED_POE_PSE_POWERSOURCE, ASN_INTEGER, RONLY,
1697 agent_h_remote_med_power, 8, { 1, 5, 4795, 1, 3, 6, 1, 2 } },
1698 { LLDP_SNMP_MED_POE_PSE_POWERPRIORITY, ASN_INTEGER, RONLY,
1699 agent_h_remote_med_power, 8, { 1, 5, 4795, 1, 3, 6, 1, 3 } },
1700 { LLDP_SNMP_MED_POE_PD_POWERVAL, ASN_GAUGE, RONLY, agent_h_remote_med_power, 8,
1701 { 1, 5, 4795, 1, 3, 7, 1, 1 } },
1702 { LLDP_SNMP_MED_POE_PD_POWERSOURCE, ASN_INTEGER, RONLY,
1703 agent_h_remote_med_power, 8, { 1, 5, 4795, 1, 3, 7, 1, 2 } },
1704 { LLDP_SNMP_MED_POE_PD_POWERPRIORITY, ASN_INTEGER, RONLY,
1705 agent_h_remote_med_power, 8, { 1, 5, 4795, 1, 3, 7, 1, 3 } },
1706#endif
1707/* Dot1, local and remote ports */
1708#ifdef ENABLE_DOT1
1709 { LLDP_SNMP_DOT1_PVID, ASN_INTEGER, RONLY, agent_h_local_port, 8,
1710 { 1, 5, 32962, 1, 2, 1, 1, 1 } },
1711 { LLDP_SNMP_DOT1_PPVLAN_SUPPORTED, ASN_INTEGER, RONLY, agent_h_local_ppvid, 8,
1712 { 1, 5, 32962, 1, 2, 2, 1, 2 } },
1713 { LLDP_SNMP_DOT1_PPVLAN_ENABLED, ASN_INTEGER, RONLY, agent_h_local_ppvid, 8,
1714 { 1, 5, 32962, 1, 2, 2, 1, 3 } },
1715 { LLDP_SNMP_DOT1_VLANNAME, ASN_OCTET_STR, RONLY, agent_h_local_vlan, 8,
1716 { 1, 5, 32962, 1, 2, 3, 1, 2 } },
1717 { LLDP_SNMP_DOT1_PI, ASN_OCTET_STR, RONLY, agent_h_local_pi, 8,
1718 { 1, 5, 32962, 1, 2, 4, 1, 2 } },
1719#endif
1720#ifdef ENABLE_DOT1
1721 { LLDP_SNMP_DOT1_PVID, ASN_INTEGER, RONLY, agent_h_remote_port, 8,
1722 { 1, 5, 32962, 1, 3, 1, 1, 1 } },
1723 { LLDP_SNMP_DOT1_PPVLAN_SUPPORTED, ASN_INTEGER, RONLY, agent_h_remote_ppvid, 8,
1724 { 1, 5, 32962, 1, 3, 2, 1, 2 } },
1725 { LLDP_SNMP_DOT1_PPVLAN_ENABLED, ASN_INTEGER, RONLY, agent_h_remote_ppvid, 8,
1726 { 1, 5, 32962, 1, 3, 2, 1, 3 } },
1727 /* Remote vlans */
1728 { LLDP_SNMP_DOT1_VLANNAME, ASN_OCTET_STR, RONLY, agent_h_remote_vlan, 8,
1729 { 1, 5, 32962, 1, 3, 3, 1, 2 } },
1730 /* Protocol identity */
1731 { LLDP_SNMP_DOT1_PI, ASN_OCTET_STR, RONLY, agent_h_remote_pi, 8,
1732 { 1, 5, 32962, 1, 3, 4, 1, 2 } },
1733#endif
1734};
1735size_t
1736agent_lldp_vars_size(void)
1737{
1738 return sizeof(agent_lldp_vars) / sizeof(struct variable8);
1739}
1740
1741/**
1742 * Send a notification about a change in one remote neighbor.
1743 *
1744 * @param hardware Interface on which the change has happened.
1745 * @param type Type of change (add, delete, update)
1746 * @param rport Changed remote port
1747 */
1748void
1749agent_notify(struct lldpd_hardware *hardware, int type, struct lldpd_port *rport)
1750{
1751 struct lldpd_hardware *h;
1752
1753 /* OID of the notification */
1754 oid notification_oid[] = { LLDP_OID, 0, 0, 1 };
1755 size_t notification_oid_len = OID_LENGTH(notification_oid);
1756 /* OID for snmpTrapOID.0 */
1757 oid objid_snmptrap[] = { SNMPTRAP_OID };
1758 size_t objid_snmptrap_len = OID_LENGTH(objid_snmptrap);
1759
1760 /* Other OID */
1761 oid inserts_oid[] = { LLDP_OID, 1, 2, 2 };
1762 size_t inserts_oid_len = OID_LENGTH(inserts_oid);
1763 unsigned long inserts = 0;
1764
1765 oid deletes_oid[] = { LLDP_OID, 1, 2, 3 };
1766 size_t deletes_oid_len = OID_LENGTH(deletes_oid);
1767 unsigned long deletes = 0;
1768
1769 oid drops_oid[] = { LLDP_OID, 1, 2, 4 };
1770 size_t drops_oid_len = OID_LENGTH(drops_oid);
1771 unsigned long drops = 0;
1772
1773 oid ageouts_oid[] = { LLDP_OID, 1, 2, 5 };
1774 size_t ageouts_oid_len = OID_LENGTH(ageouts_oid);
1775 unsigned long ageouts = 0;
1776
1777 /* We also add some extra. Easy ones. */
1778 oid locport_oid[] = { LLDP_OID, 1, 3, 7, 1, 4, hardware->h_ifindex };
1779 size_t locport_oid_len = OID_LENGTH(locport_oid);
1780 oid sysname_oid[] = { LLDP_OID, 1, 4, 1, 1, 9, lastchange(rport),
1781 hardware->h_ifindex, rport->p_chassis->c_index };
1782 size_t sysname_oid_len = OID_LENGTH(sysname_oid);
1783 oid portdescr_oid[] = { LLDP_OID, 1, 4, 1, 1, 8, lastchange(rport),
1784 hardware->h_ifindex, rport->p_chassis->c_index };
1785 size_t portdescr_oid_len = OID_LENGTH(portdescr_oid);
1786
1787 netsnmp_variable_list *notification_vars = NULL;
1788
1789 if (!hardware->h_cfg->g_snmp) return;
1790
1791 switch (type) {
1792 case NEIGHBOR_CHANGE_DELETED:
1793 log_debug("snmp", "send notification for neighbor deleted on %s",
1794 hardware->h_ifname);
1795 break;
1796 case NEIGHBOR_CHANGE_UPDATED:
1797 log_debug("snmp", "send notification for neighbor updated on %s",
1798 hardware->h_ifname);
1799 break;
1800 case NEIGHBOR_CHANGE_ADDED:
1801 log_debug("snmp", "send notification for neighbor added on %s",
1802 hardware->h_ifname);
1803 break;
1804 }
1805
1806 TAILQ_FOREACH (h, &hardware->h_cfg->g_hardware, h_entries) {
1807 inserts += h->h_insert_cnt;
1808 deletes += h->h_delete_cnt;
1809 ageouts += h->h_ageout_cnt;
1810 drops += h->h_drop_cnt;
1811 }
1812
1813 /* snmpTrapOID */
1814 snmp_varlist_add_variable(&notification_vars, objid_snmptrap,
1815 objid_snmptrap_len, ASN_OBJECT_ID, (u_char *)notification_oid,
1816 notification_oid_len * sizeof(oid));
1817
1818 snmp_varlist_add_variable(&notification_vars, inserts_oid, inserts_oid_len,
1819 ASN_GAUGE, (u_char *)&inserts, sizeof(inserts));
1820 snmp_varlist_add_variable(&notification_vars, deletes_oid, deletes_oid_len,
1821 ASN_GAUGE, (u_char *)&deletes, sizeof(inserts));
1822 snmp_varlist_add_variable(&notification_vars, drops_oid, drops_oid_len,
1823 ASN_GAUGE, (u_char *)&drops, sizeof(drops));
1824 snmp_varlist_add_variable(&notification_vars, ageouts_oid, ageouts_oid_len,
1825 ASN_GAUGE, (u_char *)&ageouts, sizeof(ageouts));
1826
1827 if (type != NEIGHBOR_CHANGE_DELETED) {
1828 snmp_varlist_add_variable(&notification_vars, locport_oid,
1829 locport_oid_len, ASN_OCTET_STR, (u_char *)hardware->h_ifname,
1830 strnlen(hardware->h_ifname, IFNAMSIZ));
1831 if (rport->p_chassis->c_name && *rport->p_chassis->c_name != '\0') {
1832 snmp_varlist_add_variable(&notification_vars, sysname_oid,
1833 sysname_oid_len, ASN_OCTET_STR,
1834 (u_char *)rport->p_chassis->c_name,
1835 strlen(rport->p_chassis->c_name));
1836 }
1837 if (rport->p_descr) {
1838 snmp_varlist_add_variable(&notification_vars, portdescr_oid,
1839 portdescr_oid_len, ASN_OCTET_STR, (u_char *)rport->p_descr,
1840 strlen(rport->p_descr));
1841 }
1842 }
1843
1844 log_debug("snmp", "sending SNMP trap (%ld, %ld, %ld)", inserts, deletes,
1845 ageouts);
1846 send_v2trap(notification_vars);
1847 snmp_free_varbind(notification_vars);
1848}
1849
1850/* Logging NetSNMP messages */
1851static int
1852agent_log_callback(int major, int minor, void *serverarg, void *clientarg)
1853{
1854 struct snmp_log_message *slm = (struct snmp_log_message *)serverarg;
1855 char *msg = strdup(slm->msg);
1856 (void)major;
1857 (void)minor;
1858 (void)clientarg;
1859
1860 if (msg && msg[strlen(msg) - 1] == '\n') msg[strlen(msg) - 1] = '\0';
1861 switch (slm->priority) {
1862 case LOG_EMERG:
1863 log_warnx("libsnmp", "%s", msg ? msg : slm->msg);
1864 break;
1865 case LOG_ALERT:
1866 log_warnx("libsnmp", "%s", msg ? msg : slm->msg);
1867 break;
1868 case LOG_CRIT:
1869 log_warnx("libsnmp", "%s", msg ? msg : slm->msg);
1870 break;
1871 case LOG_ERR:
1872 log_warnx("libsnmp", "%s", msg ? msg : slm->msg);
1873 break;
1874 case LOG_WARNING:
1875 log_warnx("libsnmp", "%s", msg ? msg : slm->msg);
1876 break;
1877 case LOG_NOTICE:
1878 log_info("libsnmp", "%s", msg ? msg : slm->msg);
1879 break;
1880 case LOG_INFO:
1881 log_info("libsnmp", "%s", msg ? msg : slm->msg);
1882 break;
1883 case LOG_DEBUG:
1884 log_debug("libsnmp", "%s", msg ? msg : slm->msg);
1885 break;
1886 }
1887 free(msg);
1888 return SNMP_ERR_NOERROR;
1889}
1890
1891void
1892agent_init(struct lldpd *cfg, const char *agentx)
1893{
1894 int rc;
1895
1896 log_info("snmp", "enable SNMP subagent");
1897 netsnmp_enable_subagent();
1898
1899 log_debug("snmp", "enable logging");
1900 snmp_disable_log();
1901 snmp_enable_calllog();
1902 snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING,
1903 agent_log_callback, NULL);
1904
1905 scfg = cfg;
1906
1907 /* We are chrooted, we don't want to handle persistent states */
1908 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PERSIST_STATE,
1909 TRUE);
1910 /* Do not load any MIB */
1911 setenv("MIBS", "", 1);
1912 setenv("MIBDIRS", "/dev/null", 1);
1913
1914#ifdef ENABLE_PRIVSEP
1915 /* We provide our UNIX domain transport */
1916 log_debug("snmp", "register UNIX domain transport");
1917 agent_priv_register_domain();
1918#endif
1919
1920 if (agentx)
1921 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
1922 NETSNMP_DS_AGENT_X_SOCKET, agentx);
1923 init_agent("lldpAgent");
1924 REGISTER_MIB("lldp", agent_lldp_vars, variable8, lldp_oid);
1925 init_snmp("lldpAgent");
1926
1927 log_debug("snmp", "register to sysORTable");
1928 if ((rc = register_sysORTable(lldp_oid, OID_LENGTH(lldp_oid),
1929 "lldpMIB implementation by lldpd")) != 0)
1930 log_warnx("snmp", "unable to register to sysORTable (%d)", rc);
1931}
1932
1933void
1934agent_shutdown()
1935{
1936 log_debug("snmp", "agent shutdown");
1937 unregister_sysORTable(lldp_oid, OID_LENGTH(lldp_oid));
1938 snmp_shutdown("lldpAgent");
1939}