]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/lib/atom-private.c
lldpd: make notifications work when a port goes down
[thirdparty/lldpd.git] / src / lib / atom-private.c
1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3 * Copyright (c) 2012 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 <stdio.h>
19 #include <stdarg.h>
20 #include <string.h>
21 #include <arpa/inet.h>
22
23 #include "lldpctl.h"
24 #include "../lldpd-structs.h"
25 #include "../log.h"
26 #include "private.h"
27 #include "fixedpoint.h"
28
29 /* Translation from constants to string */
30 static lldpctl_map_t lldpd_protocol_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 static lldpctl_map_t chassis_id_subtype_map[] = {
41 { LLDP_CHASSISID_SUBTYPE_IFNAME, "ifname"},
42 { LLDP_CHASSISID_SUBTYPE_IFALIAS, "ifalias" },
43 { LLDP_CHASSISID_SUBTYPE_LOCAL, "local" },
44 { LLDP_CHASSISID_SUBTYPE_LLADDR, "mac" },
45 { LLDP_CHASSISID_SUBTYPE_ADDR, "ip" },
46 { LLDP_CHASSISID_SUBTYPE_PORT, "unhandled" },
47 { LLDP_CHASSISID_SUBTYPE_CHASSIS, "unhandled" },
48 { 0, NULL},
49 };
50
51 static lldpctl_map_t port_id_subtype_map[] = {
52 { LLDP_PORTID_SUBTYPE_IFNAME, "ifname"},
53 { LLDP_PORTID_SUBTYPE_IFALIAS, "ifalias" },
54 { LLDP_PORTID_SUBTYPE_LOCAL, "local" },
55 { LLDP_PORTID_SUBTYPE_LLADDR, "mac" },
56 { LLDP_PORTID_SUBTYPE_ADDR, "ip" },
57 { LLDP_PORTID_SUBTYPE_PORT, "unhandled" },
58 { LLDP_PORTID_SUBTYPE_AGENTCID, "unhandled" },
59 { 0, NULL},
60 };
61
62 #ifdef ENABLE_DOT3
63 static lldpctl_map_t operational_mau_type_values[] = {
64 { 1, "AUI - no internal MAU, view from AUI" },
65 { 2, "10Base5 - thick coax MAU" },
66 { 3, "Foirl - FOIRL MAU" },
67 { 4, "10Base2 - thin coax MAU" },
68 { 5, "10BaseT - UTP MAU" },
69 { 6, "10BaseFP - passive fiber MAU" },
70 { 7, "10BaseFB - sync fiber MAU" },
71 { 8, "10BaseFL - async fiber MAU" },
72 { 9, "10Broad36 - broadband DTE MAU" },
73 { 10, "10BaseTHD - UTP MAU, half duplex mode" },
74 { 11, "10BaseTFD - UTP MAU, full duplex mode" },
75 { 12, "10BaseFLHD - async fiber MAU, half duplex mode" },
76 { 13, "10BaseFLDF - async fiber MAU, full duplex mode" },
77 { 14, "10BaseT4 - 4 pair category 3 UTP" },
78 { 15, "100BaseTXHD - 2 pair category 5 UTP, half duplex mode" },
79 { 16, "100BaseTXFD - 2 pair category 5 UTP, full duplex mode" },
80 { 17, "100BaseFXHD - X fiber over PMT, half duplex mode" },
81 { 18, "100BaseFXFD - X fiber over PMT, full duplex mode" },
82 { 19, "100BaseT2HD - 2 pair category 3 UTP, half duplex mode" },
83 { 20, "100BaseT2FD - 2 pair category 3 UTP, full duplex mode" },
84 { 21, "1000BaseXHD - PCS/PMA, unknown PMD, half duplex mode" },
85 { 22, "1000BaseXFD - PCS/PMA, unknown PMD, full duplex mode" },
86 { 23, "1000BaseLXHD - Fiber over long-wavelength laser, half duplex mode" },
87 { 24, "1000BaseLXFD - Fiber over long-wavelength laser, full duplex mode" },
88 { 25, "1000BaseSXHD - Fiber over short-wavelength laser, half duplex mode" },
89 { 26, "1000BaseSXFD - Fiber over short-wavelength laser, full duplex mode" },
90 { 27, "1000BaseCXHD - Copper over 150-Ohm balanced cable, half duplex mode" },
91 { 28, "1000BaseCXFD - Copper over 150-Ohm balanced cable, full duplex mode" },
92 { 29, "1000BaseTHD - Four-pair Category 5 UTP, half duplex mode" },
93 { 30, "1000BaseTFD - Four-pair Category 5 UTP, full duplex mode" },
94 { 31, "10GigBaseX - X PCS/PMA, unknown PMD." },
95 { 32, "10GigBaseLX4 - X fiber over WWDM optics" },
96 { 33, "10GigBaseR - R PCS/PMA, unknown PMD." },
97 { 34, "10GigBaseER - R fiber over 1550 nm optics" },
98 { 35, "10GigBaseLR - R fiber over 1310 nm optics" },
99 { 36, "10GigBaseSR - R fiber over 850 nm optics" },
100 { 37, "10GigBaseW - W PCS/PMA, unknown PMD." },
101 { 38, "10GigBaseEW - W fiber over 1550 nm optics" },
102 { 39, "10GigBaseLW - W fiber over 1310 nm optics" },
103 { 40, "10GigBaseSW - W fiber over 850 nm optics" },
104 { 41, "10GigBaseCX4 - X copper over 8 pair 100-Ohm balanced cable" },
105 { 42, "2BaseTL - Voice grade UTP copper, up to 2700m, optional PAF" },
106 { 43, "10PassTS - Voice grade UTP copper, up to 750m, optional PAF" },
107 { 44, "100BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" },
108 { 45, "100BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" },
109 { 46, "100BaseLX10 - Two single-mode fibers, long wavelength, 10km" },
110 { 47, "1000BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" },
111 { 48, "1000BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" },
112 { 49, "1000BaseLX10 - Two sigle-mode fiber, long wavelength, 10km" },
113 { 50, "1000BasePX10D - One single-mode fiber EPON OLT, 10km" },
114 { 51, "1000BasePX10U - One single-mode fiber EPON ONU, 10km" },
115 { 52, "1000BasePX20D - One single-mode fiber EPON OLT, 20km" },
116 { 53, "1000BasePX20U - One single-mode fiber EPON ONU, 20km" },
117 { 0, NULL }
118 };
119
120 static lldpctl_map_t port_dot3_power_devicetype_map[] = {
121 { LLDP_DOT3_POWER_PSE, "PSE" },
122 { LLDP_DOT3_POWER_PD, "PD" },
123 { 0, NULL }
124 };
125
126 static lldpctl_map_t port_dot3_power_pairs_map[] = {
127 { LLDP_DOT3_POWERPAIRS_SIGNAL, "signal" },
128 { LLDP_DOT3_POWERPAIRS_SPARE, "spare" },
129 { 0, NULL }
130 };
131
132 static lldpctl_map_t port_dot3_power_class_map[] = {
133 { 1, "class 0" },
134 { 2, "class 1" },
135 { 3, "class 2" },
136 { 4, "class 3" },
137 { 5, "class 4" },
138 { 0, NULL }
139 };
140
141 static lldpctl_map_t port_dot3_power_pse_source_map[] = {
142 { LLDP_DOT3_POWER_SOURCE_BOTH, "PSE + Local" },
143 { LLDP_DOT3_POWER_SOURCE_PSE, "PSE" },
144 { 0, NULL }
145 };
146
147 static lldpctl_map_t port_dot3_power_pd_source_map[] = {
148 { LLDP_DOT3_POWER_SOURCE_BACKUP, "Backup source" },
149 { LLDP_DOT3_POWER_SOURCE_PRIMARY, "Primary power source" },
150 { 0, NULL }
151 };
152
153 static lldpctl_map_t port_dot3_power_priority_map[] = {
154 { 0, "unknown" },
155 { LLDP_MED_POW_PRIO_CRITICAL, "critical" },
156 { LLDP_MED_POW_PRIO_HIGH, "high" },
157 { LLDP_MED_POW_PRIO_LOW, "low" },
158 { 0, NULL },
159 };
160 #endif
161
162 #ifdef ENABLE_LLDPMED
163 static lldpctl_map_t chassis_med_type_map[] = {
164 { LLDP_MED_CLASS_I, "Generic Endpoint (Class I)" },
165 { LLDP_MED_CLASS_II, "Media Endpoint (Class II)" },
166 { LLDP_MED_CLASS_III, "Communication Device Endpoint (Class III)" },
167 { LLDP_MED_NETWORK_DEVICE, "Network Connectivity Device" },
168 { 0, NULL },
169 };
170
171 static lldpctl_map_t port_med_policy_map[] = {
172 { LLDP_MED_APPTYPE_VOICE , "Voice"},
173 { LLDP_MED_APPTYPE_VOICESIGNAL, "Voice Signaling"},
174 { LLDP_MED_APPTYPE_GUESTVOICE, "Guest Voice"},
175 { LLDP_MED_APPTYPE_GUESTVOICESIGNAL, "Guest Voice Signaling"},
176 { LLDP_MED_APPTYPE_SOFTPHONEVOICE, "Softphone Voice"},
177 { LLDP_MED_APPTYPE_VIDEOCONFERENCE, "Video Conferencing"},
178 { LLDP_MED_APPTYPE_VIDEOSTREAM, "Streaming Video"},
179 { LLDP_MED_APPTYPE_VIDEOSIGNAL, "Video Signaling"},
180 { 0, NULL },
181 };
182
183 static lldpctl_map_t port_med_policy_prio_map[] = {
184 { 0, "Background" },
185 { 1, "Spare" },
186 { 2, "Best effort" },
187 { 3, "Excellent effort" },
188 { 4, "Controlled load" },
189 { 5, "Video" },
190 { 6, "Voice" },
191 { 7, "Network control" },
192 { 0, NULL },
193 };
194
195 static lldpctl_map_t port_med_location_map[] = {
196 { LLDP_MED_LOCFORMAT_COORD, "Coordinates" },
197 { LLDP_MED_LOCFORMAT_CIVIC, "Civic address" },
198 { LLDP_MED_LOCFORMAT_ELIN, "ELIN" },
199 { 0, NULL },
200 };
201
202 static lldpctl_map_t civic_address_type_map[] = {
203 { 0, "Language" },
204 { 1, "Country subdivision" },
205 { 2, "County" },
206 { 3, "City" },
207 { 4, "City division" },
208 { 5, "Block" },
209 { 6, "Street" },
210 { 16, "Direction" },
211 { 17, "Trailing street suffix" },
212 { 18, "Street suffix" },
213 { 19, "Number" },
214 { 20, "Number suffix" },
215 { 21, "Landmark" },
216 { 22, "Additional" },
217 { 23, "Name" },
218 { 24, "ZIP" },
219 { 25, "Building" },
220 { 26, "Unit" },
221 { 27, "Floor" },
222 { 28, "Room" },
223 { 29, "Place type" },
224 { 128, "Script" },
225 { 0, NULL }
226 };
227
228 static lldpctl_map_t port_med_geoid_map[] = {
229 { LLDP_MED_LOCATION_GEOID_WGS84, "WGS84" },
230 { LLDP_MED_LOCATION_GEOID_NAD83, "NAD83" },
231 { LLDP_MED_LOCATION_GEOID_NAD83_MLLW, "NAD83/MLLW" },
232 { 0, NULL },
233 };
234
235 static lldpctl_map_t port_med_pow_devicetype_map[] = {
236 { LLDP_MED_POW_TYPE_PSE, "PSE" },
237 { LLDP_MED_POW_TYPE_PD, "PD" },
238 { 0, NULL },
239 };
240
241 static lldpctl_map_t port_med_pow_source_map[] = {
242 { LLDP_MED_POW_SOURCE_PRIMARY, "Primary Power Source" },
243 { LLDP_MED_POW_SOURCE_BACKUP, "Backup Power Source / Power Conservation Mode" },
244 { LLDP_MED_POW_SOURCE_PSE, "PSE" },
245 { LLDP_MED_POW_SOURCE_LOCAL, "Local"},
246 { LLDP_MED_POW_SOURCE_BOTH, "PSE + Local"},
247 { 0, NULL },
248 };
249
250 static lldpctl_map_t port_med_pow_source_map2[] = {
251 { 0, "unknown" },
252 { LLDP_MED_POW_SOURCE_PRIMARY, "primary" },
253 { LLDP_MED_POW_SOURCE_BACKUP, "backup" },
254 { LLDP_MED_POW_SOURCE_PSE, "pse" },
255 { LLDP_MED_POW_SOURCE_LOCAL, "local" },
256 { LLDP_MED_POW_SOURCE_BOTH, "both" },
257 { 0, NULL }
258 };
259
260 static lldpctl_map_t *port_med_pow_priority_map = port_dot3_power_priority_map;
261 #endif
262
263 static lldpctl_map_t bond_slave_src_mac_map[] = {
264 { LLDP_BOND_SLAVE_SRC_MAC_TYPE_REAL, "real"},
265 { LLDP_BOND_SLAVE_SRC_MAC_TYPE_ZERO, "zero"},
266 { LLDP_BOND_SLAVE_SRC_MAC_TYPE_FIXED, "fixed"},
267 { LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED, "local" },
268 { LLDP_BOND_SLAVE_SRC_MAC_TYPE_UNKNOWN, NULL},
269 };
270
271 static const char*
272 map_lookup(lldpctl_map_t *list, int n)
273 {
274
275 unsigned int i;
276
277 for (i = 0; list[i].string != NULL; i++) {
278 if (list[i].value == n) {
279 return list[i].string;
280 }
281 }
282
283 return "unknown";
284 }
285
286 #if defined ENABLE_LLDPMED || defined ENABLE_DOT3
287 static int
288 map_reverse_lookup(lldpctl_map_t *list, const char *string)
289 {
290 unsigned int i;
291
292 for (i = 0; list[i].string != NULL; i++) {
293 if (!strcasecmp(list[i].string, string))
294 return list[i].value;
295 }
296
297 return -1;
298 }
299 #endif
300
301 static lldpctl_map_t empty_map[] = {{ 0, NULL }};
302
303 lldpctl_map_t*
304 lldpctl_key_get_map(lldpctl_key_t key)
305 {
306 switch (key) {
307 #ifdef ENABLE_LLDPMED
308 case lldpctl_k_med_location_geoid:
309 return port_med_geoid_map;
310 case lldpctl_k_med_civicaddress_type:
311 return civic_address_type_map;
312 case lldpctl_k_med_policy_type:
313 return port_med_policy_map;
314 case lldpctl_k_med_policy_priority:
315 return port_med_policy_prio_map;
316 case lldpctl_k_med_power_priority:
317 return port_med_pow_priority_map;
318 #endif
319 #ifdef ENABLE_DOT3
320 case lldpctl_k_dot3_power_pairs:
321 return port_dot3_power_pairs_map;
322 case lldpctl_k_dot3_power_class:
323 return port_dot3_power_class_map;
324 case lldpctl_k_dot3_power_priority:
325 return port_dot3_power_priority_map;
326 #endif
327 case lldpctl_k_config_bond_slave_src_mac_type:
328 return bond_slave_src_mac_map;
329 default: return empty_map;
330 }
331 }
332
333 /* Atom methods */
334
335 static int
336 _lldpctl_atom_new_config(lldpctl_atom_t *atom, va_list ap)
337 {
338 struct _lldpctl_atom_config_t *c =
339 (struct _lldpctl_atom_config_t *)atom;
340 c->config = va_arg(ap, struct lldpd_config *);
341 return 1;
342 }
343
344 static void
345 _lldpctl_atom_free_config(lldpctl_atom_t *atom)
346 {
347 struct _lldpctl_atom_config_t *c =
348 (struct _lldpctl_atom_config_t *)atom;
349 lldpd_config_cleanup(c->config);
350 free(c->config);
351 }
352
353 static const char*
354 _lldpctl_atom_get_str_config(lldpctl_atom_t *atom, lldpctl_key_t key)
355 {
356 char *res = NULL;
357 struct _lldpctl_atom_config_t *c =
358 (struct _lldpctl_atom_config_t *)atom;
359 switch (key) {
360 case lldpctl_k_config_mgmt_pattern:
361 res = c->config->c_mgmt_pattern; break;
362 case lldpctl_k_config_iface_pattern:
363 res = c->config->c_iface_pattern; break;
364 case lldpctl_k_config_cid_pattern:
365 res = c->config->c_cid_pattern; break;
366 case lldpctl_k_config_description:
367 res = c->config->c_description; break;
368 case lldpctl_k_config_platform:
369 res = c->config->c_platform; break;
370 case lldpctl_k_config_bond_slave_src_mac_type:
371 return map_lookup(bond_slave_src_mac_map,
372 c->config->c_bond_slave_src_mac_type);
373 default:
374 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
375 return NULL;
376 }
377 return res?res:"";
378 }
379
380 static lldpctl_atom_t*
381 _lldpctl_atom_set_str_config(lldpctl_atom_t *atom, lldpctl_key_t key,
382 const char *value)
383 {
384 struct _lldpctl_atom_config_t *c =
385 (struct _lldpctl_atom_config_t *)atom;
386 struct lldpd_config config = {};
387 char *iface_pattern = NULL;
388 char *description = NULL;
389 int rc, len;
390
391 len = strlen(value) + 1;
392
393 switch (key) {
394 case lldpctl_k_config_iface_pattern:
395 iface_pattern = _lldpctl_alloc_in_atom(atom, strlen(value) + 1);
396 if (!iface_pattern)
397 return NULL;
398 memcpy(iface_pattern, value, len);
399 config.c_iface_pattern = iface_pattern;
400 free(c->config->c_iface_pattern);
401 c->config->c_iface_pattern = strdup(iface_pattern);
402 break;
403 case lldpctl_k_config_description:
404 description = _lldpctl_alloc_in_atom(atom, strlen(value) + 1);
405 if (!description)
406 return NULL;
407 memcpy(description, value, len);
408 config.c_description = description;
409 free(c->config->c_description);
410 c->config->c_description = strdup(description);
411 break;
412 case lldpctl_k_config_platform:
413 description = _lldpctl_alloc_in_atom(atom, strlen(value) + 1);
414 if (!description)
415 return NULL;
416 memcpy(description, value, len);
417 config.c_platform = description;
418 free(c->config->c_platform);
419 c->config->c_description = strdup(description);
420 break;
421 default:
422 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
423 return NULL;
424 }
425
426 rc = _lldpctl_do_something(atom->conn,
427 CONN_STATE_SET_CONFIG_SEND, CONN_STATE_SET_CONFIG_RECV,
428 NULL,
429 SET_CONFIG, &config, &MARSHAL_INFO(lldpd_config),
430 NULL, NULL);
431 if (rc == 0) return atom;
432
433 return NULL;
434 }
435
436 static long int
437 _lldpctl_atom_get_int_config(lldpctl_atom_t *atom, lldpctl_key_t key)
438 {
439 struct _lldpctl_atom_config_t *c =
440 (struct _lldpctl_atom_config_t *)atom;
441 switch (key) {
442 case lldpctl_k_config_paused:
443 return c->config->c_paused;
444 case lldpctl_k_config_tx_interval:
445 return c->config->c_tx_interval;
446 case lldpctl_k_config_receiveonly:
447 return c->config->c_receiveonly;
448 case lldpctl_k_config_advertise_version:
449 return c->config->c_advertise_version;
450 case lldpctl_k_config_ifdescr_update:
451 return c->config->c_set_ifdescr;
452 #ifdef ENABLE_LLDPMED
453 case lldpctl_k_config_lldpmed_noinventory:
454 return c->config->c_noinventory;
455 case lldpctl_k_config_fast_start_enabled:
456 return c->config->c_enable_fast_start;
457 case lldpctl_k_config_fast_start_interval:
458 return c->config->c_tx_fast_interval;
459 #endif
460 case lldpctl_k_config_tx_hold:
461 return c->config->c_tx_hold;
462 default:
463 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
464 }
465 }
466
467 static lldpctl_atom_t*
468 _lldpctl_atom_set_int_config(lldpctl_atom_t *atom, lldpctl_key_t key,
469 long int value)
470 {
471 int rc;
472 struct _lldpctl_atom_config_t *c =
473 (struct _lldpctl_atom_config_t *)atom;
474 struct lldpd_config config = {};
475
476 switch (key) {
477 case lldpctl_k_config_paused:
478 config.c_paused = c->config->c_paused = value;
479 break;
480 case lldpctl_k_config_tx_interval:
481 config.c_tx_interval = value;
482 if (value > 0) c->config->c_tx_interval = value;
483 break;
484 case lldpctl_k_config_ifdescr_update:
485 config.c_set_ifdescr = c->config->c_set_ifdescr = value;
486 break;
487 #ifdef ENABLE_LLDPMED
488 case lldpctl_k_config_fast_start_enabled:
489 config.c_enable_fast_start = value?1:2;
490 c->config->c_enable_fast_start = value;
491 break;
492 case lldpctl_k_config_fast_start_interval:
493 config.c_tx_fast_interval = c->config->c_tx_fast_interval = value;
494 break;
495 #endif
496 case lldpctl_k_config_tx_hold:
497 config.c_tx_hold = value;
498 if (value > 0) c->config->c_tx_hold = value;
499 break;
500 case lldpctl_k_config_bond_slave_src_mac_type:
501 config.c_bond_slave_src_mac_type = value;
502 c->config->c_bond_slave_src_mac_type = value;
503 break;
504 default:
505 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
506 return NULL;
507 }
508
509 rc = _lldpctl_do_something(atom->conn,
510 CONN_STATE_SET_CONFIG_SEND, CONN_STATE_SET_CONFIG_RECV,
511 NULL,
512 SET_CONFIG, &config, &MARSHAL_INFO(lldpd_config),
513 NULL, NULL);
514 if (rc == 0) return atom;
515 return NULL;
516 return atom;
517 }
518
519 static int
520 _lldpctl_atom_new_interfaces_list(lldpctl_atom_t *atom, va_list ap)
521 {
522 struct _lldpctl_atom_interfaces_list_t *iflist =
523 (struct _lldpctl_atom_interfaces_list_t *)atom;
524 iflist->ifs = va_arg(ap, struct lldpd_interface_list *);
525 return 1;
526 }
527
528 static void
529 _lldpctl_atom_free_interfaces_list(lldpctl_atom_t *atom)
530 {
531 struct _lldpctl_atom_interfaces_list_t *iflist =
532 (struct _lldpctl_atom_interfaces_list_t *)atom;
533 struct lldpd_interface *iface, *iface_next;
534 for (iface = TAILQ_FIRST(iflist->ifs);
535 iface != NULL;
536 iface = iface_next) {
537 /* Don't TAILQ_REMOVE, this is not a real list! */
538 iface_next = TAILQ_NEXT(iface, next);
539 free(iface->name);
540 free(iface);
541 }
542 free(iflist->ifs);
543 }
544
545 static lldpctl_atom_iter_t*
546 _lldpctl_atom_iter_interfaces_list(lldpctl_atom_t *atom)
547 {
548 struct _lldpctl_atom_interfaces_list_t *iflist =
549 (struct _lldpctl_atom_interfaces_list_t *)atom;
550 return (lldpctl_atom_iter_t*)TAILQ_FIRST(iflist->ifs);
551 }
552
553 static lldpctl_atom_iter_t*
554 _lldpctl_atom_next_interfaces_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
555 {
556 return (lldpctl_atom_iter_t*)TAILQ_NEXT((struct lldpd_interface *)iter, next);
557 }
558
559 static lldpctl_atom_t*
560 _lldpctl_atom_value_interfaces_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
561 {
562 struct lldpd_interface *iface = (struct lldpd_interface *)iter;
563 return _lldpctl_new_atom(atom->conn, atom_interface, iface->name);
564 }
565
566 static int
567 _lldpctl_atom_new_interface(lldpctl_atom_t *atom, va_list ap)
568 {
569 struct _lldpctl_atom_interface_t *port =
570 (struct _lldpctl_atom_interface_t *)atom;
571 port->name = strdup(va_arg(ap, char *));
572 return (port->name != NULL);
573 }
574
575 static void
576 _lldpctl_atom_free_interface(lldpctl_atom_t *atom)
577 {
578 struct _lldpctl_atom_interface_t *port =
579 (struct _lldpctl_atom_interface_t *)atom;
580 free(port->name);
581 }
582
583 static const char*
584 _lldpctl_atom_get_str_interface(lldpctl_atom_t *atom, lldpctl_key_t key)
585 {
586 struct _lldpctl_atom_interface_t *port =
587 (struct _lldpctl_atom_interface_t *)atom;
588 switch (key) {
589 case lldpctl_k_interface_name:
590 return port->name;
591 default:
592 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
593 return NULL;
594 }
595 }
596
597 static int
598 _lldpctl_atom_new_any_list(lldpctl_atom_t *atom, va_list ap)
599 {
600 struct _lldpctl_atom_any_list_t *plist =
601 (struct _lldpctl_atom_any_list_t *)atom;
602 plist->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
603 lldpctl_atom_inc_ref((lldpctl_atom_t *)plist->parent);
604 return 1;
605 }
606
607 static void
608 _lldpctl_atom_free_any_list(lldpctl_atom_t *atom)
609 {
610 struct _lldpctl_atom_any_list_t *plist =
611 (struct _lldpctl_atom_any_list_t *)atom;
612 lldpctl_atom_dec_ref((lldpctl_atom_t *)plist->parent);
613 }
614
615 static lldpctl_atom_iter_t*
616 _lldpctl_atom_iter_ports_list(lldpctl_atom_t *atom)
617 {
618 struct _lldpctl_atom_any_list_t *plist =
619 (struct _lldpctl_atom_any_list_t *)atom;
620 return (lldpctl_atom_iter_t*)TAILQ_FIRST(&plist->parent->hardware->h_rports);
621 }
622
623 static lldpctl_atom_iter_t*
624 _lldpctl_atom_next_ports_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
625 {
626 struct lldpd_port *port = (struct lldpd_port *)iter;
627 return (lldpctl_atom_iter_t*)TAILQ_NEXT(port, p_entries);
628 }
629
630 static lldpctl_atom_t*
631 _lldpctl_atom_value_ports_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
632 {
633 struct lldpd_port *port = (struct lldpd_port *)iter;
634 return _lldpctl_new_atom(atom->conn, atom_port, NULL, port,
635 ((struct _lldpctl_atom_any_list_t *)atom)->parent);
636 }
637
638 static int
639 _lldpctl_atom_new_port(lldpctl_atom_t *atom, va_list ap)
640 {
641 struct _lldpctl_atom_port_t *port =
642 (struct _lldpctl_atom_port_t *)atom;
643 port->hardware = va_arg(ap, struct lldpd_hardware*);
644 port->port = va_arg(ap, struct lldpd_port*);
645 port->parent = va_arg(ap, struct _lldpctl_atom_port_t*);
646 if (port->parent)
647 lldpctl_atom_inc_ref((lldpctl_atom_t*)port->parent);
648 return 1;
649 }
650
651 TAILQ_HEAD(chassis_list, lldpd_chassis);
652
653 static void
654 add_chassis(struct chassis_list *chassis_list,
655 struct lldpd_chassis *chassis)
656 {
657 struct lldpd_chassis *one_chassis;
658 TAILQ_FOREACH(one_chassis, chassis_list, c_entries) {
659 if (one_chassis == chassis) return;
660 }
661 TAILQ_INSERT_TAIL(chassis_list,
662 chassis, c_entries);
663 }
664
665 static void
666 _lldpctl_atom_free_port(lldpctl_atom_t *atom)
667 {
668 struct _lldpctl_atom_port_t *port =
669 (struct _lldpctl_atom_port_t *)atom;
670 struct lldpd_hardware *hardware = port->hardware;
671 struct lldpd_chassis *one_chassis, *one_chassis_next;
672 struct lldpd_port *one_port;
673
674 /* We need to free the whole struct lldpd_hardware: local port, local
675 * chassis and remote ports... The same chassis may be present several
676 * times. We build a list of chassis (we don't use reference count). */
677 struct chassis_list chassis_list;
678 TAILQ_INIT(&chassis_list);
679
680 if (port->parent) lldpctl_atom_dec_ref((lldpctl_atom_t*)port->parent);
681 else if (!hardware) {
682 /* No parent, no hardware, we assume a single neighbor: one
683 * port, one chassis. */
684 lldpd_chassis_cleanup(port->port->p_chassis, 1);
685 port->port->p_chassis = NULL;
686 lldpd_port_cleanup(port->port, 1);
687 free(port->port);
688 }
689 if (!hardware) return;
690
691 add_chassis(&chassis_list, port->port->p_chassis);
692 TAILQ_FOREACH(one_port, &hardware->h_rports, p_entries)
693 add_chassis(&chassis_list, one_port->p_chassis);
694
695 /* Free hardware port */
696 lldpd_remote_cleanup(hardware, NULL, 1);
697 lldpd_port_cleanup(port->port, 1);
698 free(port->hardware);
699
700 /* Free list of chassis */
701 for (one_chassis = TAILQ_FIRST(&chassis_list);
702 one_chassis != NULL;
703 one_chassis = one_chassis_next) {
704 one_chassis_next = TAILQ_NEXT(one_chassis, c_entries);
705 lldpd_chassis_cleanup(one_chassis, 1);
706 }
707 }
708
709 static lldpctl_atom_t*
710 _lldpctl_atom_get_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key)
711 {
712 struct _lldpctl_atom_port_t *p =
713 (struct _lldpctl_atom_port_t *)atom;
714 struct lldpd_port *port = p->port;
715 struct lldpd_hardware *hardware = p->hardware;
716
717 /* Local port only */
718 if (hardware != NULL) {
719 switch (key) {
720 case lldpctl_k_port_neighbors:
721 return _lldpctl_new_atom(atom->conn, atom_ports_list, p);
722 default: break;
723 }
724 }
725
726 /* Local and remote port */
727 switch (key) {
728 case lldpctl_k_chassis_mgmt:
729 return _lldpctl_new_atom(atom->conn, atom_mgmts_list,
730 p, port->p_chassis);
731 #ifdef ENABLE_DOT3
732 case lldpctl_k_port_dot3_power:
733 return _lldpctl_new_atom(atom->conn, atom_dot3_power,
734 p);
735 #endif
736 #ifdef ENABLE_DOT1
737 case lldpctl_k_port_vlans:
738 return _lldpctl_new_atom(atom->conn, atom_vlans_list,
739 p);
740 case lldpctl_k_port_ppvids:
741 return _lldpctl_new_atom(atom->conn, atom_ppvids_list,
742 p);
743 case lldpctl_k_port_pis:
744 return _lldpctl_new_atom(atom->conn, atom_pis_list,
745 p);
746 #endif
747 #ifdef ENABLE_LLDPMED
748 case lldpctl_k_port_med_policies:
749 return _lldpctl_new_atom(atom->conn, atom_med_policies_list,
750 p);
751 case lldpctl_k_port_med_locations:
752 return _lldpctl_new_atom(atom->conn, atom_med_locations_list,
753 p);
754 case lldpctl_k_port_med_power:
755 return _lldpctl_new_atom(atom->conn, atom_med_power, p);
756 #endif
757 default:
758 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
759 return NULL;
760 }
761 }
762
763 static lldpctl_atom_t*
764 _lldpctl_atom_set_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key, lldpctl_atom_t *value)
765 {
766 struct _lldpctl_atom_port_t *p =
767 (struct _lldpctl_atom_port_t *)atom;
768 struct lldpd_hardware *hardware = p->hardware;
769 struct lldpd_port_set set = {};
770 int rc;
771
772 #ifdef ENABLE_DOT3
773 struct _lldpctl_atom_dot3_power_t *dpow;
774 #endif
775 #ifdef ENABLE_LLDPMED
776 struct _lldpctl_atom_med_power_t *mpow;
777 struct _lldpctl_atom_med_policy_t *mpol;
778 struct _lldpctl_atom_med_location_t *mloc;
779 #endif
780
781 /* Local port only */
782 if (hardware == NULL) {
783 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
784 return NULL;
785 }
786
787 switch (key) {
788 #ifdef ENABLE_DOT3
789 case lldpctl_k_port_dot3_power:
790 if (value->type != atom_dot3_power) {
791 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
792 return NULL;
793 }
794
795 dpow = (struct _lldpctl_atom_dot3_power_t *)value;
796 set.dot3_power = &dpow->parent->port->p_power;
797 break;
798 #endif
799 #ifdef ENABLE_LLDPMED
800 case lldpctl_k_port_med_power:
801 if (value->type != atom_med_power) {
802 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
803 return NULL;
804 }
805
806 mpow = (struct _lldpctl_atom_med_power_t *)value;
807 set.med_power = &mpow->parent->port->p_med_power;
808 break;
809 case lldpctl_k_port_med_policies:
810 if (value->type != atom_med_policy) {
811 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
812 return NULL;
813 }
814 mpol = (struct _lldpctl_atom_med_policy_t *)value;
815 set.med_policy = mpol->policy;
816 break;
817 case lldpctl_k_port_med_locations:
818 if (value->type != atom_med_location) {
819 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
820 return NULL;
821 }
822 mloc = (struct _lldpctl_atom_med_location_t *)value;
823 set.med_location = mloc->location;
824 break;
825 #endif
826 default:
827 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
828 return NULL;
829 }
830
831 set.ifname = hardware->h_ifname;
832 rc = _lldpctl_do_something(atom->conn,
833 CONN_STATE_SET_PORT_SEND, CONN_STATE_SET_PORT_RECV,
834 value,
835 SET_PORT, &set, &MARSHAL_INFO(lldpd_port_set),
836 NULL, NULL);
837 if (rc == 0) return atom;
838 return NULL;
839 }
840
841 static const char*
842 _lldpctl_atom_get_str_port(lldpctl_atom_t *atom, lldpctl_key_t key)
843 {
844 struct _lldpctl_atom_port_t *p =
845 (struct _lldpctl_atom_port_t *)atom;
846 struct lldpd_port *port = p->port;
847 struct lldpd_hardware *hardware = p->hardware;
848 struct lldpd_chassis *chassis = port->p_chassis;
849 char *ipaddress = NULL; size_t len;
850
851 /* Local port only */
852 if (hardware != NULL) {
853 switch (key) {
854 case lldpctl_k_port_name:
855 return hardware->h_ifname;
856 default: break;
857 }
858 }
859
860 /* Local and remote port */
861 switch (key) {
862 case lldpctl_k_port_protocol:
863 return map_lookup(lldpd_protocol_map, port->p_protocol);
864 case lldpctl_k_port_id_subtype:
865 return map_lookup(port_id_subtype_map, port->p_id_subtype);
866 case lldpctl_k_port_id:
867 switch (port->p_id_subtype) {
868 case LLDP_PORTID_SUBTYPE_IFNAME:
869 case LLDP_PORTID_SUBTYPE_IFALIAS:
870 case LLDP_PORTID_SUBTYPE_LOCAL:
871 return port->p_id;
872 case LLDP_PORTID_SUBTYPE_LLADDR:
873 return _lldpctl_dump_in_atom(atom,
874 (uint8_t*)port->p_id, port->p_id_len,
875 ':', 0);
876 case LLDP_PORTID_SUBTYPE_ADDR:
877 switch (port->p_id[0]) {
878 case LLDP_MGMT_ADDR_IP4: len = INET_ADDRSTRLEN + 1; break;
879 case LLDP_MGMT_ADDR_IP6: len = INET6_ADDRSTRLEN + 1; break;
880 default: len = 0;
881 }
882 if (len > 0) {
883 ipaddress = _lldpctl_alloc_in_atom(atom, len);
884 if (!ipaddress) return NULL;
885 if (inet_ntop((port->p_id[0] == LLDP_MGMT_ADDR_IP4)?
886 AF_INET:AF_INET6,
887 &port->p_id[1], ipaddress, len) == NULL)
888 break;
889 return ipaddress;
890 }
891 break;
892 }
893 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
894 return NULL;
895 case lldpctl_k_port_descr:
896 return port->p_descr;
897
898 #ifdef ENABLE_DOT3
899 case lldpctl_k_port_dot3_mautype:
900 return map_lookup(operational_mau_type_values,
901 port->p_macphy.mau_type);
902 #endif
903
904 case lldpctl_k_chassis_id_subtype:
905 return map_lookup(chassis_id_subtype_map, chassis->c_id_subtype);
906 case lldpctl_k_chassis_id:
907 switch (chassis->c_id_subtype) {
908 case LLDP_CHASSISID_SUBTYPE_IFNAME:
909 case LLDP_CHASSISID_SUBTYPE_IFALIAS:
910 case LLDP_CHASSISID_SUBTYPE_LOCAL:
911 return chassis->c_id;
912 case LLDP_CHASSISID_SUBTYPE_LLADDR:
913 return _lldpctl_dump_in_atom(atom,
914 (uint8_t*)chassis->c_id, chassis->c_id_len,
915 ':', 0);
916 case LLDP_CHASSISID_SUBTYPE_ADDR:
917 switch (chassis->c_id[0]) {
918 case LLDP_MGMT_ADDR_IP4: len = INET_ADDRSTRLEN + 1; break;
919 case LLDP_MGMT_ADDR_IP6: len = INET6_ADDRSTRLEN + 1; break;
920 default: len = 0;
921 }
922 if (len > 0) {
923 ipaddress = _lldpctl_alloc_in_atom(atom, len);
924 if (!ipaddress) return NULL;
925 if (inet_ntop((chassis->c_id[0] == LLDP_MGMT_ADDR_IP4)?
926 AF_INET:AF_INET6,
927 &chassis->c_id[1], ipaddress, len) == NULL)
928 break;
929 return ipaddress;
930 }
931 break;
932 }
933 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
934 return NULL;
935 case lldpctl_k_chassis_name: return chassis->c_name;
936 case lldpctl_k_chassis_descr: return chassis->c_descr;
937
938 #ifdef ENABLE_LLDPMED
939 case lldpctl_k_chassis_med_type:
940 return map_lookup(chassis_med_type_map, chassis->c_med_type);
941 case lldpctl_k_chassis_med_inventory_hw:
942 return chassis->c_med_hw;
943 case lldpctl_k_chassis_med_inventory_sw:
944 return chassis->c_med_sw;
945 case lldpctl_k_chassis_med_inventory_fw:
946 return chassis->c_med_fw;
947 case lldpctl_k_chassis_med_inventory_sn:
948 return chassis->c_med_sn;
949 case lldpctl_k_chassis_med_inventory_manuf:
950 return chassis->c_med_manuf;
951 case lldpctl_k_chassis_med_inventory_model:
952 return chassis->c_med_model;
953 case lldpctl_k_chassis_med_inventory_asset:
954 return chassis->c_med_asset;
955 #endif
956
957 default:
958 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
959 return NULL;
960 }
961 }
962
963 static long int
964 _lldpctl_atom_get_int_port(lldpctl_atom_t *atom, lldpctl_key_t key)
965 {
966 struct _lldpctl_atom_port_t *p =
967 (struct _lldpctl_atom_port_t *)atom;
968 struct lldpd_port *port = p->port;
969 struct lldpd_hardware *hardware = p->hardware;
970 struct lldpd_chassis *chassis = port->p_chassis;
971
972 /* Local port only */
973 if (hardware != NULL) {
974 switch (key) {
975 case lldpctl_k_port_index:
976 return hardware->h_ifindex;
977 case lldpctl_k_tx_cnt:
978 return hardware->h_tx_cnt;
979 case lldpctl_k_rx_cnt:
980 return hardware->h_rx_cnt;
981 case lldpctl_k_rx_discarded_cnt:
982 return hardware->h_rx_discarded_cnt;
983 case lldpctl_k_rx_unrecognized_cnt:
984 return hardware->h_rx_unrecognized_cnt;
985 case lldpctl_k_ageout_cnt:
986 return hardware->h_ageout_cnt;
987 case lldpctl_k_insert_cnt:
988 return hardware->h_insert_cnt;
989 case lldpctl_k_delete_cnt:
990 return hardware->h_delete_cnt;
991 default: break;
992 }
993 }
994
995 /* Local and remote port */
996 switch (key) {
997 case lldpctl_k_port_protocol:
998 return port->p_protocol;
999 case lldpctl_k_port_age:
1000 return port->p_lastchange;
1001 case lldpctl_k_port_id_subtype:
1002 return port->p_id_subtype;
1003 case lldpctl_k_port_hidden:
1004 return port->p_hidden_in;
1005 #ifdef ENABLE_DOT3
1006 case lldpctl_k_port_dot3_mfs:
1007 if (port->p_mfs > 0)
1008 return port->p_mfs;
1009 break;
1010 case lldpctl_k_port_dot3_aggregid:
1011 if (port->p_aggregid > 0)
1012 return port->p_aggregid;
1013 break;
1014 case lldpctl_k_port_dot3_autoneg_support:
1015 return port->p_macphy.autoneg_support;
1016 case lldpctl_k_port_dot3_autoneg_enabled:
1017 return port->p_macphy.autoneg_enabled;
1018 case lldpctl_k_port_dot3_autoneg_advertised:
1019 return port->p_macphy.autoneg_advertised;
1020 case lldpctl_k_port_dot3_mautype:
1021 return port->p_macphy.mau_type;
1022 #endif
1023 #ifdef ENABLE_DOT1
1024 case lldpctl_k_port_vlan_pvid:
1025 return port->p_pvid;
1026 #endif
1027 case lldpctl_k_chassis_index:
1028 return chassis->c_index;
1029 case lldpctl_k_chassis_id_subtype:
1030 return chassis->c_id_subtype;
1031 case lldpctl_k_chassis_cap_available:
1032 return chassis->c_cap_available;
1033 case lldpctl_k_chassis_cap_enabled:
1034 return chassis->c_cap_enabled;
1035 #ifdef ENABLE_LLDPMED
1036 case lldpctl_k_chassis_med_type:
1037 return chassis->c_med_type;
1038 case lldpctl_k_chassis_med_cap:
1039 return chassis->c_med_cap_available;
1040 #endif
1041 default:
1042 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1043 }
1044 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1045 }
1046
1047 static const uint8_t*
1048 _lldpctl_atom_get_buf_port(lldpctl_atom_t *atom, lldpctl_key_t key, size_t *n)
1049 {
1050 struct _lldpctl_atom_port_t *p =
1051 (struct _lldpctl_atom_port_t *)atom;
1052 struct lldpd_port *port = p->port;
1053 struct lldpd_chassis *chassis = port->p_chassis;
1054
1055 switch (key) {
1056 case lldpctl_k_port_id:
1057 *n = port->p_id_len;
1058 return (uint8_t*)port->p_id;
1059 case lldpctl_k_chassis_id:
1060 *n = chassis->c_id_len;
1061 return (uint8_t*)chassis->c_id;
1062 default:
1063 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1064 return NULL;
1065 }
1066 }
1067
1068 static int
1069 _lldpctl_atom_new_mgmts_list(lldpctl_atom_t *atom, va_list ap)
1070 {
1071 struct _lldpctl_atom_mgmts_list_t *plist =
1072 (struct _lldpctl_atom_mgmts_list_t *)atom;
1073 plist->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
1074 plist->chassis = va_arg(ap, struct lldpd_chassis *);
1075 lldpctl_atom_inc_ref((lldpctl_atom_t *)plist->parent);
1076 return 1;
1077 }
1078
1079 static void
1080 _lldpctl_atom_free_mgmts_list(lldpctl_atom_t *atom)
1081 {
1082 struct _lldpctl_atom_mgmts_list_t *plist =
1083 (struct _lldpctl_atom_mgmts_list_t *)atom;
1084 lldpctl_atom_dec_ref((lldpctl_atom_t *)plist->parent);
1085 }
1086
1087 static lldpctl_atom_iter_t*
1088 _lldpctl_atom_iter_mgmts_list(lldpctl_atom_t *atom)
1089 {
1090 struct _lldpctl_atom_mgmts_list_t *plist =
1091 (struct _lldpctl_atom_mgmts_list_t *)atom;
1092 return (lldpctl_atom_iter_t*)TAILQ_FIRST(&plist->chassis->c_mgmt);
1093 }
1094
1095 static lldpctl_atom_iter_t*
1096 _lldpctl_atom_next_mgmts_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
1097 {
1098 struct lldpd_mgmt *mgmt = (struct lldpd_mgmt *)iter;
1099 return (lldpctl_atom_iter_t*)TAILQ_NEXT(mgmt, m_entries);
1100 }
1101
1102 static lldpctl_atom_t*
1103 _lldpctl_atom_value_mgmts_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
1104 {
1105 struct _lldpctl_atom_mgmts_list_t *plist =
1106 (struct _lldpctl_atom_mgmts_list_t *)atom;
1107 struct lldpd_mgmt *mgmt = (struct lldpd_mgmt *)iter;
1108 return _lldpctl_new_atom(atom->conn, atom_mgmt, plist->parent, mgmt);
1109 }
1110
1111 static int
1112 _lldpctl_atom_new_mgmt(lldpctl_atom_t *atom, va_list ap)
1113 {
1114 struct _lldpctl_atom_mgmt_t *mgmt =
1115 (struct _lldpctl_atom_mgmt_t *)atom;
1116 mgmt->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
1117 mgmt->mgmt = va_arg(ap, struct lldpd_mgmt *);
1118 lldpctl_atom_inc_ref((lldpctl_atom_t *)mgmt->parent);
1119 return 1;
1120 }
1121
1122 static void
1123 _lldpctl_atom_free_mgmt(lldpctl_atom_t *atom)
1124 {
1125 struct _lldpctl_atom_mgmt_t *mgmt =
1126 (struct _lldpctl_atom_mgmt_t *)atom;
1127 lldpctl_atom_dec_ref((lldpctl_atom_t *)mgmt->parent);
1128 }
1129
1130 static const char*
1131 _lldpctl_atom_get_str_mgmt(lldpctl_atom_t *atom, lldpctl_key_t key)
1132 {
1133 char *ipaddress = NULL;
1134 size_t len; int af;
1135 struct _lldpctl_atom_mgmt_t *m =
1136 (struct _lldpctl_atom_mgmt_t *)atom;
1137
1138 /* Local and remote port */
1139 switch (key) {
1140 case lldpctl_k_mgmt_ip:
1141 switch (m->mgmt->m_family) {
1142 case LLDPD_AF_IPV4:
1143 len = INET_ADDRSTRLEN + 1;
1144 af = AF_INET;
1145 break;
1146 case LLDPD_AF_IPV6:
1147 len = INET6_ADDRSTRLEN + 1;
1148 af = AF_INET6;
1149 break;
1150 default:
1151 len = 0;
1152 }
1153 if (len == 0) break;
1154 ipaddress = _lldpctl_alloc_in_atom(atom, len);
1155 if (!ipaddress) return NULL;
1156 if (inet_ntop(af, &m->mgmt->m_addr, ipaddress, len) == NULL)
1157 break;
1158 return ipaddress;
1159 default:
1160 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1161 return NULL;
1162 }
1163 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1164 return NULL;
1165 }
1166
1167 #ifdef ENABLE_DOT3
1168 static int
1169 _lldpctl_atom_new_dot3_power(lldpctl_atom_t *atom, va_list ap)
1170 {
1171 struct _lldpctl_atom_dot3_power_t *dpow =
1172 (struct _lldpctl_atom_dot3_power_t *)atom;
1173 dpow->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
1174 lldpctl_atom_inc_ref((lldpctl_atom_t *)dpow->parent);
1175 return 1;
1176 }
1177
1178 static void
1179 _lldpctl_atom_free_dot3_power(lldpctl_atom_t *atom)
1180 {
1181 struct _lldpctl_atom_dot3_power_t *dpow =
1182 (struct _lldpctl_atom_dot3_power_t *)atom;
1183 lldpctl_atom_dec_ref((lldpctl_atom_t *)dpow->parent);
1184 }
1185
1186 static const char*
1187 _lldpctl_atom_get_str_dot3_power(lldpctl_atom_t *atom, lldpctl_key_t key)
1188 {
1189 struct _lldpctl_atom_dot3_power_t *dpow =
1190 (struct _lldpctl_atom_dot3_power_t *)atom;
1191 struct lldpd_port *port = dpow->parent->port;
1192
1193 /* Local and remote port */
1194 switch (key) {
1195 case lldpctl_k_dot3_power_devicetype:
1196 return map_lookup(port_dot3_power_devicetype_map,
1197 port->p_power.devicetype);
1198 case lldpctl_k_dot3_power_pairs:
1199 return map_lookup(port_dot3_power_pairs_map,
1200 port->p_power.pairs);
1201 case lldpctl_k_dot3_power_class:
1202 return map_lookup(port_dot3_power_class_map,
1203 port->p_power.class);
1204 case lldpctl_k_dot3_power_source:
1205 return map_lookup((port->p_power.devicetype == LLDP_DOT3_POWER_PSE)?
1206 port_dot3_power_pse_source_map:
1207 port_dot3_power_pd_source_map,
1208 port->p_power.source);
1209 case lldpctl_k_dot3_power_priority:
1210 return map_lookup(port_dot3_power_priority_map,
1211 port->p_power.priority);
1212 default:
1213 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1214 return NULL;
1215 }
1216 }
1217
1218 static long int
1219 _lldpctl_atom_get_int_dot3_power(lldpctl_atom_t *atom, lldpctl_key_t key)
1220 {
1221 struct _lldpctl_atom_dot3_power_t *dpow =
1222 (struct _lldpctl_atom_dot3_power_t *)atom;
1223 struct lldpd_port *port = dpow->parent->port;
1224
1225 /* Local and remote port */
1226 switch (key) {
1227 case lldpctl_k_dot3_power_devicetype:
1228 return port->p_power.devicetype;
1229 case lldpctl_k_dot3_power_supported:
1230 return port->p_power.supported;
1231 case lldpctl_k_dot3_power_enabled:
1232 return port->p_power.enabled;
1233 case lldpctl_k_dot3_power_paircontrol:
1234 return port->p_power.paircontrol;
1235 case lldpctl_k_dot3_power_pairs:
1236 return port->p_power.pairs;
1237 case lldpctl_k_dot3_power_class:
1238 return port->p_power.class;
1239 case lldpctl_k_dot3_power_type:
1240 return port->p_power.powertype;
1241 case lldpctl_k_dot3_power_source:
1242 return port->p_power.source;
1243 case lldpctl_k_dot3_power_priority:
1244 return port->p_power.priority;
1245 case lldpctl_k_dot3_power_requested:
1246 return port->p_power.requested * 100;
1247 case lldpctl_k_dot3_power_allocated:
1248 return port->p_power.allocated * 100;
1249 default:
1250 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1251 }
1252 }
1253
1254 static lldpctl_atom_t*
1255 _lldpctl_atom_set_int_dot3_power(lldpctl_atom_t *atom, lldpctl_key_t key,
1256 long int value)
1257 {
1258 struct _lldpctl_atom_dot3_power_t *dpow =
1259 (struct _lldpctl_atom_dot3_power_t *)atom;
1260 struct lldpd_port *port = dpow->parent->port;
1261
1262 /* Only local port can be modified */
1263 if (dpow->parent->hardware == NULL) {
1264 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1265 return NULL;
1266 }
1267
1268 switch (key) {
1269 case lldpctl_k_dot3_power_devicetype:
1270 switch (value) {
1271 case 0: /* Disabling */
1272 case LLDP_DOT3_POWER_PSE:
1273 case LLDP_DOT3_POWER_PD:
1274 port->p_power.devicetype = value;
1275 return atom;
1276 default: goto bad;
1277 }
1278 case lldpctl_k_dot3_power_supported:
1279 switch (value) {
1280 case 0:
1281 case 1:
1282 port->p_power.supported = value;
1283 return atom;
1284 default: goto bad;
1285 }
1286 case lldpctl_k_dot3_power_enabled:
1287 switch (value) {
1288 case 0:
1289 case 1:
1290 port->p_power.enabled = value;
1291 return atom;
1292 default: goto bad;
1293 }
1294 case lldpctl_k_dot3_power_paircontrol:
1295 switch (value) {
1296 case 0:
1297 case 1:
1298 port->p_power.paircontrol = value;
1299 return atom;
1300 default: goto bad;
1301 }
1302 case lldpctl_k_dot3_power_pairs:
1303 switch (value) {
1304 case 1:
1305 case 2:
1306 port->p_power.pairs = value;
1307 return atom;
1308 default: goto bad;
1309 }
1310 case lldpctl_k_dot3_power_class:
1311 if (value < 0 || value > 5)
1312 goto bad;
1313 port->p_power.class = value;
1314 return atom;
1315 case lldpctl_k_dot3_power_type:
1316 switch (value) {
1317 case LLDP_DOT3_POWER_8023AT_TYPE1:
1318 case LLDP_DOT3_POWER_8023AT_TYPE2:
1319 case LLDP_DOT3_POWER_8023AT_OFF:
1320 port->p_power.powertype = value;
1321 return atom;
1322 default: goto bad;
1323 }
1324 case lldpctl_k_dot3_power_source:
1325 if (value < 0 || value > 3)
1326 goto bad;
1327 port->p_power.source = value;
1328 return atom;
1329 case lldpctl_k_dot3_power_priority:
1330 switch (value) {
1331 case LLDP_DOT3_POWER_PRIO_UNKNOWN:
1332 case LLDP_DOT3_POWER_PRIO_CRITICAL:
1333 case LLDP_DOT3_POWER_PRIO_HIGH:
1334 case LLDP_DOT3_POWER_PRIO_LOW:
1335 port->p_power.priority = value;
1336 return atom;
1337 default: goto bad;
1338 }
1339 case lldpctl_k_dot3_power_allocated:
1340 if (value < 0) goto bad;
1341 port->p_power.allocated = value / 100;
1342 return atom;
1343 case lldpctl_k_dot3_power_requested:
1344 if (value < 0) goto bad;
1345 port->p_power.requested = value / 100;
1346 return atom;
1347 default:
1348 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1349 return NULL;
1350 }
1351
1352 return atom;
1353 bad:
1354 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
1355 return NULL;
1356 }
1357
1358 static lldpctl_atom_t*
1359 _lldpctl_atom_set_str_dot3_power(lldpctl_atom_t *atom, lldpctl_key_t key,
1360 const char *value)
1361 {
1362 switch (key) {
1363 case lldpctl_k_dot3_power_devicetype:
1364 return _lldpctl_atom_set_int_dot3_power(atom, key,
1365 map_reverse_lookup(port_dot3_power_devicetype_map, value));
1366 case lldpctl_k_dot3_power_pairs:
1367 return _lldpctl_atom_set_int_dot3_power(atom, key,
1368 map_reverse_lookup(port_dot3_power_pairs_map, value));
1369 case lldpctl_k_dot3_power_class:
1370 return _lldpctl_atom_set_int_dot3_power(atom, key,
1371 map_reverse_lookup(port_dot3_power_class_map, value));
1372 case lldpctl_k_dot3_power_priority:
1373 return _lldpctl_atom_set_int_dot3_power(atom, key,
1374 map_reverse_lookup(port_dot3_power_priority_map, value));
1375 default:
1376 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1377 return NULL;
1378 }
1379 }
1380 #endif
1381
1382 #ifdef ENABLE_DOT1
1383 static lldpctl_atom_iter_t*
1384 _lldpctl_atom_iter_vlans_list(lldpctl_atom_t *atom)
1385 {
1386 struct _lldpctl_atom_any_list_t *vlist =
1387 (struct _lldpctl_atom_any_list_t *)atom;
1388 return (lldpctl_atom_iter_t*)TAILQ_FIRST(&vlist->parent->port->p_vlans);
1389 }
1390
1391 static lldpctl_atom_iter_t*
1392 _lldpctl_atom_next_vlans_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
1393 {
1394 struct lldpd_vlan *vlan = (struct lldpd_vlan *)iter;
1395 return (lldpctl_atom_iter_t*)TAILQ_NEXT(vlan, v_entries);
1396 }
1397
1398 static lldpctl_atom_t*
1399 _lldpctl_atom_value_vlans_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
1400 {
1401 struct _lldpctl_atom_any_list_t *vlist =
1402 (struct _lldpctl_atom_any_list_t *)atom;
1403 struct lldpd_vlan *vlan = (struct lldpd_vlan *)iter;
1404 return _lldpctl_new_atom(atom->conn, atom_vlan, vlist->parent, vlan);
1405 }
1406
1407 static int
1408 _lldpctl_atom_new_vlan(lldpctl_atom_t *atom, va_list ap)
1409 {
1410 struct _lldpctl_atom_vlan_t *vlan =
1411 (struct _lldpctl_atom_vlan_t *)atom;
1412 vlan->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
1413 vlan->vlan = va_arg(ap, struct lldpd_vlan *);
1414 lldpctl_atom_inc_ref((lldpctl_atom_t *)vlan->parent);
1415 return 1;
1416 }
1417
1418 static void
1419 _lldpctl_atom_free_vlan(lldpctl_atom_t *atom)
1420 {
1421 struct _lldpctl_atom_vlan_t *vlan =
1422 (struct _lldpctl_atom_vlan_t *)atom;
1423 lldpctl_atom_dec_ref((lldpctl_atom_t *)vlan->parent);
1424 }
1425
1426 static const char*
1427 _lldpctl_atom_get_str_vlan(lldpctl_atom_t *atom, lldpctl_key_t key)
1428 {
1429 struct _lldpctl_atom_vlan_t *m =
1430 (struct _lldpctl_atom_vlan_t *)atom;
1431
1432 /* Local and remote port */
1433 switch (key) {
1434 case lldpctl_k_vlan_name:
1435 return m->vlan->v_name;
1436 default:
1437 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1438 return NULL;
1439 }
1440 }
1441
1442 static long int
1443 _lldpctl_atom_get_int_vlan(lldpctl_atom_t *atom, lldpctl_key_t key)
1444 {
1445 struct _lldpctl_atom_vlan_t *m =
1446 (struct _lldpctl_atom_vlan_t *)atom;
1447
1448 /* Local and remote port */
1449 switch (key) {
1450 case lldpctl_k_vlan_id:
1451 return m->vlan->v_vid;
1452 default:
1453 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1454 }
1455 }
1456
1457 static lldpctl_atom_iter_t*
1458 _lldpctl_atom_iter_ppvids_list(lldpctl_atom_t *atom)
1459 {
1460 struct _lldpctl_atom_any_list_t *vlist =
1461 (struct _lldpctl_atom_any_list_t *)atom;
1462 return (lldpctl_atom_iter_t*)TAILQ_FIRST(&vlist->parent->port->p_ppvids);
1463 }
1464
1465 static lldpctl_atom_iter_t*
1466 _lldpctl_atom_next_ppvids_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
1467 {
1468 struct lldpd_ppvid *ppvid = (struct lldpd_ppvid *)iter;
1469 return (lldpctl_atom_iter_t*)TAILQ_NEXT(ppvid, p_entries);
1470 }
1471
1472 static lldpctl_atom_t*
1473 _lldpctl_atom_value_ppvids_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
1474 {
1475 struct _lldpctl_atom_any_list_t *vlist =
1476 (struct _lldpctl_atom_any_list_t *)atom;
1477 struct lldpd_ppvid *ppvid = (struct lldpd_ppvid *)iter;
1478 return _lldpctl_new_atom(atom->conn, atom_ppvid, vlist->parent, ppvid);
1479 }
1480
1481 static int
1482 _lldpctl_atom_new_ppvid(lldpctl_atom_t *atom, va_list ap)
1483 {
1484 struct _lldpctl_atom_ppvid_t *ppvid =
1485 (struct _lldpctl_atom_ppvid_t *)atom;
1486 ppvid->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
1487 ppvid->ppvid = va_arg(ap, struct lldpd_ppvid *);
1488 lldpctl_atom_inc_ref((lldpctl_atom_t *)ppvid->parent);
1489 return 1;
1490 }
1491
1492 static void
1493 _lldpctl_atom_free_ppvid(lldpctl_atom_t *atom)
1494 {
1495 struct _lldpctl_atom_ppvid_t *ppvid =
1496 (struct _lldpctl_atom_ppvid_t *)atom;
1497 lldpctl_atom_dec_ref((lldpctl_atom_t *)ppvid->parent);
1498 }
1499
1500 static long int
1501 _lldpctl_atom_get_int_ppvid(lldpctl_atom_t *atom, lldpctl_key_t key)
1502 {
1503 struct _lldpctl_atom_ppvid_t *m =
1504 (struct _lldpctl_atom_ppvid_t *)atom;
1505
1506 /* Local and remote port */
1507 switch (key) {
1508 case lldpctl_k_ppvid_id:
1509 return m->ppvid->p_ppvid;
1510 case lldpctl_k_ppvid_status:
1511 return m->ppvid->p_cap_status;
1512 default:
1513 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1514 }
1515 }
1516
1517 static lldpctl_atom_iter_t*
1518 _lldpctl_atom_iter_pis_list(lldpctl_atom_t *atom)
1519 {
1520 struct _lldpctl_atom_any_list_t *vlist =
1521 (struct _lldpctl_atom_any_list_t *)atom;
1522 return (lldpctl_atom_iter_t*)TAILQ_FIRST(&vlist->parent->port->p_pids);
1523 }
1524
1525 static lldpctl_atom_iter_t*
1526 _lldpctl_atom_next_pis_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
1527 {
1528 struct lldpd_pi *pi = (struct lldpd_pi *)iter;
1529 return (lldpctl_atom_iter_t*)TAILQ_NEXT(pi, p_entries);
1530 }
1531
1532 static lldpctl_atom_t*
1533 _lldpctl_atom_value_pis_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
1534 {
1535 struct _lldpctl_atom_any_list_t *vlist =
1536 (struct _lldpctl_atom_any_list_t *)atom;
1537 struct lldpd_pi *pi = (struct lldpd_pi *)iter;
1538 return _lldpctl_new_atom(atom->conn, atom_pi, vlist->parent, pi);
1539 }
1540
1541 static int
1542 _lldpctl_atom_new_pi(lldpctl_atom_t *atom, va_list ap)
1543 {
1544 struct _lldpctl_atom_pi_t *pi =
1545 (struct _lldpctl_atom_pi_t *)atom;
1546 pi->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
1547 pi->pi = va_arg(ap, struct lldpd_pi *);
1548 lldpctl_atom_inc_ref((lldpctl_atom_t *)pi->parent);
1549 return 1;
1550 }
1551
1552 static void
1553 _lldpctl_atom_free_pi(lldpctl_atom_t *atom)
1554 {
1555 struct _lldpctl_atom_pi_t *pi =
1556 (struct _lldpctl_atom_pi_t *)atom;
1557 lldpctl_atom_dec_ref((lldpctl_atom_t *)pi->parent);
1558 }
1559
1560 static const uint8_t*
1561 _lldpctl_atom_get_buf_pi(lldpctl_atom_t *atom, lldpctl_key_t key, size_t *n)
1562 {
1563 struct _lldpctl_atom_pi_t *m =
1564 (struct _lldpctl_atom_pi_t *)atom;
1565
1566 /* Local and remote port */
1567 switch (key) {
1568 case lldpctl_k_pi_id:
1569 *n = m->pi->p_pi_len;
1570 return (const uint8_t*)m->pi->p_pi;
1571 default:
1572 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1573 return NULL;
1574 }
1575 }
1576 #endif
1577
1578 #ifdef ENABLE_LLDPMED
1579 static lldpctl_atom_iter_t*
1580 _lldpctl_atom_iter_med_policies_list(lldpctl_atom_t *atom)
1581 {
1582 int i;
1583 struct _lldpctl_atom_any_list_t *vlist =
1584 (struct _lldpctl_atom_any_list_t *)atom;
1585 for (i = 0; i < LLDP_MED_APPTYPE_LAST; i++)
1586 vlist->parent->port->p_med_policy[i].index = i;
1587 return (lldpctl_atom_iter_t*)&vlist->parent->port->p_med_policy[0];
1588 }
1589
1590 static lldpctl_atom_iter_t*
1591 _lldpctl_atom_next_med_policies_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
1592 {
1593 struct lldpd_med_policy *policy = (struct lldpd_med_policy *)iter;
1594 if (policy->index == LLDP_MED_APPTYPE_LAST - 1) return NULL;
1595 return (lldpctl_atom_iter_t*)(++policy);
1596 }
1597
1598 static lldpctl_atom_t*
1599 _lldpctl_atom_value_med_policies_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
1600 {
1601 struct _lldpctl_atom_any_list_t *vlist =
1602 (struct _lldpctl_atom_any_list_t *)atom;
1603 struct lldpd_med_policy *policy = (struct lldpd_med_policy *)iter;
1604 return _lldpctl_new_atom(atom->conn, atom_med_policy, vlist->parent, policy);
1605 }
1606
1607 static int
1608 _lldpctl_atom_new_med_policy(lldpctl_atom_t *atom, va_list ap)
1609 {
1610 struct _lldpctl_atom_med_policy_t *policy =
1611 (struct _lldpctl_atom_med_policy_t *)atom;
1612 policy->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
1613 policy->policy = va_arg(ap, struct lldpd_med_policy *);
1614 lldpctl_atom_inc_ref((lldpctl_atom_t *)policy->parent);
1615 return 1;
1616 }
1617
1618 static void
1619 _lldpctl_atom_free_med_policy(lldpctl_atom_t *atom)
1620 {
1621 struct _lldpctl_atom_med_policy_t *policy =
1622 (struct _lldpctl_atom_med_policy_t *)atom;
1623 lldpctl_atom_dec_ref((lldpctl_atom_t *)policy->parent);
1624 }
1625
1626 static long int
1627 _lldpctl_atom_get_int_med_policy(lldpctl_atom_t *atom, lldpctl_key_t key)
1628 {
1629 struct _lldpctl_atom_med_policy_t *m =
1630 (struct _lldpctl_atom_med_policy_t *)atom;
1631
1632 /* Local and remote port */
1633 switch (key) {
1634 case lldpctl_k_med_policy_type:
1635 return m->policy->type;
1636 case lldpctl_k_med_policy_unknown:
1637 return m->policy->unknown;
1638 case lldpctl_k_med_policy_tagged:
1639 return m->policy->tagged;
1640 case lldpctl_k_med_policy_vid:
1641 return m->policy->vid;
1642 case lldpctl_k_med_policy_dscp:
1643 return m->policy->dscp;
1644 case lldpctl_k_med_policy_priority:
1645 return m->policy->priority;
1646 default:
1647 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1648 }
1649 }
1650
1651 static lldpctl_atom_t*
1652 _lldpctl_atom_set_int_med_policy(lldpctl_atom_t *atom, lldpctl_key_t key,
1653 long int value)
1654 {
1655 struct _lldpctl_atom_med_policy_t *m =
1656 (struct _lldpctl_atom_med_policy_t *)atom;
1657
1658 /* Only local port can be modified */
1659 if (m->parent->hardware == NULL) {
1660 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1661 return NULL;
1662 }
1663
1664 switch (key) {
1665 case lldpctl_k_med_policy_type:
1666 /* We let set any policy type, including one whose are not
1667 * compatible with the index. If a policy type is set, the index
1668 * will be ignored. If a policy type is 0, the index will be
1669 * used to know which policy to "erase". */
1670 if (value < 0 || value > LLDP_MED_APPTYPE_LAST) goto bad;
1671 m->policy->type = value;
1672 return atom;
1673 case lldpctl_k_med_policy_unknown:
1674 if (value != 0 && value != 1) goto bad;
1675 m->policy->unknown = value;
1676 return atom;
1677 case lldpctl_k_med_policy_tagged:
1678 if (value != 0 && value != 1) goto bad;
1679 m->policy->tagged = value;
1680 return atom;
1681 case lldpctl_k_med_policy_vid:
1682 if (value < 0 || value > 4094) goto bad;
1683 m->policy->vid = value;
1684 return atom;
1685 case lldpctl_k_med_policy_dscp:
1686 if (value < 0 || value > 63) goto bad;
1687 m->policy->dscp = value;
1688 return atom;
1689 case lldpctl_k_med_policy_priority:
1690 if (value < 0 || value > 7) goto bad;
1691 m->policy->priority = value;
1692 return atom;
1693 default:
1694 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1695 return NULL;
1696 }
1697
1698 return atom;
1699 bad:
1700 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
1701 return NULL;
1702 }
1703
1704 static const char*
1705 _lldpctl_atom_get_str_med_policy(lldpctl_atom_t *atom, lldpctl_key_t key)
1706 {
1707 struct _lldpctl_atom_med_policy_t *m =
1708 (struct _lldpctl_atom_med_policy_t *)atom;
1709
1710 /* Local and remote port */
1711 switch (key) {
1712 case lldpctl_k_med_policy_type:
1713 return map_lookup(port_med_policy_map, m->policy->type);
1714 case lldpctl_k_med_policy_priority:
1715 return map_lookup(port_med_policy_prio_map, m->policy->priority);
1716 default:
1717 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1718 return NULL;
1719 }
1720 }
1721
1722 static lldpctl_atom_t*
1723 _lldpctl_atom_set_str_med_policy(lldpctl_atom_t *atom, lldpctl_key_t key,
1724 const char *value)
1725 {
1726 /* Local and remote port */
1727 switch (key) {
1728 case lldpctl_k_med_policy_type:
1729 return _lldpctl_atom_set_int_med_policy(atom, key,
1730 map_reverse_lookup(port_med_policy_map, value));
1731 case lldpctl_k_med_policy_priority:
1732 return _lldpctl_atom_set_int_med_policy(atom, key,
1733 map_reverse_lookup(port_med_policy_prio_map, value));
1734 default:
1735 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1736 return NULL;
1737 }
1738 }
1739
1740 static lldpctl_atom_iter_t*
1741 _lldpctl_atom_iter_med_locations_list(lldpctl_atom_t *atom)
1742 {
1743 int i;
1744 struct _lldpctl_atom_any_list_t *vlist =
1745 (struct _lldpctl_atom_any_list_t *)atom;
1746 for (i = 0; i < LLDP_MED_LOCFORMAT_LAST; i++)
1747 vlist->parent->port->p_med_location[i].index = i;
1748 return (lldpctl_atom_iter_t*)&vlist->parent->port->p_med_location[0];
1749 }
1750
1751 static lldpctl_atom_iter_t*
1752 _lldpctl_atom_next_med_locations_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
1753 {
1754 struct lldpd_med_loc *location = (struct lldpd_med_loc *)iter;
1755 if (location->index == LLDP_MED_LOCFORMAT_LAST - 1) return NULL;
1756 return (lldpctl_atom_iter_t*)(++location);
1757 }
1758
1759 static lldpctl_atom_t*
1760 _lldpctl_atom_value_med_locations_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
1761 {
1762 struct _lldpctl_atom_any_list_t *vlist =
1763 (struct _lldpctl_atom_any_list_t *)atom;
1764 struct lldpd_med_loc *location = (struct lldpd_med_loc *)iter;
1765 return _lldpctl_new_atom(atom->conn, atom_med_location, vlist->parent, location);
1766 }
1767
1768 static int
1769 _lldpctl_atom_new_med_location(lldpctl_atom_t *atom, va_list ap)
1770 {
1771 struct _lldpctl_atom_med_location_t *location =
1772 (struct _lldpctl_atom_med_location_t *)atom;
1773 location->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
1774 location->location = va_arg(ap, struct lldpd_med_loc *);
1775 lldpctl_atom_inc_ref((lldpctl_atom_t *)location->parent);
1776 return 1;
1777 }
1778
1779 static void
1780 _lldpctl_atom_free_med_location(lldpctl_atom_t *atom)
1781 {
1782 struct _lldpctl_atom_med_location_t *location =
1783 (struct _lldpctl_atom_med_location_t *)atom;
1784 lldpctl_atom_dec_ref((lldpctl_atom_t *)location->parent);
1785 }
1786
1787 static long int
1788 _lldpctl_atom_get_int_med_location(lldpctl_atom_t *atom, lldpctl_key_t key)
1789 {
1790 struct _lldpctl_atom_med_location_t *m =
1791 (struct _lldpctl_atom_med_location_t *)atom;
1792
1793 /* Local and remote port */
1794 switch (key) {
1795 case lldpctl_k_med_location_format:
1796 switch (m->location->format) {
1797 case LLDP_MED_LOCFORMAT_COORD:
1798 if (m->location->data_len != 16) break;
1799 return LLDP_MED_LOCFORMAT_COORD;
1800 case LLDP_MED_LOCFORMAT_CIVIC:
1801 if ((m->location->data_len < 3) ||
1802 (m->location->data_len - 1 !=
1803 m->location->data[0])) break;
1804 return LLDP_MED_LOCFORMAT_CIVIC;
1805 case LLDP_MED_LOCFORMAT_ELIN:
1806 return LLDP_MED_LOCFORMAT_ELIN;
1807 default:
1808 return 0;
1809 }
1810 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1811 case lldpctl_k_med_location_geoid:
1812 if (m->location->format != LLDP_MED_LOCFORMAT_COORD)
1813 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1814 return m->location->data[15];
1815 case lldpctl_k_med_location_altitude_unit:
1816 if (m->location->format != LLDP_MED_LOCFORMAT_COORD)
1817 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1818 return (m->location->data[10] & 0xf0) >> 4;
1819 default:
1820 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1821 }
1822 }
1823
1824 static lldpctl_atom_t*
1825 _lldpctl_atom_set_int_med_location(lldpctl_atom_t *atom, lldpctl_key_t key,
1826 long int value)
1827 {
1828 struct _lldpctl_atom_med_location_t *mloc =
1829 (struct _lldpctl_atom_med_location_t *)atom;
1830
1831 /* Only local port can be modified */
1832 if (mloc->parent->hardware == NULL) {
1833 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1834 return NULL;
1835 }
1836
1837 switch (key) {
1838 case lldpctl_k_med_location_format:
1839 switch (value) {
1840 case 0: /* Disabling */
1841 case LLDP_MED_LOCFORMAT_COORD:
1842 mloc->location->format = value;
1843 if (mloc->location->data) free(mloc->location->data);
1844 mloc->location->data = calloc(1, 16);
1845 if (mloc->location->data == NULL) {
1846 mloc->location->data_len = 0;
1847 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
1848 return NULL;
1849 }
1850 mloc->location->data_len = 16;
1851 return atom;
1852 case LLDP_MED_LOCFORMAT_CIVIC:
1853 mloc->location->format = value;
1854 if (mloc->location->data) free(mloc->location->data);
1855 mloc->location->data = calloc(1, 4);
1856 if (mloc->location->data == NULL) {
1857 mloc->location->data_len = 0;
1858 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
1859 return NULL;
1860 }
1861 mloc->location->data_len = 4;
1862 mloc->location->data[0] = 3;
1863 mloc->location->data[1] = 2; /* Client */
1864 mloc->location->data[2] = 'U';
1865 mloc->location->data[3] = 'S';
1866 return atom;
1867 case LLDP_MED_LOCFORMAT_ELIN:
1868 mloc->location->format = value;
1869 if (mloc->location->data) free(mloc->location->data);
1870 mloc->location->data = NULL;
1871 mloc->location->data_len = 0;
1872 return atom;
1873 default: goto bad;
1874 }
1875 case lldpctl_k_med_location_geoid:
1876 if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
1877 if (mloc->location->data == NULL || mloc->location->data_len != 16) goto bad;
1878 switch (value) {
1879 case 0:
1880 case LLDP_MED_LOCATION_GEOID_WGS84:
1881 case LLDP_MED_LOCATION_GEOID_NAD83:
1882 case LLDP_MED_LOCATION_GEOID_NAD83_MLLW:
1883 mloc->location->data[15] = value;
1884 return atom;
1885 default: goto bad;
1886 }
1887 case lldpctl_k_med_location_altitude_unit:
1888 if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
1889 if (mloc->location->data == NULL || mloc->location->data_len != 16) goto bad;
1890 switch (value) {
1891 case 0:
1892 case LLDP_MED_LOCATION_ALTITUDE_UNIT_METER:
1893 case LLDP_MED_LOCATION_ALTITUDE_UNIT_FLOOR:
1894 mloc->location->data[10] &= 0x0f;
1895 mloc->location->data[10] |= value << 4;
1896 return atom;
1897 default: goto bad;
1898 }
1899 default:
1900 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1901 return NULL;
1902 }
1903
1904 return atom;
1905 bad:
1906 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
1907 return NULL;
1908
1909 }
1910
1911 static const char*
1912 read_fixed_precision(lldpctl_atom_t *atom,
1913 char *buffer, unsigned shift,
1914 unsigned intbits, unsigned fltbits, const char *suffix)
1915 {
1916 struct fp_number fp = fp_buftofp((unsigned char*)buffer, intbits, fltbits, shift);
1917 char *result = fp_fptostr(fp, suffix);
1918 if (result == NULL) {
1919 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
1920 return NULL;
1921 }
1922
1923 char *stored = _lldpctl_alloc_in_atom(atom, strlen(result) + 1);
1924 if (stored == NULL) {
1925 free(result);
1926 return NULL;
1927 }
1928 strlcpy(stored, result, strlen(result) + 1);
1929 return stored;
1930 }
1931
1932 static const char*
1933 _lldpctl_atom_get_str_med_location(lldpctl_atom_t *atom, lldpctl_key_t key)
1934 {
1935 struct _lldpctl_atom_med_location_t *m =
1936 (struct _lldpctl_atom_med_location_t *)atom;
1937 char *value;
1938
1939 /* Local and remote port */
1940 switch (key) {
1941 case lldpctl_k_med_location_format:
1942 return map_lookup(port_med_location_map, m->location->format);
1943 case lldpctl_k_med_location_geoid:
1944 if (m->location->format != LLDP_MED_LOCFORMAT_COORD) break;
1945 return map_lookup(port_med_geoid_map,
1946 m->location->data[15]);
1947 case lldpctl_k_med_location_latitude:
1948 if (m->location->format != LLDP_MED_LOCFORMAT_COORD) break;
1949 return read_fixed_precision(atom, m->location->data,
1950 0, 9, 25, "NS");
1951 case lldpctl_k_med_location_longitude:
1952 if (m->location->format != LLDP_MED_LOCFORMAT_COORD) break;
1953 return read_fixed_precision(atom, m->location->data,
1954 40, 9, 25, "EW");
1955 case lldpctl_k_med_location_altitude:
1956 if (m->location->format != LLDP_MED_LOCFORMAT_COORD) break;
1957 return read_fixed_precision(atom, m->location->data,
1958 84, 22, 8, NULL);
1959 case lldpctl_k_med_location_altitude_unit:
1960 if (m->location->format != LLDP_MED_LOCFORMAT_COORD) break;
1961 switch (m->location->data[10] & 0xf0) {
1962 case (LLDP_MED_LOCATION_ALTITUDE_UNIT_METER << 4):
1963 return "m";
1964 case (LLDP_MED_LOCATION_ALTITUDE_UNIT_FLOOR << 4):
1965 return "floor";
1966 }
1967 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1968 return NULL;
1969 case lldpctl_k_med_location_country:
1970 if (m->location->format != LLDP_MED_LOCFORMAT_CIVIC) break;
1971 value = _lldpctl_alloc_in_atom(atom, 3);
1972 if (!value) return NULL;
1973 memcpy(value, m->location->data + 2, 2);
1974 return value;
1975 case lldpctl_k_med_location_elin:
1976 if (m->location->format != LLDP_MED_LOCFORMAT_ELIN) break;
1977 value = _lldpctl_alloc_in_atom(atom, m->location->data_len + 1);
1978 if (!value) return NULL;
1979 memcpy(value, m->location->data, m->location->data_len);
1980 return value;
1981 default:
1982 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1983 return NULL;
1984 }
1985 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1986 return NULL;
1987 }
1988
1989 static lldpctl_atom_t*
1990 _lldpctl_atom_set_str_med_location(lldpctl_atom_t *atom, lldpctl_key_t key,
1991 const char *value)
1992 {
1993 struct _lldpctl_atom_med_location_t *mloc =
1994 (struct _lldpctl_atom_med_location_t *)atom;
1995 struct fp_number fp;
1996 char *end;
1997
1998 /* Only local port can be modified */
1999 if (mloc->parent->hardware == NULL) {
2000 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2001 return NULL;
2002 }
2003
2004 switch (key) {
2005 case lldpctl_k_med_location_latitude:
2006 if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
2007 if (mloc->location->data == NULL || mloc->location->data_len != 16) goto bad;
2008 fp = fp_strtofp(value, &end, 9, 25);
2009 if (!end) goto bad;
2010 if (end && *end != '\0') {
2011 if (*(end+1) != '\0') goto bad;
2012 if (*end == 'S') fp = fp_negate(fp);
2013 else if (*end != 'N') goto bad;
2014 }
2015 fp_fptobuf(fp, (unsigned char*)mloc->location->data, 0);
2016 return atom;
2017 case lldpctl_k_med_location_longitude:
2018 if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
2019 if (mloc->location->data == NULL || mloc->location->data_len != 16) goto bad;
2020 fp = fp_strtofp(value, &end, 9, 25);
2021 if (!end) goto bad;
2022 if (end && *end != '\0') {
2023 if (*(end+1) != '\0') goto bad;
2024 if (*end == 'W') fp = fp_negate(fp);
2025 else if (*end != 'E') goto bad;
2026 }
2027 fp_fptobuf(fp, (unsigned char*)mloc->location->data, 40);
2028 return atom;
2029 case lldpctl_k_med_location_altitude:
2030 if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
2031 if (mloc->location->data == NULL || mloc->location->data_len != 16) goto bad;
2032 fp = fp_strtofp(value, &end, 22, 8);
2033 if (!end || *end != '\0') goto bad;
2034 fp_fptobuf(fp, (unsigned char*)mloc->location->data, 84);
2035 return atom;
2036 case lldpctl_k_med_location_altitude_unit:
2037 if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
2038 if (mloc->location->data == NULL || mloc->location->data_len != 16) goto bad;
2039 if (!strcmp(value, "m"))
2040 return _lldpctl_atom_set_int_med_location(atom, key,
2041 LLDP_MED_LOCATION_ALTITUDE_UNIT_METER);
2042 if (!strcmp(value, "f") ||
2043 (!strcmp(value, "floor")))
2044 return _lldpctl_atom_set_int_med_location(atom, key,
2045 LLDP_MED_LOCATION_ALTITUDE_UNIT_FLOOR);
2046 goto bad;
2047 case lldpctl_k_med_location_geoid:
2048 return _lldpctl_atom_set_int_med_location(atom, key,
2049 map_reverse_lookup(port_med_geoid_map, value));
2050 case lldpctl_k_med_location_country:
2051 if (mloc->location->format != LLDP_MED_LOCFORMAT_CIVIC) goto bad;
2052 if (mloc->location->data == NULL || mloc->location->data_len < 3) goto bad;
2053 if (strlen(value) != 2) goto bad;
2054 memcpy(mloc->location->data + 2, value, 2);
2055 return atom;
2056 case lldpctl_k_med_location_elin:
2057 if (mloc->location->format != LLDP_MED_LOCFORMAT_ELIN) goto bad;
2058 if (mloc->location->data) free(mloc->location->data);
2059 mloc->location->data = calloc(1, strlen(value));
2060 if (mloc->location->data == NULL) {
2061 mloc->location->data_len = 0;
2062 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
2063 return NULL;
2064 }
2065 mloc->location->data_len = strlen(value);
2066 memcpy(mloc->location->data, value,
2067 mloc->location->data_len);
2068 return atom;
2069 default:
2070 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2071 return NULL;
2072 }
2073
2074 return atom;
2075 bad:
2076 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
2077 return NULL;
2078
2079 }
2080
2081 static lldpctl_atom_t*
2082 _lldpctl_atom_get_atom_med_location(lldpctl_atom_t *atom, lldpctl_key_t key)
2083 {
2084 struct _lldpctl_atom_med_location_t *m =
2085 (struct _lldpctl_atom_med_location_t *)atom;
2086
2087 /* Local and remote port */
2088 switch (key) {
2089 case lldpctl_k_med_location_ca_elements:
2090 if (m->location->format != LLDP_MED_LOCFORMAT_CIVIC) {
2091 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2092 return NULL;
2093 }
2094 return _lldpctl_new_atom(atom->conn, atom_med_caelements_list, m);
2095 default:
2096 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2097 return NULL;
2098 }
2099 }
2100
2101 static lldpctl_atom_t*
2102 _lldpctl_atom_set_atom_med_location(lldpctl_atom_t *atom, lldpctl_key_t key,
2103 lldpctl_atom_t *value)
2104 {
2105 struct _lldpctl_atom_med_location_t *m =
2106 (struct _lldpctl_atom_med_location_t *)atom;
2107 struct _lldpctl_atom_med_caelement_t *el;
2108 uint8_t *new;
2109
2110 /* Only local port can be modified */
2111 if (m->parent->hardware == NULL) {
2112 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2113 return NULL;
2114 }
2115
2116 switch (key) {
2117 case lldpctl_k_med_location_ca_elements:
2118 if (value->type != atom_med_caelement) {
2119 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
2120 return NULL;
2121 }
2122 if (m->location->format != LLDP_MED_LOCFORMAT_CIVIC) goto bad;
2123 if (m->location->data == NULL || m->location->data_len < 3) goto bad;
2124
2125 /* We append this element. */
2126 el = (struct _lldpctl_atom_med_caelement_t *)value;
2127 new = malloc(m->location->data_len + 2 + el->len);
2128 if (new == NULL) {
2129 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
2130 return NULL;
2131 }
2132 memcpy(new, m->location->data, m->location->data_len);
2133 new[m->location->data_len] = el->type;
2134 new[m->location->data_len + 1] = el->len;
2135 memcpy(new + m->location->data_len + 2, el->value, el->len);
2136 new[0] += 2 + el->len;
2137 free(m->location->data);
2138 m->location->data = (char*)new;
2139 m->location->data_len += 2 + el->len;
2140 return atom;
2141 default:
2142 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2143 return NULL;
2144 }
2145 bad:
2146 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
2147 return NULL;
2148 }
2149
2150 struct ca_iter {
2151 uint8_t *data;
2152 size_t data_len;
2153 };
2154
2155 static lldpctl_atom_iter_t*
2156 _lldpctl_atom_iter_med_caelements_list(lldpctl_atom_t *atom)
2157 {
2158 struct _lldpctl_atom_med_caelements_list_t *plist =
2159 (struct _lldpctl_atom_med_caelements_list_t *)atom;
2160 struct ca_iter *iter = _lldpctl_alloc_in_atom(atom, sizeof(struct ca_iter));
2161 if (!iter) return NULL;
2162 iter->data = (uint8_t*)plist->parent->location->data + 4;
2163 iter->data_len = plist->parent->location->data_len - 4;
2164 return (lldpctl_atom_iter_t*)iter;
2165 }
2166
2167 static lldpctl_atom_iter_t*
2168 _lldpctl_atom_next_med_caelements_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
2169 {
2170 struct ca_iter *cai = (struct ca_iter *)iter;
2171 int len;
2172 if (cai->data_len < 2) return NULL;
2173 len = *((uint8_t *)cai->data + 1);
2174 if (cai->data_len < 2 + len) return NULL;
2175 cai->data += 2 + len;
2176 cai->data_len -= 2 + len;
2177 return (lldpctl_atom_iter_t*)cai;
2178 }
2179
2180 static lldpctl_atom_t*
2181 _lldpctl_atom_value_med_caelements_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
2182 {
2183 struct _lldpctl_atom_med_caelements_list_t *plist =
2184 (struct _lldpctl_atom_med_caelements_list_t *)atom;
2185 struct ca_iter *cai = (struct ca_iter *)iter;
2186 size_t len;
2187 if (cai->data_len < 2) return NULL;
2188 len = *((uint8_t *)cai->data + 1);
2189 if (cai->data_len < 2 + len) return NULL;
2190 return _lldpctl_new_atom(atom->conn, atom_med_caelement, plist->parent,
2191 (int)*cai->data, cai->data + 2, len);
2192 }
2193
2194 static lldpctl_atom_t*
2195 _lldpctl_atom_create_med_caelements_list(lldpctl_atom_t *atom)
2196 {
2197 struct _lldpctl_atom_med_caelements_list_t *plist =
2198 (struct _lldpctl_atom_med_caelements_list_t *)atom;
2199 return _lldpctl_new_atom(atom->conn, atom_med_caelement, plist->parent,
2200 -1, NULL, 0);
2201 }
2202
2203 static int
2204 _lldpctl_atom_new_med_caelement(lldpctl_atom_t *atom, va_list ap)
2205 {
2206 struct _lldpctl_atom_med_caelement_t *el =
2207 (struct _lldpctl_atom_med_caelement_t *)atom;
2208 el->parent = va_arg(ap, struct _lldpctl_atom_med_location_t *);
2209 el->type = va_arg(ap, int);
2210 el->value = va_arg(ap, uint8_t*);
2211 el->len = va_arg(ap, size_t);
2212 lldpctl_atom_inc_ref((lldpctl_atom_t *)el->parent);
2213 return 1;
2214 }
2215
2216 static void
2217 _lldpctl_atom_free_med_caelement(lldpctl_atom_t *atom)
2218 {
2219 struct _lldpctl_atom_med_caelement_t *el =
2220 (struct _lldpctl_atom_med_caelement_t *)atom;
2221 lldpctl_atom_dec_ref((lldpctl_atom_t *)el->parent);
2222 }
2223
2224 static long int
2225 _lldpctl_atom_get_int_med_caelement(lldpctl_atom_t *atom, lldpctl_key_t key)
2226 {
2227 struct _lldpctl_atom_med_caelement_t *m =
2228 (struct _lldpctl_atom_med_caelement_t *)atom;
2229
2230 switch (key) {
2231 case lldpctl_k_med_civicaddress_type:
2232 return m->type;
2233 default:
2234 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2235 }
2236 }
2237
2238 static lldpctl_atom_t*
2239 _lldpctl_atom_set_int_med_caelement(lldpctl_atom_t *atom, lldpctl_key_t key,
2240 long int value)
2241 {
2242 struct _lldpctl_atom_med_caelement_t *el =
2243 (struct _lldpctl_atom_med_caelement_t *)atom;
2244
2245 /* Only local port can be modified */
2246 if (el->parent->parent->hardware == NULL) {
2247 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2248 return NULL;
2249 }
2250
2251 switch (key) {
2252 case lldpctl_k_med_civicaddress_type:
2253 if (value <= 0 || value > 128) goto bad;
2254 el->type = value;
2255 return atom;
2256 default:
2257 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2258 return NULL;
2259 }
2260
2261 return atom;
2262 bad:
2263 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
2264 return NULL;
2265 }
2266
2267 static const char*
2268 _lldpctl_atom_get_str_med_caelement(lldpctl_atom_t *atom, lldpctl_key_t key)
2269 {
2270 char *value = NULL;
2271 struct _lldpctl_atom_med_caelement_t *m =
2272 (struct _lldpctl_atom_med_caelement_t *)atom;
2273
2274 /* Local and remote port */
2275 switch (key) {
2276 case lldpctl_k_med_civicaddress_type:
2277 return map_lookup(civic_address_type_map, m->type);
2278 case lldpctl_k_med_civicaddress_value:
2279 value = _lldpctl_alloc_in_atom(atom, m->len + 1);
2280 if (!value) return NULL;
2281 memcpy(value, m->value, m->len);
2282 return value;
2283 default:
2284 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2285 return NULL;
2286 }
2287 }
2288
2289 static lldpctl_atom_t*
2290 _lldpctl_atom_set_str_med_caelement(lldpctl_atom_t *atom, lldpctl_key_t key,
2291 const char *value)
2292 {
2293 struct _lldpctl_atom_med_caelement_t *el =
2294 (struct _lldpctl_atom_med_caelement_t *)atom;
2295
2296 /* Only local port can be modified */
2297 if (el->parent->parent->hardware == NULL) {
2298 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2299 return NULL;
2300 }
2301
2302 switch (key) {
2303 case lldpctl_k_med_civicaddress_value:
2304 if (strlen(value) > 250) goto bad;
2305 el->value = _lldpctl_alloc_in_atom(atom, strlen(value) + 1);
2306 if (el->value == NULL) return NULL;
2307 strlcpy((char*)el->value, value, strlen(value) + 1);
2308 el->len = strlen(value);
2309 return atom;
2310 case lldpctl_k_med_civicaddress_type:
2311 return _lldpctl_atom_set_int_med_caelement(atom, key,
2312 map_reverse_lookup(civic_address_type_map, value));
2313 default:
2314 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2315 return NULL;
2316 }
2317
2318 return atom;
2319 bad:
2320 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
2321 return NULL;
2322 }
2323
2324 static int
2325 _lldpctl_atom_new_med_power(lldpctl_atom_t *atom, va_list ap)
2326 {
2327 struct _lldpctl_atom_med_power_t *mpow =
2328 (struct _lldpctl_atom_med_power_t *)atom;
2329 mpow->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
2330 lldpctl_atom_inc_ref((lldpctl_atom_t *)mpow->parent);
2331 return 1;
2332 }
2333
2334 static void
2335 _lldpctl_atom_free_med_power(lldpctl_atom_t *atom)
2336 {
2337 struct _lldpctl_atom_med_power_t *mpow =
2338 (struct _lldpctl_atom_med_power_t *)atom;
2339 lldpctl_atom_dec_ref((lldpctl_atom_t *)mpow->parent);
2340 }
2341
2342 static const char*
2343 _lldpctl_atom_get_str_med_power(lldpctl_atom_t *atom, lldpctl_key_t key)
2344 {
2345 struct _lldpctl_atom_med_power_t *mpow =
2346 (struct _lldpctl_atom_med_power_t *)atom;
2347 struct lldpd_port *port = mpow->parent->port;
2348
2349 /* Local and remote port */
2350 switch (key) {
2351 case lldpctl_k_med_power_type:
2352 return map_lookup(port_med_pow_devicetype_map,
2353 port->p_med_power.devicetype);
2354 case lldpctl_k_med_power_source:
2355 return map_lookup(port_med_pow_source_map,
2356 port->p_med_power.source);
2357 case lldpctl_k_med_power_priority:
2358 return map_lookup(port_med_pow_priority_map,
2359 port->p_med_power.priority);
2360 default:
2361 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2362 return NULL;
2363 }
2364 }
2365
2366 static long int
2367 _lldpctl_atom_get_int_med_power(lldpctl_atom_t *atom, lldpctl_key_t key)
2368 {
2369 struct _lldpctl_atom_med_power_t *dpow =
2370 (struct _lldpctl_atom_med_power_t *)atom;
2371 struct lldpd_port *port = dpow->parent->port;
2372
2373 /* Local and remote port */
2374 switch (key) {
2375 case lldpctl_k_med_power_type:
2376 return port->p_med_power.devicetype;
2377 case lldpctl_k_med_power_source:
2378 return port->p_med_power.source;
2379 case lldpctl_k_med_power_priority:
2380 return port->p_med_power.priority;
2381 case lldpctl_k_med_power_val:
2382 return port->p_med_power.val * 100;
2383 default:
2384 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2385 }
2386 }
2387
2388 static lldpctl_atom_t*
2389 _lldpctl_atom_set_int_med_power(lldpctl_atom_t *atom, lldpctl_key_t key,
2390 long int value)
2391 {
2392 struct _lldpctl_atom_med_power_t *dpow =
2393 (struct _lldpctl_atom_med_power_t *)atom;
2394 struct lldpd_port *port = dpow->parent->port;
2395
2396 /* Only local port can be modified */
2397 if (dpow->parent->hardware == NULL) {
2398 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2399 return NULL;
2400 }
2401
2402 switch (key) {
2403 case lldpctl_k_med_power_type:
2404 switch (value) {
2405 case 0:
2406 case LLDP_MED_POW_TYPE_PSE:
2407 case LLDP_MED_POW_TYPE_PD:
2408 port->p_med_power.devicetype = value;
2409 return atom;
2410 default: goto bad;
2411 }
2412 case lldpctl_k_med_power_source:
2413 switch (value) {
2414 case LLDP_MED_POW_SOURCE_PRIMARY:
2415 case LLDP_MED_POW_SOURCE_BACKUP:
2416 if (port->p_med_power.devicetype != LLDP_MED_POW_TYPE_PSE)
2417 goto bad;
2418 port->p_med_power.source = value;
2419 return atom;
2420 case LLDP_MED_POW_SOURCE_PSE:
2421 case LLDP_MED_POW_SOURCE_LOCAL:
2422 case LLDP_MED_POW_SOURCE_BOTH:
2423 if (port->p_med_power.devicetype != LLDP_MED_POW_TYPE_PD)
2424 goto bad;
2425 port->p_med_power.source = value;
2426 return atom;
2427 case LLDP_MED_POW_SOURCE_UNKNOWN:
2428 port->p_med_power.source = value;
2429 return atom;
2430 default: goto bad;
2431 }
2432 case lldpctl_k_med_power_priority:
2433 if (value < 0 || value > 3) goto bad;
2434 port->p_med_power.priority = value;
2435 return atom;
2436 case lldpctl_k_med_power_val:
2437 if (value < 0) goto bad;
2438 port->p_med_power.val = value / 100;
2439 return atom;
2440 default:
2441 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2442 return NULL;
2443 }
2444
2445 return atom;
2446 bad:
2447 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
2448 return NULL;
2449 }
2450
2451 static lldpctl_atom_t*
2452 _lldpctl_atom_set_str_med_power(lldpctl_atom_t *atom, lldpctl_key_t key,
2453 const char *value)
2454 {
2455 switch (key) {
2456 case lldpctl_k_med_power_type:
2457 return _lldpctl_atom_set_int_med_power(atom, key,
2458 map_reverse_lookup(port_med_pow_devicetype_map, value));
2459 case lldpctl_k_med_power_source:
2460 return _lldpctl_atom_set_int_med_power(atom, key,
2461 map_reverse_lookup(port_med_pow_source_map2, value));
2462 case lldpctl_k_med_power_priority:
2463 return _lldpctl_atom_set_int_med_power(atom, key,
2464 map_reverse_lookup(port_med_pow_priority_map, value));
2465 default:
2466 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
2467 return NULL;
2468 }
2469 }
2470 #endif
2471
2472 struct atom_builder {
2473 atom_t type; /* Atom type */
2474 size_t size; /* Size of structure to allocate */
2475 int (*init)(lldpctl_atom_t *, va_list); /* Optional additional init steps */
2476 void (*free)(lldpctl_atom_t *); /* Optional deallocation steps */
2477
2478 lldpctl_atom_iter_t* (*iter)(lldpctl_atom_t *); /* Optional, return an iterator for this object */
2479 lldpctl_atom_iter_t* (*next)(lldpctl_atom_t *, lldpctl_atom_iter_t *); /* Return the next object for the provided iterator */
2480 lldpctl_atom_t* (*value)(lldpctl_atom_t *, lldpctl_atom_iter_t *); /* Return the current object for the provided iterator */
2481
2482 lldpctl_atom_t* (*get)(lldpctl_atom_t *, lldpctl_key_t);
2483 const char* (*get_str)(lldpctl_atom_t *, lldpctl_key_t);
2484 const u_int8_t* (*get_buffer)(lldpctl_atom_t *, lldpctl_key_t, size_t *);
2485 long int (*get_int)(lldpctl_atom_t *, lldpctl_key_t);
2486
2487 lldpctl_atom_t* (*set)(lldpctl_atom_t *, lldpctl_key_t, lldpctl_atom_t *);
2488 lldpctl_atom_t* (*set_str)(lldpctl_atom_t *, lldpctl_key_t, const char *);
2489 lldpctl_atom_t* (*set_buffer)(lldpctl_atom_t *, lldpctl_key_t, const u_int8_t *, size_t);
2490 lldpctl_atom_t* (*set_int)(lldpctl_atom_t *, lldpctl_key_t, long int);
2491 lldpctl_atom_t* (*create)(lldpctl_atom_t *);
2492 };
2493
2494 struct atom_builder builders[] = {
2495 { atom_config, sizeof(struct _lldpctl_atom_config_t),
2496 .init = _lldpctl_atom_new_config,
2497 .free = _lldpctl_atom_free_config,
2498 .get_str = _lldpctl_atom_get_str_config,
2499 .set_str = _lldpctl_atom_set_str_config,
2500 .get_int = _lldpctl_atom_get_int_config,
2501 .set_int = _lldpctl_atom_set_int_config },
2502 { atom_interfaces_list, sizeof(struct _lldpctl_atom_interfaces_list_t),
2503 .init = _lldpctl_atom_new_interfaces_list,
2504 .free = _lldpctl_atom_free_interfaces_list,
2505 .iter = _lldpctl_atom_iter_interfaces_list,
2506 .next = _lldpctl_atom_next_interfaces_list,
2507 .value = _lldpctl_atom_value_interfaces_list },
2508 { atom_interface, sizeof(struct _lldpctl_atom_interface_t),
2509 .init = _lldpctl_atom_new_interface,
2510 .free = _lldpctl_atom_free_interface,
2511 .get_str = _lldpctl_atom_get_str_interface },
2512 { atom_ports_list, sizeof(struct _lldpctl_atom_any_list_t),
2513 .init = _lldpctl_atom_new_any_list,
2514 .free = _lldpctl_atom_free_any_list,
2515 .iter = _lldpctl_atom_iter_ports_list,
2516 .next = _lldpctl_atom_next_ports_list,
2517 .value = _lldpctl_atom_value_ports_list },
2518 { atom_port, sizeof(struct _lldpctl_atom_port_t),
2519 .init = _lldpctl_atom_new_port,
2520 .free = _lldpctl_atom_free_port,
2521 .get = _lldpctl_atom_get_atom_port,
2522 .set = _lldpctl_atom_set_atom_port,
2523 .get_str = _lldpctl_atom_get_str_port,
2524 .get_int = _lldpctl_atom_get_int_port,
2525 .get_buffer = _lldpctl_atom_get_buf_port },
2526 { atom_mgmts_list, sizeof(struct _lldpctl_atom_mgmts_list_t),
2527 .init = _lldpctl_atom_new_mgmts_list,
2528 .free = _lldpctl_atom_free_mgmts_list,
2529 .iter = _lldpctl_atom_iter_mgmts_list,
2530 .next = _lldpctl_atom_next_mgmts_list,
2531 .value = _lldpctl_atom_value_mgmts_list },
2532 { atom_mgmt, sizeof(struct _lldpctl_atom_mgmt_t),
2533 .init = _lldpctl_atom_new_mgmt,
2534 .free = _lldpctl_atom_free_mgmt,
2535 .get_str = _lldpctl_atom_get_str_mgmt },
2536 #ifdef ENABLE_DOT3
2537 { atom_dot3_power, sizeof(struct _lldpctl_atom_dot3_power_t),
2538 .init = _lldpctl_atom_new_dot3_power,
2539 .free = _lldpctl_atom_free_dot3_power,
2540 .get_int = _lldpctl_atom_get_int_dot3_power,
2541 .set_int = _lldpctl_atom_set_int_dot3_power,
2542 .get_str = _lldpctl_atom_get_str_dot3_power,
2543 .set_str = _lldpctl_atom_set_str_dot3_power },
2544 #endif
2545 #ifdef ENABLE_DOT1
2546 { atom_vlans_list, sizeof(struct _lldpctl_atom_any_list_t),
2547 .init = _lldpctl_atom_new_any_list,
2548 .free = _lldpctl_atom_free_any_list,
2549 .iter = _lldpctl_atom_iter_vlans_list,
2550 .next = _lldpctl_atom_next_vlans_list,
2551 .value = _lldpctl_atom_value_vlans_list },
2552 { atom_vlan, sizeof(struct _lldpctl_atom_vlan_t),
2553 .init = _lldpctl_atom_new_vlan,
2554 .free = _lldpctl_atom_free_vlan,
2555 .get_str = _lldpctl_atom_get_str_vlan,
2556 .get_int = _lldpctl_atom_get_int_vlan },
2557 { atom_ppvids_list, sizeof(struct _lldpctl_atom_any_list_t),
2558 .init = _lldpctl_atom_new_any_list,
2559 .free = _lldpctl_atom_free_any_list,
2560 .iter = _lldpctl_atom_iter_ppvids_list,
2561 .next = _lldpctl_atom_next_ppvids_list,
2562 .value = _lldpctl_atom_value_ppvids_list },
2563 { atom_ppvid, sizeof(struct _lldpctl_atom_ppvid_t),
2564 .init = _lldpctl_atom_new_ppvid,
2565 .free = _lldpctl_atom_free_ppvid,
2566 .get_int = _lldpctl_atom_get_int_ppvid },
2567 { atom_pis_list, sizeof(struct _lldpctl_atom_any_list_t),
2568 .init = _lldpctl_atom_new_any_list,
2569 .free = _lldpctl_atom_free_any_list,
2570 .iter = _lldpctl_atom_iter_pis_list,
2571 .next = _lldpctl_atom_next_pis_list,
2572 .value = _lldpctl_atom_value_pis_list },
2573 { atom_pi, sizeof(struct _lldpctl_atom_pi_t),
2574 .init = _lldpctl_atom_new_pi,
2575 .free = _lldpctl_atom_free_pi,
2576 .get_buffer = _lldpctl_atom_get_buf_pi },
2577 #endif
2578 #ifdef ENABLE_LLDPMED
2579 { atom_med_policies_list, sizeof(struct _lldpctl_atom_any_list_t),
2580 .init = _lldpctl_atom_new_any_list,
2581 .free = _lldpctl_atom_free_any_list,
2582 .iter = _lldpctl_atom_iter_med_policies_list,
2583 .next = _lldpctl_atom_next_med_policies_list,
2584 .value = _lldpctl_atom_value_med_policies_list },
2585 { atom_med_policy, sizeof(struct _lldpctl_atom_med_policy_t),
2586 .init = _lldpctl_atom_new_med_policy,
2587 .free = _lldpctl_atom_free_med_policy,
2588 .get_int = _lldpctl_atom_get_int_med_policy,
2589 .set_int = _lldpctl_atom_set_int_med_policy,
2590 .get_str = _lldpctl_atom_get_str_med_policy,
2591 .set_str = _lldpctl_atom_set_str_med_policy },
2592 { atom_med_locations_list, sizeof(struct _lldpctl_atom_any_list_t),
2593 .init = _lldpctl_atom_new_any_list,
2594 .free = _lldpctl_atom_free_any_list,
2595 .iter = _lldpctl_atom_iter_med_locations_list,
2596 .next = _lldpctl_atom_next_med_locations_list,
2597 .value = _lldpctl_atom_value_med_locations_list },
2598 { atom_med_location, sizeof(struct _lldpctl_atom_med_location_t),
2599 .init = _lldpctl_atom_new_med_location,
2600 .free = _lldpctl_atom_free_med_location,
2601 .get = _lldpctl_atom_get_atom_med_location,
2602 .set = _lldpctl_atom_set_atom_med_location,
2603 .get_int = _lldpctl_atom_get_int_med_location,
2604 .set_int = _lldpctl_atom_set_int_med_location,
2605 .get_str = _lldpctl_atom_get_str_med_location,
2606 .set_str = _lldpctl_atom_set_str_med_location },
2607 { atom_med_caelements_list, sizeof(struct _lldpctl_atom_med_caelements_list_t),
2608 .init = _lldpctl_atom_new_any_list,
2609 .free = _lldpctl_atom_free_any_list,
2610 .iter = _lldpctl_atom_iter_med_caelements_list,
2611 .next = _lldpctl_atom_next_med_caelements_list,
2612 .value = _lldpctl_atom_value_med_caelements_list,
2613 .create = _lldpctl_atom_create_med_caelements_list },
2614 { atom_med_caelement, sizeof(struct _lldpctl_atom_med_caelement_t),
2615 .init = _lldpctl_atom_new_med_caelement,
2616 .free = _lldpctl_atom_free_med_caelement,
2617 .get_int = _lldpctl_atom_get_int_med_caelement,
2618 .set_int = _lldpctl_atom_set_int_med_caelement,
2619 .get_str = _lldpctl_atom_get_str_med_caelement,
2620 .set_str = _lldpctl_atom_set_str_med_caelement },
2621 { atom_med_power, sizeof(struct _lldpctl_atom_med_power_t),
2622 .init = _lldpctl_atom_new_med_power,
2623 .free = _lldpctl_atom_free_med_power,
2624 .get_int = _lldpctl_atom_get_int_med_power,
2625 .set_int = _lldpctl_atom_set_int_med_power,
2626 .get_str = _lldpctl_atom_get_str_med_power,
2627 .set_str = _lldpctl_atom_set_str_med_power },
2628 #endif
2629 { 0, 0, .init = NULL, .free = NULL }
2630 };
2631
2632 lldpctl_atom_t*
2633 _lldpctl_new_atom(lldpctl_conn_t *conn, atom_t type, ...)
2634 {
2635 struct atom_builder *builder;
2636 struct lldpctl_atom_t *atom;
2637 va_list(ap);
2638 for (builder = builders; builder->size > 0; builder++) {
2639 if (builder->type != type) continue;
2640 atom = calloc(1, builder->size);
2641 if (atom == NULL) {
2642 SET_ERROR(conn, LLDPCTL_ERR_NOMEM);
2643 return NULL;
2644 }
2645 atom->count = 1;
2646 atom->type = type;
2647 atom->conn = conn;
2648 TAILQ_INIT(&atom->buffers);
2649 atom->free = builder->free;
2650
2651 atom->iter = builder->iter;
2652 atom->next = builder->next;
2653 atom->value = builder->value;
2654
2655 atom->get = builder->get;
2656 atom->get_str = builder->get_str;
2657 atom->get_buffer= builder->get_buffer;
2658 atom->get_int = builder->get_int;
2659
2660 atom->set = builder->set;
2661 atom->set_str = builder->set_str;
2662 atom->set_buffer= builder->set_buffer;
2663 atom->set_int = builder->set_int;
2664 atom->create = builder->create;
2665
2666 va_start(ap, type);
2667 if (builder->init && builder->init(atom, ap) == 0) {
2668 free(atom);
2669 va_end(ap);
2670 /* Error to be set in init() */
2671 return NULL;
2672 }
2673 va_end(ap);
2674 return atom;
2675 }
2676 log_warnx("rpc", "unknown atom type: %d", type);
2677 SET_ERROR(conn, LLDPCTL_ERR_FATAL);
2678 return NULL;
2679 }
2680
2681 /**
2682 * Allocate a buffer inside an atom.
2683 *
2684 * It will be freed automatically when the atom is released. This buffer cannot
2685 * be reallocated and should not be freed!
2686 *
2687 * @param atom Atom which will be used as a container.
2688 * @param size Size of the allocated area.
2689 * @return Pointer to the buffer or @c NULL if allocation fails.
2690 */
2691 void*
2692 _lldpctl_alloc_in_atom(lldpctl_atom_t *atom, size_t size)
2693 {
2694 struct atom_buffer *buffer;
2695
2696 if ((buffer = calloc(1, size + sizeof(struct atom_buffer))) == NULL) {
2697 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
2698 return NULL;
2699 }
2700 TAILQ_INSERT_TAIL(&atom->buffers, buffer, next);
2701 return &buffer->data[0];
2702 }
2703
2704 /**
2705 * Allocate a buffer inside an atom and dump another buffer in it.
2706 *
2707 * The dump is done in hexadecimal with the provided separator.
2708 *
2709 * @param atom Atom which will be used as a container.
2710 * @param input Buffer we want to dump.
2711 * @param size Size of the buffer
2712 * @param sep Separator to use.
2713 * @param max Maximum number of bytes to dump. Can be 0 if no maximum.
2714 * @return A string representing the dump of the buffer or @c NULL if error.
2715 */
2716 const char*
2717 _lldpctl_dump_in_atom(lldpctl_atom_t *atom,
2718 const uint8_t *input, size_t size,
2719 char sep, size_t max)
2720 {
2721 static const char truncation[] = "[...]";
2722 size_t i, len;
2723 char *buffer = NULL;
2724
2725 if (max > 0 && size > max)
2726 len = max * 3 + sizeof(truncation) + 1;
2727 else
2728 len = size * 3 + 1;
2729
2730 if ((buffer = _lldpctl_alloc_in_atom(atom, len)) == NULL)
2731 return NULL;
2732
2733 for (i = 0; (i < size) && (max == 0 || i < max); i++)
2734 snprintf(buffer + i * 3, 4, "%02x%c", *(u_int8_t*)(input + i), sep);
2735 if (max > 0 && size > max)
2736 snprintf(buffer + i * 3, sizeof(truncation) + 1, "%s", truncation);
2737 else
2738 *(buffer + i*3 - 1) = 0;
2739 return buffer;
2740 }