]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/ctl.c
Implement LLDP-MED reception and display
[thirdparty/lldpd.git] / src / ctl.c
1 /*
2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "lldpd.h"
18
19 #include <unistd.h>
20 #include <errno.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24
25 int
26 ctl_create(char *name)
27 {
28 int s;
29 struct sockaddr_un su;
30 int rc;
31
32 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
33 return -1;
34 su.sun_family = AF_UNIX;
35 strlcpy(su.sun_path, name, UNIX_PATH_MAX);
36 if (bind(s, (struct sockaddr *)&su, sizeof(struct sockaddr_un)) == -1) {
37 rc = errno; close(s); errno = rc;
38 return -1;
39 }
40 if (listen(s, 5) == -1) {
41 rc = errno; close(s); errno = rc;
42 return -1;
43 }
44 return s;
45 }
46
47 int
48 ctl_connect(char *name)
49 {
50 int s;
51 struct sockaddr_un su;
52 int rc;
53
54 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
55 return -1;
56 su.sun_family = AF_UNIX;
57 strlcpy(su.sun_path, name, UNIX_PATH_MAX);
58 if (connect(s, (struct sockaddr *)&su, sizeof(struct sockaddr_un)) == -1) {
59 rc = errno;
60 LLOG_WARN("unable to connect to socket " LLDPD_CTL_SOCKET);
61 errno = rc; return -1;
62 }
63 return s;
64 }
65
66 int
67 ctl_accept(struct lldpd *cfg, int c)
68 {
69 int s;
70 struct lldpd_client *lc;
71 if ((s = accept(c, NULL, NULL)) == -1) {
72 LLOG_WARN("unable to accept connection from socket");
73 return -1;
74 }
75 if ((lc = (struct lldpd_client *)malloc(sizeof(
76 struct lldpd_client))) == NULL) {
77 LLOG_WARN("failed to allocate memory for new client");
78 close(s);
79 return -1;
80 }
81 lc->fd = s;
82 TAILQ_INSERT_TAIL(&cfg->g_clients, lc, next);
83 return 1;
84 }
85
86 void
87 ctl_msg_init(struct hmsg *t, enum hmsg_type type)
88 {
89 t->hdr.type = type;
90 t->hdr.len = 0;
91 t->hdr.pid = getpid();
92 }
93
94 int
95 ctl_msg_send(int fd, struct hmsg *t)
96 {
97 return write(fd, t, t->hdr.len + sizeof(struct hmsg_hdr));
98 }
99
100 int
101 ctl_msg_recv(int fd, struct hmsg *t)
102 {
103 int n;
104 if ((n = read(fd, t, MAX_HMSGSIZE)) == -1) {
105 return -1;
106 }
107 if (n < sizeof(struct hmsg_hdr)) {
108 LLOG_WARNX("message received too short");
109 errno = 0;
110 return -1;
111 }
112 if (n != sizeof(struct hmsg_hdr) + t->hdr.len) {
113 LLOG_WARNX("message from %d seems to be truncated (or too large)",
114 t->hdr.pid);
115 errno = 0;
116 return -1;
117 }
118 return 1;
119 }
120
121 int
122 ctl_close(struct lldpd *cfg, int c)
123 {
124 struct lldpd_client *client, *client_next;
125 for (client = TAILQ_FIRST(&cfg->g_clients);
126 client != NULL;
127 client = client_next) {
128 client_next = TAILQ_NEXT(client, next);
129 if (client->fd == c) {
130 close(client->fd);
131 TAILQ_REMOVE(&cfg->g_clients, client, next);
132 free(client);
133 return 1;
134 }
135 }
136 /* Not found */
137 return -1;
138 }
139
140 void
141 ctl_cleanup(char *name)
142 {
143 if (unlink(name) == -1)
144 LLOG_WARN("unable to unlink %s", name);
145 }
146
147 /* Packing/unpacking */
148
149 /* This structure is used to track memory allocation when unpacking */
150 struct gc {
151 TAILQ_ENTRY(gc) next;
152 void *pointer;
153 };
154 TAILQ_HEAD(gc_l, gc);
155
156 typedef struct { char c; int16_t x; } st_int16;
157 typedef struct { char c; int32_t x; } st_int32;
158 typedef struct { char c; void *x; } st_void_p;
159
160 #define INT16_ALIGN (sizeof(st_int16) - sizeof(int16_t))
161 #define INT32_ALIGN (sizeof(st_int32) - sizeof(int32_t))
162 #define VOID_P_ALIGN (sizeof(st_void_p) - sizeof(void *))
163
164 struct formatdef {
165 char format;
166 int size;
167 int alignment;
168 int (*pack)(struct hmsg*, void **, void *,
169 const struct formatdef *);
170 int (*unpack)(struct hmsg*, void **, void *,
171 const struct formatdef *, struct gc_l *);
172 };
173
174 /* void** is a pointer to a pointer to the end of struct hmsg*. It should be
175 * updated. void* is a pointer to the entity to pack */
176
177 int
178 _ctl_alloc_pointer(struct gc_l *pointers, void *pointer)
179 {
180 struct gc *gpointer;
181 if (pointers != NULL) {
182 if ((gpointer = (struct gc *)calloc(1,
183 sizeof(struct gc))) == NULL) {
184 LLOG_WARN("unable to allocate memory for garbage collector");
185 return -1;
186 }
187 gpointer->pointer = pointer;
188 TAILQ_INSERT_TAIL(pointers, gpointer, next);
189 }
190 return 0;
191 }
192
193 void
194 _ctl_free_pointers(struct gc_l *pointers, int listonly)
195 {
196 struct gc *pointer, *pointer_next;
197 for (pointer = TAILQ_FIRST(pointers);
198 pointer != NULL;
199 pointer = pointer_next) {
200 pointer_next = TAILQ_NEXT(pointer, next);
201 TAILQ_REMOVE(pointers, pointer, next);
202 if (!listonly)
203 free(pointer->pointer);
204 free(pointer);
205 }
206 }
207
208 int
209 pack_copy(struct hmsg *h, void **p, void *s,
210 const struct formatdef *ct)
211 {
212 if (h->hdr.len + ct->size > MAX_HMSGSIZE - sizeof(struct hmsg_hdr)) {
213 LLOG_WARNX("message became too large");
214 return -1;
215 }
216 memcpy(*p, s, ct->size);
217 *p += ct->size;
218 h->hdr.len += ct->size;
219 return ct->size;
220 }
221
222 int
223 unpack_copy(struct hmsg *h, void **p, void *s,
224 const struct formatdef *ct, struct gc_l *pointers)
225 {
226 memcpy(s, *p, ct->size);
227 *p += ct->size;
228 return ct->size;
229 }
230
231 int
232 pack_string(struct hmsg *h, void **p, void *s,
233 const struct formatdef *ct)
234 {
235 int len, ss;
236 if ((*(char**)s) == NULL)
237 len = -1;
238 else
239 len = strlen(*(char**)s);
240 if (h->hdr.len + len + sizeof(int) > MAX_HMSGSIZE -
241 sizeof(struct hmsg_hdr)) {
242 LLOG_WARNX("message became too large");
243 return -1;
244 }
245 memcpy(*p, &len, sizeof(int));
246 *p += sizeof(int);
247 ss = sizeof(int);
248 if (len != -1) {
249 memcpy(*p, *(char **)s, len);
250 *p += len;
251 ss += len;
252 }
253 h->hdr.len += ss;
254 return ss;
255 }
256
257 int
258 unpack_string(struct hmsg *h, void **p, void *s,
259 const struct formatdef *ct, struct gc_l *pointers)
260 {
261 char *string;
262 int len = *(int*)*p;
263 *p += sizeof(int);
264 if (len == -1) {
265 string = NULL;
266 } else {
267 if ((string = (char *)calloc(1, len + 1)) == NULL) {
268 LLOG_WARNX("unable to allocate new string");
269 return -1;
270 }
271 if (_ctl_alloc_pointer(pointers, string) == -1) {
272 free(string);
273 return -1;
274 }
275 memcpy(string, *p, len);
276 *p += len;
277 }
278 memcpy(s, &string, sizeof(char *));
279 return sizeof(char*);
280 }
281
282 int
283 pack_chars(struct hmsg *h, void **p, void *s,
284 const struct formatdef *ct)
285 {
286 char *string;
287 int string_len;
288 string = *(char **)s;
289 s += sizeof(char *);
290 string_len = *(int *)s;
291
292 if (h->hdr.len + string_len + sizeof(int) > MAX_HMSGSIZE -
293 sizeof(struct hmsg_hdr)) {
294 LLOG_WARNX("message became too large");
295 return -1;
296 }
297 memcpy(*p, &string_len, sizeof(int));
298 *p += sizeof(int);
299 memcpy(*p, string, string_len);
300 *p += string_len;
301 h->hdr.len += sizeof(int) + string_len;
302 return sizeof(int) + string_len;
303 }
304
305 int
306 unpack_chars(struct hmsg *h, void **p, void *s,
307 const struct formatdef *ct, struct gc_l *pointers)
308 {
309 char *string;
310 struct {
311 char *string;
312 int len;
313 } reals __attribute__ ((__packed__));
314 int len = *(int*)*p;
315 *p += sizeof(int);
316 if ((string = (char *)malloc(len)) == NULL) {
317 LLOG_WARN("unable to allocate new string");
318 return -1;
319 }
320 if (_ctl_alloc_pointer(pointers, string) == -1) {
321 free(string);
322 return -1;
323 }
324 memcpy(string, *p, len);
325 *p += len;
326 reals.string = string;
327 reals.len = len;
328 memcpy(s, &reals, sizeof(reals));
329 return sizeof(char*);
330 }
331
332 int
333 pack_zero(struct hmsg *h, void **p, void *s,
334 const struct formatdef *ct)
335 {
336 if (h->hdr.len + ct->size > MAX_HMSGSIZE - sizeof(struct hmsg_hdr)) {
337 LLOG_WARNX("message became too large");
338 return -1;
339 }
340 memset(*p, 0, ct->size);
341 *p += ct->size;
342 h->hdr.len += ct->size;
343 return ct->size;
344 }
345
346 static struct formatdef conv_table[] = {
347 {'b', 1, 0,
348 pack_copy, unpack_copy},
349 {'w', 2, INT16_ALIGN,
350 pack_copy, unpack_copy},
351 {'l', 4, INT32_ALIGN,
352 pack_copy, unpack_copy},
353 /* Null terminated string */
354 {'s', sizeof(void*), VOID_P_ALIGN,
355 pack_string, unpack_string},
356 /* Pointer (is packed with 0) */
357 {'P', sizeof(void*), VOID_P_ALIGN,
358 pack_zero, unpack_copy},
359 /* A list (same as pointer), should be at the beginning */
360 {'L', sizeof(void*)*2, VOID_P_ALIGN,
361 pack_zero, unpack_copy},
362 /* Non null terminated string, followed by an int for the size */
363 {'C', sizeof(void*) + sizeof(int), VOID_P_ALIGN,
364 pack_chars, unpack_chars},
365 {0}
366 };
367
368 /* Lists can be packed only if the "next" member is the first one of the
369 * structure! No check is done for this. */
370 struct fakelist_m {
371 TAILQ_ENTRY(fakelist_m) next;
372 void *data;
373 };
374 TAILQ_HEAD(fakelist_l, fakelist_m);
375
376 int
377 ctl_msg_pack_structure(char *format, void *structure, unsigned int size,
378 struct hmsg *h, void **p)
379 {
380 char *f;
381 struct formatdef *ce;
382 unsigned int csize = 0;
383 uintptr_t offset;
384 int maxalign = 0;
385
386 for (f = format; *f != 0; f++) {
387 for (ce = conv_table;
388 ce->format != 0;
389 ce++) {
390 if (ce->format == *f)
391 break;
392 }
393 if (ce->format != *f) {
394 LLOG_WARNX("unknown format char %c in %s", *f,
395 format);
396 return -1;
397 }
398 if (ce->alignment != 0) {
399 maxalign = (maxalign>ce->alignment)?maxalign:ce->alignment;
400 offset = (uintptr_t)structure % ce->alignment;
401 if (offset != 0) {
402 structure = structure +
403 (ce->alignment - offset);
404 csize += ce->alignment - offset;
405 }
406 }
407 if (ce->pack(h, p, structure, ce) == -1) {
408 LLOG_WARNX("error while packing %c in %s", *f,
409 format);
410 return -1;
411 }
412 structure += ce->size;
413 csize += ce->size;
414 }
415
416 /* End padding */
417 if ((maxalign > 0) && (csize % maxalign != 0))
418 csize = csize + maxalign - (csize % maxalign);
419 if (size != csize) {
420 LLOG_WARNX("size of structure does not match its "
421 "declaration (%d vs %d)", size, csize);
422 return -1;
423 }
424 return 0;
425 }
426
427 int
428 _ctl_msg_unpack_structure(char *format, void *structure, unsigned int size,
429 struct hmsg *h, void **p, struct gc_l *pointers)
430 {
431 char *f;
432 struct formatdef *ce;
433 unsigned int csize = 0;
434 uintptr_t offset;
435 int maxalign = 0;
436
437 for (f = format; *f != 0; f++) {
438 for (ce = conv_table;
439 ce->format != 0;
440 ce++) {
441 if (ce->format == *f)
442 break;
443 }
444 if (ce->format != *f) {
445 LLOG_WARNX("unknown format char %c", *f);
446 return -1;
447 }
448 if (ce->alignment != 0) {
449 maxalign = (maxalign>ce->alignment)?maxalign:ce->alignment;
450 offset = (uintptr_t)structure % ce->alignment;
451 if (offset != 0) {
452 structure = structure +
453 (ce->alignment - offset);
454 csize += ce->alignment - offset;
455 }
456 }
457 csize += ce->size;
458 if (csize > size) {
459 LLOG_WARNX("size of structure is too small for given "
460 "format (%d vs %d)", size, csize);
461 return -1;
462 }
463
464 if (ce->unpack(h, p, structure, ce, pointers) == -1) {
465 LLOG_WARNX("error while unpacking %c", *f);
466 return -1;
467 }
468 structure += ce->size;
469 }
470
471 /* End padding */
472 if ((maxalign > 0) && (csize % maxalign != 0))
473 csize = csize + maxalign - (csize % maxalign);
474 if (size < csize) {
475 LLOG_WARNX("size of structure does not match its "
476 "declaration (%d vs %d)", size, csize);
477 return -1;
478 }
479 return 0;
480 }
481
482 int
483 ctl_msg_unpack_structure(char *format, void *structure, unsigned int size,
484 struct hmsg *h, void **p)
485 {
486 struct gc_l pointers;
487 int rc;
488 TAILQ_INIT(&pointers);
489 if ((rc = _ctl_msg_unpack_structure(format, structure, size,
490 h, p, &pointers)) == -1) {
491 LLOG_WARNX("unable to unpack structure, freeing");
492 _ctl_free_pointers(&pointers, 0);
493 return -1;
494 }
495 _ctl_free_pointers(&pointers, 1);
496 return rc;
497 }
498
499 int
500 ctl_msg_pack_list(char *format, void *list, unsigned int size, struct hmsg *h, void **p)
501 {
502 struct fakelist_m *member;
503 struct fakelist_l *flist = (struct fakelist_l *)list;
504 TAILQ_FOREACH(member, flist, next) {
505 if (ctl_msg_pack_structure(format, member, size, h, p) == -1) {
506 LLOG_WARNX("error while packing list, aborting");
507 return -1;
508 }
509 }
510 return 0;
511 }
512
513 int
514 ctl_msg_unpack_list(char *format, void *list, unsigned int size, struct hmsg *h, void **p)
515 {
516 struct fakelist_m *member, *member_next;
517 struct gc_l pointers;
518 struct fakelist_l *flist = (struct fakelist_l *)list;
519 if (format[0] != 'L') {
520 LLOG_WARNX("to unpack a list, format should start with 'L'");
521 return -1;
522 }
523 TAILQ_INIT(flist);
524 TAILQ_INIT(&pointers);
525 while (*p - (void *)h - sizeof(struct hmsg_hdr) < h->hdr.len) {
526 if ((member = calloc(1, size)) == NULL) {
527 LLOG_WARN("unable to allocate memory for structure");
528 return -1;
529 }
530 if (_ctl_msg_unpack_structure(format, member, size,
531 h, p, &pointers) == -1) {
532 LLOG_WARNX("unable to unpack list, aborting");
533 free(member);
534 /* Free each list member */
535 for (member = TAILQ_FIRST(flist);
536 member != NULL;
537 member = member_next) {
538 member_next = TAILQ_NEXT(member, next);
539 TAILQ_REMOVE(flist, member, next);
540 free(member);
541 }
542 _ctl_free_pointers(&pointers, 0);
543 return -1;
544 }
545 TAILQ_INSERT_TAIL(flist, member, next);
546 }
547 _ctl_free_pointers(&pointers, 1);
548 return 0;
549 }