1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
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.
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.
21 #include <arpa/inet.h>
23 #include "../lldpctl.h"
24 #include "../../log.h"
26 #include "../helpers.h"
27 #include "../fixedpoint.h"
31 static lldpctl_map_t port_med_location_map
[] = {
32 { LLDP_MED_LOCFORMAT_COORD
, "Coordinates" },
33 { LLDP_MED_LOCFORMAT_CIVIC
, "Civic address" },
34 { LLDP_MED_LOCFORMAT_ELIN
, "ELIN" },
38 static lldpctl_map_t port_med_pow_devicetype_map
[] = {
39 { LLDP_MED_POW_TYPE_PSE
, "PSE" },
40 { LLDP_MED_POW_TYPE_PD
, "PD" },
44 static lldpctl_map_t port_med_pow_source_map
[] = {
45 { LLDP_MED_POW_SOURCE_PRIMARY
, "Primary Power Source" },
46 { LLDP_MED_POW_SOURCE_BACKUP
, "Backup Power Source / Power Conservation Mode" },
47 { LLDP_MED_POW_SOURCE_PSE
, "PSE" },
48 { LLDP_MED_POW_SOURCE_LOCAL
, "Local" },
49 { LLDP_MED_POW_SOURCE_BOTH
, "PSE + Local" },
53 static lldpctl_map_t port_med_pow_source_map2
[] = {
55 { LLDP_MED_POW_SOURCE_PRIMARY
, "primary" },
56 { LLDP_MED_POW_SOURCE_BACKUP
, "backup" },
57 { LLDP_MED_POW_SOURCE_PSE
, "pse" },
58 { LLDP_MED_POW_SOURCE_LOCAL
, "local" },
59 { LLDP_MED_POW_SOURCE_BOTH
, "both" },
63 static struct atom_map port_med_geoid_map
= {
64 .key
= lldpctl_k_med_location_geoid
,
66 { LLDP_MED_LOCATION_GEOID_WGS84
, "WGS84" },
67 { LLDP_MED_LOCATION_GEOID_NAD83
, "NAD83" },
68 { LLDP_MED_LOCATION_GEOID_NAD83_MLLW
, "NAD83/MLLW" },
73 static struct atom_map civic_address_type_map
= {
74 .key
= lldpctl_k_med_civicaddress_type
,
77 { 1, "Country subdivision" },
80 { 4, "City division" },
84 { 17, "Trailing street suffix" },
85 { 18, "Street suffix" },
87 { 20, "Number suffix" },
102 static struct atom_map port_med_policy_map
= { .key
= lldpctl_k_med_policy_type
,
104 { LLDP_MED_APPTYPE_VOICE
, "Voice" },
105 { LLDP_MED_APPTYPE_VOICESIGNAL
, "Voice Signaling" },
106 { LLDP_MED_APPTYPE_GUESTVOICE
, "Guest Voice" },
107 { LLDP_MED_APPTYPE_GUESTVOICESIGNAL
, "Guest Voice Signaling" },
108 { LLDP_MED_APPTYPE_SOFTPHONEVOICE
, "Softphone Voice" },
109 { LLDP_MED_APPTYPE_VIDEOCONFERENCE
, "Video Conferencing" },
110 { LLDP_MED_APPTYPE_VIDEOSTREAM
, "Streaming Video" },
111 { LLDP_MED_APPTYPE_VIDEOSIGNAL
, "Video Signaling" },
115 static struct atom_map port_med_policy_prio_map
= {
116 .key
= lldpctl_k_med_policy_priority
,
119 { 0, "Best effort" },
120 { 2, "Excellent effort" },
121 { 3, "Critical applications" },
124 { 6, "Internetwork control" },
125 { 7, "Network control" },
130 static struct atom_map port_med_pow_priority_map
= {
131 .key
= lldpctl_k_med_power_priority
,
134 { LLDP_MED_POW_PRIO_CRITICAL
, "critical" },
135 { LLDP_MED_POW_PRIO_HIGH
, "high" },
136 { LLDP_MED_POW_PRIO_LOW
, "low" },
141 ATOM_MAP_REGISTER(port_med_geoid_map
, 7);
142 ATOM_MAP_REGISTER(civic_address_type_map
, 8);
143 ATOM_MAP_REGISTER(port_med_policy_map
, 9);
144 ATOM_MAP_REGISTER(port_med_policy_prio_map
, 10);
145 ATOM_MAP_REGISTER(port_med_pow_priority_map
, 11);
147 static lldpctl_atom_iter_t
*
148 _lldpctl_atom_iter_med_policies_list(lldpctl_atom_t
*atom
)
151 struct _lldpctl_atom_any_list_t
*vlist
=
152 (struct _lldpctl_atom_any_list_t
*)atom
;
153 for (i
= 0; i
< LLDP_MED_APPTYPE_LAST
; i
++)
154 vlist
->parent
->port
->p_med_policy
[i
].index
= i
;
155 return (lldpctl_atom_iter_t
*)&vlist
->parent
->port
->p_med_policy
[0];
158 static lldpctl_atom_iter_t
*
159 _lldpctl_atom_next_med_policies_list(lldpctl_atom_t
*atom
, lldpctl_atom_iter_t
*iter
)
161 struct lldpd_med_policy
*policy
= (struct lldpd_med_policy
*)iter
;
162 if (policy
->index
== LLDP_MED_APPTYPE_LAST
- 1) return NULL
;
163 return (lldpctl_atom_iter_t
*)(++policy
);
166 static lldpctl_atom_t
*
167 _lldpctl_atom_value_med_policies_list(lldpctl_atom_t
*atom
, lldpctl_atom_iter_t
*iter
)
169 struct _lldpctl_atom_any_list_t
*vlist
=
170 (struct _lldpctl_atom_any_list_t
*)atom
;
171 struct lldpd_med_policy
*policy
= (struct lldpd_med_policy
*)iter
;
172 return _lldpctl_new_atom(atom
->conn
, atom_med_policy
, vlist
->parent
, policy
);
176 _lldpctl_atom_new_med_policy(lldpctl_atom_t
*atom
, va_list ap
)
178 struct _lldpctl_atom_med_policy_t
*policy
=
179 (struct _lldpctl_atom_med_policy_t
*)atom
;
180 policy
->parent
= va_arg(ap
, struct _lldpctl_atom_port_t
*);
181 policy
->policy
= va_arg(ap
, struct lldpd_med_policy
*);
182 lldpctl_atom_inc_ref((lldpctl_atom_t
*)policy
->parent
);
187 _lldpctl_atom_free_med_policy(lldpctl_atom_t
*atom
)
189 struct _lldpctl_atom_med_policy_t
*policy
=
190 (struct _lldpctl_atom_med_policy_t
*)atom
;
191 lldpctl_atom_dec_ref((lldpctl_atom_t
*)policy
->parent
);
195 _lldpctl_atom_get_int_med_policy(lldpctl_atom_t
*atom
, lldpctl_key_t key
)
197 struct _lldpctl_atom_med_policy_t
*m
=
198 (struct _lldpctl_atom_med_policy_t
*)atom
;
200 /* Local and remote port */
202 case lldpctl_k_med_policy_type
:
203 return m
->policy
->type
;
204 case lldpctl_k_med_policy_unknown
:
205 return m
->policy
->unknown
;
206 case lldpctl_k_med_policy_tagged
:
207 return m
->policy
->tagged
;
208 case lldpctl_k_med_policy_vid
:
209 return m
->policy
->vid
;
210 case lldpctl_k_med_policy_dscp
:
211 return m
->policy
->dscp
;
212 case lldpctl_k_med_policy_priority
:
213 return m
->policy
->priority
;
215 return SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
219 static lldpctl_atom_t
*
220 _lldpctl_atom_set_int_med_policy(lldpctl_atom_t
*atom
, lldpctl_key_t key
,
223 struct _lldpctl_atom_med_policy_t
*m
=
224 (struct _lldpctl_atom_med_policy_t
*)atom
;
226 /* Only local port can be modified */
227 if (!m
->parent
->local
) {
228 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
233 case lldpctl_k_med_policy_type
:
234 /* We let set any policy type, including one whose are not
235 * compatible with the index. If a policy type is set, the index
236 * will be ignored. If a policy type is 0, the index will be
237 * used to know which policy to "erase". */
238 if (value
< 0 || value
> LLDP_MED_APPTYPE_LAST
) goto bad
;
239 m
->policy
->type
= value
;
241 case lldpctl_k_med_policy_unknown
:
242 if (value
!= 0 && value
!= 1) goto bad
;
243 m
->policy
->unknown
= value
;
245 case lldpctl_k_med_policy_tagged
:
246 if (value
!= 0 && value
!= 1) goto bad
;
247 m
->policy
->tagged
= value
;
249 case lldpctl_k_med_policy_vid
:
250 if (value
< 0 || value
> 4094) goto bad
;
251 m
->policy
->vid
= value
;
253 case lldpctl_k_med_policy_dscp
:
254 if (value
< 0 || value
> 63) goto bad
;
255 m
->policy
->dscp
= value
;
257 case lldpctl_k_med_policy_priority
:
258 if (value
< 0 || value
> 7) goto bad
;
259 m
->policy
->priority
= value
;
262 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
268 SET_ERROR(atom
->conn
, LLDPCTL_ERR_BAD_VALUE
);
273 _lldpctl_atom_get_str_med_policy(lldpctl_atom_t
*atom
, lldpctl_key_t key
)
275 struct _lldpctl_atom_med_policy_t
*m
=
276 (struct _lldpctl_atom_med_policy_t
*)atom
;
278 /* Local and remote port */
280 case lldpctl_k_med_policy_type
:
281 return map_lookup(port_med_policy_map
.map
, m
->policy
->type
);
282 case lldpctl_k_med_policy_priority
:
283 return map_lookup(port_med_policy_prio_map
.map
, m
->policy
->priority
);
285 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
290 static lldpctl_atom_t
*
291 _lldpctl_atom_set_str_med_policy(lldpctl_atom_t
*atom
, lldpctl_key_t key
,
294 /* Local and remote port */
296 case lldpctl_k_med_policy_type
:
297 return _lldpctl_atom_set_int_med_policy(atom
, key
,
298 map_reverse_lookup(port_med_policy_map
.map
, value
));
299 case lldpctl_k_med_policy_priority
:
300 return _lldpctl_atom_set_int_med_policy(atom
, key
,
301 map_reverse_lookup(port_med_policy_prio_map
.map
, value
));
303 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
308 static lldpctl_atom_iter_t
*
309 _lldpctl_atom_iter_med_locations_list(lldpctl_atom_t
*atom
)
312 struct _lldpctl_atom_any_list_t
*vlist
=
313 (struct _lldpctl_atom_any_list_t
*)atom
;
314 for (i
= 0; i
< LLDP_MED_LOCFORMAT_LAST
; i
++)
315 vlist
->parent
->port
->p_med_location
[i
].index
= i
;
316 return (lldpctl_atom_iter_t
*)&vlist
->parent
->port
->p_med_location
[0];
319 static lldpctl_atom_iter_t
*
320 _lldpctl_atom_next_med_locations_list(lldpctl_atom_t
*atom
, lldpctl_atom_iter_t
*iter
)
322 struct lldpd_med_loc
*location
= (struct lldpd_med_loc
*)iter
;
323 if (location
->index
== LLDP_MED_LOCFORMAT_LAST
- 1) return NULL
;
324 return (lldpctl_atom_iter_t
*)(++location
);
327 static lldpctl_atom_t
*
328 _lldpctl_atom_value_med_locations_list(lldpctl_atom_t
*atom
, lldpctl_atom_iter_t
*iter
)
330 struct _lldpctl_atom_any_list_t
*vlist
=
331 (struct _lldpctl_atom_any_list_t
*)atom
;
332 struct lldpd_med_loc
*location
= (struct lldpd_med_loc
*)iter
;
333 return _lldpctl_new_atom(atom
->conn
, atom_med_location
, vlist
->parent
,
338 _lldpctl_atom_new_med_location(lldpctl_atom_t
*atom
, va_list ap
)
340 struct _lldpctl_atom_med_location_t
*location
=
341 (struct _lldpctl_atom_med_location_t
*)atom
;
342 location
->parent
= va_arg(ap
, struct _lldpctl_atom_port_t
*);
343 location
->location
= va_arg(ap
, struct lldpd_med_loc
*);
344 lldpctl_atom_inc_ref((lldpctl_atom_t
*)location
->parent
);
349 _lldpctl_atom_free_med_location(lldpctl_atom_t
*atom
)
351 struct _lldpctl_atom_med_location_t
*location
=
352 (struct _lldpctl_atom_med_location_t
*)atom
;
353 lldpctl_atom_dec_ref((lldpctl_atom_t
*)location
->parent
);
357 _lldpctl_atom_get_int_med_location(lldpctl_atom_t
*atom
, lldpctl_key_t key
)
359 struct _lldpctl_atom_med_location_t
*m
=
360 (struct _lldpctl_atom_med_location_t
*)atom
;
362 /* Local and remote port */
364 case lldpctl_k_med_location_format
:
365 switch (m
->location
->format
) {
366 case LLDP_MED_LOCFORMAT_COORD
:
367 if (m
->location
->data_len
!= 16) break;
368 return LLDP_MED_LOCFORMAT_COORD
;
369 case LLDP_MED_LOCFORMAT_CIVIC
:
370 if ((m
->location
->data_len
< 3) ||
371 (m
->location
->data_len
- 1 < m
->location
->data
[0]))
373 return LLDP_MED_LOCFORMAT_CIVIC
;
374 case LLDP_MED_LOCFORMAT_ELIN
:
375 return LLDP_MED_LOCFORMAT_ELIN
;
379 return SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
380 case lldpctl_k_med_location_geoid
:
381 if (m
->location
->format
!= LLDP_MED_LOCFORMAT_COORD
)
382 return SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
383 return m
->location
->data
[15];
384 case lldpctl_k_med_location_altitude_unit
:
385 if (m
->location
->format
!= LLDP_MED_LOCFORMAT_COORD
)
386 return SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
387 return (m
->location
->data
[10] & 0xf0) >> 4;
389 return SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
393 static lldpctl_atom_t
*
394 _lldpctl_atom_set_int_med_location(lldpctl_atom_t
*atom
, lldpctl_key_t key
,
397 struct _lldpctl_atom_med_location_t
*mloc
=
398 (struct _lldpctl_atom_med_location_t
*)atom
;
400 /* Only local port can be modified */
401 if (!mloc
->parent
->local
) {
402 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
407 case lldpctl_k_med_location_format
:
409 case 0: /* Disabling */
410 case LLDP_MED_LOCFORMAT_COORD
:
411 mloc
->location
->format
= value
;
412 free(mloc
->location
->data
);
413 mloc
->location
->data
= calloc(1, 16);
414 if (mloc
->location
->data
== NULL
) {
415 mloc
->location
->data_len
= 0;
416 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOMEM
);
419 mloc
->location
->data_len
= 16;
421 case LLDP_MED_LOCFORMAT_CIVIC
:
422 mloc
->location
->format
= value
;
423 free(mloc
->location
->data
);
424 mloc
->location
->data
= calloc(1, 4);
425 if (mloc
->location
->data
== NULL
) {
426 mloc
->location
->data_len
= 0;
427 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOMEM
);
430 mloc
->location
->data_len
= 4;
431 mloc
->location
->data
[0] = 3;
432 mloc
->location
->data
[1] = 2; /* Client */
433 mloc
->location
->data
[2] = 'U';
434 mloc
->location
->data
[3] = 'S';
436 case LLDP_MED_LOCFORMAT_ELIN
:
437 mloc
->location
->format
= value
;
438 free(mloc
->location
->data
);
439 mloc
->location
->data
= NULL
;
440 mloc
->location
->data_len
= 0;
445 case lldpctl_k_med_location_geoid
:
446 if (mloc
->location
->format
!= LLDP_MED_LOCFORMAT_COORD
) goto bad
;
447 if (mloc
->location
->data
== NULL
|| mloc
->location
->data_len
!= 16)
451 case LLDP_MED_LOCATION_GEOID_WGS84
:
452 case LLDP_MED_LOCATION_GEOID_NAD83
:
453 case LLDP_MED_LOCATION_GEOID_NAD83_MLLW
:
454 mloc
->location
->data
[15] = value
;
459 case lldpctl_k_med_location_altitude_unit
:
460 if (mloc
->location
->format
!= LLDP_MED_LOCFORMAT_COORD
) goto bad
;
461 if (mloc
->location
->data
== NULL
|| mloc
->location
->data_len
!= 16)
465 case LLDP_MED_LOCATION_ALTITUDE_UNIT_METER
:
466 case LLDP_MED_LOCATION_ALTITUDE_UNIT_FLOOR
:
467 mloc
->location
->data
[10] &= 0x0f;
468 mloc
->location
->data
[10] |= value
<< 4;
474 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
480 SET_ERROR(atom
->conn
, LLDPCTL_ERR_BAD_VALUE
);
485 read_fixed_precision(lldpctl_atom_t
*atom
, char *buffer
, unsigned shift
,
486 unsigned intbits
, unsigned fltbits
, const char *suffix
)
488 struct fp_number fp
=
489 fp_buftofp((unsigned char *)buffer
, intbits
, fltbits
, shift
);
490 char *result
= fp_fptostr(fp
, suffix
);
491 if (result
== NULL
) {
492 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOMEM
);
496 size_t len
= strlen(result
) + 1;
497 char *stored
= _lldpctl_alloc_in_atom(atom
, len
);
498 if (stored
== NULL
) {
502 strlcpy(stored
, result
, len
);
508 _lldpctl_atom_get_str_med_location(lldpctl_atom_t
*atom
, lldpctl_key_t key
)
510 struct _lldpctl_atom_med_location_t
*m
=
511 (struct _lldpctl_atom_med_location_t
*)atom
;
514 /* Local and remote port */
516 case lldpctl_k_med_location_format
:
517 return map_lookup(port_med_location_map
, m
->location
->format
);
518 case lldpctl_k_med_location_geoid
:
519 if (m
->location
->format
!= LLDP_MED_LOCFORMAT_COORD
) break;
520 return map_lookup(port_med_geoid_map
.map
, m
->location
->data
[15]);
521 case lldpctl_k_med_location_latitude
:
522 if (m
->location
->format
!= LLDP_MED_LOCFORMAT_COORD
) break;
523 return read_fixed_precision(atom
, m
->location
->data
, 0, 9, 25, "NS");
524 case lldpctl_k_med_location_longitude
:
525 if (m
->location
->format
!= LLDP_MED_LOCFORMAT_COORD
) break;
526 return read_fixed_precision(atom
, m
->location
->data
, 40, 9, 25, "EW");
527 case lldpctl_k_med_location_altitude
:
528 if (m
->location
->format
!= LLDP_MED_LOCFORMAT_COORD
) break;
529 return read_fixed_precision(atom
, m
->location
->data
, 84, 22, 8, NULL
);
530 case lldpctl_k_med_location_altitude_unit
:
531 if (m
->location
->format
!= LLDP_MED_LOCFORMAT_COORD
) break;
532 switch (m
->location
->data
[10] & 0xf0) {
533 case (LLDP_MED_LOCATION_ALTITUDE_UNIT_METER
<< 4):
535 case (LLDP_MED_LOCATION_ALTITUDE_UNIT_FLOOR
<< 4):
538 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
540 case lldpctl_k_med_location_country
:
541 if (m
->location
->format
!= LLDP_MED_LOCFORMAT_CIVIC
) break;
542 if (m
->location
->data_len
< 4) return NULL
;
543 value
= _lldpctl_alloc_in_atom(atom
, 3);
544 if (!value
) return NULL
;
545 memcpy(value
, m
->location
->data
+ 2, 2);
547 case lldpctl_k_med_location_elin
:
548 if (m
->location
->format
!= LLDP_MED_LOCFORMAT_ELIN
) break;
549 value
= _lldpctl_alloc_in_atom(atom
, m
->location
->data_len
+ 1);
550 if (!value
) return NULL
;
551 memcpy(value
, m
->location
->data
, m
->location
->data_len
);
554 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
557 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
561 static lldpctl_atom_t
*
562 _lldpctl_atom_set_str_med_location(lldpctl_atom_t
*atom
, lldpctl_key_t key
,
565 struct _lldpctl_atom_med_location_t
*mloc
=
566 (struct _lldpctl_atom_med_location_t
*)atom
;
570 /* Only local port can be modified */
571 if (!mloc
->parent
->local
) {
572 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
577 case lldpctl_k_med_location_latitude
:
578 if (mloc
->location
->format
!= LLDP_MED_LOCFORMAT_COORD
) goto bad
;
579 if (mloc
->location
->data
== NULL
|| mloc
->location
->data_len
!= 16)
581 if (value
) fp
= fp_strtofp(value
, &end
, 9, 25);
583 if (end
&& *end
!= '\0') {
584 if (*(end
+ 1) != '\0') goto bad
;
587 else if (*end
!= 'N')
590 fp_fptobuf(fp
, (unsigned char *)mloc
->location
->data
, 0);
592 case lldpctl_k_med_location_longitude
:
593 if (mloc
->location
->format
!= LLDP_MED_LOCFORMAT_COORD
) goto bad
;
594 if (mloc
->location
->data
== NULL
|| mloc
->location
->data_len
!= 16)
596 if (value
) fp
= fp_strtofp(value
, &end
, 9, 25);
598 if (end
&& *end
!= '\0') {
599 if (*(end
+ 1) != '\0') goto bad
;
602 else if (*end
!= 'E')
605 fp_fptobuf(fp
, (unsigned char *)mloc
->location
->data
, 40);
607 case lldpctl_k_med_location_altitude
:
608 if (mloc
->location
->format
!= LLDP_MED_LOCFORMAT_COORD
) goto bad
;
609 if (mloc
->location
->data
== NULL
|| mloc
->location
->data_len
!= 16)
611 if (value
) fp
= fp_strtofp(value
, &end
, 22, 8);
612 if (!end
|| *end
!= '\0') goto bad
;
613 fp_fptobuf(fp
, (unsigned char *)mloc
->location
->data
, 84);
615 case lldpctl_k_med_location_altitude_unit
:
616 if (!value
) goto bad
;
617 if (mloc
->location
->format
!= LLDP_MED_LOCFORMAT_COORD
) goto bad
;
618 if (mloc
->location
->data
== NULL
|| mloc
->location
->data_len
!= 16)
620 if (!strcmp(value
, "m"))
621 return _lldpctl_atom_set_int_med_location(atom
, key
,
622 LLDP_MED_LOCATION_ALTITUDE_UNIT_METER
);
623 if (!strcmp(value
, "f") || (!strcmp(value
, "floor")))
624 return _lldpctl_atom_set_int_med_location(atom
, key
,
625 LLDP_MED_LOCATION_ALTITUDE_UNIT_FLOOR
);
628 case lldpctl_k_med_location_geoid
:
629 return _lldpctl_atom_set_int_med_location(atom
, key
,
630 map_reverse_lookup(port_med_geoid_map
.map
, value
));
631 case lldpctl_k_med_location_country
:
632 if (mloc
->location
->format
!= LLDP_MED_LOCFORMAT_CIVIC
) goto bad
;
633 if (mloc
->location
->data
== NULL
|| mloc
->location
->data_len
< 3)
635 if (!value
|| strlen(value
) != 2) goto bad
;
636 memcpy(mloc
->location
->data
+ 2, value
, 2);
638 case lldpctl_k_med_location_elin
:
639 if (!value
) goto bad
;
640 if (mloc
->location
->format
!= LLDP_MED_LOCFORMAT_ELIN
) goto bad
;
641 free(mloc
->location
->data
);
642 mloc
->location
->data
= calloc(1, strlen(value
));
643 if (mloc
->location
->data
== NULL
) {
644 mloc
->location
->data_len
= 0;
645 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOMEM
);
648 mloc
->location
->data_len
= strlen(value
);
649 memcpy(mloc
->location
->data
, value
, mloc
->location
->data_len
);
652 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
658 SET_ERROR(atom
->conn
, LLDPCTL_ERR_BAD_VALUE
);
662 static lldpctl_atom_t
*
663 _lldpctl_atom_get_atom_med_location(lldpctl_atom_t
*atom
, lldpctl_key_t key
)
665 struct _lldpctl_atom_med_location_t
*m
=
666 (struct _lldpctl_atom_med_location_t
*)atom
;
668 /* Local and remote port */
670 case lldpctl_k_med_location_ca_elements
:
671 if (m
->location
->format
!= LLDP_MED_LOCFORMAT_CIVIC
) {
672 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
675 return _lldpctl_new_atom(atom
->conn
, atom_med_caelements_list
, m
);
677 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
682 static lldpctl_atom_t
*
683 _lldpctl_atom_set_atom_med_location(lldpctl_atom_t
*atom
, lldpctl_key_t key
,
684 lldpctl_atom_t
*value
)
686 struct _lldpctl_atom_med_location_t
*m
=
687 (struct _lldpctl_atom_med_location_t
*)atom
;
688 struct _lldpctl_atom_med_caelement_t
*el
;
691 /* Only local port can be modified */
692 if (!m
->parent
->local
) {
693 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
698 case lldpctl_k_med_location_ca_elements
:
699 if (value
->type
!= atom_med_caelement
) {
700 SET_ERROR(atom
->conn
, LLDPCTL_ERR_INCORRECT_ATOM_TYPE
);
703 if (m
->location
->format
!= LLDP_MED_LOCFORMAT_CIVIC
) goto bad
;
704 if (m
->location
->data
== NULL
|| m
->location
->data_len
< 3) goto bad
;
706 /* We append this element. */
707 el
= (struct _lldpctl_atom_med_caelement_t
*)value
;
708 new = malloc(m
->location
->data_len
+ 2 + el
->len
);
710 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOMEM
);
713 memcpy(new, m
->location
->data
, m
->location
->data_len
);
714 new[m
->location
->data_len
] = el
->type
;
715 new[m
->location
->data_len
+ 1] = el
->len
;
716 memcpy(new + m
->location
->data_len
+ 2, el
->value
, el
->len
);
717 new[0] += 2 + el
->len
;
718 free(m
->location
->data
);
719 m
->location
->data
= (char *)new;
720 m
->location
->data_len
+= 2 + el
->len
;
723 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
727 SET_ERROR(atom
->conn
, LLDPCTL_ERR_BAD_VALUE
);
736 static lldpctl_atom_iter_t
*
737 _lldpctl_atom_iter_med_caelements_list(lldpctl_atom_t
*atom
)
739 struct _lldpctl_atom_med_caelements_list_t
*plist
=
740 (struct _lldpctl_atom_med_caelements_list_t
*)atom
;
741 struct ca_iter
*iter
;
742 if (plist
->parent
->location
->data_len
< 4 ||
743 *(uint8_t *)plist
->parent
->location
->data
< 3 ||
744 !(iter
= _lldpctl_alloc_in_atom(atom
, sizeof(struct ca_iter
))))
746 iter
->data
= (uint8_t *)plist
->parent
->location
->data
+ 4;
747 iter
->data_len
= *(uint8_t *)plist
->parent
->location
->data
- 3;
748 return (lldpctl_atom_iter_t
*)iter
;
751 static lldpctl_atom_iter_t
*
752 _lldpctl_atom_next_med_caelements_list(lldpctl_atom_t
*atom
, lldpctl_atom_iter_t
*iter
)
754 struct ca_iter
*cai
= (struct ca_iter
*)iter
;
756 if (cai
->data_len
< 2) return NULL
;
757 len
= *((uint8_t *)cai
->data
+ 1);
758 if (cai
->data_len
< 2 + len
) return NULL
;
759 cai
->data
+= 2 + len
;
760 cai
->data_len
-= 2 + len
;
761 return (lldpctl_atom_iter_t
*)cai
;
764 static lldpctl_atom_t
*
765 _lldpctl_atom_value_med_caelements_list(lldpctl_atom_t
*atom
, lldpctl_atom_iter_t
*iter
)
767 struct _lldpctl_atom_med_caelements_list_t
*plist
=
768 (struct _lldpctl_atom_med_caelements_list_t
*)atom
;
769 struct ca_iter
*cai
= (struct ca_iter
*)iter
;
771 if (cai
->data_len
< 2) return NULL
;
772 len
= *((uint8_t *)cai
->data
+ 1);
773 if (cai
->data_len
< 2 + len
) return NULL
;
774 return _lldpctl_new_atom(atom
->conn
, atom_med_caelement
, plist
->parent
,
775 (int)*cai
->data
, cai
->data
+ 2, len
);
778 static lldpctl_atom_t
*
779 _lldpctl_atom_create_med_caelements_list(lldpctl_atom_t
*atom
)
781 struct _lldpctl_atom_med_caelements_list_t
*plist
=
782 (struct _lldpctl_atom_med_caelements_list_t
*)atom
;
783 return _lldpctl_new_atom(atom
->conn
, atom_med_caelement
, plist
->parent
, -1,
788 _lldpctl_atom_new_med_caelement(lldpctl_atom_t
*atom
, va_list ap
)
790 struct _lldpctl_atom_med_caelement_t
*el
=
791 (struct _lldpctl_atom_med_caelement_t
*)atom
;
792 el
->parent
= va_arg(ap
, struct _lldpctl_atom_med_location_t
*);
793 el
->type
= va_arg(ap
, int);
794 el
->value
= va_arg(ap
, uint8_t *);
795 el
->len
= va_arg(ap
, size_t);
796 lldpctl_atom_inc_ref((lldpctl_atom_t
*)el
->parent
);
801 _lldpctl_atom_free_med_caelement(lldpctl_atom_t
*atom
)
803 struct _lldpctl_atom_med_caelement_t
*el
=
804 (struct _lldpctl_atom_med_caelement_t
*)atom
;
805 lldpctl_atom_dec_ref((lldpctl_atom_t
*)el
->parent
);
809 _lldpctl_atom_get_int_med_caelement(lldpctl_atom_t
*atom
, lldpctl_key_t key
)
811 struct _lldpctl_atom_med_caelement_t
*m
=
812 (struct _lldpctl_atom_med_caelement_t
*)atom
;
815 case lldpctl_k_med_civicaddress_type
:
818 return SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
822 static lldpctl_atom_t
*
823 _lldpctl_atom_set_int_med_caelement(lldpctl_atom_t
*atom
, lldpctl_key_t key
,
826 struct _lldpctl_atom_med_caelement_t
*el
=
827 (struct _lldpctl_atom_med_caelement_t
*)atom
;
829 /* Only local port can be modified */
830 if (!el
->parent
->parent
->local
) {
831 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
836 case lldpctl_k_med_civicaddress_type
:
837 if (value
< 0 || value
> 128) goto bad
;
841 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
847 SET_ERROR(atom
->conn
, LLDPCTL_ERR_BAD_VALUE
);
852 _lldpctl_atom_get_str_med_caelement(lldpctl_atom_t
*atom
, lldpctl_key_t key
)
855 struct _lldpctl_atom_med_caelement_t
*m
=
856 (struct _lldpctl_atom_med_caelement_t
*)atom
;
858 /* Local and remote port */
860 case lldpctl_k_med_civicaddress_type
:
861 return map_lookup(civic_address_type_map
.map
, m
->type
);
862 case lldpctl_k_med_civicaddress_value
:
863 value
= _lldpctl_alloc_in_atom(atom
, m
->len
+ 1);
864 if (!value
) return NULL
;
865 memcpy(value
, m
->value
, m
->len
);
868 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
873 static lldpctl_atom_t
*
874 _lldpctl_atom_set_str_med_caelement(lldpctl_atom_t
*atom
, lldpctl_key_t key
,
877 struct _lldpctl_atom_med_caelement_t
*el
=
878 (struct _lldpctl_atom_med_caelement_t
*)atom
;
881 /* Only local port can be modified */
882 if (!el
->parent
->parent
->local
) {
883 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
888 case lldpctl_k_med_civicaddress_value
:
889 if (!value
) goto bad
;
890 len
= strlen(value
) + 1;
891 if (len
> 251) goto bad
;
892 el
->value
= _lldpctl_alloc_in_atom(atom
, len
);
893 if (el
->value
== NULL
) return NULL
;
894 strlcpy((char *)el
->value
, value
, len
);
895 el
->len
= strlen(value
);
897 case lldpctl_k_med_civicaddress_type
:
898 return _lldpctl_atom_set_int_med_caelement(atom
, key
,
899 map_reverse_lookup(civic_address_type_map
.map
, value
));
901 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
907 SET_ERROR(atom
->conn
, LLDPCTL_ERR_BAD_VALUE
);
912 _lldpctl_atom_new_med_power(lldpctl_atom_t
*atom
, va_list ap
)
914 struct _lldpctl_atom_med_power_t
*mpow
=
915 (struct _lldpctl_atom_med_power_t
*)atom
;
916 mpow
->parent
= va_arg(ap
, struct _lldpctl_atom_port_t
*);
917 lldpctl_atom_inc_ref((lldpctl_atom_t
*)mpow
->parent
);
922 _lldpctl_atom_free_med_power(lldpctl_atom_t
*atom
)
924 struct _lldpctl_atom_med_power_t
*mpow
=
925 (struct _lldpctl_atom_med_power_t
*)atom
;
926 lldpctl_atom_dec_ref((lldpctl_atom_t
*)mpow
->parent
);
930 _lldpctl_atom_get_str_med_power(lldpctl_atom_t
*atom
, lldpctl_key_t key
)
932 struct _lldpctl_atom_med_power_t
*mpow
=
933 (struct _lldpctl_atom_med_power_t
*)atom
;
934 struct lldpd_port
*port
= mpow
->parent
->port
;
936 /* Local and remote port */
938 case lldpctl_k_med_power_type
:
939 return map_lookup(port_med_pow_devicetype_map
,
940 port
->p_med_power
.devicetype
);
941 case lldpctl_k_med_power_source
:
942 return map_lookup(port_med_pow_source_map
, port
->p_med_power
.source
);
943 case lldpctl_k_med_power_priority
:
944 return map_lookup(port_med_pow_priority_map
.map
,
945 port
->p_med_power
.priority
);
947 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
953 _lldpctl_atom_get_int_med_power(lldpctl_atom_t
*atom
, lldpctl_key_t key
)
955 struct _lldpctl_atom_med_power_t
*dpow
=
956 (struct _lldpctl_atom_med_power_t
*)atom
;
957 struct lldpd_port
*port
= dpow
->parent
->port
;
959 /* Local and remote port */
961 case lldpctl_k_med_power_type
:
962 return port
->p_med_power
.devicetype
;
963 case lldpctl_k_med_power_source
:
964 return port
->p_med_power
.source
;
965 case lldpctl_k_med_power_priority
:
966 return port
->p_med_power
.priority
;
967 case lldpctl_k_med_power_val
:
968 return port
->p_med_power
.val
* 100;
970 return SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
974 static lldpctl_atom_t
*
975 _lldpctl_atom_set_int_med_power(lldpctl_atom_t
*atom
, lldpctl_key_t key
, long int value
)
977 struct _lldpctl_atom_med_power_t
*dpow
=
978 (struct _lldpctl_atom_med_power_t
*)atom
;
979 struct lldpd_port
*port
= dpow
->parent
->port
;
981 /* Only local port can be modified */
982 if (!dpow
->parent
->local
) {
983 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
988 case lldpctl_k_med_power_type
:
991 case LLDP_MED_POW_TYPE_PSE
:
992 case LLDP_MED_POW_TYPE_PD
:
993 port
->p_med_power
.devicetype
= value
;
998 case lldpctl_k_med_power_source
:
1000 case LLDP_MED_POW_SOURCE_PRIMARY
:
1001 case LLDP_MED_POW_SOURCE_BACKUP
:
1002 if (port
->p_med_power
.devicetype
!= LLDP_MED_POW_TYPE_PSE
)
1004 port
->p_med_power
.source
= value
;
1006 case LLDP_MED_POW_SOURCE_PSE
:
1007 case LLDP_MED_POW_SOURCE_LOCAL
:
1008 case LLDP_MED_POW_SOURCE_BOTH
:
1009 if (port
->p_med_power
.devicetype
!= LLDP_MED_POW_TYPE_PD
)
1011 port
->p_med_power
.source
= value
;
1013 case LLDP_MED_POW_SOURCE_UNKNOWN
:
1014 port
->p_med_power
.source
= value
;
1019 case lldpctl_k_med_power_priority
:
1020 if (value
< 0 || value
> 3) goto bad
;
1021 port
->p_med_power
.priority
= value
;
1023 case lldpctl_k_med_power_val
:
1024 if (value
< 0) goto bad
;
1025 port
->p_med_power
.val
= value
/ 100;
1028 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
1034 SET_ERROR(atom
->conn
, LLDPCTL_ERR_BAD_VALUE
);
1038 static lldpctl_atom_t
*
1039 _lldpctl_atom_set_str_med_power(lldpctl_atom_t
*atom
, lldpctl_key_t key
,
1043 case lldpctl_k_med_power_type
:
1044 return _lldpctl_atom_set_int_med_power(atom
, key
,
1045 map_reverse_lookup(port_med_pow_devicetype_map
, value
));
1046 case lldpctl_k_med_power_source
:
1047 return _lldpctl_atom_set_int_med_power(atom
, key
,
1048 map_reverse_lookup(port_med_pow_source_map2
, value
));
1049 case lldpctl_k_med_power_priority
:
1050 return _lldpctl_atom_set_int_med_power(atom
, key
,
1051 map_reverse_lookup(port_med_pow_priority_map
.map
, value
));
1053 SET_ERROR(atom
->conn
, LLDPCTL_ERR_NOT_EXIST
);
1058 static struct atom_builder med_policies_list
= { atom_med_policies_list
,
1059 sizeof(struct _lldpctl_atom_any_list_t
), .init
= _lldpctl_atom_new_any_list
,
1060 .free
= _lldpctl_atom_free_any_list
,
1061 .iter
= _lldpctl_atom_iter_med_policies_list
,
1062 .next
= _lldpctl_atom_next_med_policies_list
,
1063 .value
= _lldpctl_atom_value_med_policies_list
};
1065 static struct atom_builder med_policy
= { atom_med_policy
,
1066 sizeof(struct _lldpctl_atom_med_policy_t
), .init
= _lldpctl_atom_new_med_policy
,
1067 .free
= _lldpctl_atom_free_med_policy
,
1068 .get_int
= _lldpctl_atom_get_int_med_policy
,
1069 .set_int
= _lldpctl_atom_set_int_med_policy
,
1070 .get_str
= _lldpctl_atom_get_str_med_policy
,
1071 .set_str
= _lldpctl_atom_set_str_med_policy
};
1073 static struct atom_builder med_locations_list
= { atom_med_locations_list
,
1074 sizeof(struct _lldpctl_atom_any_list_t
), .init
= _lldpctl_atom_new_any_list
,
1075 .free
= _lldpctl_atom_free_any_list
,
1076 .iter
= _lldpctl_atom_iter_med_locations_list
,
1077 .next
= _lldpctl_atom_next_med_locations_list
,
1078 .value
= _lldpctl_atom_value_med_locations_list
};
1080 static struct atom_builder med_location
= { atom_med_location
,
1081 sizeof(struct _lldpctl_atom_med_location_t
),
1082 .init
= _lldpctl_atom_new_med_location
, .free
= _lldpctl_atom_free_med_location
,
1083 .get
= _lldpctl_atom_get_atom_med_location
,
1084 .set
= _lldpctl_atom_set_atom_med_location
,
1085 .get_int
= _lldpctl_atom_get_int_med_location
,
1086 .set_int
= _lldpctl_atom_set_int_med_location
,
1087 .get_str
= _lldpctl_atom_get_str_med_location
,
1088 .set_str
= _lldpctl_atom_set_str_med_location
};
1090 static struct atom_builder med_caelements_list
= { atom_med_caelements_list
,
1091 sizeof(struct _lldpctl_atom_med_caelements_list_t
),
1092 .init
= _lldpctl_atom_new_any_list
, .free
= _lldpctl_atom_free_any_list
,
1093 .iter
= _lldpctl_atom_iter_med_caelements_list
,
1094 .next
= _lldpctl_atom_next_med_caelements_list
,
1095 .value
= _lldpctl_atom_value_med_caelements_list
,
1096 .create
= _lldpctl_atom_create_med_caelements_list
};
1098 static struct atom_builder med_caelement
= { atom_med_caelement
,
1099 sizeof(struct _lldpctl_atom_med_caelement_t
),
1100 .init
= _lldpctl_atom_new_med_caelement
,
1101 .free
= _lldpctl_atom_free_med_caelement
,
1102 .get_int
= _lldpctl_atom_get_int_med_caelement
,
1103 .set_int
= _lldpctl_atom_set_int_med_caelement
,
1104 .get_str
= _lldpctl_atom_get_str_med_caelement
,
1105 .set_str
= _lldpctl_atom_set_str_med_caelement
};
1107 static struct atom_builder med_power
= { atom_med_power
,
1108 sizeof(struct _lldpctl_atom_med_power_t
), .init
= _lldpctl_atom_new_med_power
,
1109 .free
= _lldpctl_atom_free_med_power
,
1110 .get_int
= _lldpctl_atom_get_int_med_power
,
1111 .set_int
= _lldpctl_atom_set_int_med_power
,
1112 .get_str
= _lldpctl_atom_get_str_med_power
,
1113 .set_str
= _lldpctl_atom_set_str_med_power
};
1115 ATOM_BUILDER_REGISTER(med_policies_list
, 15);
1116 ATOM_BUILDER_REGISTER(med_policy
, 16);
1117 ATOM_BUILDER_REGISTER(med_locations_list
, 17);
1118 ATOM_BUILDER_REGISTER(med_location
, 18);
1119 ATOM_BUILDER_REGISTER(med_caelements_list
, 19);
1120 ATOM_BUILDER_REGISTER(med_caelement
, 20);
1121 ATOM_BUILDER_REGISTER(med_power
, 21);