]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/lib/atoms/med.c
client: update LLDP-MED policy L2 priority values to match 802.1Q-2005
[thirdparty/lldpd.git] / src / lib / atoms / med.c
CommitLineData
94c98157
AA
1/* -*- mode: c; c-file-style: "openbsd" -*- */
2/*
3 * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <stdio.h>
19#include <stdarg.h>
20#include <string.h>
21#include <arpa/inet.h>
22
23#include "lldpctl.h"
94c98157 24#include "../log.h"
a5f98717 25#include "atom.h"
94c98157
AA
26#include "helpers.h"
27#include "fixedpoint.h"
28
29#ifdef ENABLE_LLDPMED
30
31static 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" },
35 { 0, NULL },
36};
37
38static lldpctl_map_t port_med_pow_devicetype_map[] = {
39 { LLDP_MED_POW_TYPE_PSE, "PSE" },
40 { LLDP_MED_POW_TYPE_PD, "PD" },
41 { 0, NULL },
42};
43
44static 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"},
50 { 0, NULL },
51};
52
53static lldpctl_map_t port_med_pow_source_map2[] = {
54 { 0, "unknown" },
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" },
60 { 0, NULL },
61};
62
63static struct atom_map port_med_geoid_map = {
64 .key = lldpctl_k_med_location_geoid,
65 .map = {
66 { LLDP_MED_LOCATION_GEOID_WGS84, "WGS84" },
67 { LLDP_MED_LOCATION_GEOID_NAD83, "NAD83" },
68 { LLDP_MED_LOCATION_GEOID_NAD83_MLLW, "NAD83/MLLW" },
69 { 0, NULL },
70 },
71};
72
73static struct atom_map civic_address_type_map = {
74 .key = lldpctl_k_med_civicaddress_type,
75 .map = {
76 { 0, "Language" },
77 { 1, "Country subdivision" },
78 { 2, "County" },
79 { 3, "City" },
80 { 4, "City division" },
81 { 5, "Block" },
82 { 6, "Street" },
83 { 16, "Direction" },
84 { 17, "Trailing street suffix" },
85 { 18, "Street suffix" },
86 { 19, "Number" },
87 { 20, "Number suffix" },
88 { 21, "Landmark" },
89 { 22, "Additional" },
90 { 23, "Name" },
91 { 24, "ZIP" },
92 { 25, "Building" },
93 { 26, "Unit" },
94 { 27, "Floor" },
95 { 28, "Room" },
96 { 29, "Place type" },
97 { 128, "Script" },
98 { 0, NULL },
99 },
100};
101
102static struct atom_map port_med_policy_map = {
103 .key = lldpctl_k_med_policy_type,
104 .map = {
105 { LLDP_MED_APPTYPE_VOICE , "Voice"},
106 { LLDP_MED_APPTYPE_VOICESIGNAL, "Voice Signaling"},
107 { LLDP_MED_APPTYPE_GUESTVOICE, "Guest Voice"},
108 { LLDP_MED_APPTYPE_GUESTVOICESIGNAL, "Guest Voice Signaling"},
109 { LLDP_MED_APPTYPE_SOFTPHONEVOICE, "Softphone Voice"},
110 { LLDP_MED_APPTYPE_VIDEOCONFERENCE, "Video Conferencing"},
111 { LLDP_MED_APPTYPE_VIDEOSTREAM, "Streaming Video"},
112 { LLDP_MED_APPTYPE_VIDEOSIGNAL, "Video Signaling"},
113 { 0, NULL },
114 }
115};
116
117static struct atom_map port_med_policy_prio_map = {
118 .key = lldpctl_k_med_policy_priority,
119 .map = {
e7f83dc0 120 { 1, "Background" },
e7f83dc0 121 { 0, "Best effort" },
c56e4067
VB
122 { 2, "Excellent effort" },
123 { 3, "Critical applications" },
124 { 4, "Video" },
125 { 5, "Voice" },
126 { 6, "Internetwork control" },
94c98157
AA
127 { 7, "Network control" },
128 { 0, NULL },
129 },
130};
131
132static struct atom_map port_med_pow_priority_map = {
133 .key = lldpctl_k_med_power_priority,
134 .map = {
135 { 0, "unknown" },
136 { LLDP_MED_POW_PRIO_CRITICAL, "critical" },
137 { LLDP_MED_POW_PRIO_HIGH, "high" },
138 { LLDP_MED_POW_PRIO_LOW, "low" },
139 { 0, NULL },
140 },
141};
142
143ATOM_MAP_REGISTER(port_med_geoid_map, 7);
144ATOM_MAP_REGISTER(civic_address_type_map, 8);
145ATOM_MAP_REGISTER(port_med_policy_map, 9);
146ATOM_MAP_REGISTER(port_med_policy_prio_map, 10);
147ATOM_MAP_REGISTER(port_med_pow_priority_map, 11);
148
149static lldpctl_atom_iter_t*
150_lldpctl_atom_iter_med_policies_list(lldpctl_atom_t *atom)
151{
152 int i;
153 struct _lldpctl_atom_any_list_t *vlist =
154 (struct _lldpctl_atom_any_list_t *)atom;
155 for (i = 0; i < LLDP_MED_APPTYPE_LAST; i++)
156 vlist->parent->port->p_med_policy[i].index = i;
157 return (lldpctl_atom_iter_t*)&vlist->parent->port->p_med_policy[0];
158}
159
160static lldpctl_atom_iter_t*
161_lldpctl_atom_next_med_policies_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
162{
163 struct lldpd_med_policy *policy = (struct lldpd_med_policy *)iter;
164 if (policy->index == LLDP_MED_APPTYPE_LAST - 1) return NULL;
165 return (lldpctl_atom_iter_t*)(++policy);
166}
167
168static lldpctl_atom_t*
169_lldpctl_atom_value_med_policies_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
170{
171 struct _lldpctl_atom_any_list_t *vlist =
172 (struct _lldpctl_atom_any_list_t *)atom;
173 struct lldpd_med_policy *policy = (struct lldpd_med_policy *)iter;
174 return _lldpctl_new_atom(atom->conn, atom_med_policy, vlist->parent, policy);
175}
176
177static int
178_lldpctl_atom_new_med_policy(lldpctl_atom_t *atom, va_list ap)
179{
180 struct _lldpctl_atom_med_policy_t *policy =
181 (struct _lldpctl_atom_med_policy_t *)atom;
182 policy->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
183 policy->policy = va_arg(ap, struct lldpd_med_policy *);
184 lldpctl_atom_inc_ref((lldpctl_atom_t *)policy->parent);
185 return 1;
186}
187
188static void
189_lldpctl_atom_free_med_policy(lldpctl_atom_t *atom)
190{
191 struct _lldpctl_atom_med_policy_t *policy =
192 (struct _lldpctl_atom_med_policy_t *)atom;
193 lldpctl_atom_dec_ref((lldpctl_atom_t *)policy->parent);
194}
195
196static long int
197_lldpctl_atom_get_int_med_policy(lldpctl_atom_t *atom, lldpctl_key_t key)
198{
199 struct _lldpctl_atom_med_policy_t *m =
200 (struct _lldpctl_atom_med_policy_t *)atom;
201
202 /* Local and remote port */
203 switch (key) {
204 case lldpctl_k_med_policy_type:
205 return m->policy->type;
206 case lldpctl_k_med_policy_unknown:
207 return m->policy->unknown;
208 case lldpctl_k_med_policy_tagged:
209 return m->policy->tagged;
210 case lldpctl_k_med_policy_vid:
211 return m->policy->vid;
212 case lldpctl_k_med_policy_dscp:
213 return m->policy->dscp;
214 case lldpctl_k_med_policy_priority:
215 return m->policy->priority;
216 default:
217 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
218 }
219}
220
221static lldpctl_atom_t*
222_lldpctl_atom_set_int_med_policy(lldpctl_atom_t *atom, lldpctl_key_t key,
223 long int value)
224{
225 struct _lldpctl_atom_med_policy_t *m =
226 (struct _lldpctl_atom_med_policy_t *)atom;
227
228 /* Only local port can be modified */
9da663f7 229 if (!m->parent->local) {
94c98157
AA
230 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
231 return NULL;
232 }
233
234 switch (key) {
235 case lldpctl_k_med_policy_type:
236 /* We let set any policy type, including one whose are not
237 * compatible with the index. If a policy type is set, the index
238 * will be ignored. If a policy type is 0, the index will be
239 * used to know which policy to "erase". */
240 if (value < 0 || value > LLDP_MED_APPTYPE_LAST) goto bad;
241 m->policy->type = value;
242 return atom;
243 case lldpctl_k_med_policy_unknown:
244 if (value != 0 && value != 1) goto bad;
245 m->policy->unknown = value;
246 return atom;
247 case lldpctl_k_med_policy_tagged:
248 if (value != 0 && value != 1) goto bad;
249 m->policy->tagged = value;
250 return atom;
251 case lldpctl_k_med_policy_vid:
252 if (value < 0 || value > 4094) goto bad;
253 m->policy->vid = value;
254 return atom;
255 case lldpctl_k_med_policy_dscp:
256 if (value < 0 || value > 63) goto bad;
257 m->policy->dscp = value;
258 return atom;
259 case lldpctl_k_med_policy_priority:
260 if (value < 0 || value > 7) goto bad;
261 m->policy->priority = value;
262 return atom;
263 default:
264 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
265 return NULL;
266 }
267
268 return atom;
269bad:
270 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
271 return NULL;
272}
273
274static const char*
275_lldpctl_atom_get_str_med_policy(lldpctl_atom_t *atom, lldpctl_key_t key)
276{
277 struct _lldpctl_atom_med_policy_t *m =
278 (struct _lldpctl_atom_med_policy_t *)atom;
279
280 /* Local and remote port */
281 switch (key) {
282 case lldpctl_k_med_policy_type:
283 return map_lookup(port_med_policy_map.map, m->policy->type);
284 case lldpctl_k_med_policy_priority:
285 return map_lookup(port_med_policy_prio_map.map, m->policy->priority);
286 default:
287 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
288 return NULL;
289 }
290}
291
292static lldpctl_atom_t*
293_lldpctl_atom_set_str_med_policy(lldpctl_atom_t *atom, lldpctl_key_t key,
294 const char *value)
295{
296 /* Local and remote port */
297 switch (key) {
298 case lldpctl_k_med_policy_type:
299 return _lldpctl_atom_set_int_med_policy(atom, key,
300 map_reverse_lookup(port_med_policy_map.map, value));
301 case lldpctl_k_med_policy_priority:
302 return _lldpctl_atom_set_int_med_policy(atom, key,
303 map_reverse_lookup(port_med_policy_prio_map.map, value));
304 default:
305 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
306 return NULL;
307 }
308}
309
310static lldpctl_atom_iter_t*
311_lldpctl_atom_iter_med_locations_list(lldpctl_atom_t *atom)
312{
313 int i;
314 struct _lldpctl_atom_any_list_t *vlist =
315 (struct _lldpctl_atom_any_list_t *)atom;
316 for (i = 0; i < LLDP_MED_LOCFORMAT_LAST; i++)
317 vlist->parent->port->p_med_location[i].index = i;
318 return (lldpctl_atom_iter_t*)&vlist->parent->port->p_med_location[0];
319}
320
321static lldpctl_atom_iter_t*
322_lldpctl_atom_next_med_locations_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
323{
324 struct lldpd_med_loc *location = (struct lldpd_med_loc *)iter;
325 if (location->index == LLDP_MED_LOCFORMAT_LAST - 1) return NULL;
326 return (lldpctl_atom_iter_t*)(++location);
327}
328
329static lldpctl_atom_t*
330_lldpctl_atom_value_med_locations_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
331{
332 struct _lldpctl_atom_any_list_t *vlist =
333 (struct _lldpctl_atom_any_list_t *)atom;
334 struct lldpd_med_loc *location = (struct lldpd_med_loc *)iter;
335 return _lldpctl_new_atom(atom->conn, atom_med_location, vlist->parent, location);
336}
337
338static int
339_lldpctl_atom_new_med_location(lldpctl_atom_t *atom, va_list ap)
340{
341 struct _lldpctl_atom_med_location_t *location =
342 (struct _lldpctl_atom_med_location_t *)atom;
343 location->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
344 location->location = va_arg(ap, struct lldpd_med_loc *);
345 lldpctl_atom_inc_ref((lldpctl_atom_t *)location->parent);
346 return 1;
347}
348
349static void
350_lldpctl_atom_free_med_location(lldpctl_atom_t *atom)
351{
352 struct _lldpctl_atom_med_location_t *location =
353 (struct _lldpctl_atom_med_location_t *)atom;
354 lldpctl_atom_dec_ref((lldpctl_atom_t *)location->parent);
355}
356
357static long int
358_lldpctl_atom_get_int_med_location(lldpctl_atom_t *atom, lldpctl_key_t key)
359{
360 struct _lldpctl_atom_med_location_t *m =
361 (struct _lldpctl_atom_med_location_t *)atom;
362
363 /* Local and remote port */
364 switch (key) {
365 case lldpctl_k_med_location_format:
366 switch (m->location->format) {
367 case LLDP_MED_LOCFORMAT_COORD:
368 if (m->location->data_len != 16) break;
369 return LLDP_MED_LOCFORMAT_COORD;
370 case LLDP_MED_LOCFORMAT_CIVIC:
371 if ((m->location->data_len < 3) ||
372 (m->location->data_len - 1 !=
373 m->location->data[0])) break;
374 return LLDP_MED_LOCFORMAT_CIVIC;
375 case LLDP_MED_LOCFORMAT_ELIN:
376 return LLDP_MED_LOCFORMAT_ELIN;
377 default:
378 return 0;
379 }
380 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
381 case lldpctl_k_med_location_geoid:
382 if (m->location->format != LLDP_MED_LOCFORMAT_COORD)
383 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
384 return m->location->data[15];
385 case lldpctl_k_med_location_altitude_unit:
386 if (m->location->format != LLDP_MED_LOCFORMAT_COORD)
387 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
388 return (m->location->data[10] & 0xf0) >> 4;
389 default:
390 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
391 }
392}
393
394static lldpctl_atom_t*
395_lldpctl_atom_set_int_med_location(lldpctl_atom_t *atom, lldpctl_key_t key,
396 long int value)
397{
398 struct _lldpctl_atom_med_location_t *mloc =
399 (struct _lldpctl_atom_med_location_t *)atom;
400
401 /* Only local port can be modified */
9da663f7 402 if (!mloc->parent->local) {
94c98157
AA
403 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
404 return NULL;
405 }
406
407 switch (key) {
408 case lldpctl_k_med_location_format:
409 switch (value) {
410 case 0: /* Disabling */
411 case LLDP_MED_LOCFORMAT_COORD:
412 mloc->location->format = value;
413 free(mloc->location->data);
414 mloc->location->data = calloc(1, 16);
415 if (mloc->location->data == NULL) {
416 mloc->location->data_len = 0;
417 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
418 return NULL;
419 }
420 mloc->location->data_len = 16;
421 return atom;
422 case LLDP_MED_LOCFORMAT_CIVIC:
423 mloc->location->format = value;
424 free(mloc->location->data);
425 mloc->location->data = calloc(1, 4);
426 if (mloc->location->data == NULL) {
427 mloc->location->data_len = 0;
428 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
429 return NULL;
430 }
431 mloc->location->data_len = 4;
432 mloc->location->data[0] = 3;
433 mloc->location->data[1] = 2; /* Client */
434 mloc->location->data[2] = 'U';
435 mloc->location->data[3] = 'S';
436 return atom;
437 case LLDP_MED_LOCFORMAT_ELIN:
438 mloc->location->format = value;
439 free(mloc->location->data);
440 mloc->location->data = NULL;
441 mloc->location->data_len = 0;
442 return atom;
443 default: goto bad;
444 }
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) goto bad;
448 switch (value) {
449 case 0:
450 case LLDP_MED_LOCATION_GEOID_WGS84:
451 case LLDP_MED_LOCATION_GEOID_NAD83:
452 case LLDP_MED_LOCATION_GEOID_NAD83_MLLW:
453 mloc->location->data[15] = value;
454 return atom;
455 default: goto bad;
456 }
457 case lldpctl_k_med_location_altitude_unit:
458 if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
459 if (mloc->location->data == NULL || mloc->location->data_len != 16) goto bad;
460 switch (value) {
461 case 0:
462 case LLDP_MED_LOCATION_ALTITUDE_UNIT_METER:
463 case LLDP_MED_LOCATION_ALTITUDE_UNIT_FLOOR:
464 mloc->location->data[10] &= 0x0f;
465 mloc->location->data[10] |= value << 4;
466 return atom;
467 default: goto bad;
468 }
469 default:
470 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
471 return NULL;
472 }
473
474 return atom;
475bad:
476 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
477 return NULL;
478
479}
480
481static const char*
482read_fixed_precision(lldpctl_atom_t *atom,
483 char *buffer, unsigned shift,
484 unsigned intbits, unsigned fltbits, const char *suffix)
485{
486 struct fp_number fp = fp_buftofp((unsigned char*)buffer, intbits, fltbits, shift);
487 char *result = fp_fptostr(fp, suffix);
488 if (result == NULL) {
489 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
490 return NULL;
491 }
492
493 size_t len = strlen(result) + 1;
494 char *stored = _lldpctl_alloc_in_atom(atom, len);
495 if (stored == NULL) {
496 free(result);
497 return NULL;
498 }
499 strlcpy(stored, result, len);
fa289087 500 free(result);
94c98157
AA
501 return stored;
502}
503
504static const char*
505_lldpctl_atom_get_str_med_location(lldpctl_atom_t *atom, lldpctl_key_t key)
506{
507 struct _lldpctl_atom_med_location_t *m =
508 (struct _lldpctl_atom_med_location_t *)atom;
509 char *value;
510
511 /* Local and remote port */
512 switch (key) {
513 case lldpctl_k_med_location_format:
514 return map_lookup(port_med_location_map, m->location->format);
515 case lldpctl_k_med_location_geoid:
516 if (m->location->format != LLDP_MED_LOCFORMAT_COORD) break;
517 return map_lookup(port_med_geoid_map.map,
518 m->location->data[15]);
519 case lldpctl_k_med_location_latitude:
520 if (m->location->format != LLDP_MED_LOCFORMAT_COORD) break;
521 return read_fixed_precision(atom, m->location->data,
522 0, 9, 25, "NS");
523 case lldpctl_k_med_location_longitude:
524 if (m->location->format != LLDP_MED_LOCFORMAT_COORD) break;
525 return read_fixed_precision(atom, m->location->data,
526 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,
530 84, 22, 8, NULL);
531 case lldpctl_k_med_location_altitude_unit:
532 if (m->location->format != LLDP_MED_LOCFORMAT_COORD) break;
533 switch (m->location->data[10] & 0xf0) {
534 case (LLDP_MED_LOCATION_ALTITUDE_UNIT_METER << 4):
535 return "m";
536 case (LLDP_MED_LOCATION_ALTITUDE_UNIT_FLOOR << 4):
537 return "floor";
538 }
539 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
540 return NULL;
541 case lldpctl_k_med_location_country:
542 if (m->location->format != LLDP_MED_LOCFORMAT_CIVIC) break;
543 value = _lldpctl_alloc_in_atom(atom, 3);
544 if (!value) return NULL;
545 memcpy(value, m->location->data + 2, 2);
546 return value;
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);
552 return value;
553 default:
554 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
555 return NULL;
556 }
557 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
558 return NULL;
559}
560
561static lldpctl_atom_t*
562_lldpctl_atom_set_str_med_location(lldpctl_atom_t *atom, lldpctl_key_t key,
563 const char *value)
564{
565 struct _lldpctl_atom_med_location_t *mloc =
566 (struct _lldpctl_atom_med_location_t *)atom;
567 struct fp_number fp;
568 char *end = NULL;
569
570 /* Only local port can be modified */
9da663f7 571 if (!mloc->parent->local) {
94c98157
AA
572 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
573 return NULL;
574 }
575
576 switch (key) {
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) goto bad;
580 if (value) fp = fp_strtofp(value, &end, 9, 25);
581 if (!end) goto bad;
582 if (end && *end != '\0') {
583 if (*(end+1) != '\0') goto bad;
584 if (*end == 'S') fp = fp_negate(fp);
585 else if (*end != 'N') goto bad;
586 }
587 fp_fptobuf(fp, (unsigned char*)mloc->location->data, 0);
588 return atom;
589 case lldpctl_k_med_location_longitude:
590 if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
591 if (mloc->location->data == NULL || mloc->location->data_len != 16) goto bad;
592 if (value) fp = fp_strtofp(value, &end, 9, 25);
593 if (!end) goto bad;
594 if (end && *end != '\0') {
595 if (*(end+1) != '\0') goto bad;
596 if (*end == 'W') fp = fp_negate(fp);
597 else if (*end != 'E') goto bad;
598 }
599 fp_fptobuf(fp, (unsigned char*)mloc->location->data, 40);
600 return atom;
601 case lldpctl_k_med_location_altitude:
602 if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
603 if (mloc->location->data == NULL || mloc->location->data_len != 16) goto bad;
604 if (value) fp = fp_strtofp(value, &end, 22, 8);
605 if (!end || *end != '\0') goto bad;
606 fp_fptobuf(fp, (unsigned char*)mloc->location->data, 84);
607 return atom;
608 case lldpctl_k_med_location_altitude_unit:
609 if (!value) goto bad;
610 if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
611 if (mloc->location->data == NULL || mloc->location->data_len != 16) goto bad;
612 if (!strcmp(value, "m"))
613 return _lldpctl_atom_set_int_med_location(atom, key,
614 LLDP_MED_LOCATION_ALTITUDE_UNIT_METER);
615 if (!strcmp(value, "f") ||
616 (!strcmp(value, "floor")))
617 return _lldpctl_atom_set_int_med_location(atom, key,
618 LLDP_MED_LOCATION_ALTITUDE_UNIT_FLOOR);
619 goto bad;
620 break;
621 case lldpctl_k_med_location_geoid:
622 return _lldpctl_atom_set_int_med_location(atom, key,
623 map_reverse_lookup(port_med_geoid_map.map, value));
624 case lldpctl_k_med_location_country:
625 if (mloc->location->format != LLDP_MED_LOCFORMAT_CIVIC) goto bad;
626 if (mloc->location->data == NULL || mloc->location->data_len < 3) goto bad;
627 if (!value || strlen(value) != 2) goto bad;
628 memcpy(mloc->location->data + 2, value, 2);
629 return atom;
630 case lldpctl_k_med_location_elin:
631 if (!value) goto bad;
632 if (mloc->location->format != LLDP_MED_LOCFORMAT_ELIN) goto bad;
633 free(mloc->location->data);
634 mloc->location->data = calloc(1, strlen(value));
635 if (mloc->location->data == NULL) {
636 mloc->location->data_len = 0;
637 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
638 return NULL;
639 }
640 mloc->location->data_len = strlen(value);
641 memcpy(mloc->location->data, value,
642 mloc->location->data_len);
643 return atom;
644 default:
645 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
646 return NULL;
647 }
648
649 return atom;
650bad:
651 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
652 return NULL;
653
654}
655
656static lldpctl_atom_t*
657_lldpctl_atom_get_atom_med_location(lldpctl_atom_t *atom, lldpctl_key_t key)
658{
659 struct _lldpctl_atom_med_location_t *m =
660 (struct _lldpctl_atom_med_location_t *)atom;
661
662 /* Local and remote port */
663 switch (key) {
664 case lldpctl_k_med_location_ca_elements:
665 if (m->location->format != LLDP_MED_LOCFORMAT_CIVIC) {
666 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
667 return NULL;
668 }
669 return _lldpctl_new_atom(atom->conn, atom_med_caelements_list, m);
670 default:
671 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
672 return NULL;
673 }
674}
675
676static lldpctl_atom_t*
677_lldpctl_atom_set_atom_med_location(lldpctl_atom_t *atom, lldpctl_key_t key,
678 lldpctl_atom_t *value)
679{
680 struct _lldpctl_atom_med_location_t *m =
681 (struct _lldpctl_atom_med_location_t *)atom;
682 struct _lldpctl_atom_med_caelement_t *el;
683 uint8_t *new;
684
685 /* Only local port can be modified */
9da663f7 686 if (!m->parent->local) {
94c98157
AA
687 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
688 return NULL;
689 }
690
691 switch (key) {
692 case lldpctl_k_med_location_ca_elements:
693 if (value->type != atom_med_caelement) {
694 SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
695 return NULL;
696 }
697 if (m->location->format != LLDP_MED_LOCFORMAT_CIVIC) goto bad;
698 if (m->location->data == NULL || m->location->data_len < 3) goto bad;
699
700 /* We append this element. */
701 el = (struct _lldpctl_atom_med_caelement_t *)value;
702 new = malloc(m->location->data_len + 2 + el->len);
703 if (new == NULL) {
704 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
705 return NULL;
706 }
707 memcpy(new, m->location->data, m->location->data_len);
708 new[m->location->data_len] = el->type;
709 new[m->location->data_len + 1] = el->len;
710 memcpy(new + m->location->data_len + 2, el->value, el->len);
711 new[0] += 2 + el->len;
712 free(m->location->data);
713 m->location->data = (char*)new;
714 m->location->data_len += 2 + el->len;
715 return atom;
716 default:
717 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
718 return NULL;
719 }
720bad:
721 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
722 return NULL;
723}
724
725struct ca_iter {
726 uint8_t *data;
727 size_t data_len;
728};
729
730static lldpctl_atom_iter_t*
731_lldpctl_atom_iter_med_caelements_list(lldpctl_atom_t *atom)
732{
733 struct _lldpctl_atom_med_caelements_list_t *plist =
734 (struct _lldpctl_atom_med_caelements_list_t *)atom;
735 struct ca_iter *iter = _lldpctl_alloc_in_atom(atom, sizeof(struct ca_iter));
736 if (!iter) return NULL;
737 iter->data = (uint8_t*)plist->parent->location->data + 4;
738 iter->data_len = plist->parent->location->data_len - 4;
739 return (lldpctl_atom_iter_t*)iter;
740}
741
742static lldpctl_atom_iter_t*
743_lldpctl_atom_next_med_caelements_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
744{
745 struct ca_iter *cai = (struct ca_iter *)iter;
746 int len;
747 if (cai->data_len < 2) return NULL;
748 len = *((uint8_t *)cai->data + 1);
749 if (cai->data_len < 2 + len) return NULL;
750 cai->data += 2 + len;
751 cai->data_len -= 2 + len;
752 return (lldpctl_atom_iter_t*)cai;
753}
754
755static lldpctl_atom_t*
756_lldpctl_atom_value_med_caelements_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
757{
758 struct _lldpctl_atom_med_caelements_list_t *plist =
759 (struct _lldpctl_atom_med_caelements_list_t *)atom;
760 struct ca_iter *cai = (struct ca_iter *)iter;
761 size_t len;
762 if (cai->data_len < 2) return NULL;
763 len = *((uint8_t *)cai->data + 1);
764 if (cai->data_len < 2 + len) return NULL;
765 return _lldpctl_new_atom(atom->conn, atom_med_caelement, plist->parent,
766 (int)*cai->data, cai->data + 2, len);
767}
768
769static lldpctl_atom_t*
770_lldpctl_atom_create_med_caelements_list(lldpctl_atom_t *atom)
771{
772 struct _lldpctl_atom_med_caelements_list_t *plist =
773 (struct _lldpctl_atom_med_caelements_list_t *)atom;
774 return _lldpctl_new_atom(atom->conn, atom_med_caelement, plist->parent,
775 -1, NULL, 0);
776}
777
778static int
779_lldpctl_atom_new_med_caelement(lldpctl_atom_t *atom, va_list ap)
780{
781 struct _lldpctl_atom_med_caelement_t *el =
782 (struct _lldpctl_atom_med_caelement_t *)atom;
783 el->parent = va_arg(ap, struct _lldpctl_atom_med_location_t *);
784 el->type = va_arg(ap, int);
785 el->value = va_arg(ap, uint8_t*);
786 el->len = va_arg(ap, size_t);
787 lldpctl_atom_inc_ref((lldpctl_atom_t *)el->parent);
788 return 1;
789}
790
791static void
792_lldpctl_atom_free_med_caelement(lldpctl_atom_t *atom)
793{
794 struct _lldpctl_atom_med_caelement_t *el =
795 (struct _lldpctl_atom_med_caelement_t *)atom;
796 lldpctl_atom_dec_ref((lldpctl_atom_t *)el->parent);
797}
798
799static long int
800_lldpctl_atom_get_int_med_caelement(lldpctl_atom_t *atom, lldpctl_key_t key)
801{
802 struct _lldpctl_atom_med_caelement_t *m =
803 (struct _lldpctl_atom_med_caelement_t *)atom;
804
805 switch (key) {
806 case lldpctl_k_med_civicaddress_type:
807 return m->type;
808 default:
809 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
810 }
811}
812
813static lldpctl_atom_t*
814_lldpctl_atom_set_int_med_caelement(lldpctl_atom_t *atom, lldpctl_key_t key,
815 long int value)
816{
817 struct _lldpctl_atom_med_caelement_t *el =
818 (struct _lldpctl_atom_med_caelement_t *)atom;
819
820 /* Only local port can be modified */
9da663f7 821 if (!el->parent->parent->local) {
94c98157
AA
822 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
823 return NULL;
824 }
825
826 switch (key) {
827 case lldpctl_k_med_civicaddress_type:
451b0c3c 828 if (value < 0 || value > 128) goto bad;
94c98157
AA
829 el->type = value;
830 return atom;
831 default:
832 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
833 return NULL;
834 }
835
836 return atom;
837bad:
838 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
839 return NULL;
840}
841
842static const char*
843_lldpctl_atom_get_str_med_caelement(lldpctl_atom_t *atom, lldpctl_key_t key)
844{
845 char *value = NULL;
846 struct _lldpctl_atom_med_caelement_t *m =
847 (struct _lldpctl_atom_med_caelement_t *)atom;
848
849 /* Local and remote port */
850 switch (key) {
851 case lldpctl_k_med_civicaddress_type:
852 return map_lookup(civic_address_type_map.map, m->type);
853 case lldpctl_k_med_civicaddress_value:
854 value = _lldpctl_alloc_in_atom(atom, m->len + 1);
855 if (!value) return NULL;
856 memcpy(value, m->value, m->len);
857 return value;
858 default:
859 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
860 return NULL;
861 }
862}
863
864static lldpctl_atom_t*
865_lldpctl_atom_set_str_med_caelement(lldpctl_atom_t *atom, lldpctl_key_t key,
866 const char *value)
867{
868 struct _lldpctl_atom_med_caelement_t *el =
869 (struct _lldpctl_atom_med_caelement_t *)atom;
870 size_t len;
871
872 /* Only local port can be modified */
9da663f7 873 if (!el->parent->parent->local) {
94c98157
AA
874 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
875 return NULL;
876 }
877
878 switch (key) {
879 case lldpctl_k_med_civicaddress_value:
880 if (!value) goto bad;
881 len = strlen(value) + 1;
882 if (len > 251) goto bad;
883 el->value = _lldpctl_alloc_in_atom(atom, len);
884 if (el->value == NULL) return NULL;
885 strlcpy((char*)el->value, value, len);
886 el->len = strlen(value);
887 return atom;
888 case lldpctl_k_med_civicaddress_type:
889 return _lldpctl_atom_set_int_med_caelement(atom, key,
890 map_reverse_lookup(civic_address_type_map.map, value));
891 default:
892 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
893 return NULL;
894 }
895
896 return atom;
897bad:
898 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
899 return NULL;
900}
901
902static int
903_lldpctl_atom_new_med_power(lldpctl_atom_t *atom, va_list ap)
904{
905 struct _lldpctl_atom_med_power_t *mpow =
906 (struct _lldpctl_atom_med_power_t *)atom;
907 mpow->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
908 lldpctl_atom_inc_ref((lldpctl_atom_t *)mpow->parent);
909 return 1;
910}
911
912static void
913_lldpctl_atom_free_med_power(lldpctl_atom_t *atom)
914{
915 struct _lldpctl_atom_med_power_t *mpow =
916 (struct _lldpctl_atom_med_power_t *)atom;
917 lldpctl_atom_dec_ref((lldpctl_atom_t *)mpow->parent);
918}
919
920static const char*
921_lldpctl_atom_get_str_med_power(lldpctl_atom_t *atom, lldpctl_key_t key)
922{
923 struct _lldpctl_atom_med_power_t *mpow =
924 (struct _lldpctl_atom_med_power_t *)atom;
925 struct lldpd_port *port = mpow->parent->port;
926
927 /* Local and remote port */
928 switch (key) {
929 case lldpctl_k_med_power_type:
930 return map_lookup(port_med_pow_devicetype_map,
931 port->p_med_power.devicetype);
932 case lldpctl_k_med_power_source:
933 return map_lookup(port_med_pow_source_map,
934 port->p_med_power.source);
935 case lldpctl_k_med_power_priority:
936 return map_lookup(port_med_pow_priority_map.map,
937 port->p_med_power.priority);
938 default:
939 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
940 return NULL;
941 }
942}
943
944static long int
945_lldpctl_atom_get_int_med_power(lldpctl_atom_t *atom, lldpctl_key_t key)
946{
947 struct _lldpctl_atom_med_power_t *dpow =
948 (struct _lldpctl_atom_med_power_t *)atom;
949 struct lldpd_port *port = dpow->parent->port;
950
951 /* Local and remote port */
952 switch (key) {
953 case lldpctl_k_med_power_type:
954 return port->p_med_power.devicetype;
955 case lldpctl_k_med_power_source:
956 return port->p_med_power.source;
957 case lldpctl_k_med_power_priority:
958 return port->p_med_power.priority;
959 case lldpctl_k_med_power_val:
960 return port->p_med_power.val * 100;
961 default:
962 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
963 }
964}
965
966static lldpctl_atom_t*
967_lldpctl_atom_set_int_med_power(lldpctl_atom_t *atom, lldpctl_key_t key,
968 long int value)
969{
970 struct _lldpctl_atom_med_power_t *dpow =
971 (struct _lldpctl_atom_med_power_t *)atom;
972 struct lldpd_port *port = dpow->parent->port;
973
974 /* Only local port can be modified */
9da663f7 975 if (!dpow->parent->local) {
94c98157
AA
976 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
977 return NULL;
978 }
979
980 switch (key) {
981 case lldpctl_k_med_power_type:
982 switch (value) {
983 case 0:
984 case LLDP_MED_POW_TYPE_PSE:
985 case LLDP_MED_POW_TYPE_PD:
986 port->p_med_power.devicetype = value;
987 return atom;
988 default: goto bad;
989 }
990 case lldpctl_k_med_power_source:
991 switch (value) {
992 case LLDP_MED_POW_SOURCE_PRIMARY:
993 case LLDP_MED_POW_SOURCE_BACKUP:
994 if (port->p_med_power.devicetype != LLDP_MED_POW_TYPE_PSE)
995 goto bad;
996 port->p_med_power.source = value;
997 return atom;
998 case LLDP_MED_POW_SOURCE_PSE:
999 case LLDP_MED_POW_SOURCE_LOCAL:
1000 case LLDP_MED_POW_SOURCE_BOTH:
1001 if (port->p_med_power.devicetype != LLDP_MED_POW_TYPE_PD)
1002 goto bad;
1003 port->p_med_power.source = value;
1004 return atom;
1005 case LLDP_MED_POW_SOURCE_UNKNOWN:
1006 port->p_med_power.source = value;
1007 return atom;
1008 default: goto bad;
1009 }
1010 case lldpctl_k_med_power_priority:
1011 if (value < 0 || value > 3) goto bad;
1012 port->p_med_power.priority = value;
1013 return atom;
1014 case lldpctl_k_med_power_val:
1015 if (value < 0) goto bad;
1016 port->p_med_power.val = value / 100;
1017 return atom;
1018 default:
1019 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1020 return NULL;
1021 }
1022
1023 return atom;
1024bad:
1025 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
1026 return NULL;
1027}
1028
1029static lldpctl_atom_t*
1030_lldpctl_atom_set_str_med_power(lldpctl_atom_t *atom, lldpctl_key_t key,
1031 const char *value)
1032{
1033 switch (key) {
1034 case lldpctl_k_med_power_type:
1035 return _lldpctl_atom_set_int_med_power(atom, key,
1036 map_reverse_lookup(port_med_pow_devicetype_map, value));
1037 case lldpctl_k_med_power_source:
1038 return _lldpctl_atom_set_int_med_power(atom, key,
1039 map_reverse_lookup(port_med_pow_source_map2, value));
1040 case lldpctl_k_med_power_priority:
1041 return _lldpctl_atom_set_int_med_power(atom, key,
1042 map_reverse_lookup(port_med_pow_priority_map.map, value));
1043 default:
1044 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
1045 return NULL;
1046 }
1047}
1048
1049static struct atom_builder med_policies_list =
1050 { atom_med_policies_list, sizeof(struct _lldpctl_atom_any_list_t),
1051 .init = _lldpctl_atom_new_any_list,
1052 .free = _lldpctl_atom_free_any_list,
1053 .iter = _lldpctl_atom_iter_med_policies_list,
1054 .next = _lldpctl_atom_next_med_policies_list,
1055 .value = _lldpctl_atom_value_med_policies_list };
1056
1057static struct atom_builder med_policy =
1058 { atom_med_policy, sizeof(struct _lldpctl_atom_med_policy_t),
1059 .init = _lldpctl_atom_new_med_policy,
1060 .free = _lldpctl_atom_free_med_policy,
1061 .get_int = _lldpctl_atom_get_int_med_policy,
1062 .set_int = _lldpctl_atom_set_int_med_policy,
1063 .get_str = _lldpctl_atom_get_str_med_policy,
1064 .set_str = _lldpctl_atom_set_str_med_policy };
1065
1066static struct atom_builder med_locations_list =
1067 { atom_med_locations_list, sizeof(struct _lldpctl_atom_any_list_t),
1068 .init = _lldpctl_atom_new_any_list,
1069 .free = _lldpctl_atom_free_any_list,
1070 .iter = _lldpctl_atom_iter_med_locations_list,
1071 .next = _lldpctl_atom_next_med_locations_list,
1072 .value = _lldpctl_atom_value_med_locations_list };
1073
1074static struct atom_builder med_location =
1075 { atom_med_location, sizeof(struct _lldpctl_atom_med_location_t),
1076 .init = _lldpctl_atom_new_med_location,
1077 .free = _lldpctl_atom_free_med_location,
1078 .get = _lldpctl_atom_get_atom_med_location,
1079 .set = _lldpctl_atom_set_atom_med_location,
1080 .get_int = _lldpctl_atom_get_int_med_location,
1081 .set_int = _lldpctl_atom_set_int_med_location,
1082 .get_str = _lldpctl_atom_get_str_med_location,
1083 .set_str = _lldpctl_atom_set_str_med_location };
1084
1085static struct atom_builder med_caelements_list =
1086 { atom_med_caelements_list, sizeof(struct _lldpctl_atom_med_caelements_list_t),
1087 .init = _lldpctl_atom_new_any_list,
1088 .free = _lldpctl_atom_free_any_list,
1089 .iter = _lldpctl_atom_iter_med_caelements_list,
1090 .next = _lldpctl_atom_next_med_caelements_list,
1091 .value = _lldpctl_atom_value_med_caelements_list,
1092 .create = _lldpctl_atom_create_med_caelements_list };
1093
1094static struct atom_builder med_caelement =
1095 { atom_med_caelement, sizeof(struct _lldpctl_atom_med_caelement_t),
1096 .init = _lldpctl_atom_new_med_caelement,
1097 .free = _lldpctl_atom_free_med_caelement,
1098 .get_int = _lldpctl_atom_get_int_med_caelement,
1099 .set_int = _lldpctl_atom_set_int_med_caelement,
1100 .get_str = _lldpctl_atom_get_str_med_caelement,
1101 .set_str = _lldpctl_atom_set_str_med_caelement };
1102
1103static struct atom_builder med_power =
1104 { atom_med_power, sizeof(struct _lldpctl_atom_med_power_t),
1105 .init = _lldpctl_atom_new_med_power,
1106 .free = _lldpctl_atom_free_med_power,
1107 .get_int = _lldpctl_atom_get_int_med_power,
1108 .set_int = _lldpctl_atom_set_int_med_power,
1109 .get_str = _lldpctl_atom_get_str_med_power,
1110 .set_str = _lldpctl_atom_set_str_med_power };
1111
1112ATOM_BUILDER_REGISTER(med_policies_list, 15);
1113ATOM_BUILDER_REGISTER(med_policy, 16);
1114ATOM_BUILDER_REGISTER(med_locations_list, 17);
1115ATOM_BUILDER_REGISTER(med_location, 18);
1116ATOM_BUILDER_REGISTER(med_caelements_list, 19);
1117ATOM_BUILDER_REGISTER(med_caelement, 20);
1118ATOM_BUILDER_REGISTER(med_power, 21);
1119
1120#endif
1121