]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | ||
e7331ce9 VB |
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 | ||
94c98157 AA |
67 | static 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 |
124 | static 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 | ||
132 | static 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 | ||
139 | static 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 | ||
147 | static 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 | ||
168 | TAILQ_HEAD(chassis_list, lldpd_chassis); | |
169 | ||
170 | static void | |
171 | add_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 | ||
182 | static 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 | ||
232 | static 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 | ||
297 | static 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 | ||
408 | static 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 |
482 | static 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 |
508 | static 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 | ||
546 | static 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 | ||
625 | static 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 | ||
642 | static 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 | ||
650 | static 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 | ||
662 | ATOM_BUILDER_REGISTER(ports_list, 4); | |
663 | ATOM_BUILDER_REGISTER(port, 5); | |
664 |