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