]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/lib/atoms/dot3.c
test: add tests for 802.3BT additions
[thirdparty/lldpd.git] / src / lib / atoms / dot3.c
1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3 * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <stdio.h>
19 #include <stdarg.h>
20 #include <string.h>
21 #include <arpa/inet.h>
22
23 #include "lldpctl.h"
24 #include "../log.h"
25 #include "atom.h"
26 #include "helpers.h"
27
28 #ifdef ENABLE_DOT3
29
30 static lldpctl_map_t port_dot3_power_devicetype_map[] = {
31 { LLDP_DOT3_POWER_PSE, "PSE" },
32 { LLDP_DOT3_POWER_PD, "PD" },
33 { 0, NULL }
34 };
35
36 static lldpctl_map_t port_dot3_power_pse_source_map[] = {
37 { LLDP_DOT3_POWER_SOURCE_BOTH, "PSE + Local" },
38 { LLDP_DOT3_POWER_SOURCE_PSE, "PSE" },
39 { 0, NULL }
40 };
41
42 static lldpctl_map_t port_dot3_power_pd_source_map[] = {
43 { LLDP_DOT3_POWER_SOURCE_BACKUP, "Backup source" },
44 { LLDP_DOT3_POWER_SOURCE_PRIMARY, "Primary power source" },
45 { 0, NULL }
46 };
47
48 static struct atom_map port_dot3_power_pairs_map = {
49 .key = lldpctl_k_dot3_power_pairs,
50 .map = {
51 { LLDP_DOT3_POWERPAIRS_SIGNAL, "signal" },
52 { LLDP_DOT3_POWERPAIRS_SPARE, "spare" },
53 { 0, NULL }
54 },
55 };
56
57 static struct atom_map port_dot3_power_class_map = {
58 .key = lldpctl_k_dot3_power_class,
59 .map = {
60 { 1, "class 0" },
61 { 2, "class 1" },
62 { 3, "class 2" },
63 { 4, "class 3" },
64 { 5, "class 4" },
65 { 0, NULL }
66 },
67 };
68
69 static struct atom_map port_dot3_power_priority_map = {
70 .key = lldpctl_k_dot3_power_priority,
71 .map = {
72 { 0, "unknown" },
73 { LLDP_MED_POW_PRIO_CRITICAL, "critical" },
74 { LLDP_MED_POW_PRIO_HIGH, "high" },
75 { LLDP_MED_POW_PRIO_LOW, "low" },
76 { 0, NULL },
77 },
78 };
79
80 static struct atom_map port_dot3_power_pd_4pid_map = {
81 .key = lldpctl_k_dot3_power_pd_4pid,
82 .map = {
83 { 0, "PD does not support powering both modes" },
84 { 1, "PD supports powering both modes" },
85 },
86 };
87
88 static struct atom_map port_dot3_power_pse_status_map = {
89 .key = lldpctl_k_dot3_power_pse_status,
90 .map = {
91 { 0, "Unknown" },
92 { 1, "2-pair powering" },
93 { 2, "4-pair powering dual-signature PD" },
94 { 3, "4-pair powering single-signature PD" },
95 },
96 };
97
98 static struct atom_map port_dot3_power_pd_status_map = {
99 .key = lldpctl_k_dot3_power_pd_status,
100 .map = {
101 { 0, "Unknown" },
102 { 1, "2-pair powered PD" },
103 { 2, "4-pair powered dual-signature PD" },
104 { 3, "4-pair powered single-signature PD" },
105 },
106 };
107
108 static struct atom_map port_dot3_power_pse_pairs_ext_map = {
109 .key = lldpctl_k_dot3_power_pse_pairs_ext,
110 .map = {
111 { 0, "Unknown" },
112 { 1, "Alternative A" },
113 { 2, "Alternative B" },
114 { 3, "Both alternatives" },
115 },
116 };
117
118 static struct atom_map port_dot3_power_class_a_map = {
119 .key = lldpctl_k_dot3_power_class_a,
120 .map = {
121 { 0, "Unknown" },
122 { 1, "Class 1" },
123 { 2, "Class 2" },
124 { 3, "Class 3" },
125 { 4, "Class 4" },
126 { 5, "Class 5" },
127 { 6, "Unknown" },
128 { 7, "Single-signature PD or 2-pair only PSE" },
129 },
130 };
131
132 static struct atom_map port_dot3_power_class_b_map = {
133 .key = lldpctl_k_dot3_power_class_b,
134 .map = {
135 { 0, "Unknown" },
136 { 1, "Class 1" },
137 { 2, "Class 2" },
138 { 3, "Class 3" },
139 { 4, "Class 4" },
140 { 5, "Class 5" },
141 { 6, "Unknown" },
142 { 7, "Single-signature PD or 2-pair only PSE" },
143 },
144 };
145
146 static struct atom_map port_dot3_power_class_ext_map = {
147 .key = lldpctl_k_dot3_power_class_ext,
148 .map = {
149 { 0, "Unknown" },
150 { 1, "Class 1" },
151 { 2, "Class 2" },
152 { 3, "Class 3" },
153 { 4, "Class 4" },
154 { 5, "Class 5" },
155 { 6, "Class 6" },
156 { 7, "Class 7" },
157 { 8, "Class 8" },
158 { 9, "Unknown" },
159 { 10, "Unknown" },
160 { 11, "Unknown" },
161 { 12, "Unknown" },
162 { 13, "Unknown" },
163 { 14, "Unknown" },
164 { 15, "Dual-signature PD" },
165 },
166 };
167
168 static struct atom_map port_dot3_power_type_ext_map = {
169 .key = lldpctl_k_dot3_power_type_ext,
170 .map = {
171 { LLDP_DOT3_POWER_8023BT_OFF, "802.3bt off" },
172 { 1, "Type 3 PSE" },
173 { 2, "Type 4 PSE" },
174 { 3, "Type 3 single-signature PD" },
175 { 4, "Type 3 dual-signature PD" },
176 { 5, "Type 4 single-signature PD" },
177 { 6, "Type 4 dual-signature PD" },
178 { 7, "Unknown" },
179 { 8, "Unknown" },
180 },
181 };
182
183 static struct atom_map port_dot3_power_pd_load_map = {
184 .key = lldpctl_k_dot3_power_pd_load,
185 .map = {
186 { 0, "PD is single- or dual-signature and power is not "
187 "electrically isolated" },
188 { 1, "PD is dual-signature and power is electrically "
189 "isolated" },
190 },
191 };
192
193
194 ATOM_MAP_REGISTER(port_dot3_power_pairs_map, 4);
195 ATOM_MAP_REGISTER(port_dot3_power_class_map, 5);
196 ATOM_MAP_REGISTER(port_dot3_power_priority_map, 6);
197
198 static int
199 _lldpctl_atom_new_dot3_power(lldpctl_atom_t *atom, va_list ap)
200 {
201 struct _lldpctl_atom_dot3_power_t *dpow =
202 (struct _lldpctl_atom_dot3_power_t *)atom;
203 dpow->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
204 lldpctl_atom_inc_ref((lldpctl_atom_t *)dpow->parent);
205 return 1;
206 }
207
208 static void
209 _lldpctl_atom_free_dot3_power(lldpctl_atom_t *atom)
210 {
211 struct _lldpctl_atom_dot3_power_t *dpow =
212 (struct _lldpctl_atom_dot3_power_t *)atom;
213 lldpctl_atom_dec_ref((lldpctl_atom_t *)dpow->parent);
214 }
215
216 static const char*
217 _lldpctl_atom_get_str_dot3_power(lldpctl_atom_t *atom, lldpctl_key_t key)
218 {
219 struct _lldpctl_atom_dot3_power_t *dpow =
220 (struct _lldpctl_atom_dot3_power_t *)atom;
221 struct lldpd_port *port = dpow->parent->port;
222
223 /* Local and remote port */
224 switch (key) {
225 case lldpctl_k_dot3_power_devicetype:
226 return map_lookup(port_dot3_power_devicetype_map,
227 port->p_power.devicetype);
228 case lldpctl_k_dot3_power_pairs:
229 return map_lookup(port_dot3_power_pairs_map.map,
230 port->p_power.pairs);
231 case lldpctl_k_dot3_power_class:
232 return map_lookup(port_dot3_power_class_map.map,
233 port->p_power.class);
234 case lldpctl_k_dot3_power_source:
235 return map_lookup((port->p_power.devicetype == LLDP_DOT3_POWER_PSE)?
236 port_dot3_power_pse_source_map:
237 port_dot3_power_pd_source_map,
238 port->p_power.source);
239 case lldpctl_k_dot3_power_priority:
240 return map_lookup(port_dot3_power_priority_map.map,
241 port->p_power.priority);
242 case lldpctl_k_dot3_power_pd_4pid:
243 return map_lookup(port_dot3_power_pd_4pid_map.map,
244 port->p_power.pd_4pid);
245 case lldpctl_k_dot3_power_pse_status:
246 return map_lookup(port_dot3_power_pse_status_map.map,
247 port->p_power.pse_status);
248 case lldpctl_k_dot3_power_pd_status:
249 return map_lookup(port_dot3_power_pd_status_map.map,
250 port->p_power.pd_status);
251 case lldpctl_k_dot3_power_pse_pairs_ext:
252 return map_lookup(port_dot3_power_pse_pairs_ext_map.map,
253 port->p_power.pse_pairs_ext);
254 case lldpctl_k_dot3_power_class_a:
255 return map_lookup(port_dot3_power_class_a_map.map,
256 port->p_power.class_a);
257 case lldpctl_k_dot3_power_class_b:
258 return map_lookup(port_dot3_power_class_b_map.map,
259 port->p_power.class_b);
260 case lldpctl_k_dot3_power_class_ext:
261 return map_lookup(port_dot3_power_class_ext_map.map,
262 port->p_power.class_ext);
263 case lldpctl_k_dot3_power_type_ext:
264 return map_lookup(port_dot3_power_type_ext_map.map,
265 port->p_power.type_ext);
266 case lldpctl_k_dot3_power_pd_load:
267 return map_lookup(port_dot3_power_pd_load_map.map,
268 port->p_power.pd_load);
269 default:
270 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
271 return NULL;
272 }
273 }
274
275 static long int
276 _lldpctl_atom_get_int_dot3_power(lldpctl_atom_t *atom, lldpctl_key_t key)
277 {
278 struct _lldpctl_atom_dot3_power_t *dpow =
279 (struct _lldpctl_atom_dot3_power_t *)atom;
280 struct lldpd_port *port = dpow->parent->port;
281
282 /* Local and remote port */
283 switch (key) {
284 case lldpctl_k_dot3_power_devicetype:
285 return port->p_power.devicetype;
286 case lldpctl_k_dot3_power_supported:
287 return port->p_power.supported;
288 case lldpctl_k_dot3_power_enabled:
289 return port->p_power.enabled;
290 case lldpctl_k_dot3_power_paircontrol:
291 return port->p_power.paircontrol;
292 case lldpctl_k_dot3_power_pairs:
293 return port->p_power.pairs;
294 case lldpctl_k_dot3_power_class:
295 return port->p_power.class;
296 case lldpctl_k_dot3_power_type:
297 return port->p_power.powertype;
298 case lldpctl_k_dot3_power_source:
299 return port->p_power.source;
300 case lldpctl_k_dot3_power_priority:
301 return port->p_power.priority;
302 case lldpctl_k_dot3_power_requested:
303 return port->p_power.requested * 100;
304 case lldpctl_k_dot3_power_allocated:
305 return port->p_power.allocated * 100;
306 /* 802.3bt additions */
307 case lldpctl_k_dot3_power_pd_4pid:
308 return port->p_power.pd_4pid;
309 case lldpctl_k_dot3_power_requested_a:
310 return port->p_power.requested_a * 100;
311 case lldpctl_k_dot3_power_requested_b:
312 return port->p_power.requested_b * 100;
313 case lldpctl_k_dot3_power_allocated_a:
314 return port->p_power.allocated_a * 100;
315 case lldpctl_k_dot3_power_allocated_b:
316 return port->p_power.allocated_b * 100;
317 case lldpctl_k_dot3_power_pse_status:
318 return port->p_power.pse_status;
319 case lldpctl_k_dot3_power_pd_status:
320 return port->p_power.pd_status;
321 case lldpctl_k_dot3_power_pse_pairs_ext:
322 return port->p_power.pse_pairs_ext;
323 case lldpctl_k_dot3_power_class_a:
324 return port->p_power.class_a;
325 case lldpctl_k_dot3_power_class_b:
326 return port->p_power.class_b;
327 case lldpctl_k_dot3_power_class_ext:
328 return port->p_power.class_ext;
329 case lldpctl_k_dot3_power_type_ext:
330 return port->p_power.type_ext;
331 case lldpctl_k_dot3_power_pd_load:
332 return port->p_power.pd_load;
333 case lldpctl_k_dot3_power_pse_max:
334 return port->p_power.pse_max * 100;
335 default:
336 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
337 }
338 }
339
340 static lldpctl_atom_t*
341 _lldpctl_atom_set_int_dot3_power(lldpctl_atom_t *atom, lldpctl_key_t key,
342 long int value)
343 {
344 struct _lldpctl_atom_dot3_power_t *dpow =
345 (struct _lldpctl_atom_dot3_power_t *)atom;
346 struct lldpd_port *port = dpow->parent->port;
347
348 /* Only local port can be modified */
349 if (!dpow->parent->local) {
350 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
351 return NULL;
352 }
353
354 switch (key) {
355 case lldpctl_k_dot3_power_devicetype:
356 switch (value) {
357 case 0: /* Disabling */
358 case LLDP_DOT3_POWER_PSE:
359 case LLDP_DOT3_POWER_PD:
360 port->p_power.devicetype = value;
361 return atom;
362 default: goto bad;
363 }
364 case lldpctl_k_dot3_power_supported:
365 switch (value) {
366 case 0:
367 case 1:
368 port->p_power.supported = value;
369 return atom;
370 default: goto bad;
371 }
372 case lldpctl_k_dot3_power_enabled:
373 switch (value) {
374 case 0:
375 case 1:
376 port->p_power.enabled = value;
377 return atom;
378 default: goto bad;
379 }
380 case lldpctl_k_dot3_power_paircontrol:
381 switch (value) {
382 case 0:
383 case 1:
384 port->p_power.paircontrol = value;
385 return atom;
386 default: goto bad;
387 }
388 case lldpctl_k_dot3_power_pairs:
389 switch (value) {
390 case 1:
391 case 2:
392 port->p_power.pairs = value;
393 return atom;
394 default: goto bad;
395 }
396 case lldpctl_k_dot3_power_class:
397 if (value < 0 || value > 5)
398 goto bad;
399 port->p_power.class = value;
400 return atom;
401 case lldpctl_k_dot3_power_type:
402 switch (value) {
403 case LLDP_DOT3_POWER_8023AT_TYPE1:
404 case LLDP_DOT3_POWER_8023AT_TYPE2:
405 case LLDP_DOT3_POWER_8023AT_OFF:
406 port->p_power.powertype = value;
407 return atom;
408 default: goto bad;
409 }
410 case lldpctl_k_dot3_power_source:
411 if (value < 0 || value > 3)
412 goto bad;
413 port->p_power.source = value;
414 return atom;
415 case lldpctl_k_dot3_power_priority:
416 switch (value) {
417 case LLDP_DOT3_POWER_PRIO_UNKNOWN:
418 case LLDP_DOT3_POWER_PRIO_CRITICAL:
419 case LLDP_DOT3_POWER_PRIO_HIGH:
420 case LLDP_DOT3_POWER_PRIO_LOW:
421 port->p_power.priority = value;
422 return atom;
423 default: goto bad;
424 }
425 case lldpctl_k_dot3_power_allocated:
426 if (value < 0) goto bad;
427 port->p_power.allocated = value / 100;
428 return atom;
429 case lldpctl_k_dot3_power_requested:
430 if (value < 0) goto bad;
431 port->p_power.requested = value / 100;
432 return atom;
433 /* 802.3bt additions */
434 case lldpctl_k_dot3_power_pd_4pid:
435 port->p_power.pd_4pid = value;
436 return atom;
437 case lldpctl_k_dot3_power_requested_a:
438 port->p_power.requested_a = value / 100;
439 return atom;
440 case lldpctl_k_dot3_power_requested_b:
441 port->p_power.requested_b = value / 100;
442 return atom;
443 case lldpctl_k_dot3_power_allocated_a:
444 port->p_power.allocated_a = value / 100;
445 return atom;
446 case lldpctl_k_dot3_power_allocated_b:
447 port->p_power.allocated_b = value / 100;
448 return atom;
449 case lldpctl_k_dot3_power_pse_status:
450 port->p_power.pse_status = value;
451 return atom;
452 case lldpctl_k_dot3_power_pd_status:
453 port->p_power.pd_status = value;
454 return atom;
455 case lldpctl_k_dot3_power_pse_pairs_ext:
456 port->p_power.pse_pairs_ext = value;
457 return atom;
458 case lldpctl_k_dot3_power_class_a:
459 port->p_power.class_a = value;
460 return atom;
461 case lldpctl_k_dot3_power_class_b:
462 port->p_power.class_b = value;
463 return atom;
464 case lldpctl_k_dot3_power_class_ext:
465 port->p_power.class_ext = value;
466 return atom;
467 case lldpctl_k_dot3_power_type_ext:
468 port->p_power.type_ext = value;
469 return atom;
470 case lldpctl_k_dot3_power_pd_load:
471 port->p_power.pd_load = value;
472 return atom;
473 case lldpctl_k_dot3_power_pse_max:
474 port->p_power.pse_max = value / 100;
475 return atom;
476 default:
477 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
478 return NULL;
479 }
480
481 return atom;
482 bad:
483 SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
484 return NULL;
485 }
486
487 static lldpctl_atom_t*
488 _lldpctl_atom_set_str_dot3_power(lldpctl_atom_t *atom, lldpctl_key_t key,
489 const char *value)
490 {
491 switch (key) {
492 case lldpctl_k_dot3_power_devicetype:
493 return _lldpctl_atom_set_int_dot3_power(atom, key,
494 map_reverse_lookup(port_dot3_power_devicetype_map, value));
495 case lldpctl_k_dot3_power_pairs:
496 return _lldpctl_atom_set_int_dot3_power(atom, key,
497 map_reverse_lookup(port_dot3_power_pairs_map.map, value));
498 case lldpctl_k_dot3_power_class:
499 return _lldpctl_atom_set_int_dot3_power(atom, key,
500 map_reverse_lookup(port_dot3_power_class_map.map, value));
501 case lldpctl_k_dot3_power_priority:
502 return _lldpctl_atom_set_int_dot3_power(atom, key,
503 map_reverse_lookup(port_dot3_power_priority_map.map, value));
504 default:
505 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
506 return NULL;
507 }
508 }
509
510 static struct atom_builder dot3_power =
511 { atom_dot3_power, sizeof(struct _lldpctl_atom_dot3_power_t),
512 .init = _lldpctl_atom_new_dot3_power,
513 .free = _lldpctl_atom_free_dot3_power,
514 .get_int = _lldpctl_atom_get_int_dot3_power,
515 .set_int = _lldpctl_atom_set_int_dot3_power,
516 .get_str = _lldpctl_atom_get_str_dot3_power,
517 .set_str = _lldpctl_atom_set_str_dot3_power };
518
519 ATOM_BUILDER_REGISTER(dot3_power, 8);
520
521 #endif
522