]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/lib/atoms/port.c
lib: use constants from lldp-const.h for Dot3 MAU
[thirdparty/lldpd.git] / src / lib / atoms / port.c
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"
24 #include "../log.h"
25 #include "atom.h"
26 #include "helpers.h"
27
28 static 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
41 ATOM_MAP_REGISTER(lldpd_protocol_map, 3);
42
43 static 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
54 static 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
65 ATOM_MAP_REGISTER(port_status_map, 3);
66
67 #ifdef ENABLE_DOT3
68 static lldpctl_map_t operational_mau_type_values[] = {
69 { LLDP_DOT3_MAU_AUI, "AUI - No internal MAU, view from AUI" },
70 { LLDP_DOT3_MAU_10BASE5, "10Base5 - Thick coax MAU" },
71 { LLDP_DOT3_MAU_FOIRL, "Foirl - FOIRL MAU" },
72 { LLDP_DOT3_MAU_10BASE2, "10Base2 - Thin coax MAU" },
73 { LLDP_DOT3_MAU_10BASET, "10BaseT - UTP MAU" },
74 { LLDP_DOT3_MAU_10BASEFP, "10BaseFP - Passive fiber MAU" },
75 { LLDP_DOT3_MAU_10BASEFB, "10BaseFB - Sync fiber MAU" },
76 { LLDP_DOT3_MAU_10BASEFL, "10BaseFL - Async fiber MAU" },
77 { LLDP_DOT3_MAU_10BROAD36, "10Broad36 - Broadband DTE MAU" },
78 { LLDP_DOT3_MAU_10BASETHD, "10BaseTHD - UTP MAU, half duplex mode" },
79 { LLDP_DOT3_MAU_10BASETFD, "10BaseTFD - UTP MAU, full duplex mode" },
80 { LLDP_DOT3_MAU_10BASEFLHD, "10BaseFLHD - Async fiber MAU, half duplex mode" },
81 { LLDP_DOT3_MAU_10BASEFLFD, "10BaseFLDF - Async fiber MAU, full duplex mode" },
82 { LLDP_DOT3_MAU_100BASET4, "100BaseT4 - 4 pair category 3 UTP" },
83 { LLDP_DOT3_MAU_100BASETXHD, "100BaseTXHD - 2 pair category 5 UTP, half duplex mode" },
84 { LLDP_DOT3_MAU_100BASETXFD, "100BaseTXFD - 2 pair category 5 UTP, full duplex mode" },
85 { LLDP_DOT3_MAU_100BASEFXHD, "100BaseFXHD - X fiber over PMT, half duplex mode" },
86 { LLDP_DOT3_MAU_100BASEFXFD, "100BaseFXFD - X fiber over PMT, full duplex mode" },
87 { LLDP_DOT3_MAU_100BASET2HD, "100BaseT2HD - 2 pair category 3 UTP, half duplex mode" },
88 { LLDP_DOT3_MAU_100BASET2FD, "100BaseT2FD - 2 pair category 3 UTP, full duplex mode" },
89 { LLDP_DOT3_MAU_1000BASEXHD, "1000BaseXHD - PCS/PMA, unknown PMD, half duplex mode" },
90 { LLDP_DOT3_MAU_1000BASEXFD, "1000BaseXFD - PCS/PMA, unknown PMD, full duplex mode" },
91 { LLDP_DOT3_MAU_1000BASELXHD, "1000BaseLXHD - Fiber over long-wavelength laser, half duplex mode" },
92 { LLDP_DOT3_MAU_1000BASELXFD, "1000BaseLXFD - Fiber over long-wavelength laser, full duplex mode" },
93 { LLDP_DOT3_MAU_1000BASESXHD, "1000BaseSXHD - Fiber over short-wavelength laser, half duplex mode" },
94 { LLDP_DOT3_MAU_1000BASESXFD, "1000BaseSXFD - Fiber over short-wavelength laser, full duplex mode" },
95 { LLDP_DOT3_MAU_1000BASECXHD, "1000BaseCXHD - Copper over 150-Ohm balanced cable, half duplex mode" },
96 { LLDP_DOT3_MAU_1000BASECXFD, "1000BaseCXFD - Copper over 150-Ohm balanced cable, full duplex mode" },
97 { LLDP_DOT3_MAU_1000BASETHD, "1000BaseTHD - Four-pair Category 5 UTP, half duplex mode" },
98 { LLDP_DOT3_MAU_1000BASETFD, "1000BaseTFD - Four-pair Category 5 UTP, full duplex mode" },
99 { LLDP_DOT3_MAU_10GIGBASEX, "10GigBaseX - X PCS/PMA, unknown PMD." },
100 { LLDP_DOT3_MAU_10GIGBASELX4, "10GigBaseLX4 - X fiber over WWDM optics" },
101 { LLDP_DOT3_MAU_10GIGBASER, "10GigBaseR - R PCS/PMA, unknown PMD." },
102 { LLDP_DOT3_MAU_10GIGBASEER, "10GigBaseER - R fiber over 1550 nm optics" },
103 { LLDP_DOT3_MAU_10GIGBASELR, "10GigBaseLR - R fiber over 1310 nm optics" },
104 { LLDP_DOT3_MAU_10GIGBASESR, "10GigBaseSR - R fiber over 850 nm optics" },
105 { LLDP_DOT3_MAU_10GIGBASEW, "10GigBaseW - W PCS/PMA, unknown PMD." },
106 { LLDP_DOT3_MAU_10GIGBASEEW, "10GigBaseEW - W fiber over 1550 nm optics" },
107 { LLDP_DOT3_MAU_10GIGBASELW, "10GigBaseLW - W fiber over 1310 nm optics" },
108 { LLDP_DOT3_MAU_10GIGBASESW, "10GigBaseSW - W fiber over 850 nm optics" },
109 { LLDP_DOT3_MAU_10GIGBASECX4, "10GigBaseCX4 - X copper over 8 pair 100-Ohm balanced cable" },
110 { LLDP_DOT3_MAU_2BASETL, "2BaseTL - Voice grade UTP copper, up to 2700m, optional PAF" },
111 { LLDP_DOT3_MAU_10PASSTS, "10PassTS - Voice grade UTP copper, up to 750m, optional PAF" },
112 { LLDP_DOT3_MAU_100BASEBX10D, "100BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" },
113 { LLDP_DOT3_MAU_100BASEBX10U, "100BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" },
114 { LLDP_DOT3_MAU_100BASELX10, "100BaseLX10 - Two single-mode fibers, long wavelength, 10km" },
115 { LLDP_DOT3_MAU_1000BASEBX10D, "1000BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" },
116 { LLDP_DOT3_MAU_1000BASEBX10U, "1000BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" },
117 { LLDP_DOT3_MAU_1000BASELX10, "1000BaseLX10 - Two sigle-mode fiber, long wavelength, 10km" },
118 { LLDP_DOT3_MAU_1000BASEPX10D, "1000BasePX10D - One single-mode fiber EPON OLT, 10km" },
119 { LLDP_DOT3_MAU_1000BASEPX10U, "1000BasePX10U - One single-mode fiber EPON ONU, 10km" },
120 { LLDP_DOT3_MAU_1000BASEPX20D, "1000BasePX20D - One single-mode fiber EPON OLT, 20km" },
121 { LLDP_DOT3_MAU_1000BASEPX20U, "1000BasePX20U - One single-mode fiber EPON ONU, 20km" },
122 { LLDP_DOT3_MAU_10GBASET, "10GbaseT - Four-pair Category 6A or better, full duplex mode only" },
123 { LLDP_DOT3_MAU_10GBASELRM, "10GbaseLRM - R multimode fiber over 1310 nm optics" },
124 { LLDP_DOT3_MAU_1000BASEKX, "1000baseKX - X backplane, full duplex mode only" },
125 { LLDP_DOT3_MAU_10GBASEKX4, "10GbaseKX4 - 4 lane X backplane, full duplex mode only" },
126 { LLDP_DOT3_MAU_10GBASEKR, "10GbaseKR - R backplane, full duplex mode only" },
127 { LLDP_DOT3_MAU_10G1GBASEPRXD1, "10G1GbasePRXD1 - One single-mode fiber asymmetric-rate EPON OLT, low power budget (PRX10)" },
128 { LLDP_DOT3_MAU_10G1GBASEPRXD2, "10G1GbasePRXD2 - One single-mode fiber asymmetric-rate EPON OLT, medium power budget (PRX20)" },
129 { LLDP_DOT3_MAU_10G1GBASEPRXD3, "10G1GbasePRXD3 - One single-mode fiber asymmetric-rate EPON OLT, high power budget (PRX30)" },
130 { LLDP_DOT3_MAU_10G1GBASEPRXU1, "10G1GbasePRXU1 - One single-mode fiber asymmetric-rate EPON ONU, low power budget (PRX10)" },
131 { LLDP_DOT3_MAU_10G1GBASEPRXU2, "10G1GbasePRXU2 - One single-mode fiber asymmetric-rate EPON ONU, medium power budget (PRX20)" },
132 { LLDP_DOT3_MAU_10G1GBASEPRXU3, "10G1GbasePRXU3 - One single-mode fiber asymmetric-rate EPON ONU, high power budget (PRX30)" },
133 { LLDP_DOT3_MAU_10GBASEPRD1, "10GbasePRD1 - One single-mode fiber symmetric-rate EPON OLT, low power budget (PR10)" },
134 { LLDP_DOT3_MAU_10GBASEPRD2, "10GbasePRD2 - One single-mode fiber symmetric-rate EPON OLT, medium power budget (PR20)" },
135 { LLDP_DOT3_MAU_10GBASEPRD3, "10GbasePRD3 - One single-mode fiber symmetric-rate EPON OLT, high power budget (PR30)" },
136 { LLDP_DOT3_MAU_10GBASEPRU1, "10GbasePRU1 - One single-mode fiber symmetric-rate EPON ONU, low and medium power budget" },
137 { LLDP_DOT3_MAU_10GBASEPRU3, "10GbasePRU3 - One single-mode fiber symmetric-rate EPON ONU, high power budget (PR30)" },
138 { LLDP_DOT3_MAU_40GBASEKR4, "40GbaseKR4 - 40GBASE-R PCS/PMA over an electrical backplane" },
139 { LLDP_DOT3_MAU_40GBASECR4, "40GbaseCR4 - 40GBASE-R PCS/PMA over 4 lane shielded copper balanced cable" },
140 { LLDP_DOT3_MAU_40GBASESR4, "40GbaseSR4 - 40GBASE-R PCS/PMA over 4 lane multimode fiber" },
141 { LLDP_DOT3_MAU_40GBASEFR, "40GbaseFR - 40GBASE-R PCS/PMA over single mode fiber" },
142 { LLDP_DOT3_MAU_40GBASELR4, "40GbaseLR4 - 40GBASE-R PCS/PMA over 4 WDM lane single mode fiber" },
143 { LLDP_DOT3_MAU_100GBASECR10, "100GbaseCR10 - 100GBASE-R PCS/PMA over 10 lane shielded copper balanced cable" },
144 { LLDP_DOT3_MAU_100GBASESR10, "100GbaseSR10 - 100GBASE-R PCS/PMA over 10 lane multimode fiber" },
145 { LLDP_DOT3_MAU_100GBASELR4, "100GbaseLR4 - 100GBASE-R PCS/PMA over 4 WDM lane single mode fiber, long reach" },
146 { LLDP_DOT3_MAU_100GBASEER4, "100GbaseER4 - 100GBASE-R PCS/PMA over 4 WDM lane single mode fiber PMD, extended reach" },
147 { 0, NULL }
148 };
149 #endif
150
151 static lldpctl_atom_iter_t*
152 _lldpctl_atom_iter_ports_list(lldpctl_atom_t *atom)
153 {
154 struct _lldpctl_atom_any_list_t *plist =
155 (struct _lldpctl_atom_any_list_t *)atom;
156 return (lldpctl_atom_iter_t*)TAILQ_FIRST(&plist->parent->hardware->h_rports);
157 }
158
159 static lldpctl_atom_iter_t*
160 _lldpctl_atom_next_ports_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
161 {
162 struct lldpd_port *port = (struct lldpd_port *)iter;
163 return (lldpctl_atom_iter_t*)TAILQ_NEXT(port, p_entries);
164 }
165
166 static lldpctl_atom_t*
167 _lldpctl_atom_value_ports_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
168 {
169 struct lldpd_port *port = (struct lldpd_port *)iter;
170 return _lldpctl_new_atom(atom->conn, atom_port, 0, NULL, port,
171 ((struct _lldpctl_atom_any_list_t *)atom)->parent);
172 }
173
174 static int
175 _lldpctl_atom_new_port(lldpctl_atom_t *atom, va_list ap)
176 {
177 struct _lldpctl_atom_port_t *port =
178 (struct _lldpctl_atom_port_t *)atom;
179 port->local = va_arg(ap, int);
180 port->hardware = va_arg(ap, struct lldpd_hardware*);
181 port->port = va_arg(ap, struct lldpd_port*);
182 port->parent = va_arg(ap, struct _lldpctl_atom_port_t*);
183 if (port->parent)
184 lldpctl_atom_inc_ref((lldpctl_atom_t*)port->parent);
185
186 if (port->port) {
187 /* Internal atom. We are the parent, but our reference count is
188 * not incremented. */
189 port->chassis = _lldpctl_new_atom(atom->conn, atom_chassis,
190 port->port->p_chassis, port, 1);
191 }
192 return 1;
193 }
194
195 TAILQ_HEAD(chassis_list, lldpd_chassis);
196
197 static void
198 add_chassis(struct chassis_list *chassis_list,
199 struct lldpd_chassis *chassis)
200 {
201 struct lldpd_chassis *one_chassis;
202 TAILQ_FOREACH(one_chassis, chassis_list, c_entries) {
203 if (one_chassis == chassis) return;
204 }
205 TAILQ_INSERT_TAIL(chassis_list,
206 chassis, c_entries);
207 }
208
209 static void
210 _lldpctl_atom_free_port(lldpctl_atom_t *atom)
211 {
212 struct _lldpctl_atom_port_t *port =
213 (struct _lldpctl_atom_port_t *)atom;
214 struct lldpd_hardware *hardware = port->hardware;
215 struct lldpd_chassis *one_chassis, *one_chassis_next;
216 struct lldpd_port *one_port;
217
218 /* Free internal chassis atom. Should be freed immediately since we
219 * should have the only reference. */
220 lldpctl_atom_dec_ref((lldpctl_atom_t*)port->chassis);
221
222 /* We need to free the whole struct lldpd_hardware: local port, local
223 * chassis and remote ports... The same chassis may be present several
224 * times. We build a list of chassis (we don't use reference count). */
225 struct chassis_list chassis_list;
226 TAILQ_INIT(&chassis_list);
227
228 if (port->parent) lldpctl_atom_dec_ref((lldpctl_atom_t*)port->parent);
229 else if (!hardware && port->port) {
230 /* No parent, no hardware, we assume a single neighbor: one
231 * port, one chassis. */
232 if (port->port->p_chassis) {
233 lldpd_chassis_cleanup(port->port->p_chassis, 1);
234 port->port->p_chassis = NULL;
235 }
236 lldpd_port_cleanup(port->port, 1);
237 free(port->port);
238 }
239 if (!hardware) return;
240
241 add_chassis(&chassis_list, port->port->p_chassis);
242 TAILQ_FOREACH(one_port, &hardware->h_rports, p_entries)
243 add_chassis(&chassis_list, one_port->p_chassis);
244
245 /* Free hardware port */
246 lldpd_remote_cleanup(hardware, NULL, 1);
247 lldpd_port_cleanup(port->port, 1);
248 free(port->hardware);
249
250 /* Free list of chassis */
251 for (one_chassis = TAILQ_FIRST(&chassis_list);
252 one_chassis != NULL;
253 one_chassis = one_chassis_next) {
254 one_chassis_next = TAILQ_NEXT(one_chassis, c_entries);
255 lldpd_chassis_cleanup(one_chassis, 1);
256 }
257 }
258
259 static lldpctl_atom_t*
260 _lldpctl_atom_get_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key)
261 {
262 struct _lldpctl_atom_port_t *p =
263 (struct _lldpctl_atom_port_t *)atom;
264 struct lldpd_port *port = p->port;
265 struct lldpd_hardware *hardware = p->hardware;
266
267 /* Local port only */
268 if (hardware != NULL) {
269 switch (key) {
270 case lldpctl_k_port_neighbors:
271 return _lldpctl_new_atom(atom->conn, atom_ports_list, p);
272 default: break;
273 }
274 }
275
276 /* Local and remote port */
277 switch (key) {
278 case lldpctl_k_port_chassis:
279 if (port->p_chassis) {
280 return _lldpctl_new_atom(atom->conn, atom_chassis,
281 port->p_chassis, p, 0);
282 }
283 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
284 return NULL;
285 #ifdef ENABLE_DOT3
286 case lldpctl_k_port_dot3_power:
287 return _lldpctl_new_atom(atom->conn, atom_dot3_power,
288 p);
289 #endif
290 #ifdef ENABLE_DOT1
291 case lldpctl_k_port_vlans:
292 return _lldpctl_new_atom(atom->conn, atom_vlans_list,
293 p);
294 case lldpctl_k_port_ppvids:
295 return _lldpctl_new_atom(atom->conn, atom_ppvids_list,
296 p);
297 case lldpctl_k_port_pis:
298 return _lldpctl_new_atom(atom->conn, atom_pis_list,
299 p);
300 #endif
301 #ifdef ENABLE_LLDPMED
302 case lldpctl_k_port_med_policies:
303 return _lldpctl_new_atom(atom->conn, atom_med_policies_list,
304 p);
305 case lldpctl_k_port_med_locations:
306 return _lldpctl_new_atom(atom->conn, atom_med_locations_list,
307 p);
308 case lldpctl_k_port_med_power:
309 return _lldpctl_new_atom(atom->conn, atom_med_power, p);
310 #endif
311 #ifdef ENABLE_CUSTOM
312 case lldpctl_k_custom_tlvs:
313 return _lldpctl_new_atom(atom->conn, atom_custom_list, p);
314 #endif
315 default:
316 /* Compatibility: query the associated chassis too */
317 if (port->p_chassis)
318 return lldpctl_atom_get(p->chassis, key);
319 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
320 return NULL;
321 }
322 }
323
324 static lldpctl_atom_t*
325 _lldpctl_atom_set_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key, lldpctl_atom_t *value)
326 {
327 struct _lldpctl_atom_port_t *p =
328 (struct _lldpctl_atom_port_t *)atom;
329 struct lldpd_hardware *hardware = p->hardware;
330 struct lldpd_port_set set = {};
331 int rc;
332 char *canary;
333
334 #ifdef ENABLE_DOT3
335 struct _lldpctl_atom_dot3_power_t *dpow;
336 #endif
337 #ifdef ENABLE_LLDPMED
338 struct _lldpctl_atom_med_power_t *mpow;
339 struct _lldpctl_atom_med_policy_t *mpol;
340 struct _lldpctl_atom_med_location_t *mloc;
341 #endif
342 #ifdef ENABLE_CUSTOM
343 struct _lldpctl_atom_custom_t *custom;
344 #endif
345
346 /* Local and default port only */
347 if (!p->local) {
348 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
349 return NULL;
350 }
351
352 switch (key) {
353 case lldpctl_k_port_id:
354 set.local_id = p->port->p_id;
355 break;
356 case lldpctl_k_port_descr:
357 set.local_descr = p->port->p_descr;
358 break;
359 case lldpctl_k_port_status:
360 set.rxtx = LLDPD_RXTX_FROM_PORT(p->port);
361 break;
362 #ifdef ENABLE_DOT3
363 case lldpctl_k_port_dot3_power:
364 if (value->type != atom_dot3_power) {
365 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
366 return NULL;
367 }
368
369 dpow = (struct _lldpctl_atom_dot3_power_t *)value;
370 set.dot3_power = &dpow->parent->port->p_power;
371 break;
372 #endif
373 #ifdef ENABLE_LLDPMED
374 case lldpctl_k_port_med_power:
375 if (value->type != atom_med_power) {
376 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
377 return NULL;
378 }
379
380 mpow = (struct _lldpctl_atom_med_power_t *)value;
381 set.med_power = &mpow->parent->port->p_med_power;
382 break;
383 case lldpctl_k_port_med_policies:
384 if (value->type != atom_med_policy) {
385 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
386 return NULL;
387 }
388 mpol = (struct _lldpctl_atom_med_policy_t *)value;
389 set.med_policy = mpol->policy;
390 break;
391 case lldpctl_k_port_med_locations:
392 if (value->type != atom_med_location) {
393 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
394 return NULL;
395 }
396 mloc = (struct _lldpctl_atom_med_location_t *)value;
397 set.med_location = mloc->location;
398 break;
399 #endif
400 #ifdef ENABLE_CUSTOM
401 case lldpctl_k_custom_tlvs_clear:
402 set.custom_list_clear = 1;
403 break;
404 case lldpctl_k_custom_tlv:
405 if (value->type != atom_custom) {
406 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
407 return NULL;
408 }
409 custom = (struct _lldpctl_atom_custom_t *)value;
410 set.custom = custom->tlv;
411 set.custom_tlv_op = custom->op;
412 break;
413 #endif
414 default:
415 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
416 return NULL;
417 }
418
419 set.ifname = hardware ? hardware->h_ifname : "";
420
421 if (asprintf(&canary, "%d%p%s", key, value, set.ifname) == -1) {
422 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
423 return NULL;
424 }
425 rc = _lldpctl_do_something(atom->conn,
426 CONN_STATE_SET_PORT_SEND, CONN_STATE_SET_PORT_RECV,
427 canary,
428 SET_PORT, &set, &MARSHAL_INFO(lldpd_port_set),
429 NULL, NULL);
430 free(canary);
431 if (rc == 0) return atom;
432 return NULL;
433 }
434
435 static const char*
436 _lldpctl_atom_get_str_port(lldpctl_atom_t *atom, lldpctl_key_t key)
437 {
438 struct _lldpctl_atom_port_t *p =
439 (struct _lldpctl_atom_port_t *)atom;
440 struct lldpd_port *port = p->port;
441 struct lldpd_hardware *hardware = p->hardware;
442 char *ipaddress = NULL; size_t len;
443
444 /* Local port only */
445 switch (key) {
446 case lldpctl_k_port_name:
447 if (hardware != NULL) return hardware->h_ifname;
448 break;
449 case lldpctl_k_port_status:
450 if (p->local) return map_lookup(port_status_map.map,
451 LLDPD_RXTX_FROM_PORT(port));
452 break;
453 default: break;
454 }
455
456 if (!port)
457 return NULL;
458
459 /* Local and remote port */
460 switch (key) {
461 case lldpctl_k_port_protocol:
462 return map_lookup(lldpd_protocol_map.map, port->p_protocol);
463 case lldpctl_k_port_id_subtype:
464 return map_lookup(port_id_subtype_map, port->p_id_subtype);
465 case lldpctl_k_port_id:
466 switch (port->p_id_subtype) {
467 case LLDP_PORTID_SUBTYPE_IFNAME:
468 case LLDP_PORTID_SUBTYPE_IFALIAS:
469 case LLDP_PORTID_SUBTYPE_LOCAL:
470 return port->p_id;
471 case LLDP_PORTID_SUBTYPE_LLADDR:
472 return _lldpctl_dump_in_atom(atom,
473 (uint8_t*)port->p_id, port->p_id_len,
474 ':', 0);
475 case LLDP_PORTID_SUBTYPE_ADDR:
476 switch (port->p_id[0]) {
477 case LLDP_MGMT_ADDR_IP4: len = INET_ADDRSTRLEN + 1; break;
478 case LLDP_MGMT_ADDR_IP6: len = INET6_ADDRSTRLEN + 1; break;
479 default: len = 0;
480 }
481 if (len > 0) {
482 ipaddress = _lldpctl_alloc_in_atom(atom, len);
483 if (!ipaddress) return NULL;
484 if (inet_ntop((port->p_id[0] == LLDP_MGMT_ADDR_IP4)?
485 AF_INET:AF_INET6,
486 &port->p_id[1], ipaddress, len) == NULL)
487 break;
488 return ipaddress;
489 }
490 break;
491 }
492 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
493 return NULL;
494 case lldpctl_k_port_descr:
495 return port->p_descr;
496
497 #ifdef ENABLE_DOT3
498 case lldpctl_k_port_dot3_mautype:
499 return map_lookup(operational_mau_type_values,
500 port->p_macphy.mau_type);
501 #endif
502
503 default:
504 /* Compatibility: query the associated chassis too */
505 return lldpctl_atom_get_str(p->chassis, key);
506 }
507 }
508
509 static lldpctl_atom_t*
510 _lldpctl_atom_set_int_port(lldpctl_atom_t *atom, lldpctl_key_t key,
511 long int value)
512 {
513 struct _lldpctl_atom_port_t *p =
514 (struct _lldpctl_atom_port_t *)atom;
515 struct lldpd_port *port = p->port;
516
517 if (p->local) {
518 switch (key) {
519 case lldpctl_k_port_status:
520 port->p_disable_rx = !LLDPD_RXTX_RXENABLED(value);
521 port->p_disable_tx = !LLDPD_RXTX_TXENABLED(value);
522 break;
523 default:
524 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
525 return NULL;
526 }
527 } else {
528 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
529 return NULL;
530 }
531
532 return _lldpctl_atom_set_atom_port(atom, key, NULL);
533 }
534
535 static lldpctl_atom_t*
536 _lldpctl_atom_set_str_port(lldpctl_atom_t *atom, lldpctl_key_t key,
537 const char *value)
538 {
539 struct _lldpctl_atom_port_t *p =
540 (struct _lldpctl_atom_port_t *)atom;
541 struct lldpd_port *port = p->port;
542
543 if (!value || !strlen(value))
544 return NULL;
545
546 if (p->local) {
547 switch (key) {
548 case lldpctl_k_port_status:
549 return _lldpctl_atom_set_int_port(atom, key,
550 map_reverse_lookup(port_status_map.map, value));
551 default: break;
552 }
553 }
554
555 switch (key) {
556 case lldpctl_k_port_id:
557 free(port->p_id);
558 port->p_id = strdup(value);
559 port->p_id_len = strlen(value);
560 break;
561 case lldpctl_k_port_descr:
562 free(port->p_descr);
563 port->p_descr = strdup(value);
564 break;
565 default:
566 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
567 return NULL;
568 }
569
570 return _lldpctl_atom_set_atom_port(atom, key, NULL);
571 }
572
573 static long int
574 _lldpctl_atom_get_int_port(lldpctl_atom_t *atom, lldpctl_key_t key)
575 {
576 struct _lldpctl_atom_port_t *p =
577 (struct _lldpctl_atom_port_t *)atom;
578 struct lldpd_port *port = p->port;
579 struct lldpd_hardware *hardware = p->hardware;
580
581 /* Local port only */
582 if (hardware != NULL) {
583 switch (key) {
584 case lldpctl_k_port_index:
585 return hardware->h_ifindex;
586 case lldpctl_k_tx_cnt:
587 return hardware->h_tx_cnt;
588 case lldpctl_k_rx_cnt:
589 return hardware->h_rx_cnt;
590 case lldpctl_k_rx_discarded_cnt:
591 return hardware->h_rx_discarded_cnt;
592 case lldpctl_k_rx_unrecognized_cnt:
593 return hardware->h_rx_unrecognized_cnt;
594 case lldpctl_k_ageout_cnt:
595 return hardware->h_ageout_cnt;
596 case lldpctl_k_insert_cnt:
597 return hardware->h_insert_cnt;
598 case lldpctl_k_delete_cnt:
599 return hardware->h_delete_cnt;
600 default: break;
601 }
602 }
603 if (p->local) {
604 switch (key) {
605 case lldpctl_k_port_status:
606 return LLDPD_RXTX_FROM_PORT(port);
607 default: break;
608 }
609 }
610 if (!port)
611 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
612
613 /* Local and remote port */
614 switch (key) {
615 case lldpctl_k_port_protocol:
616 return port->p_protocol;
617 case lldpctl_k_port_age:
618 return port->p_lastchange;
619 case lldpctl_k_port_ttl:
620 return port->p_ttl;
621 case lldpctl_k_port_id_subtype:
622 return port->p_id_subtype;
623 case lldpctl_k_port_hidden:
624 return port->p_hidden_in;
625 #ifdef ENABLE_DOT3
626 case lldpctl_k_port_dot3_mfs:
627 if (port->p_mfs > 0)
628 return port->p_mfs;
629 break;
630 case lldpctl_k_port_dot3_aggregid:
631 if (port->p_aggregid > 0)
632 return port->p_aggregid;
633 break;
634 case lldpctl_k_port_dot3_autoneg_support:
635 return port->p_macphy.autoneg_support;
636 case lldpctl_k_port_dot3_autoneg_enabled:
637 return port->p_macphy.autoneg_enabled;
638 case lldpctl_k_port_dot3_autoneg_advertised:
639 return port->p_macphy.autoneg_advertised;
640 case lldpctl_k_port_dot3_mautype:
641 return port->p_macphy.mau_type;
642 #endif
643 #ifdef ENABLE_DOT1
644 case lldpctl_k_port_vlan_pvid:
645 return port->p_pvid;
646 #endif
647 default:
648 /* Compatibility: query the associated chassis too */
649 return lldpctl_atom_get_int(p->chassis, key);
650 }
651 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
652 }
653
654 static const uint8_t*
655 _lldpctl_atom_get_buf_port(lldpctl_atom_t *atom, lldpctl_key_t key, size_t *n)
656 {
657 struct _lldpctl_atom_port_t *p =
658 (struct _lldpctl_atom_port_t *)atom;
659 struct lldpd_port *port = p->port;
660
661 switch (key) {
662 case lldpctl_k_port_id:
663 *n = port->p_id_len;
664 return (uint8_t*)port->p_id;
665 default:
666 /* Compatibility: query the associated chassis too */
667 return lldpctl_atom_get_buffer(p->chassis, key, n);
668 }
669 }
670
671 static struct atom_builder ports_list =
672 { atom_ports_list, sizeof(struct _lldpctl_atom_any_list_t),
673 .init = _lldpctl_atom_new_any_list,
674 .free = _lldpctl_atom_free_any_list,
675 .iter = _lldpctl_atom_iter_ports_list,
676 .next = _lldpctl_atom_next_ports_list,
677 .value = _lldpctl_atom_value_ports_list };
678
679 static struct atom_builder port =
680 { atom_port, sizeof(struct _lldpctl_atom_port_t),
681 .init = _lldpctl_atom_new_port,
682 .free = _lldpctl_atom_free_port,
683 .get = _lldpctl_atom_get_atom_port,
684 .set = _lldpctl_atom_set_atom_port,
685 .get_str = _lldpctl_atom_get_str_port,
686 .set_str = _lldpctl_atom_set_str_port,
687 .get_int = _lldpctl_atom_get_int_port,
688 .set_int = _lldpctl_atom_set_int_port,
689 .get_buffer = _lldpctl_atom_get_buf_port };
690
691 ATOM_BUILDER_REGISTER(ports_list, 4);
692 ATOM_BUILDER_REGISTER(port, 5);
693