]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/lib/atoms/port.c
lib/atoms/port: fix segfaults with minimal information
[thirdparty/lldpd.git] / src / lib / atoms / port.c
CommitLineData
94c98157
AA
1/* -*- mode: c; c-file-style: "openbsd" -*- */
2/*
3 * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
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 <stdio.h>
19#include <stdarg.h>
20#include <string.h>
21#include <arpa/inet.h>
22
23#include "lldpctl.h"
94c98157 24#include "../log.h"
a5f98717 25#include "atom.h"
94c98157
AA
26#include "helpers.h"
27
28static struct atom_map lldpd_protocol_map = {
29 .key = lldpctl_k_port_protocol,
30 .map = {
31 { LLDPD_MODE_LLDP, "LLDP" },
32 { LLDPD_MODE_CDPV1, "CDPv1"},
33 { LLDPD_MODE_CDPV2, "CDPv2"},
34 { LLDPD_MODE_EDP, "EDP" },
35 { LLDPD_MODE_FDP, "FDP"},
36 { LLDPD_MODE_SONMP, "SONMP"},
37 { 0, NULL },
38 }
39};
40
41ATOM_MAP_REGISTER(lldpd_protocol_map, 3);
42
43static lldpctl_map_t port_id_subtype_map[] = {
44 { LLDP_PORTID_SUBTYPE_IFNAME, "ifname"},
45 { LLDP_PORTID_SUBTYPE_IFALIAS, "ifalias" },
46 { LLDP_PORTID_SUBTYPE_LOCAL, "local" },
47 { LLDP_PORTID_SUBTYPE_LLADDR, "mac" },
48 { LLDP_PORTID_SUBTYPE_ADDR, "ip" },
49 { LLDP_PORTID_SUBTYPE_PORT, "unhandled" },
50 { LLDP_PORTID_SUBTYPE_AGENTCID, "unhandled" },
51 { 0, NULL},
52};
53
e7331ce9
VB
54static struct atom_map port_status_map = {
55 .key = lldpctl_k_port_status,
56 .map = {
57 { LLDPD_RXTX_TXONLY, "TX only" },
58 { LLDPD_RXTX_RXONLY, "RX only" },
59 { LLDPD_RXTX_DISABLED, "disabled" },
60 { LLDPD_RXTX_BOTH, "RX and TX" },
61 { 0, NULL },
62 }
63};
64
65ATOM_MAP_REGISTER(port_status_map, 3);
66
94c98157
AA
67static lldpctl_map_t operational_mau_type_values[] = {
68 { 1, "AUI - no internal MAU, view from AUI" },
69 { 2, "10Base5 - thick coax MAU" },
70 { 3, "Foirl - FOIRL MAU" },
71 { 4, "10Base2 - thin coax MAU" },
72 { 5, "10BaseT - UTP MAU" },
73 { 6, "10BaseFP - passive fiber MAU" },
74 { 7, "10BaseFB - sync fiber MAU" },
75 { 8, "10BaseFL - async fiber MAU" },
76 { 9, "10Broad36 - broadband DTE MAU" },
77 { 10, "10BaseTHD - UTP MAU, half duplex mode" },
78 { 11, "10BaseTFD - UTP MAU, full duplex mode" },
79 { 12, "10BaseFLHD - async fiber MAU, half duplex mode" },
80 { 13, "10BaseFLDF - async fiber MAU, full duplex mode" },
81 { 14, "10BaseT4 - 4 pair category 3 UTP" },
82 { 15, "100BaseTXHD - 2 pair category 5 UTP, half duplex mode" },
83 { 16, "100BaseTXFD - 2 pair category 5 UTP, full duplex mode" },
84 { 17, "100BaseFXHD - X fiber over PMT, half duplex mode" },
85 { 18, "100BaseFXFD - X fiber over PMT, full duplex mode" },
86 { 19, "100BaseT2HD - 2 pair category 3 UTP, half duplex mode" },
87 { 20, "100BaseT2FD - 2 pair category 3 UTP, full duplex mode" },
88 { 21, "1000BaseXHD - PCS/PMA, unknown PMD, half duplex mode" },
89 { 22, "1000BaseXFD - PCS/PMA, unknown PMD, full duplex mode" },
90 { 23, "1000BaseLXHD - Fiber over long-wavelength laser, half duplex mode" },
91 { 24, "1000BaseLXFD - Fiber over long-wavelength laser, full duplex mode" },
92 { 25, "1000BaseSXHD - Fiber over short-wavelength laser, half duplex mode" },
93 { 26, "1000BaseSXFD - Fiber over short-wavelength laser, full duplex mode" },
94 { 27, "1000BaseCXHD - Copper over 150-Ohm balanced cable, half duplex mode" },
95 { 28, "1000BaseCXFD - Copper over 150-Ohm balanced cable, full duplex mode" },
96 { 29, "1000BaseTHD - Four-pair Category 5 UTP, half duplex mode" },
97 { 30, "1000BaseTFD - Four-pair Category 5 UTP, full duplex mode" },
98 { 31, "10GigBaseX - X PCS/PMA, unknown PMD." },
99 { 32, "10GigBaseLX4 - X fiber over WWDM optics" },
100 { 33, "10GigBaseR - R PCS/PMA, unknown PMD." },
101 { 34, "10GigBaseER - R fiber over 1550 nm optics" },
102 { 35, "10GigBaseLR - R fiber over 1310 nm optics" },
103 { 36, "10GigBaseSR - R fiber over 850 nm optics" },
104 { 37, "10GigBaseW - W PCS/PMA, unknown PMD." },
105 { 38, "10GigBaseEW - W fiber over 1550 nm optics" },
106 { 39, "10GigBaseLW - W fiber over 1310 nm optics" },
107 { 40, "10GigBaseSW - W fiber over 850 nm optics" },
108 { 41, "10GigBaseCX4 - X copper over 8 pair 100-Ohm balanced cable" },
109 { 42, "2BaseTL - Voice grade UTP copper, up to 2700m, optional PAF" },
110 { 43, "10PassTS - Voice grade UTP copper, up to 750m, optional PAF" },
111 { 44, "100BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" },
112 { 45, "100BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" },
113 { 46, "100BaseLX10 - Two single-mode fibers, long wavelength, 10km" },
114 { 47, "1000BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" },
115 { 48, "1000BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" },
116 { 49, "1000BaseLX10 - Two sigle-mode fiber, long wavelength, 10km" },
117 { 50, "1000BasePX10D - One single-mode fiber EPON OLT, 10km" },
118 { 51, "1000BasePX10U - One single-mode fiber EPON ONU, 10km" },
119 { 52, "1000BasePX20D - One single-mode fiber EPON OLT, 20km" },
120 { 53, "1000BasePX20U - One single-mode fiber EPON ONU, 20km" },
121 { 0, NULL }
122};
123
94c98157
AA
124static lldpctl_atom_iter_t*
125_lldpctl_atom_iter_ports_list(lldpctl_atom_t *atom)
126{
127 struct _lldpctl_atom_any_list_t *plist =
128 (struct _lldpctl_atom_any_list_t *)atom;
129 return (lldpctl_atom_iter_t*)TAILQ_FIRST(&plist->parent->hardware->h_rports);
130}
131
132static lldpctl_atom_iter_t*
133_lldpctl_atom_next_ports_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
134{
135 struct lldpd_port *port = (struct lldpd_port *)iter;
136 return (lldpctl_atom_iter_t*)TAILQ_NEXT(port, p_entries);
137}
138
139static lldpctl_atom_t*
140_lldpctl_atom_value_ports_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
141{
142 struct lldpd_port *port = (struct lldpd_port *)iter;
9da663f7 143 return _lldpctl_new_atom(atom->conn, atom_port, 0, NULL, port,
94c98157
AA
144 ((struct _lldpctl_atom_any_list_t *)atom)->parent);
145}
146
147static int
148_lldpctl_atom_new_port(lldpctl_atom_t *atom, va_list ap)
149{
150 struct _lldpctl_atom_port_t *port =
151 (struct _lldpctl_atom_port_t *)atom;
9da663f7 152 port->local = va_arg(ap, int);
94c98157
AA
153 port->hardware = va_arg(ap, struct lldpd_hardware*);
154 port->port = va_arg(ap, struct lldpd_port*);
155 port->parent = va_arg(ap, struct _lldpctl_atom_port_t*);
156 if (port->parent)
157 lldpctl_atom_inc_ref((lldpctl_atom_t*)port->parent);
e55e7492 158
825b37a7
BH
159 if (port->port) {
160 /* Internal atom. We are the parent, but our reference count is
161 * not incremented. */
162 port->chassis = _lldpctl_new_atom(atom->conn, atom_chassis,
163 port->port->p_chassis, port, 1);
164 }
94c98157
AA
165 return 1;
166}
167
168TAILQ_HEAD(chassis_list, lldpd_chassis);
169
170static void
171add_chassis(struct chassis_list *chassis_list,
172 struct lldpd_chassis *chassis)
173{
174 struct lldpd_chassis *one_chassis;
175 TAILQ_FOREACH(one_chassis, chassis_list, c_entries) {
176 if (one_chassis == chassis) return;
177 }
178 TAILQ_INSERT_TAIL(chassis_list,
179 chassis, c_entries);
180}
181
182static void
183_lldpctl_atom_free_port(lldpctl_atom_t *atom)
184{
185 struct _lldpctl_atom_port_t *port =
186 (struct _lldpctl_atom_port_t *)atom;
187 struct lldpd_hardware *hardware = port->hardware;
188 struct lldpd_chassis *one_chassis, *one_chassis_next;
189 struct lldpd_port *one_port;
190
e55e7492
VB
191 /* Free internal chassis atom. Should be freed immediately since we
192 * should have the only reference. */
193 lldpctl_atom_dec_ref((lldpctl_atom_t*)port->chassis);
194
94c98157
AA
195 /* We need to free the whole struct lldpd_hardware: local port, local
196 * chassis and remote ports... The same chassis may be present several
197 * times. We build a list of chassis (we don't use reference count). */
198 struct chassis_list chassis_list;
199 TAILQ_INIT(&chassis_list);
200
201 if (port->parent) lldpctl_atom_dec_ref((lldpctl_atom_t*)port->parent);
825b37a7 202 else if (!hardware && port->port) {
94c98157
AA
203 /* No parent, no hardware, we assume a single neighbor: one
204 * port, one chassis. */
9da663f7
VB
205 if (port->port->p_chassis) {
206 lldpd_chassis_cleanup(port->port->p_chassis, 1);
207 port->port->p_chassis = NULL;
208 }
94c98157
AA
209 lldpd_port_cleanup(port->port, 1);
210 free(port->port);
211 }
212 if (!hardware) return;
213
214 add_chassis(&chassis_list, port->port->p_chassis);
215 TAILQ_FOREACH(one_port, &hardware->h_rports, p_entries)
216 add_chassis(&chassis_list, one_port->p_chassis);
217
218 /* Free hardware port */
219 lldpd_remote_cleanup(hardware, NULL, 1);
220 lldpd_port_cleanup(port->port, 1);
221 free(port->hardware);
222
223 /* Free list of chassis */
224 for (one_chassis = TAILQ_FIRST(&chassis_list);
225 one_chassis != NULL;
226 one_chassis = one_chassis_next) {
227 one_chassis_next = TAILQ_NEXT(one_chassis, c_entries);
228 lldpd_chassis_cleanup(one_chassis, 1);
229 }
230}
231
232static lldpctl_atom_t*
233_lldpctl_atom_get_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key)
234{
235 struct _lldpctl_atom_port_t *p =
236 (struct _lldpctl_atom_port_t *)atom;
237 struct lldpd_port *port = p->port;
238 struct lldpd_hardware *hardware = p->hardware;
239
240 /* Local port only */
241 if (hardware != NULL) {
242 switch (key) {
243 case lldpctl_k_port_neighbors:
244 return _lldpctl_new_atom(atom->conn, atom_ports_list, p);
245 default: break;
246 }
247 }
248
249 /* Local and remote port */
250 switch (key) {
99ef55d3 251 case lldpctl_k_port_chassis:
9da663f7
VB
252 if (port->p_chassis) {
253 return _lldpctl_new_atom(atom->conn, atom_chassis,
254 port->p_chassis, p, 0);
255 }
256 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
257 return NULL;
94c98157
AA
258#ifdef ENABLE_DOT3
259 case lldpctl_k_port_dot3_power:
260 return _lldpctl_new_atom(atom->conn, atom_dot3_power,
261 p);
262#endif
263#ifdef ENABLE_DOT1
264 case lldpctl_k_port_vlans:
265 return _lldpctl_new_atom(atom->conn, atom_vlans_list,
266 p);
267 case lldpctl_k_port_ppvids:
268 return _lldpctl_new_atom(atom->conn, atom_ppvids_list,
269 p);
270 case lldpctl_k_port_pis:
271 return _lldpctl_new_atom(atom->conn, atom_pis_list,
272 p);
273#endif
274#ifdef ENABLE_LLDPMED
275 case lldpctl_k_port_med_policies:
276 return _lldpctl_new_atom(atom->conn, atom_med_policies_list,
277 p);
278 case lldpctl_k_port_med_locations:
279 return _lldpctl_new_atom(atom->conn, atom_med_locations_list,
280 p);
281 case lldpctl_k_port_med_power:
282 return _lldpctl_new_atom(atom->conn, atom_med_power, p);
283#endif
fb1b78bb 284#ifdef ENABLE_CUSTOM
c576fd21
AA
285 case lldpctl_k_custom_tlvs:
286 return _lldpctl_new_atom(atom->conn, atom_custom_list, p);
fb1b78bb 287#endif
94c98157 288 default:
e55e7492 289 /* Compatibility: query the associated chassis too */
9da663f7
VB
290 if (port->p_chassis)
291 return lldpctl_atom_get(p->chassis, key);
292 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
293 return NULL;
94c98157
AA
294 }
295}
296
297static lldpctl_atom_t*
298_lldpctl_atom_set_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key, lldpctl_atom_t *value)
299{
300 struct _lldpctl_atom_port_t *p =
301 (struct _lldpctl_atom_port_t *)atom;
302 struct lldpd_hardware *hardware = p->hardware;
303 struct lldpd_port_set set = {};
304 int rc;
305 char *canary;
306
307#ifdef ENABLE_DOT3
308 struct _lldpctl_atom_dot3_power_t *dpow;
309#endif
310#ifdef ENABLE_LLDPMED
311 struct _lldpctl_atom_med_power_t *mpow;
312 struct _lldpctl_atom_med_policy_t *mpol;
313 struct _lldpctl_atom_med_location_t *mloc;
314#endif
fb1b78bb 315#ifdef ENABLE_CUSTOM
c576fd21 316 struct _lldpctl_atom_custom_t *custom;
fb1b78bb 317#endif
94c98157 318
9da663f7
VB
319 /* Local and default port only */
320 if (!p->local) {
94c98157
AA
321 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
322 return NULL;
323 }
324
325 switch (key) {
326 case lldpctl_k_port_id:
327 set.local_id = p->port->p_id;
328 break;
329 case lldpctl_k_port_descr:
330 set.local_descr = p->port->p_descr;
331 break;
e7331ce9
VB
332 case lldpctl_k_port_status:
333 set.rxtx = LLDPD_RXTX_FROM_PORT(p->port);
334 break;
94c98157
AA
335#ifdef ENABLE_DOT3
336 case lldpctl_k_port_dot3_power:
337 if (value->type != atom_dot3_power) {
338 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
339 return NULL;
340 }
341
342 dpow = (struct _lldpctl_atom_dot3_power_t *)value;
343 set.dot3_power = &dpow->parent->port->p_power;
344 break;
345#endif
346#ifdef ENABLE_LLDPMED
347 case lldpctl_k_port_med_power:
348 if (value->type != atom_med_power) {
349 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
350 return NULL;
351 }
352
353 mpow = (struct _lldpctl_atom_med_power_t *)value;
354 set.med_power = &mpow->parent->port->p_med_power;
355 break;
356 case lldpctl_k_port_med_policies:
357 if (value->type != atom_med_policy) {
358 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
359 return NULL;
360 }
361 mpol = (struct _lldpctl_atom_med_policy_t *)value;
362 set.med_policy = mpol->policy;
363 break;
364 case lldpctl_k_port_med_locations:
365 if (value->type != atom_med_location) {
366 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
367 return NULL;
368 }
369 mloc = (struct _lldpctl_atom_med_location_t *)value;
370 set.med_location = mloc->location;
371 break;
372#endif
fb1b78bb 373#ifdef ENABLE_CUSTOM
c576fd21
AA
374 case lldpctl_k_custom_tlvs_clear:
375 set.custom_list_clear = 1;
376 break;
377 case lldpctl_k_custom_tlv:
378 if (value->type != atom_custom) {
379 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
380 return NULL;
381 }
382 custom = (struct _lldpctl_atom_custom_t *)value;
383 set.custom = custom->tlv;
7c26c8b4 384 set.custom_tlv_op = custom->op;
c576fd21 385 break;
fb1b78bb 386#endif
94c98157
AA
387 default:
388 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
389 return NULL;
390 }
391
9da663f7 392 set.ifname = hardware ? hardware->h_ifname : "";
94c98157
AA
393
394 if (asprintf(&canary, "%d%p%s", key, value, set.ifname) == -1) {
395 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
396 return NULL;
397 }
398 rc = _lldpctl_do_something(atom->conn,
399 CONN_STATE_SET_PORT_SEND, CONN_STATE_SET_PORT_RECV,
400 canary,
401 SET_PORT, &set, &MARSHAL_INFO(lldpd_port_set),
402 NULL, NULL);
403 free(canary);
404 if (rc == 0) return atom;
405 return NULL;
406}
407
408static const char*
409_lldpctl_atom_get_str_port(lldpctl_atom_t *atom, lldpctl_key_t key)
410{
411 struct _lldpctl_atom_port_t *p =
412 (struct _lldpctl_atom_port_t *)atom;
413 struct lldpd_port *port = p->port;
414 struct lldpd_hardware *hardware = p->hardware;
94c98157
AA
415 char *ipaddress = NULL; size_t len;
416
417 /* Local port only */
e7331ce9
VB
418 switch (key) {
419 case lldpctl_k_port_name:
420 if (hardware != NULL) return hardware->h_ifname;
421 break;
422 case lldpctl_k_port_status:
423 if (p->local) return map_lookup(port_status_map.map,
424 LLDPD_RXTX_FROM_PORT(port));
425 break;
426 default: break;
94c98157
AA
427 }
428
825b37a7
BH
429 if (!port)
430 return NULL;
431
94c98157
AA
432 /* Local and remote port */
433 switch (key) {
434 case lldpctl_k_port_protocol:
435 return map_lookup(lldpd_protocol_map.map, port->p_protocol);
436 case lldpctl_k_port_id_subtype:
437 return map_lookup(port_id_subtype_map, port->p_id_subtype);
438 case lldpctl_k_port_id:
439 switch (port->p_id_subtype) {
440 case LLDP_PORTID_SUBTYPE_IFNAME:
441 case LLDP_PORTID_SUBTYPE_IFALIAS:
442 case LLDP_PORTID_SUBTYPE_LOCAL:
443 return port->p_id;
444 case LLDP_PORTID_SUBTYPE_LLADDR:
445 return _lldpctl_dump_in_atom(atom,
446 (uint8_t*)port->p_id, port->p_id_len,
447 ':', 0);
448 case LLDP_PORTID_SUBTYPE_ADDR:
449 switch (port->p_id[0]) {
450 case LLDP_MGMT_ADDR_IP4: len = INET_ADDRSTRLEN + 1; break;
451 case LLDP_MGMT_ADDR_IP6: len = INET6_ADDRSTRLEN + 1; break;
452 default: len = 0;
453 }
454 if (len > 0) {
455 ipaddress = _lldpctl_alloc_in_atom(atom, len);
456 if (!ipaddress) return NULL;
457 if (inet_ntop((port->p_id[0] == LLDP_MGMT_ADDR_IP4)?
458 AF_INET:AF_INET6,
459 &port->p_id[1], ipaddress, len) == NULL)
460 break;
461 return ipaddress;
462 }
463 break;
464 }
465 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
466 return NULL;
467 case lldpctl_k_port_descr:
468 return port->p_descr;
469
470#ifdef ENABLE_DOT3
471 case lldpctl_k_port_dot3_mautype:
472 return map_lookup(operational_mau_type_values,
473 port->p_macphy.mau_type);
474#endif
475
94c98157 476 default:
e55e7492
VB
477 /* Compatibility: query the associated chassis too */
478 return lldpctl_atom_get_str(p->chassis, key);
94c98157
AA
479 }
480}
481
e7331ce9
VB
482static lldpctl_atom_t*
483_lldpctl_atom_set_int_port(lldpctl_atom_t *atom, lldpctl_key_t key,
484 long int value)
485{
486 struct _lldpctl_atom_port_t *p =
487 (struct _lldpctl_atom_port_t *)atom;
488 struct lldpd_port *port = p->port;
489
490 if (p->local) {
491 switch (key) {
492 case lldpctl_k_port_status:
493 port->p_disable_rx = !LLDPD_RXTX_RXENABLED(value);
494 port->p_disable_tx = !LLDPD_RXTX_TXENABLED(value);
495 break;
496 default:
497 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
498 return NULL;
499 }
500 } else {
501 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
502 return NULL;
503 }
504
505 return _lldpctl_atom_set_atom_port(atom, key, NULL);
506}
507
94c98157
AA
508static lldpctl_atom_t*
509_lldpctl_atom_set_str_port(lldpctl_atom_t *atom, lldpctl_key_t key,
510 const char *value)
511{
512 struct _lldpctl_atom_port_t *p =
513 (struct _lldpctl_atom_port_t *)atom;
514 struct lldpd_port *port = p->port;
515
516 if (!value || !strlen(value))
517 return NULL;
518
e7331ce9
VB
519 if (p->local) {
520 switch (key) {
521 case lldpctl_k_port_status:
522 return _lldpctl_atom_set_int_port(atom, key,
523 map_reverse_lookup(port_status_map.map, value));
524 default: break;
525 }
526 }
527
94c98157
AA
528 switch (key) {
529 case lldpctl_k_port_id:
530 free(port->p_id);
531 port->p_id = strdup(value);
532 port->p_id_len = strlen(value);
533 break;
534 case lldpctl_k_port_descr:
535 free(port->p_descr);
536 port->p_descr = strdup(value);
537 break;
538 default:
539 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
540 return NULL;
541 }
542
543 return _lldpctl_atom_set_atom_port(atom, key, NULL);
544}
545
546static long int
547_lldpctl_atom_get_int_port(lldpctl_atom_t *atom, lldpctl_key_t key)
548{
549 struct _lldpctl_atom_port_t *p =
550 (struct _lldpctl_atom_port_t *)atom;
551 struct lldpd_port *port = p->port;
552 struct lldpd_hardware *hardware = p->hardware;
94c98157
AA
553
554 /* Local port only */
555 if (hardware != NULL) {
556 switch (key) {
557 case lldpctl_k_port_index:
558 return hardware->h_ifindex;
559 case lldpctl_k_tx_cnt:
560 return hardware->h_tx_cnt;
561 case lldpctl_k_rx_cnt:
562 return hardware->h_rx_cnt;
563 case lldpctl_k_rx_discarded_cnt:
564 return hardware->h_rx_discarded_cnt;
565 case lldpctl_k_rx_unrecognized_cnt:
566 return hardware->h_rx_unrecognized_cnt;
567 case lldpctl_k_ageout_cnt:
568 return hardware->h_ageout_cnt;
569 case lldpctl_k_insert_cnt:
570 return hardware->h_insert_cnt;
571 case lldpctl_k_delete_cnt:
572 return hardware->h_delete_cnt;
573 default: break;
574 }
575 }
e7331ce9
VB
576 if (p->local) {
577 switch (key) {
578 case lldpctl_k_port_status:
579 return LLDPD_RXTX_FROM_PORT(port);
580 default: break;
581 }
582 }
825b37a7
BH
583 if (!port)
584 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
94c98157
AA
585
586 /* Local and remote port */
587 switch (key) {
588 case lldpctl_k_port_protocol:
589 return port->p_protocol;
590 case lldpctl_k_port_age:
591 return port->p_lastchange;
592 case lldpctl_k_port_id_subtype:
593 return port->p_id_subtype;
594 case lldpctl_k_port_hidden:
595 return port->p_hidden_in;
596#ifdef ENABLE_DOT3
597 case lldpctl_k_port_dot3_mfs:
598 if (port->p_mfs > 0)
599 return port->p_mfs;
600 break;
601 case lldpctl_k_port_dot3_aggregid:
602 if (port->p_aggregid > 0)
603 return port->p_aggregid;
604 break;
605 case lldpctl_k_port_dot3_autoneg_support:
606 return port->p_macphy.autoneg_support;
607 case lldpctl_k_port_dot3_autoneg_enabled:
608 return port->p_macphy.autoneg_enabled;
609 case lldpctl_k_port_dot3_autoneg_advertised:
610 return port->p_macphy.autoneg_advertised;
611 case lldpctl_k_port_dot3_mautype:
612 return port->p_macphy.mau_type;
613#endif
614#ifdef ENABLE_DOT1
615 case lldpctl_k_port_vlan_pvid:
616 return port->p_pvid;
94c98157
AA
617#endif
618 default:
e55e7492
VB
619 /* Compatibility: query the associated chassis too */
620 return lldpctl_atom_get_int(p->chassis, key);
94c98157
AA
621 }
622 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
623}
624
625static const uint8_t*
626_lldpctl_atom_get_buf_port(lldpctl_atom_t *atom, lldpctl_key_t key, size_t *n)
627{
628 struct _lldpctl_atom_port_t *p =
629 (struct _lldpctl_atom_port_t *)atom;
630 struct lldpd_port *port = p->port;
94c98157
AA
631
632 switch (key) {
633 case lldpctl_k_port_id:
634 *n = port->p_id_len;
635 return (uint8_t*)port->p_id;
94c98157 636 default:
e55e7492
VB
637 /* Compatibility: query the associated chassis too */
638 return lldpctl_atom_get_buffer(p->chassis, key, n);
94c98157
AA
639 }
640}
641
642static struct atom_builder ports_list =
643 { atom_ports_list, sizeof(struct _lldpctl_atom_any_list_t),
644 .init = _lldpctl_atom_new_any_list,
645 .free = _lldpctl_atom_free_any_list,
646 .iter = _lldpctl_atom_iter_ports_list,
647 .next = _lldpctl_atom_next_ports_list,
648 .value = _lldpctl_atom_value_ports_list };
649
650static struct atom_builder port =
651 { atom_port, sizeof(struct _lldpctl_atom_port_t),
652 .init = _lldpctl_atom_new_port,
653 .free = _lldpctl_atom_free_port,
654 .get = _lldpctl_atom_get_atom_port,
655 .set = _lldpctl_atom_set_atom_port,
656 .get_str = _lldpctl_atom_get_str_port,
657 .set_str = _lldpctl_atom_set_str_port,
658 .get_int = _lldpctl_atom_get_int_port,
e7331ce9 659 .set_int = _lldpctl_atom_set_int_port,
94c98157
AA
660 .get_buffer = _lldpctl_atom_get_buf_port };
661
662ATOM_BUILDER_REGISTER(ports_list, 4);
663ATOM_BUILDER_REGISTER(port, 5);
664