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 <string.h>
20 #include <limits.h>
21 #include "lldpctl.h"
22 #include "atom.h"
23 #include "../log.h"
24 #include "../marshal.h"
25 #include "../ctl.h"
26
27 lldpctl_conn_t*
lldpctl_atom_get_connection(lldpctl_atom_t * atom)28 lldpctl_atom_get_connection(lldpctl_atom_t *atom)
29 {
30 if (atom)
31 return atom->conn;
32 return NULL;
33 }
34
35 void
lldpctl_atom_inc_ref(lldpctl_atom_t * atom)36 lldpctl_atom_inc_ref(lldpctl_atom_t *atom)
37 {
38 if (atom)
39 atom->count++;
40 }
41
42 void
lldpctl_atom_dec_ref(lldpctl_atom_t * atom)43 lldpctl_atom_dec_ref(lldpctl_atom_t *atom)
44 {
45 struct atom_buffer *buffer, *buffer_next;
46 if (atom && (--atom->count == 0)) {
47 if (atom->free)
48 atom->free(atom);
49
50 /* Remove special allocated buffers */
51 for (buffer = TAILQ_FIRST(&atom->buffers);
52 buffer;
53 buffer = buffer_next) {
54 buffer_next = TAILQ_NEXT(buffer, next);
55 free(buffer);
56 }
57
58 free(atom);
59 }
60 }
61
62 lldpctl_atom_t*
lldpctl_atom_get(lldpctl_atom_t * atom,lldpctl_key_t key)63 lldpctl_atom_get(lldpctl_atom_t *atom, lldpctl_key_t key)
64 {
65 if (atom == NULL) return NULL;
66 RESET_ERROR(atom->conn);
67
68 if (atom->get == NULL) {
69 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
70 return NULL;
71 }
72 return atom->get(atom, key);
73 }
74
75 lldpctl_atom_t*
lldpctl_atom_set(lldpctl_atom_t * atom,lldpctl_key_t key,lldpctl_atom_t * value)76 lldpctl_atom_set(lldpctl_atom_t *atom, lldpctl_key_t key,
77 lldpctl_atom_t *value)
78 {
79 if (atom == NULL) return NULL;
80 RESET_ERROR(atom->conn);
81
82 if (atom->set == NULL) {
83 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
84 return NULL;
85 }
86 return atom->set(atom, key, value);
87 }
88
89 const char*
lldpctl_atom_get_str(lldpctl_atom_t * atom,lldpctl_key_t key)90 lldpctl_atom_get_str(lldpctl_atom_t *atom, lldpctl_key_t key)
91 {
92 char *strresult = NULL;
93 const uint8_t *bufresult = NULL;
94 long int intresult = -1;
95 int n1;
96 size_t n2;
97
98 if (atom == NULL) return NULL;
99 RESET_ERROR(atom->conn);
100
101 if (atom->get_str != NULL) {
102 strresult = (char *)atom->get_str(atom, key);
103 if (strresult) return strresult;
104 if (lldpctl_last_error(atom->conn) != LLDPCTL_ERR_NOT_EXIST)
105 return NULL;
106 }
107
108 RESET_ERROR(atom->conn);
109 if (atom->get_int != NULL) {
110 intresult = atom->get_int(atom, key);
111 if (lldpctl_last_error(atom->conn) != LLDPCTL_ERR_NOT_EXIST) {
112 strresult = _lldpctl_alloc_in_atom(atom, 21);
113 if (!strresult) return NULL;
114 n1 = snprintf(strresult, 21, "%ld", intresult);
115 if (n1 > -1 && n1 < 21)
116 return strresult;
117 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM); /* Not really true... */
118 return NULL;
119 }
120 }
121
122 RESET_ERROR(atom->conn);
123 if (atom->get_buffer != NULL) {
124 bufresult = atom->get_buffer(atom, key, &n2);
125 if (bufresult)
126 return _lldpctl_dump_in_atom(atom, bufresult, n2, ' ', 0);
127 if (lldpctl_last_error(atom->conn) != LLDPCTL_ERR_NOT_EXIST)
128 return NULL;
129 }
130
131 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
132 return NULL;
133 }
134
135 lldpctl_atom_t*
lldpctl_atom_set_str(lldpctl_atom_t * atom,lldpctl_key_t key,const char * value)136 lldpctl_atom_set_str(lldpctl_atom_t *atom, lldpctl_key_t key,
137 const char *value)
138 {
139 lldpctl_atom_t *result = NULL;
140 const char *errstr;
141 long long converted = 0;
142 int isint = 0;
143 int bad = 0;
144
145 if (atom == NULL) return NULL;
146 RESET_ERROR(atom->conn);
147
148 if (atom->set_str != NULL) {
149 result = atom->set_str(atom, key, value);
150 if (result) return result;
151 if (lldpctl_last_error(atom->conn) != LLDPCTL_ERR_NOT_EXIST &&
152 lldpctl_last_error(atom->conn) != LLDPCTL_ERR_BAD_VALUE)
153 return NULL;
154 bad = bad || (lldpctl_last_error(atom->conn) == LLDPCTL_ERR_BAD_VALUE);
155 }
156
157 if (value) {
158 converted = strtonum(value, LLONG_MIN, LLONG_MAX, &errstr);
159 isint = (errstr == NULL);
160 }
161
162 RESET_ERROR(atom->conn);
163 if (atom->set_int != NULL && isint) {
164 result = atom->set_int(atom, key, converted);
165 if (result) return result;
166 if (lldpctl_last_error(atom->conn) != LLDPCTL_ERR_NOT_EXIST &&
167 lldpctl_last_error(atom->conn) != LLDPCTL_ERR_BAD_VALUE)
168 return NULL;
169 bad = bad || (lldpctl_last_error(atom->conn) == LLDPCTL_ERR_BAD_VALUE);
170 }
171
172 RESET_ERROR(atom->conn);
173 if (atom->set_buffer != NULL) {
174 result = atom->set_buffer(atom, key, (u_int8_t*)value, value?strlen(value):0);
175 if (result) return result;
176 if (lldpctl_last_error(atom->conn) != LLDPCTL_ERR_NOT_EXIST &&
177 lldpctl_last_error(atom->conn) != LLDPCTL_ERR_BAD_VALUE)
178 return NULL;
179 bad = bad || (lldpctl_last_error(atom->conn) == LLDPCTL_ERR_BAD_VALUE);
180 }
181
182 SET_ERROR(atom->conn, bad?LLDPCTL_ERR_BAD_VALUE:LLDPCTL_ERR_NOT_EXIST);
183 return NULL;
184 }
185
186 const u_int8_t*
lldpctl_atom_get_buffer(lldpctl_atom_t * atom,lldpctl_key_t key,size_t * length)187 lldpctl_atom_get_buffer(lldpctl_atom_t *atom, lldpctl_key_t key,
188 size_t *length)
189 {
190 if (atom == NULL) return NULL;
191 RESET_ERROR(atom->conn);
192
193 if (atom->get_buffer == NULL) {
194 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
195 return NULL;
196 }
197 return atom->get_buffer(atom, key, length);
198 }
199
200 lldpctl_atom_t*
lldpctl_atom_set_buffer(lldpctl_atom_t * atom,lldpctl_key_t key,const u_int8_t * value,size_t length)201 lldpctl_atom_set_buffer(lldpctl_atom_t *atom, lldpctl_key_t key,
202 const u_int8_t* value, size_t length)
203 {
204 if (atom == NULL) return NULL;
205 RESET_ERROR(atom->conn);
206
207 if (atom->set_buffer == NULL) {
208 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
209 return NULL;
210 }
211 return atom->set_buffer(atom, key, value, length);
212 }
213
214 long int
lldpctl_atom_get_int(lldpctl_atom_t * atom,lldpctl_key_t key)215 lldpctl_atom_get_int(lldpctl_atom_t *atom, lldpctl_key_t key)
216 {
217 if (atom == NULL) return LLDPCTL_ERR_NOT_EXIST;
218 RESET_ERROR(atom->conn);
219
220 if (atom->get_int == NULL)
221 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
222 return atom->get_int(atom, key);
223 }
224
225 lldpctl_atom_t*
lldpctl_atom_set_int(lldpctl_atom_t * atom,lldpctl_key_t key,long int value)226 lldpctl_atom_set_int(lldpctl_atom_t *atom, lldpctl_key_t key,
227 long int value)
228 {
229 if (atom == NULL) return NULL;
230 RESET_ERROR(atom->conn);
231
232 if (atom->set_int == NULL) {
233 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
234 return NULL;
235 }
236 return atom->set_int(atom, key, value);
237 }
238
239 lldpctl_atom_iter_t*
lldpctl_atom_iter(lldpctl_atom_t * atom)240 lldpctl_atom_iter(lldpctl_atom_t *atom)
241 {
242 if (atom == NULL) return NULL;
243 RESET_ERROR(atom->conn);
244
245 if (!atom->iter) {
246 SET_ERROR(atom->conn, LLDPCTL_ERR_CANNOT_ITERATE);
247 return NULL;
248 }
249 return atom->iter(atom);
250 }
251
252 lldpctl_atom_iter_t*
lldpctl_atom_iter_next(lldpctl_atom_t * atom,lldpctl_atom_iter_t * iter)253 lldpctl_atom_iter_next(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
254 {
255 if (atom == NULL) return NULL;
256 RESET_ERROR(atom->conn);
257
258 if (!atom->next) {
259 SET_ERROR(atom->conn, LLDPCTL_ERR_CANNOT_ITERATE);
260 return NULL;
261 }
262 return atom->next(atom, iter);
263 }
264
265 lldpctl_atom_t*
lldpctl_atom_iter_value(lldpctl_atom_t * atom,lldpctl_atom_iter_t * iter)266 lldpctl_atom_iter_value(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
267 {
268 if (atom == NULL) return NULL;
269 RESET_ERROR(atom->conn);
270
271 if (!atom->value) {
272 SET_ERROR(atom->conn, LLDPCTL_ERR_CANNOT_ITERATE);
273 return NULL;
274 }
275 return atom->value(atom, iter);
276 }
277
278 lldpctl_atom_t*
lldpctl_atom_create(lldpctl_atom_t * atom)279 lldpctl_atom_create(lldpctl_atom_t *atom)
280 {
281 if (atom == NULL) return NULL;
282 RESET_ERROR(atom->conn);
283
284 if (!atom->create) {
285 SET_ERROR(atom->conn, LLDPCTL_ERR_CANNOT_CREATE);
286 return NULL;
287 }
288 return atom->create(atom);
289 }
290
291 /**
292 * Get somethin with IO.
293 *
294 * @param conn The connection to lldpd.
295 * @param state_send State to be when "sending"
296 * @param state_recv State to be when "receiving"
297 * @param state_data Ancillary data for state handling
298 * @param type Type of message to send (and receive)
299 * @param to_send Data to send.
300 * @param mi_send Marshalling info for data to send.
301 * @param to_recv Data to receive.
302 * @param mi_recv Marshalling info for data to recive.
303 * @return 0 in case of success, a negative integer in case of failure.
304 *
305 * The current state must match one of @c CONN_STATE_IDLE, @c state_send or @c
306 * state_recv and in the two later cases, the provided @c state_data must match.
307 */
308 int
_lldpctl_do_something(lldpctl_conn_t * conn,int state_send,int state_recv,const char * state_data,enum hmsg_type type,void * to_send,struct marshal_info * mi_send,void ** to_recv,struct marshal_info * mi_recv)309 _lldpctl_do_something(lldpctl_conn_t *conn,
310 int state_send, int state_recv, const char *state_data,
311 enum hmsg_type type,
312 void *to_send, struct marshal_info *mi_send,
313 void **to_recv, struct marshal_info *mi_recv)
314 {
315 ssize_t rc;
316
317 if (conn->state == CONN_STATE_WATCHING)
318 /* The connection cannot be used anymore. */
319 return SET_ERROR(conn, LLDPCTL_ERR_INVALID_STATE);
320
321 if (conn->state == CONN_STATE_IDLE) {
322 /* We need to build the message to send, then send
323 * it. */
324 if (ctl_msg_send_unserialized(&conn->output_buffer, &conn->output_buffer_len,
325 type, to_send, mi_send) != 0)
326 return SET_ERROR(conn, LLDPCTL_ERR_SERIALIZATION);
327 conn->state = state_send;
328 if (state_data)
329 strlcpy(conn->state_data, state_data, sizeof(conn->state_data));
330 else
331 conn->state_data[0] = 0;
332 }
333 if (conn->state == state_send &&
334 (state_data == NULL || !strncmp(conn->state_data, state_data, sizeof(conn->state_data) - 1))) {
335 /* We need to send the currently built message */
336 rc = lldpctl_send(conn);
337 if (rc < 0)
338 return SET_ERROR(conn, rc);
339 conn->state = state_recv;
340 }
341 if (conn->state == state_recv &&
342 (state_data == NULL || !strncmp(conn->state_data, state_data, sizeof(conn->state_data) - 1))) {
343 /* We need to receive the answer */
344 while ((rc = ctl_msg_recv_unserialized(&conn->input_buffer,
345 &conn->input_buffer_len,
346 type, to_recv, mi_recv)) > 0) {
347 /* We need more bytes */
348 rc = _lldpctl_needs(conn, rc);
349 if (rc < 0)
350 return SET_ERROR(conn, rc);
351 }
352 if (rc < 0)
353 return SET_ERROR(conn, LLDPCTL_ERR_SERIALIZATION);
354 /* rc == 0 */
355 conn->state = CONN_STATE_IDLE;
356 conn->state_data[0] = 0;
357 return 0;
358 } else
359 return SET_ERROR(conn, LLDPCTL_ERR_INVALID_STATE);
360 }
361
362
363 int
lldpctl_watch_callback(lldpctl_conn_t * conn,lldpctl_change_callback cb,void * data)364 lldpctl_watch_callback(lldpctl_conn_t *conn,
365 lldpctl_change_callback cb,
366 void *data)
367 {
368 int rc;
369
370 RESET_ERROR(conn);
371
372 rc = _lldpctl_do_something(conn,
373 CONN_STATE_SET_WATCH_SEND, CONN_STATE_SET_WATCH_RECV, NULL,
374 SUBSCRIBE, NULL, NULL, NULL, NULL);
375 if (rc == 0) {
376 conn->watch_cb = cb;
377 conn->watch_data = data;
378 conn->state = CONN_STATE_WATCHING;
379 }
380 return rc;
381 }
382
383 int
lldpctl_watch_callback2(lldpctl_conn_t * conn,lldpctl_change_callback2 cb,void * data)384 lldpctl_watch_callback2(lldpctl_conn_t *conn,
385 lldpctl_change_callback2 cb,
386 void *data)
387 {
388 int rc;
389
390 RESET_ERROR(conn);
391
392 rc = _lldpctl_do_something(conn,
393 CONN_STATE_SET_WATCH_SEND, CONN_STATE_SET_WATCH_RECV, NULL,
394 SUBSCRIBE, NULL, NULL, NULL, NULL);
395 if (rc == 0) {
396 conn->watch_cb2 = cb;
397 conn->watch_data = data;
398 conn->state = CONN_STATE_WATCHING;
399 }
400 return rc;
401 }
402
403 int
lldpctl_watch(lldpctl_conn_t * conn)404 lldpctl_watch(lldpctl_conn_t *conn)
405 {
406 int rc = 0;
407
408 RESET_ERROR(conn);
409
410 if (conn->state != CONN_STATE_WATCHING)
411 return SET_ERROR(conn, LLDPCTL_ERR_INVALID_STATE);
412
413 conn->watch_triggered = 0;
414 while (!conn->watch_triggered) {
415 rc = _lldpctl_needs(conn, 1);
416 if (rc < 0)
417 return SET_ERROR(conn, rc);
418 }
419
420 RESET_ERROR(conn);
421 return 0;
422 }
423
424 lldpctl_atom_t*
lldpctl_get_configuration(lldpctl_conn_t * conn)425 lldpctl_get_configuration(lldpctl_conn_t *conn)
426 {
427 int rc;
428 struct lldpd_config *config;
429 void *p;
430
431 RESET_ERROR(conn);
432
433 rc = _lldpctl_do_something(conn,
434 CONN_STATE_GET_CONFIG_SEND, CONN_STATE_GET_CONFIG_RECV, NULL,
435 GET_CONFIG,
436 NULL, NULL,
437 &p, &MARSHAL_INFO(lldpd_config));
438 if (rc == 0) {
439 config = p;
440 return _lldpctl_new_atom(conn, atom_config, config);
441 }
442 return NULL;
443 }
444
445 lldpctl_atom_t*
lldpctl_get_interfaces(lldpctl_conn_t * conn)446 lldpctl_get_interfaces(lldpctl_conn_t *conn)
447 {
448 struct lldpd_interface_list *ifs;
449 void *p;
450 int rc;
451
452 RESET_ERROR(conn);
453
454 rc = _lldpctl_do_something(conn,
455 CONN_STATE_GET_INTERFACES_SEND, CONN_STATE_GET_INTERFACES_RECV, NULL,
456 GET_INTERFACES,
457 NULL, NULL,
458 &p, &MARSHAL_INFO(lldpd_interface_list));
459 if (rc == 0) {
460 ifs = p;
461 return _lldpctl_new_atom(conn, atom_interfaces_list, ifs);
462 }
463 return NULL;
464 }
465
466 lldpctl_atom_t*
lldpctl_get_local_chassis(lldpctl_conn_t * conn)467 lldpctl_get_local_chassis(lldpctl_conn_t *conn)
468 {
469 struct lldpd_chassis *chassis;
470 void *p;
471 int rc;
472
473 RESET_ERROR(conn);
474
475 rc = _lldpctl_do_something(conn,
476 CONN_STATE_GET_CHASSIS_SEND, CONN_STATE_GET_CHASSIS_RECV, NULL,
477 GET_CHASSIS,
478 NULL, NULL,
479 &p, &MARSHAL_INFO(lldpd_chassis));
480 if (rc == 0) {
481 chassis = p;
482 return _lldpctl_new_atom(conn, atom_chassis, chassis, NULL, 0);
483 }
484 return NULL;
485 }
486
487 lldpctl_atom_t*
lldpctl_get_port(lldpctl_atom_t * atom)488 lldpctl_get_port(lldpctl_atom_t *atom)
489 {
490 int rc;
491 lldpctl_conn_t *conn = atom->conn;
492 struct lldpd_hardware *hardware;
493 void *p;
494 struct _lldpctl_atom_interface_t *iface =
495 (struct _lldpctl_atom_interface_t *)atom;
496
497 RESET_ERROR(conn);
498
499 if (atom->type != atom_interface) {
500 SET_ERROR(conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
501 return NULL;
502 }
503 rc = _lldpctl_do_something(conn,
504 CONN_STATE_GET_PORT_SEND, CONN_STATE_GET_PORT_RECV, iface->name,
505 GET_INTERFACE, (void*)iface->name, &MARSHAL_INFO(string),
506 &p, &MARSHAL_INFO(lldpd_hardware));
507 if (rc == 0) {
508 hardware = p;
509 return _lldpctl_new_atom(conn, atom_port, 1,
510 hardware, &hardware->h_lport, NULL);
511 }
512 return NULL;
513 }
514
515 lldpctl_atom_t*
lldpctl_get_default_port(lldpctl_conn_t * conn)516 lldpctl_get_default_port(lldpctl_conn_t *conn)
517 {
518 struct lldpd_port *port;
519 void *p;
520 int rc;
521
522 RESET_ERROR(conn);
523
524 rc = _lldpctl_do_something(conn,
525 CONN_STATE_GET_DEFAULT_PORT_SEND, CONN_STATE_GET_DEFAULT_PORT_RECV, "",
526 GET_DEFAULT_PORT, NULL, NULL,
527 &p, &MARSHAL_INFO(lldpd_port));
528 if (rc == 0) {
529 port = p;
530 return _lldpctl_new_atom(conn, atom_port, 1, NULL, port, NULL);
531 }
532 return NULL;
533 }
534
535 static lldpctl_map_t empty_map[] = {{ 0, NULL }};
536
537 static struct atom_map atom_map_list = {
538 .next = NULL
539 };
540
541 lldpctl_map_t*
lldpctl_key_get_map(lldpctl_key_t key)542 lldpctl_key_get_map(lldpctl_key_t key)
543 {
544 init_atom_map();
545 struct atom_map *map;
546 for (map = atom_map_list.next; map ; map = map->next) {
547 if (map->key == key)
548 return map->map;
549 }
550 return empty_map;
551 }
552
atom_map_register(struct atom_map * map,int prio)553 void atom_map_register(struct atom_map *map, int prio)
554 {
555 (void)prio;
556 struct atom_map* iter = &atom_map_list;
557
558 while (iter->next)
559 iter = iter->next;
560
561 iter->next = map;
562 }
563
564 static struct atom_builder atom_builder_list = {
565 .nextb = NULL
566 };
567
atom_builder_register(struct atom_builder * builder,int prio)568 void atom_builder_register(struct atom_builder *builder, int prio)
569 {
570 (void)prio;
571 struct atom_builder* iter = &atom_builder_list;
572
573 while (iter->nextb)
574 iter = iter->nextb;
575
576 iter->nextb = builder;
577 }
578
579 lldpctl_atom_t*
_lldpctl_new_atom(lldpctl_conn_t * conn,atom_t type,...)580 _lldpctl_new_atom(lldpctl_conn_t *conn, atom_t type, ...)
581 {
582 init_atom_builder();
583 struct atom_builder *builder;
584 struct lldpctl_atom_t *atom;
585 va_list(ap);
586 for (builder = atom_builder_list.nextb; builder ; builder = builder->nextb) {
587 if (builder->type != type) continue;
588 atom = calloc(1, builder->size);
589 if (atom == NULL) {
590 SET_ERROR(conn, LLDPCTL_ERR_NOMEM);
591 return NULL;
592 }
593 atom->count = 1;
594 atom->type = type;
595 atom->conn = conn;
596 TAILQ_INIT(&atom->buffers);
597 atom->free = builder->free;
598
599 atom->iter = builder->iter;
600 atom->next = builder->next;
601 atom->value = builder->value;
602
603 atom->get = builder->get;
604 atom->get_str = builder->get_str;
605 atom->get_buffer= builder->get_buffer;
606 atom->get_int = builder->get_int;
607
608 atom->set = builder->set;
609 atom->set_str = builder->set_str;
610 atom->set_buffer= builder->set_buffer;
611 atom->set_int = builder->set_int;
612 atom->create = builder->create;
613
614 va_start(ap, type);
615 if (builder->init && builder->init(atom, ap) == 0) {
616 free(atom);
617 va_end(ap);
618 /* Error to be set in init() */
619 return NULL;
620 }
621 va_end(ap);
622 return atom;
623 }
624 log_warnx("rpc", "unknown atom type: %d", type);
625 SET_ERROR(conn, LLDPCTL_ERR_FATAL);
626 return NULL;
627 }
628
629 /**
630 * Allocate a buffer inside an atom.
631 *
632 * It will be freed automatically when the atom is released. This buffer cannot
633 * be reallocated and should not be freed!
634 *
635 * @param atom Atom which will be used as a container.
636 * @param size Size of the allocated area.
637 * @return Pointer to the buffer or @c NULL if allocation fails.
638 */
639 void*
_lldpctl_alloc_in_atom(lldpctl_atom_t * atom,size_t size)640 _lldpctl_alloc_in_atom(lldpctl_atom_t *atom, size_t size)
641 {
642 struct atom_buffer *buffer;
643
644 if ((buffer = calloc(1, size + sizeof(struct atom_buffer))) == NULL) {
645 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
646 return NULL;
647 }
648 TAILQ_INSERT_TAIL(&atom->buffers, buffer, next);
649 return &buffer->data[0];
650 }
651
652 /**
653 * Allocate a buffer inside an atom and dump another buffer in it.
654 *
655 * The dump is done in hexadecimal with the provided separator.
656 *
657 * @param atom Atom which will be used as a container.
658 * @param input Buffer we want to dump.
659 * @param size Size of the buffer
660 * @param sep Separator to use.
661 * @param max Maximum number of bytes to dump. Can be 0 if no maximum.
662 * @return A string representing the dump of the buffer or @c NULL if error.
663 */
664 const char*
_lldpctl_dump_in_atom(lldpctl_atom_t * atom,const uint8_t * input,size_t size,char sep,size_t max)665 _lldpctl_dump_in_atom(lldpctl_atom_t *atom,
666 const uint8_t *input, size_t size,
667 char sep, size_t max)
668 {
669 static const char truncation[] = "[...]";
670 size_t i, len;
671 char *buffer = NULL;
672
673 if (max > 0 && size > max)
674 len = max * 3 + sizeof(truncation) + 1;
675 else
676 len = size * 3 + 1;
677
678 if ((buffer = _lldpctl_alloc_in_atom(atom, len)) == NULL)
679 return NULL;
680
681 for (i = 0; (i < size) && (max == 0 || i < max); i++)
682 snprintf(buffer + i * 3, 4, "%02x%c", *(u_int8_t*)(input + i), sep);
683 if (max > 0 && size > max)
684 snprintf(buffer + i * 3, sizeof(truncation) + 1, "%s", truncation);
685 else
686 *(buffer + i*3 - 1) = 0;
687 return buffer;
688 }
689