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