From: Vincent Bernat Date: Mon, 23 Jan 2012 21:24:00 +0000 (+0100) Subject: Major rewrite: rewrite lldpd/lldpctl communication mechanism X-Git-Tag: 0.6.0~60 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f6d206319b2fb5ec30a9bef8d6e04a5ffa118ca6;p=thirdparty%2Flldpd.git Major rewrite: rewrite lldpd/lldpctl communication mechanism The new marshalling stuff is used instead of the previous packing mechanism. Less code. Better code. --- diff --git a/src/Makefile.am b/src/Makefile.am index 6931ef63..006ac624 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,7 +15,7 @@ lldpd_SOURCES = main.c lldpd_LDADD = liblldpd.la ## lldpctl -lldpctl_SOURCES = lldpctl.c display.c writer.h text_writer.c kv_writer.c +lldpctl_SOURCES = lldpctl.h lldpctl.c display.c writer.h text_writer.c kv_writer.c lldpctl_LDADD = libcommon.la ## With SNMP... diff --git a/src/client.c b/src/client.c index 036fa89d..b9bfca48 100644 --- a/src/client.c +++ b/src/client.c @@ -16,100 +16,28 @@ #include "lldpd.h" -static struct client_handle client_handles[] = { - { HMSG_NONE, client_handle_none }, - { HMSG_GET_INTERFACES, client_handle_get_interfaces }, - { HMSG_GET_NB_PORTS, client_handle_port_related }, - { HMSG_GET_PORT, client_handle_port_related }, - { HMSG_GET_CHASSIS, client_handle_port_related }, -#ifdef ENABLE_LLDPMED - { HMSG_SET_LOCATION, client_handle_port_related }, - { HMSG_SET_POLICY, client_handle_port_related }, - { HMSG_SET_POWER, client_handle_port_related }, -#endif -#ifdef ENABLE_DOT3 - { HMSG_SET_DOT3_POWER, client_handle_port_related }, -#endif -#ifdef ENABLE_DOT1 - { HMSG_GET_VLANS, client_handle_port_related }, - { HMSG_GET_PPVIDS, client_handle_port_related }, - { HMSG_GET_PIDS, client_handle_port_related }, -#endif - { HMSG_SHUTDOWN, client_handle_shutdown }, - { 0, NULL } }; - -void -client_handle_client(struct lldpd *cfg, struct lldpd_callback *callback, - char *buffer, int n) +static int +client_handle_none(struct lldpd *cfg, enum hmsg_type *type, + void *input, int input_len, void **output) { - struct hmsg *h; /* Reception */ - struct hmsg *t; /* Sending */ - struct client_handle *ch; - - if (n < sizeof(struct hmsg_hdr)) { - LLOG_WARNX("too short message request received"); - return; - } - h = (struct hmsg *)buffer; - n -= sizeof(struct hmsg_hdr); - if (n != h->hdr.len) { - LLOG_WARNX("incorrect message size received from %d", - h->hdr.pid); - return; - } - - if ((t = (struct hmsg*)malloc(MAX_HMSGSIZE)) == NULL) { - LLOG_WARNX("unable to allocate memory to answer to %d", - h->hdr.pid); - return; - } - ctl_msg_init(t, h->hdr.type); - for (ch = client_handles; ch->handle != NULL; ch++) { - if (ch->type == h->hdr.type) { - ch->handle(cfg, h, t); - if (t->hdr.len == -1) { - t->hdr.len = 0; - t->hdr.type = HMSG_NONE; - } - if (ctl_msg_send(callback->fd, t) == -1) - LLOG_WARN("unable to send answer to client %d", - h->hdr.pid); - free(t); - return; - } - } - - LLOG_WARNX("unknown message request (%d) received from %d", - h->hdr.type, h->hdr.pid); - free(t); - return; + LLOG_INFO("received noop request from client"); + *type = NONE; + return 0; } -void -client_handle_shutdown(struct lldpd *cfg, struct hmsg *r, struct hmsg *s) -{ - LLOG_INFO("received shutdown request from client %d", - r->hdr.pid); - exit(0); -} - -void -client_handle_none(struct lldpd *cfg, struct hmsg *r, struct hmsg *s) -{ - LLOG_INFO("received noop request from client %d", - r->hdr.pid); - s->hdr.len = -1; -} - -void -client_handle_get_interfaces(struct lldpd *cfg, struct hmsg *r, struct hmsg *s) +/* Return the list of interfaces. + Input: nothing. + Output: list of interface names (lldpd_interface_list) +*/ +static int +client_handle_get_interfaces(struct lldpd *cfg, enum hmsg_type *type, + void *input, int input_len, void **output) { struct lldpd_interface *iff, *iff_next; struct lldpd_hardware *hardware; - void *p; /* Build the list of interfaces */ - TAILQ_HEAD(, lldpd_interface) ifs; + struct lldpd_interface_list ifs; TAILQ_INIT(&ifs); TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) { if ((iff = (struct lldpd_interface*)malloc(sizeof( @@ -119,11 +47,10 @@ client_handle_get_interfaces(struct lldpd *cfg, struct hmsg *r, struct hmsg *s) TAILQ_INSERT_TAIL(&ifs, iff, next); } - p = &s->data; - if (ctl_msg_pack_list(STRUCT_LLDPD_INTERFACE, &ifs, - sizeof(struct lldpd_interface), s, &p) == -1) { - LLOG_WARNX("unable to pack list of interfaces"); - s->hdr.len = -1; + int output_len = marshal_serialize(lldpd_interface_list, &ifs, output); + if (output_len <= 0) { + output_len = 0; + *type = NONE; } /* Free the temporary list */ @@ -134,227 +61,161 @@ client_handle_get_interfaces(struct lldpd *cfg, struct hmsg *r, struct hmsg *s) TAILQ_REMOVE(&ifs, iff, next); free(iff); } + + return output_len; } -void -client_handle_port_related(struct lldpd *cfg, struct hmsg *r, struct hmsg *s) +/* Return all available information related to an interface + Input: name of the interface (serialized) + Output: Information about the interface (lldpd_hardware) +*/ +static int +client_handle_get_interface(struct lldpd *cfg, enum hmsg_type *type, + void *input, int input_len, void **output) { - char *ifname; + /* Get name of the interface */ + char *name; + if (marshal_unserialize(string, input, input_len, &name) <= 0) { + *type = NONE; + return 0; + } + + /* Search appropriate hardware */ struct lldpd_hardware *hardware; - struct lldpd_port *port; - void *p; - int i; + TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) + if (!strcmp(hardware->h_ifname, name)) { + int output_len = marshal_serialize(lldpd_hardware, hardware, output); + free(name); + if (output_len <= 0) { + *type = NONE; + free(name); + return 0; + } + return output_len; + } + + free(name); + LLOG_WARNX("no interface %s found", name); + *type = NONE; + return 0; +} + +/* Set some port related settings (policy, location, power) + Input: name of the interface, policy/location/power setting to be modified + Output: nothing +*/ +static int +client_handle_set_port(struct lldpd *cfg, enum hmsg_type *type, + void *input, int input_len, void **output) +{ + int ret = 0; + struct lldpd_port_set *set; - ifname = (char*)(&r->data); - if ((r->hdr.len < IFNAMSIZ) || (ifname[IFNAMSIZ - 1] != 0)) { - LLOG_WARNX("bad message format for get port related message (%d)", - r->hdr.type); - s->hdr.len = -1; - return; + if (marshal_unserialize(lldpd_port_set, input, input_len, &set) <= 0) { + *type = NONE; + return 0; } - TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) { - if (strncmp(ifname, hardware->h_ifname, IFNAMSIZ) == 0) { - switch (r->hdr.type) { + if (!set->ifname) { + LLOG_WARNX("no interface provided"); + goto set_port_finished; + } + + /* Search the appropriate hardware */ + struct lldpd_hardware *hardware; + TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) + if (!strcmp(hardware->h_ifname, set->ifname)) { + struct lldpd_port *port = &hardware->h_lport; #ifdef ENABLE_LLDPMED - case HMSG_SET_LOCATION: - p = (char*)&r->data + IFNAMSIZ; - for (i=0; i < LLDPMED_LOCFORMAT_LAST; i++) { - free(hardware->h_lport.p_med_location[i].data); - hardware->h_lport.p_med_location[i].data = NULL; - hardware->h_lport.p_med_location[i].format = 0; - } - if (ctl_msg_unpack_structure(STRUCT_LLDPD_MED_LOC - STRUCT_LLDPD_MED_LOC STRUCT_LLDPD_MED_LOC, - hardware->h_lport.p_med_location, - 3*sizeof(struct lldpd_med_loc), r, &p) == -1) { - LLOG_WARNX("unable to set location for %s", ifname); - s->hdr.len = -1; - return; - } - hardware->h_lport.p_med_cap_enabled |= LLDPMED_CAP_LOCATION; - break; - case HMSG_SET_POLICY: - p = (char*)&r->data + IFNAMSIZ; - for (i=0; i < LLDPMED_APPTYPE_LAST; i++) { - hardware->h_lport.p_med_policy[i].type = 0; - hardware->h_lport.p_med_policy[i].unknown = 0; - hardware->h_lport.p_med_policy[i].tagged = 0; - hardware->h_lport.p_med_policy[i].vid = 0; - hardware->h_lport.p_med_policy[i].priority = 0; - hardware->h_lport.p_med_policy[i].dscp = 0; - } - if (ctl_msg_unpack_structure( - STRUCT_LLDPD_MED_POLICY - STRUCT_LLDPD_MED_POLICY - STRUCT_LLDPD_MED_POLICY - STRUCT_LLDPD_MED_POLICY - STRUCT_LLDPD_MED_POLICY - STRUCT_LLDPD_MED_POLICY - STRUCT_LLDPD_MED_POLICY - STRUCT_LLDPD_MED_POLICY, - hardware->h_lport.p_med_policy, - 8*sizeof(struct lldpd_med_policy), - r, &p) == -1) { - LLOG_WARNX("unable to set network policy for %s", ifname); - s->hdr.len = -1; - return; - } - hardware->h_lport.p_med_cap_enabled |= - LLDPMED_CAP_POLICY; - break; - case HMSG_SET_POWER: - p = (char*)&r->data + IFNAMSIZ; - memset(&hardware->h_lport.p_med_power, 0, - sizeof(struct lldpd_med_power)); - if (ctl_msg_unpack_structure(STRUCT_LLDPD_MED_POWER, - &hardware->h_lport.p_med_power, - sizeof(struct lldpd_med_power), - r, &p) == -1) { - LLOG_WARNX("unable to set POE-MDI for %s", - ifname); - s->hdr.len = -1; - return; - } - hardware->h_lport.p_med_cap_enabled &= ~( - LLDPMED_CAP_MDI_PD | LLDPMED_CAP_MDI_PSE); - switch (hardware->h_lport.p_med_power.devicetype) - { - case LLDPMED_POW_TYPE_PSE: - hardware->h_lport.p_med_cap_enabled |= - LLDPMED_CAP_MDI_PSE; - break; - case LLDPMED_POW_TYPE_PD: - hardware->h_lport.p_med_cap_enabled |= - LLDPMED_CAP_MDI_PD; - break; - } - break; + if (set->med_policy && set->med_policy->type > 0) { + if (set->med_policy->type > LLDPMED_APPTYPE_LAST) { + LLOG_WARNX("invalid policy provided: %d", + set->med_policy->type); + goto set_port_finished; + } + memcpy(&port->p_med_policy[set->med_policy->type - 1], + set->med_policy, sizeof(struct lldpd_med_policy)); + port->p_med_cap_enabled |= LLDPMED_CAP_POLICY; + } + if (set->med_location && set->med_location->format > 0) { + if (set->med_location->format > LLDPMED_LOCFORMAT_LAST) { + LLOG_WARNX("invalid location format provided: %d", + set->med_location->format); + goto set_port_finished; + } + struct lldpd_med_loc *loc = \ + &port->p_med_location[set->med_location->format - 1]; + free(loc->data); + memcpy(loc, set->med_location, sizeof(struct lldpd_med_loc)); + if (!loc->data || !(loc->data = strdup(loc->data))) loc->data_len = 0; + port->p_med_cap_enabled |= LLDPMED_CAP_LOCATION; + } + if (set->med_power) { + memcpy(&port->p_med_power, set->med_power, + sizeof(struct lldpd_med_power)); + switch (set->med_power->devicetype) { + case LLDPMED_POW_TYPE_PD: + port->p_med_cap_enabled |= LLDPMED_CAP_MDI_PD; + port->p_med_cap_enabled &= ~LLDPMED_CAP_MDI_PSE; + break; + case LLDPMED_POW_TYPE_PSE: + port->p_med_cap_enabled |= LLDPMED_CAP_MDI_PSE; + port->p_med_cap_enabled &= ~LLDPMED_CAP_MDI_PD; + break; + } + } #endif #ifdef ENABLE_DOT3 - case HMSG_SET_DOT3_POWER: - p = (char*)&r->data + IFNAMSIZ; - memset(&hardware->h_lport.p_power, 0, - sizeof(struct lldpd_dot3_power)); - if (ctl_msg_unpack_structure(STRUCT_LLDPD_DOT3_POWER, - &hardware->h_lport.p_power, - sizeof(struct lldpd_dot3_power), - r, &p) == -1) { - LLOG_WARNX("unable to set POE-MDI for %s", - ifname); - s->hdr.len = -1; - return; - } - break; + if (set->dot3_power) + memcpy(&port->p_power, set->dot3_power, + sizeof(struct lldpd_dot3_power)); #endif - case HMSG_GET_NB_PORTS: - p = &s->data; - i = 0; - TAILQ_FOREACH(port, &hardware->h_rports, p_entries) { - if (SMART_HIDDEN(port)) continue; - i++; - } - memcpy(p, &i, sizeof(int)); - s->hdr.len = sizeof(int); - break; - case HMSG_GET_VLANS: - case HMSG_GET_PPVIDS: - case HMSG_GET_PIDS: - case HMSG_GET_PORT: - case HMSG_GET_CHASSIS: - /* We read the index which is right after the interface name */ - if (r->hdr.len < IFNAMSIZ + sizeof(int)) { - LLOG_WARNX("too short message format for get " - "port related message (%d)", r->hdr.type); - s->hdr.len = -1; - return; - } - p = (char*)&r->data + IFNAMSIZ; - memcpy(&i, p, sizeof(int)); - p = &s->data; - TAILQ_FOREACH(port, &hardware->h_rports, p_entries) { - if (SMART_HIDDEN(port)) continue; - if (i-- == 0) break; - } - if (!port) { - LLOG_INFO("out of range index requested for port " - "related information on interface %s for %d", - ifname, r->hdr.pid); - s->hdr.len = -1; - return; - } - p = (char*)&s->data; - switch (r->hdr.type) { -#ifdef ENABLE_DOT1 - case HMSG_GET_VLANS: - if (ctl_msg_pack_list(STRUCT_LLDPD_VLAN, - &port->p_vlans, - sizeof(struct lldpd_vlan), s, &p) == -1) { - LLOG_WARNX("unable to send vlans information for " - "interface %s for %d", ifname, r->hdr.pid); - s->hdr.len = -1; - return; - } - break; - case HMSG_GET_PPVIDS: - if (ctl_msg_pack_list( - STRUCT_LLDPD_PPVID, - &port->p_ppvids, - sizeof(struct lldpd_ppvid), s, &p) == -1) { - LLOG_WARNX("unable to send ppvids information for " - "interface %s for %d", ifname, r->hdr.pid); - s->hdr.len = -1; - return; - } - break; - case HMSG_GET_PIDS: - if (ctl_msg_pack_list( - STRUCT_LLDPD_PI, - &port->p_pids, - sizeof(struct lldpd_pi), s, &p) == -1) { - LLOG_WARNX("unable to send PI's information for " - "interface %s for %d", ifname, r->hdr.pid); - s->hdr.len = -1; - return; - } - break; + ret = 1; + break; + } + + if (ret == 0) + LLOG_WARN("no interface %s found", set->ifname); + +set_port_finished: + if (!ret) *type = NONE; + free(set->ifname); +#ifdef ENABLE_LLDPMED + free(set->med_policy); + if (set->med_location) free(set->med_location->data); + free(set->med_location); + free(set->med_power); #endif - case HMSG_GET_PORT: - if (ctl_msg_pack_structure(STRUCT_LLDPD_PORT, - port, - sizeof(struct lldpd_port), s, &p) == -1) { - LLOG_WARNX("unable to send port information for " - "interface %s for %d", ifname, r->hdr.pid); - s->hdr.len = -1; - return; - } - break; - case HMSG_GET_CHASSIS: - if (ctl_msg_pack_structure(STRUCT_LLDPD_CHASSIS, - port->p_chassis, - sizeof(struct lldpd_chassis), s, &p) == -1) { - LLOG_WARNX("unable to send chassis information " - "for interface %s for %d", - ifname, r->hdr.pid); - s->hdr.len = -1; - return; - } - break; - default: - LLOG_WARNX("don't know what to do"); - s->hdr.len = -1; - return; - } - break; - default: - LLOG_WARNX("don't know what to do"); - s->hdr.len = -1; - return; - } - return; +#ifdef ENABLE_DOT3 + free(set->dot3_power); +#endif + return 0; +} + +static struct client_handle client_handles[] = { + { NONE, client_handle_none }, + { GET_INTERFACES, client_handle_get_interfaces }, + { GET_INTERFACE, client_handle_get_interface }, + { SET_PORT, client_handle_set_port }, + { 0, NULL } }; + +int +client_handle_client(struct lldpd *cfg, struct lldpd_callback *callback, + enum hmsg_type type, void *buffer, int n) +{ + struct client_handle *ch; + void *answer; int len, sent; + for (ch = client_handles; ch->handle != NULL; ch++) { + if (ch->type == type) { + answer = NULL; len = 0; + len = ch->handle(cfg, &type, buffer, n, &answer); + if ((sent = ctl_msg_send(callback->fd, type, answer, len)) == -1) + LLOG_WARN("unable to send answer to client"); + free(answer); + return sent; } } - LLOG_WARNX("requested interface %s by %d was not found", - ifname, r->hdr.pid); - s->hdr.len = -1; - return; + + LLOG_WARNX("unknown message request (%d) received", + type); + return -1; } diff --git a/src/ctl-server.c b/src/ctl-server.c index 090db258..a0d5e962 100644 --- a/src/ctl-server.c +++ b/src/ctl-server.c @@ -25,23 +25,12 @@ static void ctl_callback(struct lldpd *cfg, struct lldpd_callback *callback) { - char *buffer; - int n; + enum hmsg_type type; + void *buffer = NULL; + int n; - if ((buffer = (char *)malloc(MAX_HMSGSIZE)) == - NULL) { - LLOG_WARN("failed to alloc reception buffer"); - return; - } - if ((n = recv(callback->fd, buffer, - MAX_HMSGSIZE, 0)) == -1) { - LLOG_WARN("error while receiving message"); - free(buffer); - return; - } - if (n > 0) - client_handle_client(cfg, callback, buffer, n); - else { + if ((n = ctl_msg_recv(callback->fd, &type, &buffer)) == -1 || + client_handle_client(cfg, callback, type, buffer, n) == -1) { close(callback->fd); lldpd_callback_del(cfg, callback->fd, ctl_callback); } diff --git a/src/ctl.c b/src/ctl.c index 3bf38030..6c644cbd 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -17,6 +17,7 @@ #include "lldpd.h" #include +#include #include #include #include @@ -63,499 +64,146 @@ ctl_connect(char *name) return s; } -void -ctl_msg_init(struct hmsg *t, enum hmsg_type type) -{ - memset(t, 0, MAX_HMSGSIZE); - t->hdr.type = type; - t->hdr.len = 0; - t->hdr.pid = getpid(); -} +struct hmsg_header { + enum hmsg_type type; + size_t len; +}; +/* The protocol is pretty simple. We send a single message containing the + * provided message type with the message length, followed by the message + * content. It is expected the message content to be serialized. */ int -ctl_msg_send(int fd, struct hmsg *t) +ctl_msg_send(int fd, enum hmsg_type type, void *t, size_t len) { - return write(fd, t, t->hdr.len + sizeof(struct hmsg_hdr)); + struct iovec iov[2]; + struct hmsg_header hdr; + hdr.type = type; + hdr.len = len; + iov[0].iov_base = &hdr; + iov[0].iov_len = sizeof(struct hmsg_header); + iov[1].iov_base = t; + iov[1].iov_len = len; + return writev(fd, iov, t?2:1); } int -ctl_msg_recv(int fd, struct hmsg *t) -{ - int n; - if ((n = read(fd, t, MAX_HMSGSIZE)) == -1) { - return -1; - } - if (n < sizeof(struct hmsg_hdr)) { - LLOG_WARNX("message received too short"); - errno = 0; - return -1; - } - if (n != sizeof(struct hmsg_hdr) + t->hdr.len) { - LLOG_WARNX("message from %d seems to be truncated (or too large)", - t->hdr.pid); - errno = 0; - return -1; - } - return 1; -} - -void -ctl_cleanup(char *name) -{ - if (unlink(name) == -1) - LLOG_WARN("unable to unlink %s", name); -} - -/* Packing/unpacking */ - -/* This structure is used to track memory allocation when unpacking */ -struct gc { - TAILQ_ENTRY(gc) next; - void *pointer; -}; -TAILQ_HEAD(gc_l, gc); - -typedef struct { char c; int16_t x; } st_int16; -typedef struct { char c; int32_t x; } st_int32; -typedef struct { char c; time_t x; } st_timet; -typedef struct { char c; void *x; } st_void_p; - -#define INT16_ALIGN (sizeof(st_int16) - sizeof(int16_t)) -#define INT32_ALIGN (sizeof(st_int32) - sizeof(int32_t)) -#define TIMET_ALIGN (sizeof(st_timet) - sizeof(time_t)) -#define VOID_P_ALIGN (sizeof(st_void_p) - sizeof(void *)) - -struct formatdef { - char format; - int size; - int alignment; - int (*pack)(struct hmsg*, void **, void *, - const struct formatdef *); - int (*unpack)(struct hmsg*, void **, void *, - const struct formatdef *, struct gc_l *); -}; - -/* void** is a pointer to a pointer to the end of struct hmsg*. It should be - * updated. void* is a pointer to the entity to pack */ - -static int -ctl_alloc_pointer(struct gc_l *pointers, void *pointer) -{ - struct gc *gpointer; - if (pointers != NULL) { - if ((gpointer = (struct gc *)calloc(1, - sizeof(struct gc))) == NULL) { - LLOG_WARN("unable to allocate memory for garbage collector"); - return -1; - } - gpointer->pointer = pointer; - TAILQ_INSERT_TAIL(pointers, gpointer, next); - } - return 0; -} - -static void -ctl_free_pointers(struct gc_l *pointers, int listonly) -{ - struct gc *pointer, *pointer_next; - for (pointer = TAILQ_FIRST(pointers); - pointer != NULL; - pointer = pointer_next) { - pointer_next = TAILQ_NEXT(pointer, next); - TAILQ_REMOVE(pointers, pointer, next); - if (!listonly) - free(pointer->pointer); - free(pointer); - } -} - -static int -pack_copy(struct hmsg *h, void **p, void *s, - const struct formatdef *ct) -{ - if (h->hdr.len + ct->size > MAX_HMSGSIZE - sizeof(struct hmsg_hdr)) { - LLOG_WARNX("message became too large"); - return -1; - } - memcpy(*p, s, ct->size); - *p += ct->size; - h->hdr.len += ct->size; - return ct->size; -} - -static int -unpack_copy(struct hmsg *h, void **p, void *s, - const struct formatdef *ct, struct gc_l *pointers) -{ - memcpy(s, *p, ct->size); - *p += ct->size; - return ct->size; -} - -static int -pack_string(struct hmsg *h, void **p, void *s, - const struct formatdef *ct) -{ - int len, ss; - if ((*(char**)s) == NULL) - len = -1; - else - len = strlen(*(char**)s); - if (h->hdr.len + len + sizeof(int) > MAX_HMSGSIZE - - sizeof(struct hmsg_hdr)) { - LLOG_WARNX("message became too large"); - return -1; - } - memcpy(*p, &len, sizeof(int)); - *p += sizeof(int); - ss = sizeof(int); - if (len != -1) { - memcpy(*p, *(char **)s, len); - *p += len; - ss += len; - } - h->hdr.len += ss; - return ss; -} - -static int -unpack_string(struct hmsg *h, void **p, void *s, - const struct formatdef *ct, struct gc_l *pointers) -{ - char *string; - int len; - memcpy(&len, *p, sizeof(int)); - *p += sizeof(int); - if (len == -1) { - string = NULL; - } else { - if ((string = (char *)calloc(1, len + 1)) == NULL) { - LLOG_WARNX("unable to allocate new string"); - return -1; - } - if (ctl_alloc_pointer(pointers, string) == -1) { - free(string); - return -1; - } - memcpy(string, *p, len); - *p += len; - } - memcpy(s, &string, sizeof(char *)); - return sizeof(char*); -} - -static int -pack_chars(struct hmsg *h, void **p, void *s, - const struct formatdef *ct) -{ - char *string; - int string_len; - string = *(char **)s; - s += sizeof(char *); - memcpy(&string_len, s, sizeof(int)); - - if (h->hdr.len + string_len + sizeof(int) > MAX_HMSGSIZE - - sizeof(struct hmsg_hdr)) { - LLOG_WARNX("message became too large"); +ctl_msg_recv(int fd, enum hmsg_type *type, void **t) +{ + int n, flags = -1; + *type = NONE; *t = NULL; + /* First, we read the header to know the size of the message */ + struct hmsg_header hdr; + if ((n = read(fd, &hdr, sizeof(struct hmsg_header))) == -1) { + LLOG_WARN("unable to read message header"); return -1; } - memcpy(*p, &string_len, sizeof(int)); - *p += sizeof(int); - memcpy(*p, string, string_len); - *p += string_len; - h->hdr.len += sizeof(int) + string_len; - return sizeof(int) + string_len; -} - -static int -unpack_chars(struct hmsg *h, void **p, void *s, - const struct formatdef *ct, struct gc_l *pointers) -{ - char *string; - struct __attribute__ ((__packed__)) { - char *string; - int len; - } reals; - int len; - memcpy(&len, *p, sizeof(int)); - *p += sizeof(int); - if ((string = (char *)malloc(len)) == NULL) { - LLOG_WARN("unable to allocate new string"); - return -1; - } - if (ctl_alloc_pointer(pointers, string) == -1) { - free(string); - return -1; - } - memcpy(string, *p, len); - *p += len; - reals.string = string; - reals.len = len; - memcpy(s, &reals, sizeof(reals)); - return sizeof(char*); -} - -static int -pack_zero(struct hmsg *h, void **p, void *s, - const struct formatdef *ct) -{ - if (h->hdr.len + ct->size > MAX_HMSGSIZE - sizeof(struct hmsg_hdr)) { - LLOG_WARNX("message became too large"); + if (n == 0) + /* Remote closed the connection. */ return -1; - } - memset(*p, 0, ct->size); - *p += ct->size; - h->hdr.len += ct->size; - return ct->size; -} - -static struct formatdef conv_table[] = { - {'b', 1, 0, - pack_copy, unpack_copy}, - {'w', 2, INT16_ALIGN, - pack_copy, unpack_copy}, - {'l', 4, INT32_ALIGN, - pack_copy, unpack_copy}, - {'t', sizeof(time_t), TIMET_ALIGN, - pack_copy, unpack_copy}, - /* Null terminated string */ - {'s', sizeof(void*), VOID_P_ALIGN, - pack_string, unpack_string}, - /* Pointer (is packed with 0) */ - {'P', sizeof(void*), VOID_P_ALIGN, - pack_zero, unpack_copy}, - /* A list (same as pointer), should be at the beginning */ - {'L', sizeof(void*)*2, VOID_P_ALIGN, - pack_zero, unpack_copy}, - /* Non null terminated string, followed by an int for the size */ - {'C', sizeof(void*) + sizeof(int), VOID_P_ALIGN, - pack_chars, unpack_chars}, - {0, 0, 0, NULL, NULL} -}; - -/* Lists can be packed only if the "next" member is the first one of the - * structure! No check is done for this. */ -struct fakelist_m { - TAILQ_ENTRY(fakelist_m) next; - void *data; -}; -TAILQ_HEAD(fakelist_l, fakelist_m); - -static int ctl_msg_get_alignment(char *format) -{ - char *f; - int maxalign = 0, align; - int paren = 0; - struct formatdef *ce; - - /* We just want to get the maximum required alignment for the - * structure. Instead of going recursive, we just count parentheses to - * get the end of the structure. */ - for (f = format; *f != 0; f++) { - if (*f == ')') { - paren--; - if (!paren) - return maxalign; - continue; - } else if (*f == '(') { - paren++; - continue; - } else { - for (ce = conv_table; - (ce->format != 0) && (ce->format != *f); - ce++); - align = ce->alignment; - } - if (align != 0) - maxalign = (maxalign>align)?maxalign:align; - } - if (paren) - LLOG_WARNX("unbalanced parenthesis in format '%s'", - format); - return maxalign; -} - -/* Define a stack of align values */ -struct stack_align { - SLIST_ENTRY(stack_align) next; - int align; -}; - -static int -ctl_msg_packunpack_structure(char *format, void *structure, unsigned int size, - struct hmsg *h, void **p, struct gc_l *pointers, int pack) -{ - char *f; - struct formatdef *ce = NULL; - unsigned int csize = 0; - uintptr_t offset; - struct stack_align *align, *align_next; - int talign; - SLIST_HEAD(, stack_align) aligns; - - SLIST_INIT(&aligns); - for (f = format; *f != 0; f++) { - /* If we have a substructure, when entering into the structure, - * we get the alignment and push it to the stack. When exiting - * the structure, we pop the alignment from the stack and we do - * the padding. This means that the whole structure should be - * enclosed into parentheses, otherwise the padding won't - * occur. */ - ce = NULL; - if (*f == '(') { - /* We need to align, compute the needed alignment */ - if ((align = calloc(1, - sizeof(struct stack_align))) == NULL) { - LLOG_WARN("unable to allocate memory " - "for alignment stack"); - goto packunpack_error; - } - talign = align->align = ctl_msg_get_alignment(f); - SLIST_INSERT_HEAD(&aligns, align, next); - } else if (*f == ')') { - /* We need to pad, retrieve the needed alignment */ - align = SLIST_FIRST(&aligns); - talign = align->align; - align_next = SLIST_NEXT(align, next); - SLIST_REMOVE_HEAD(&aligns, next); - free(align); - } else { - for (ce = conv_table; - (ce->format != 0) && (ce->format != *f); - ce++); - if (ce->format != *f) { - LLOG_WARNX("unknown format char %c", *f); - goto packunpack_error; - } - talign = ce->alignment; - } - - /* Align the structure member */ - if (talign != 0) { - offset = (uintptr_t)structure % talign; - if (offset != 0) { - structure += talign - offset; - csize += talign - offset; - } - } - - if (!ce) continue; - - /* Check that the size is still ok */ - csize += ce->size; - if (csize > size) { - LLOG_WARNX("size of structure is too small for given " - "format (%d vs %d)", size, csize); - goto packunpack_error; - } - - /* Pack or unpack */ - if (pack) { - if (ce->pack(h, p, structure, ce) == -1) { - LLOG_WARNX("error while packing %c in %s", *f, - format); - goto packunpack_error; - } - } else { - if (ce->unpack(h, p, structure, ce, pointers) == -1) { - LLOG_WARNX("error while unpacking %c", *f); - goto packunpack_error; - } + if (n < sizeof(struct hmsg_header)) { + LLOG_WARNX("message received too short (%d)", n); + goto recv_error; + } + if (hdr.len > (1<<15)) { + LLOG_WARNX("message received is too large"); + goto recv_error; + } + if (hdr.len == 0) { + /* No answer */ + *type = hdr.type; + return 0; + } + /* Now, we read the remaining message. We need to use non-blocking stuff + * just in case the message was truncated. */ + if ((*t = malloc(hdr.len)) == NULL) { + LLOG_WARNX("not enough space available for incoming message"); + goto recv_error; + } + if ((flags = fcntl(fd, F_GETFL, 0)) == -1 || + fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { + LLOG_WARN("unable to set socket access mode to non blocking"); + goto recv_error; + } + if ((n = read(fd, *t, hdr.len)) == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + LLOG_WARNX("message seems truncated"); + goto recv_error; } - structure += ce->size; - } - - if (size < csize) { - LLOG_WARNX("size of structure does not match its " - "declaration (%d vs %d)", size, csize); - goto packunpack_error; - } - if (!SLIST_EMPTY(&aligns)) { - LLOG_WARNX("format is badly balanced ('%s')", format); - goto packunpack_error; - } - return 0; - -packunpack_error: - for (align = SLIST_FIRST(&aligns); - align != NULL; - align = align_next) { - align_next = SLIST_NEXT(align, next); - SLIST_REMOVE_HEAD(&aligns, next); - free(align); - } + LLOG_WARN("unable to read incoming request"); + goto recv_error; + } + if (n != hdr.len) { + LLOG_WARNX("received message is too short (%d < %ld)", + n, hdr.len); + goto recv_error; + } + fcntl(fd, F_SETFL, flags); /* No error check */ + *type = hdr.type; + return hdr.len; +recv_error: + free(*t); *t = NULL; + if (flags != -1) fcntl(fd, F_SETFL, flags); return -1; - -} - -int -ctl_msg_pack_structure(char *format, void *structure, unsigned int size, - struct hmsg *h, void **p) -{ - return ctl_msg_packunpack_structure(format, structure, size, h, p, NULL, 1); } int -ctl_msg_unpack_structure(char *format, void *structure, unsigned int size, - struct hmsg *h, void **p) -{ - struct gc_l pointers; - int rc; - TAILQ_INIT(&pointers); - if ((rc = ctl_msg_packunpack_structure(format, structure, size, - h, p, &pointers, 0)) == -1) { - LLOG_WARNX("unable to unpack structure, freeing"); - ctl_free_pointers(&pointers, 0); - return -1; - } - ctl_free_pointers(&pointers, 1); - return rc; -} - -int -ctl_msg_pack_list(char *format, void *list, unsigned int size, struct hmsg *h, void **p) -{ - struct fakelist_m *member; - struct fakelist_l *flist = (struct fakelist_l *)list; - TAILQ_FOREACH(member, flist, next) { - if (ctl_msg_pack_structure(format, member, size, h, p) == -1) { - LLOG_WARNX("error while packing list, aborting"); +ctl_msg_send_recv(int fd, + enum hmsg_type type, + void *input, struct marshal_info *input_mi, + void **output, struct marshal_info *output_mi) +{ + int n, input_len = 0; + void *input_buffer = NULL; + void *serialized = NULL; + enum hmsg_type received_type; + + /* Serialize */ + if (input) { + input_len = marshal_serialize_(input_mi, input, &input_buffer, 0, NULL, 0); + if (input_len <= 0) { + LLOG_WARNX("unable to serialize input data"); return -1; } } + /* Send request */ + if (ctl_msg_send(fd, type, input_buffer, input_len) == -1) { + LLOG_WARN("unable to send request"); + goto send_recv_error; + } + free(input_buffer); input_buffer = NULL; + /* Receive answer */ + if ((n = ctl_msg_recv(fd, &received_type, &serialized)) == -1) + goto send_recv_error; + /* Check type */ + if (received_type != type) { + LLOG_WARNX("incorrect received message type (expected: %d, received: %d)", + type, received_type); + goto send_recv_error; + } + /* Unserialize */ + if (output == NULL) { + free(serialized); + return 0; + } + if (n == 0) { + LLOG_WARNX("no payload available in answer"); + goto send_recv_error; + } + if (marshal_unserialize_(output_mi, serialized, n, output, NULL, 0, 0) <= 0) { + LLOG_WARNX("unable to deserialize received data"); + goto send_recv_error; + } + /* All done. */ return 0; +send_recv_error: + free(serialized); + free(input_buffer); + return -1; } -int -ctl_msg_unpack_list(char *format, void *list, unsigned int size, struct hmsg *h, void **p) +void +ctl_cleanup(char *name) { - struct fakelist_m *member, *member_next; - struct gc_l pointers; - struct fakelist_l *flist = (struct fakelist_l *)list; - TAILQ_INIT(flist); - TAILQ_INIT(&pointers); - while (*p - (void *)h - sizeof(struct hmsg_hdr) < h->hdr.len) { - if ((member = calloc(1, size)) == NULL) { - LLOG_WARN("unable to allocate memory for structure"); - return -1; - } - if (ctl_msg_packunpack_structure(format, member, size, - h, p, &pointers, 0) == -1) { - LLOG_WARNX("unable to unpack list, aborting"); - free(member); - /* Free each list member */ - for (member = TAILQ_FIRST(flist); - member != NULL; - member = member_next) { - member_next = TAILQ_NEXT(member, next); - TAILQ_REMOVE(flist, member, next); - free(member); - } - ctl_free_pointers(&pointers, 0); - return -1; - } - TAILQ_INSERT_TAIL(flist, member, next); - } - ctl_free_pointers(&pointers, 1); - return 0; + if (unlink(name) == -1) + LLOG_WARN("unable to unlink %s", name); } diff --git a/src/display.c b/src/display.c index 97f26332..1c88656f 100644 --- a/src/display.c +++ b/src/display.c @@ -14,8 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "lldpd.h" -#include "writer.h" +#include "lldpctl.h" #include #include @@ -27,11 +26,6 @@ #include TAILQ_HEAD(interfaces, lldpd_interface); -#ifdef ENABLE_DOT1 -TAILQ_HEAD(vlans, lldpd_vlan); -TAILQ_HEAD(ppvids, lldpd_ppvid); -TAILQ_HEAD(pids, lldpd_pi); -#endif #define ntohll(x) (((u_int64_t)(ntohl((int)((x << 32) >> 32))) << 32) | \ (unsigned int)ntohl(((int)(x >> 32)))) @@ -348,185 +342,6 @@ dump(void *data, int size, int max, char sep) return buffer; } - -void -get_interfaces(int s, struct interfaces *ifs) -{ - void *p; - struct hmsg *h; - - if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) - fatal(NULL); - ctl_msg_init(h, HMSG_GET_INTERFACES); - if (ctl_msg_send(s, h) == -1) - fatalx("get_interfaces: unable to send request"); - if (ctl_msg_recv(s, h) == -1) - fatalx("get_interfaces: unable to receive answer"); - if (h->hdr.type != HMSG_GET_INTERFACES) - fatalx("get_interfaces: unknown answer type received"); - p = &h->data; - if (ctl_msg_unpack_list(STRUCT_LLDPD_INTERFACE, - ifs, sizeof(struct lldpd_interface), h, &p) == -1) - fatalx("get_interfaces: unable to retrieve the list of interfaces"); -} - -#ifdef ENABLE_DOT1 -static int -get_vlans(int s, struct vlans *vls, char *interface, int nb) -{ - void *p; - struct hmsg *h; - - if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) - fatal(NULL); - ctl_msg_init(h, HMSG_GET_VLANS); - strlcpy((char *)&h->data, interface, IFNAMSIZ); - memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int)); - h->hdr.len += IFNAMSIZ + sizeof(int); - if (ctl_msg_send(s, h) == -1) - fatalx("get_vlans: unable to send request"); - if (ctl_msg_recv(s, h) == -1) - fatalx("get_vlans: unable to receive answer"); - if (h->hdr.type != HMSG_GET_VLANS) - fatalx("get_vlans: unknown answer type received"); - p = &h->data; - if (ctl_msg_unpack_list(STRUCT_LLDPD_VLAN, - vls, sizeof(struct lldpd_vlan), h, &p) == -1) - fatalx("get_vlans: unable to retrieve the list of vlans"); - return 1; -} - -static int -get_ppvids(int s, struct ppvids *pvs, char *interface, int nb) -{ - void *p; - struct hmsg *h; - - if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) - fatal(NULL); - ctl_msg_init(h, HMSG_GET_PPVIDS); - strlcpy((char *)&h->data, interface, IFNAMSIZ); - memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int)); - h->hdr.len += IFNAMSIZ + sizeof(int); - if (ctl_msg_send(s, h) == -1) - fatalx("get_ppvids: unable to send request"); - if (ctl_msg_recv(s, h) == -1) - fatalx("get_ppvids: unable to receive answer"); - if (h->hdr.type != HMSG_GET_PPVIDS) - fatalx("get_ppvids: unknown answer type received"); - p = &h->data; - if (ctl_msg_unpack_list(STRUCT_LLDPD_PPVID, - pvs, sizeof(struct lldpd_ppvid), h, &p) == -1) - fatalx("get_ppvids: unable to retrieve the list of ppvids"); - return 1; -} - -static int -get_pids(int s, struct pids *pids, char *interface, int nb) -{ - void *p; - struct hmsg *h; - - if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) - fatal(NULL); - ctl_msg_init(h, HMSG_GET_PIDS); - strlcpy((char *)&h->data, interface, IFNAMSIZ); - memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int)); - h->hdr.len += IFNAMSIZ + sizeof(int); - if (ctl_msg_send(s, h) == -1) - fatalx("get_pids: unable to send request"); - if (ctl_msg_recv(s, h) == -1) - fatalx("get_pids: unable to receive answer"); - if (h->hdr.type != HMSG_GET_PIDS) - fatalx("get_pids: unknown answer type received"); - p = &h->data; - if (ctl_msg_unpack_list(STRUCT_LLDPD_PI, - pids, sizeof(struct lldpd_pi), h, &p) == -1) - fatalx("get_pids: unable to retrieve the list of pids"); - return 1; -} -#endif - -static int -get_chassis(int s, struct lldpd_chassis *chassis, char *interface, int nb) -{ - struct hmsg *h; - void *p; - - if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) - fatal(NULL); - ctl_msg_init(h, HMSG_GET_CHASSIS); - strlcpy((char *)&h->data, interface, IFNAMSIZ); - memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int)); - h->hdr.len += IFNAMSIZ + sizeof(int); - if (ctl_msg_send(s, h) == -1) - fatalx("get_chassis: unable to send request to get chassis"); - if (ctl_msg_recv(s, h) == -1) - fatalx("get_chassis: unable to receive answer to get chassis"); - if (h->hdr.type == HMSG_NONE) - /* No chassis */ - return -1; - p = &h->data; - if (ctl_msg_unpack_structure(STRUCT_LLDPD_CHASSIS, - chassis, sizeof(struct lldpd_chassis), h, &p) == -1) { - LLOG_WARNX("unable to retrieve chassis for %s", interface); - fatalx("get_chassis: abort"); - } - return 1; -} - -static int -get_port(int s, struct lldpd_port *port, char *interface, int nb) -{ - struct hmsg *h; - void *p; - - if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) - fatal(NULL); - ctl_msg_init(h, HMSG_GET_PORT); - strlcpy((char *)&h->data, interface, IFNAMSIZ); - memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int)); - h->hdr.len += IFNAMSIZ + sizeof(int); - if (ctl_msg_send(s, h) == -1) - fatalx("get_port: unable to send request to get port"); - if (ctl_msg_recv(s, h) == -1) - fatalx("get_port: unable to receive answer to get port"); - if (h->hdr.type == HMSG_NONE) - /* No port */ - return -1; - p = &h->data; - if (ctl_msg_unpack_structure(STRUCT_LLDPD_PORT, - port, sizeof(struct lldpd_port), h, &p) == -1) { - LLOG_WARNX("unable to retrieve port information for %s", - interface); - fatalx("get_chassis: abort"); - } - return 1; -} - -static int -get_nb_port(int s, char *interface) -{ - struct hmsg *h; - int nb; - - if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) - fatal(NULL); - ctl_msg_init(h, HMSG_GET_NB_PORTS); - strlcpy((char *)&h->data, interface, IFNAMSIZ); - h->hdr.len += IFNAMSIZ; - if (ctl_msg_send(s, h) == -1) - fatalx("get_nb_port: unable to send request to get number of ports"); - if (ctl_msg_recv(s, h) == -1) - fatalx("get_nb_port: unable to receive answer to get number of ports"); - if (h->hdr.type == HMSG_NONE) - return -1; - if (h->hdr.len != sizeof(int)) - fatalx("get_nb_port: bad message length"); - memcpy(&nb, &h->data, sizeof(int)); - return nb; -} - static void display_cap(struct writer * w, struct lldpd_chassis *chassis, u_int8_t bit, char *symbol) { @@ -1109,19 +924,8 @@ display_age(struct lldpd_port *port) void display_interfaces(int s, const char * fmt, int argc, char *argv[]) { + int i; struct writer * w; - int i, nb; - struct interfaces ifs; -#ifdef ENABLE_DOT1 - struct vlans vls; - struct ppvids pvs; - struct pids pids; -#endif - struct lldpd_interface *iff; - struct lldpd_chassis chassis; - struct lldpd_port port; - char sep[80]; - if ( strcmp(fmt,"plain") == 0 ) { w = txt_init( stdout ); } else if (strcmp(fmt, "keyvalue") == 0) { @@ -1136,13 +940,15 @@ display_interfaces(int s, const char * fmt, int argc, char *argv[]) w = txt_init( stdout ); } + char sep[80]; memset(sep, '-', 79); sep[79] = 0; - get_interfaces(s, &ifs); + struct lldpd_interface *iff; + struct lldpd_interface_list *ifs = get_interfaces(s); tag_start(w, "lldp", "LLDP neighbors"); - TAILQ_FOREACH(iff, &ifs, next) { + TAILQ_FOREACH(iff, ifs, next) { if (optind < argc) { for (i = optind; i < argc; i++) if (strncmp(argv[i], iff->name, IFNAMSIZ) == 0) @@ -1150,39 +956,38 @@ display_interfaces(int s, const char * fmt, int argc, char *argv[]) if (i == argc) continue; } - nb = get_nb_port(s, iff->name); - for (i = 0; i < nb; i++) { - if (!((get_chassis(s, &chassis, iff->name, i) != -1) && - (get_port(s, &port, iff->name, i) != -1))) - continue; + + struct lldpd_port *port; + struct lldpd_chassis *chassis; + struct lldpd_hardware *hardware = get_interface(s, iff->name); + if (TAILQ_EMPTY(&hardware->h_rports)) + continue; + TAILQ_FOREACH(port, &hardware->h_rports, p_entries) { + if (SMART_HIDDEN(port)) continue; + chassis = port->p_chassis; + tag_start(w, "interface", "Interface"); tag_attr(w, "name", "", iff->name ); - tag_attr(w, "via" , "via", map_lookup(lldpd_protocol_map, port.p_protocol)); - tag_attr(w, "rid" , "RID", u2str(chassis.c_index)); - tag_attr(w, "age" , "Time", display_age(&port)); + tag_attr(w, "via" , "via", map_lookup(lldpd_protocol_map, port->p_protocol)); + tag_attr(w, "rid" , "RID", u2str(chassis->c_index)); + tag_attr(w, "age" , "Time", display_age(port)); - display_chassis(w,&chassis); - display_port(w, &port); + display_chassis(w,chassis); + display_port(w, port); #ifdef ENABLE_DOT1 - if (get_vlans(s, &vls, iff->name, i) != -1) - memcpy(&port.p_vlans, &vls, sizeof(struct vlans)); - if (!TAILQ_EMPTY(&port.p_vlans) || port.p_pvid) { - display_vlans(w, &port); + if (!TAILQ_EMPTY(&port->p_vlans) || port->p_pvid) { + display_vlans(w, port); } - if (get_ppvids(s, &pvs, iff->name, i) != -1) - memcpy(&port.p_ppvids, &pvs, sizeof(struct ppvids)); - if (!TAILQ_EMPTY(&port.p_ppvids)) { - display_ppvids(w, &port); + if (!TAILQ_EMPTY(&port->p_ppvids)) { + display_ppvids(w, port); } - if (get_pids(s, &pids, iff->name, i) != -1) - memcpy(&port.p_pids, &pids, sizeof(struct pids)); - if (!TAILQ_EMPTY(&port.p_pids)) { - display_pids(w, &port); + if (!TAILQ_EMPTY(&port->p_pids)) { + display_pids(w, port); } #endif #ifdef ENABLE_LLDPMED - if (port.p_med_cap_enabled) { - display_med(w, &chassis, &port); + if (port->p_med_cap_enabled) { + display_med(w, chassis, port); } #endif tag_end(w); /* interface */ @@ -1192,4 +997,3 @@ display_interfaces(int s, const char * fmt, int argc, char *argv[]) tag_end(w); w->finish(w); } - diff --git a/src/lldpctl.c b/src/lldpctl.c index f225c716..69ec9091 100644 --- a/src/lldpctl.c +++ b/src/lldpctl.c @@ -14,7 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "lldpd.h" +#include "lldpctl.h" #include #include @@ -27,20 +27,12 @@ static void usage(void); -TAILQ_HEAD(interfaces, lldpd_interface); - #ifdef HAVE___PROGNAME extern const char *__progname; #else # define __progname "lldpctl" #endif -extern void -get_interfaces(int s, struct interfaces *ifs); - -extern void -display_interfaces(int s, const char * fmt, int argc, char *argv[]); - #define LLDPCTL_ARGS "hdf:L:P:O:o:" static void @@ -75,13 +67,15 @@ usage(void) #ifdef ENABLE_LLDPMED static int -lldpd_parse_location(struct lldpd_port *port, const char *location) +lldpd_parse_location(struct lldpd_med_loc *medloc, const char *location) { char *l, *e, *s, *data, *n; double ll, altitude; u_int32_t intpart, floatpart; int type = 0, i; + memset(medloc, 0, sizeof(struct lldpd_med_loc)); + if (strlen(location) == 0) return 0; if ((l = strdup(location)) == NULL) @@ -94,12 +88,11 @@ lldpd_parse_location(struct lldpd_port *port, const char *location) switch (type) { case LLDPMED_LOCFORMAT_COORD: /* Coordinates */ - if ((port->p_med_location[0].data = - (char *)malloc(16)) == NULL) + if ((medloc->data = (char *)malloc(16)) == NULL) fatal(NULL); - port->p_med_location[0].data_len = 16; - port->p_med_location[0].format = LLDPMED_LOCFORMAT_COORD; - data = port->p_med_location[0].data; + medloc->data_len = 16; + medloc->format = LLDPMED_LOCFORMAT_COORD; + data = medloc->data; /* Latitude and longitude */ for (i = 0; i < 2; i++) { @@ -179,7 +172,7 @@ lldpd_parse_location(struct lldpd_port *port, const char *location) break; case LLDPMED_LOCFORMAT_CIVIC: /* Civic address */ - port->p_med_location[1].data_len = 4; + medloc->data_len = 4; s = e+1; if ((s = strchr(s, ':')) == NULL) goto invalid_location; @@ -192,19 +185,18 @@ lldpd_parse_location(struct lldpd_port *port, const char *location) if ((n = strchr(s, ':')) == NULL) n = s + strlen(s); /* n is the end of the word */ - port->p_med_location[1].data_len += (n - s) + 2; + medloc->data_len += (n - s) + 2; if ((s = strchr(s, ':')) == NULL) break; s = s+1; } while (1); s = e+1; - if ((port->p_med_location[1].data = - (char *)malloc(port->p_med_location[1].data_len)) == - NULL) + if ((medloc->data = + (char *)malloc(medloc->data_len)) == NULL) fatal(NULL); - port->p_med_location[1].format = LLDPMED_LOCFORMAT_CIVIC; - data = port->p_med_location[1].data; - *(u_int8_t *)data = port->p_med_location[1].data_len - 1; + medloc->format = LLDPMED_LOCFORMAT_CIVIC; + data = medloc->data; + *(u_int8_t *)data = medloc->data_len - 1; data++; *(u_int8_t *)data = 2; /* Client location */ data++; @@ -232,34 +224,26 @@ lldpd_parse_location(struct lldpd_port *port, const char *location) break; case LLDPMED_LOCFORMAT_ELIN: s = e+1; - port->p_med_location[2].data_len = strlen(s); - if ((port->p_med_location[2].data = - (char *)malloc(strlen(s))) == NULL) + medloc->data_len = strlen(s); + if ((medloc->data = (char *)malloc(strlen(s))) == NULL) fatal(NULL); - port->p_med_location[2].format = LLDPMED_LOCFORMAT_ELIN; - strcpy(port->p_med_location[2].data, s); + medloc->format = LLDPMED_LOCFORMAT_ELIN; + strcpy(medloc->data, s); break; default: type = 0; goto invalid_location; } - port->p_med_cap_enabled |= LLDPMED_CAP_LOCATION; return 0; invalid_location: LLOG_WARNX("the format of the location is invalid (%s)", location); - if (type) { - free(port->p_med_location[type-1].data); - memset(&port->p_med_location[type-1], 0, - sizeof(struct lldpd_med_loc)); - } - free(l); return -1; } static int -lldpd_parse_policy(struct lldpd_port *port, const char *policy) +lldpd_parse_policy(struct lldpd_med_policy *medpolicy, const char *policy) { const char *e; int app_type = 0; @@ -269,6 +253,8 @@ lldpd_parse_policy(struct lldpd_port *port, const char *policy) int l2_prio = 0; int dscp = 0; + memset(medpolicy, 0, sizeof(struct lldpd_med_policy)); + if (strlen(policy) == 0) { return 0; } @@ -342,14 +328,13 @@ lldpd_parse_policy(struct lldpd_port *port, const char *policy) goto invalid_policy; } - port->p_med_policy[app_type - 1].type = (u_int8_t) app_type; - port->p_med_policy[app_type - 1].unknown = (u_int8_t) unknown_policy_flag; - port->p_med_policy[app_type - 1].tagged = (u_int8_t) tagged_flag; - port->p_med_policy[app_type - 1].vid = (u_int16_t) vlan_id; - port->p_med_policy[app_type - 1].priority = (u_int8_t) l2_prio; - port->p_med_policy[app_type - 1].dscp = (u_int8_t) dscp; + medpolicy->type = (u_int8_t) app_type; + medpolicy->unknown = (u_int8_t) unknown_policy_flag; + medpolicy->tagged = (u_int8_t) tagged_flag; + medpolicy->vid = (u_int16_t) vlan_id; + medpolicy->priority = (u_int8_t) l2_prio; + medpolicy->dscp = (u_int8_t) dscp; - port->p_med_cap_enabled |= LLDPMED_CAP_POLICY; return 0; invalid_policy: @@ -359,7 +344,7 @@ invalid_policy: } static int -lldpd_parse_power(struct lldpd_port *port, const char *poe) +lldpd_parse_power(struct lldpd_med_power *medpower, const char *poe) { const char *e; int device_type = 0; @@ -367,6 +352,8 @@ lldpd_parse_power(struct lldpd_port *port, const char *poe) int priority = 0; int val = 0; + memset(medpower, 0, sizeof(struct lldpd_med_power)); + if (strlen(poe) == 0) return 0; e = poe; @@ -414,41 +401,39 @@ lldpd_parse_power(struct lldpd_port *port, const char *poe) goto invalid_poe; } - port->p_med_power.devicetype = device_type; - port->p_med_power.priority = priority; - port->p_med_power.val = val; + medpower->devicetype = device_type; + medpower->priority = priority; + medpower->val = val; switch (device_type) { case LLDPMED_POW_TYPE_PD: switch (source) { case 1: - port->p_med_power.source = LLDPMED_POW_SOURCE_PSE; + medpower->source = LLDPMED_POW_SOURCE_PSE; break; case 2: - port->p_med_power.source = LLDPMED_POW_SOURCE_LOCAL; + medpower->source = LLDPMED_POW_SOURCE_LOCAL; break; case 3: - port->p_med_power.source = LLDPMED_POW_SOURCE_BOTH; + medpower->source = LLDPMED_POW_SOURCE_BOTH; break; default: - port->p_med_power.source = LLDPMED_POW_SOURCE_UNKNOWN; + medpower->source = LLDPMED_POW_SOURCE_UNKNOWN; break; } - port->p_med_cap_enabled |= LLDPMED_CAP_MDI_PD; break; case LLDPMED_POW_TYPE_PSE: switch (source) { case 1: - port->p_med_power.source = LLDPMED_POW_SOURCE_PRIMARY; + medpower->source = LLDPMED_POW_SOURCE_PRIMARY; break; case 2: - port->p_med_power.source = LLDPMED_POW_SOURCE_BACKUP; + medpower->source = LLDPMED_POW_SOURCE_BACKUP; break; default: - port->p_med_power.source = LLDPMED_POW_SOURCE_UNKNOWN; + medpower->source = LLDPMED_POW_SOURCE_UNKNOWN; break; } - port->p_med_cap_enabled |= LLDPMED_CAP_MDI_PSE; break; } return 0; @@ -461,21 +446,21 @@ lldpd_parse_power(struct lldpd_port *port, const char *poe) #ifdef ENABLE_DOT3 static int -lldpd_parse_dot3_power(struct lldpd_port *port, const char *poe) +lldpd_parse_dot3_power(struct lldpd_dot3_power *dot3power, const char *poe) { const char *e; - struct lldpd_dot3_power target; + + memset(dot3power, 0, sizeof(struct lldpd_dot3_power)); if (strlen(poe) == 0) return 0; e = poe; - memset(&target, 0, sizeof(target)); /* Device type */ if (!strncmp(e, "PD", 2)) - target.devicetype = LLDP_DOT3_POWER_PD; + dot3power->devicetype = LLDP_DOT3_POWER_PD; else if (!strncmp(e, "PSE", 3)) - target.devicetype = LLDP_DOT3_POWER_PSE; + dot3power->devicetype = LLDP_DOT3_POWER_PSE; else { LLOG_WARNX("Device type should be either 'PD' or 'PSE'."); goto invalid_dot3_poe; @@ -486,9 +471,9 @@ lldpd_parse_dot3_power(struct lldpd_port *port, const char *poe) LLOG_WARNX("Expected power support."); goto invalid_dot3_poe; } - target.supported = atoi(++e); - if (target.supported > 1) { - LLOG_WARNX("Power support should be 1 or 0, not %d", target.supported); + dot3power->supported = atoi(++e); + if (dot3power->supported > 1) { + LLOG_WARNX("Power support should be 1 or 0, not %d", dot3power->supported); goto invalid_dot3_poe; } @@ -497,9 +482,9 @@ lldpd_parse_dot3_power(struct lldpd_port *port, const char *poe) LLOG_WARNX("Expected power ability."); goto invalid_dot3_poe; } - target.enabled = atoi(++e); - if (target.enabled > 1) { - LLOG_WARNX("Power ability should be 1 or 0, not %d", target.enabled); + dot3power->enabled = atoi(++e); + if (dot3power->enabled > 1) { + LLOG_WARNX("Power ability should be 1 or 0, not %d", dot3power->enabled); goto invalid_dot3_poe; } @@ -508,10 +493,10 @@ lldpd_parse_dot3_power(struct lldpd_port *port, const char *poe) LLOG_WARNX("Expected power pair control ability."); goto invalid_dot3_poe; } - target.paircontrol = atoi(++e); - if (target.paircontrol > 1) { + dot3power->paircontrol = atoi(++e); + if (dot3power->paircontrol > 1) { LLOG_WARNX("Power pair control ability should be 1 or 0, not %d", - target.paircontrol); + dot3power->paircontrol); goto invalid_dot3_poe; } @@ -520,9 +505,9 @@ lldpd_parse_dot3_power(struct lldpd_port *port, const char *poe) LLOG_WARNX("Expected power pairs."); goto invalid_dot3_poe; } - target.pairs = atoi(++e); - if (target.pairs < 1 || target.pairs > 2) { - LLOG_WARNX("Power pairs should be 1 or 2, not %d.", target.pairs); + dot3power->pairs = atoi(++e); + if (dot3power->pairs < 1 || dot3power->pairs > 2) { + LLOG_WARNX("Power pairs should be 1 or 2, not %d.", dot3power->pairs); goto invalid_dot3_poe; } @@ -531,21 +516,21 @@ lldpd_parse_dot3_power(struct lldpd_port *port, const char *poe) LLOG_WARNX("Expected power class."); goto invalid_dot3_poe; } - target.class = atoi(++e); - if (target.class > 5) { - LLOG_WARNX("Power class out of range (%d).", target.class); + dot3power->class = atoi(++e); + if (dot3power->class > 5) { + LLOG_WARNX("Power class out of range (%d).", dot3power->class); goto invalid_dot3_poe; } /* 802.3at */ if ((e = strchr(e, ':')) == NULL) { - target.powertype = LLDP_DOT3_POWER_8023AT_OFF; - goto no8023at; + dot3power->powertype = LLDP_DOT3_POWER_8023AT_OFF; + return 0; } /* 802.3at: Power type */ - target.powertype = atoi(++e); - if ((target.powertype != LLDP_DOT3_POWER_8023AT_TYPE1) && - (target.powertype != LLDP_DOT3_POWER_8023AT_TYPE2)) { - LLOG_WARNX("Incorrect power type (%d).", target.powertype); + dot3power->powertype = atoi(++e); + if ((dot3power->powertype != LLDP_DOT3_POWER_8023AT_TYPE1) && + (dot3power->powertype != LLDP_DOT3_POWER_8023AT_TYPE2)) { + LLOG_WARNX("Incorrect power type (%d).", dot3power->powertype); goto invalid_dot3_poe; } /* 802.3at: Source */ @@ -553,9 +538,9 @@ lldpd_parse_dot3_power(struct lldpd_port *port, const char *poe) LLOG_WARNX("Expected power source."); goto invalid_dot3_poe; } - target.source = atoi(++e); - if (target.source > 3) { - LLOG_WARNX("Power source out of range (%d).", target.source); + dot3power->source = atoi(++e); + if (dot3power->source > 3) { + LLOG_WARNX("Power source out of range (%d).", dot3power->source); goto invalid_dot3_poe; } /* 802.3at: priority */ @@ -563,9 +548,9 @@ lldpd_parse_dot3_power(struct lldpd_port *port, const char *poe) LLOG_WARNX("Expected power priority."); goto invalid_dot3_poe; } - target.priority = atoi(++e); - if (target.priority > 3) { - LLOG_WARNX("Power priority out of range (%d).", target.priority); + dot3power->priority = atoi(++e); + if (dot3power->priority > 3) { + LLOG_WARNX("Power priority out of range (%d).", dot3power->priority); goto invalid_dot3_poe; } /* 802.3at: requested */ @@ -573,16 +558,13 @@ lldpd_parse_dot3_power(struct lldpd_port *port, const char *poe) LLOG_WARNX("Expected requested power value."); goto invalid_dot3_poe; } - target.requested = atoi(++e); + dot3power->requested = atoi(++e); /* 802.3at: allocated */ if ((e = strchr(e, ':')) == NULL) { LLOG_WARNX("Expected allocated power value."); goto invalid_dot3_poe; } - target.allocated = atoi(++e); - - no8023at: - memcpy(&port->p_power, &target, sizeof(target)); + dot3power->allocated = atoi(++e); return 0; invalid_dot3_poe: @@ -591,206 +573,80 @@ lldpd_parse_dot3_power(struct lldpd_port *port, const char *poe) } #endif -#ifdef ENABLE_LLDPMED +#define ACTION_SET_LOCATION (1 << 0) +#define ACTION_SET_POLICY (1 << 1) +#define ACTION_SET_POWER (1 << 2) +#define ACTION_SET_DOT3_POWER (1 << 3) static void -set_location(int s, int argc, char *argv[]) +set_port(int s, int argc, char *argv[], int action) { - int i, ch; - struct interfaces ifs; - struct lldpd_interface *iff; - struct lldpd_port port; - void *p; - struct hmsg *h; - - if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) - fatal(NULL); + int ch; +#ifdef ENABLE_LLDPMED + struct lldpd_med_loc location; + struct lldpd_med_power medpower; + struct lldpd_med_policy policy; +#endif +#ifdef ENABLE_DOT3 + struct lldpd_dot3_power dot3power; +#endif + int done; + int skip[4] = {0, 0, 0, 0}; + int skip_[4]; - memset(&port, 0, sizeof(struct lldpd_port)); + redo_set_port: + memcpy(skip_, skip, sizeof(skip)); + done = 1; optind = 1; while ((ch = getopt(argc, argv, LLDPCTL_ARGS)) != -1) { switch (ch) { +#ifdef ENABLE_LLDPMED case 'L': - if ((lldpd_parse_location(&port, optarg)) == -1) - fatalx("incorrect location"); + if (action & ACTION_SET_LOCATION) { + if (skip_[0]--) break; + if (lldpd_parse_location(&location, optarg) == -1) + fatalx("set_port: incorrect location"); + done = 0; + skip[0]++; + } break; - } - } - - get_interfaces(s, &ifs); - TAILQ_FOREACH(iff, &ifs, next) { - if (optind < argc) { - for (i = optind; i < argc; i++) - if (strncmp(argv[i], iff->name, IFNAMSIZ) == 0) - break; - if (i == argc) - continue; - } - - ctl_msg_init(h, HMSG_SET_LOCATION); - strlcpy((char *)&h->data, iff->name, IFNAMSIZ); - h->hdr.len += IFNAMSIZ; - p = (char*)&h->data + IFNAMSIZ; - if (ctl_msg_pack_structure(STRUCT_LLDPD_MED_LOC - STRUCT_LLDPD_MED_LOC STRUCT_LLDPD_MED_LOC, - port.p_med_location, - 3*sizeof(struct lldpd_med_loc), h, &p) == -1) { - LLOG_WARNX("set_location: unable to set location for %s", iff->name); - fatalx("aborting"); - } - if (ctl_msg_send(s, h) == -1) - fatalx("set_location: unable to send request"); - if (ctl_msg_recv(s, h) == -1) - fatalx("set_location: unable to receive answer"); - if (h->hdr.type != HMSG_SET_LOCATION) - fatalx("set_location: unknown answer type received"); - LLOG_INFO("Location set successfully for %s", iff->name); - } -} - -static void -set_policy(int s, int argc, char *argv[]) -{ - int i, ch; - struct interfaces ifs; - struct lldpd_interface *iff; - struct lldpd_port port; - void *p; - struct hmsg *h; - - if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) - fatal(NULL); - - memset(&port, 0, sizeof(struct lldpd_port)); - optind = 1; - while ((ch = getopt(argc, argv, LLDPCTL_ARGS)) != -1) { - switch (ch) { case 'P': - if ((lldpd_parse_policy(&port, optarg)) == -1) - fatalx("Incorrect Network Policy."); + if (action & ACTION_SET_POLICY) { + if (skip_[1]--) break; + if (lldpd_parse_policy(&policy, optarg) == -1) + fatalx("set_port: incorrect network policy."); + done = 0; + skip[1]++; + } break; - } - } - - get_interfaces(s, &ifs); - TAILQ_FOREACH(iff, &ifs, next) { - if (optind < argc) { - for (i = optind; i < argc; i++) - if (strncmp(argv[i], iff->name, IFNAMSIZ) == 0) - break; - if (i == argc) - continue; - } - - ctl_msg_init(h, HMSG_SET_POLICY); - strlcpy((char *)&h->data, iff->name, IFNAMSIZ); - h->hdr.len += IFNAMSIZ; - p = (char*)&h->data + IFNAMSIZ; - if (ctl_msg_pack_structure( - STRUCT_LLDPD_MED_POLICY - STRUCT_LLDPD_MED_POLICY - STRUCT_LLDPD_MED_POLICY - STRUCT_LLDPD_MED_POLICY - STRUCT_LLDPD_MED_POLICY - STRUCT_LLDPD_MED_POLICY - STRUCT_LLDPD_MED_POLICY - STRUCT_LLDPD_MED_POLICY, - port.p_med_policy, - 8*sizeof(struct lldpd_med_policy), h, &p) == -1) { - LLOG_WARNX("set_policy: Unable to set Network Policy for %s", iff->name); - fatalx("aborting"); - } - if (ctl_msg_send(s, h) == -1) - fatalx("set_policy: unable to send request"); - if (ctl_msg_recv(s, h) == -1) - fatalx("set_policy: unable to receive answer"); - if (h->hdr.type != HMSG_SET_POLICY) - fatalx("set_policy: unknown answer type received"); - LLOG_INFO("Network Policy successfully set for %s", iff->name); - } -} - -static void -set_power(int s, int argc, char *argv[]) -{ - int i, ch; - struct interfaces ifs; - struct lldpd_interface *iff; - struct lldpd_port port; - void *p; - struct hmsg *h; - - if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) - fatal(NULL); - - memset(&port, 0, sizeof(struct lldpd_port)); - optind = 1; - while ((ch = getopt(argc, argv, LLDPCTL_ARGS)) != -1) { - switch (ch) { case 'O': - if ((lldpd_parse_power(&port, optarg)) == -1) - fatalx("Incorrect POE-MDI."); + if (action & ACTION_SET_POWER) { + if (skip_[2]--) break; + if (lldpd_parse_power(&medpower, optarg) == -1) + fatalx("set_port: incorrect MED POE-MDI."); + done = 0; + skip[2]++; + } break; - } - } - - get_interfaces(s, &ifs); - TAILQ_FOREACH(iff, &ifs, next) { - if (optind < argc) { - for (i = optind; i < argc; i++) - if (strncmp(argv[i], iff->name, IFNAMSIZ) == 0) - break; - if (i == argc) - continue; - } - - ctl_msg_init(h, HMSG_SET_POWER); - strlcpy((char *)&h->data, iff->name, IFNAMSIZ); - h->hdr.len += IFNAMSIZ; - p = (char*)&h->data + IFNAMSIZ; - if (ctl_msg_pack_structure(STRUCT_LLDPD_MED_POWER, - &port.p_med_power, - sizeof(struct lldpd_med_power), h, &p) == -1) { - LLOG_WARNX("set_power: Unable to set POE-MDI for %s", iff->name); - fatalx("aborting"); - } - if (ctl_msg_send(s, h) == -1) - fatalx("set_power: unable to send request"); - if (ctl_msg_recv(s, h) == -1) - fatalx("set_power: unable to receive answer"); - if (h->hdr.type != HMSG_SET_POWER) - fatalx("set_power: unknown answer type received"); - LLOG_INFO("POE-MDI successfully set for %s", iff->name); - } -} #endif - #ifdef ENABLE_DOT3 -static void -set_dot3_power(int s, int argc, char *argv[]) -{ - int i, ch; - struct interfaces ifs; - struct lldpd_interface *iff; - struct lldpd_port port; - void *p; - struct hmsg *h; - - if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) - fatal(NULL); - - memset(&port, 0, sizeof(struct lldpd_port)); - optind = 1; - while ((ch = getopt(argc, argv, LLDPCTL_ARGS)) != -1) { - switch (ch) { case 'o': - if ((lldpd_parse_dot3_power(&port, optarg)) == -1) - fatalx("Incorrect POE-MDI."); + if (action & ACTION_SET_DOT3_POWER) { + if (skip_[3]--) break; + if (lldpd_parse_dot3_power(&dot3power, optarg) == -1) + fatalx("set_port: incorrect DOT3 POE-MDI."); + done = 0; + skip[3]++; + } break; +#endif } } + if (done) return; - get_interfaces(s, &ifs); - TAILQ_FOREACH(iff, &ifs, next) { + struct lldpd_interface *iff; + struct lldpd_interface_list *ifs = get_interfaces(s); + int i; + TAILQ_FOREACH(iff, ifs, next) { if (optind < argc) { for (i = optind; i < argc; i++) if (strncmp(argv[i], iff->name, IFNAMSIZ) == 0) @@ -799,36 +655,52 @@ set_dot3_power(int s, int argc, char *argv[]) continue; } - ctl_msg_init(h, HMSG_SET_DOT3_POWER); - strlcpy((char *)&h->data, iff->name, IFNAMSIZ); - h->hdr.len += IFNAMSIZ; - p = (char*)&h->data + IFNAMSIZ; - if (ctl_msg_pack_structure(STRUCT_LLDPD_DOT3_POWER, - &port.p_power, - sizeof(struct lldpd_dot3_power), h, &p) == -1) { - LLOG_WARNX("set_dot3_power: Unable to set POE-MDI for %s", iff->name); - fatalx("aborting"); - } - if (ctl_msg_send(s, h) == -1) - fatalx("set_dot3_power: unable to send request"); - if (ctl_msg_recv(s, h) == -1) - fatalx("set_dot3_power: unable to receive answer"); - if (h->hdr.type != HMSG_SET_DOT3_POWER) - fatalx("set_dot3_power: unknown answer type received"); - LLOG_INFO("Dot3 POE-MDI successfully set for %s", iff->name); + struct lldpd_port_set set; + memset(&set, 0, sizeof(struct lldpd_port_set)); + set.ifname = iff->name; +#ifdef ENABLE_LLDPMED + if (action & ACTION_SET_LOCATION) set.med_location = &location; + if (action & ACTION_SET_POLICY) set.med_policy = &policy; + if (action & ACTION_SET_POWER) set.med_power = &medpower; +#endif +#ifdef ENABLE_DOT3 + if (action & ACTION_SET_DOT3_POWER)set.dot3_power = &dot3power; +#endif + if (ctl_msg_send_recv(s, SET_PORT, + &set, &MARSHAL_INFO(lldpd_port_set), + NULL, NULL) == -1) + fatalx("set_port: unable to send new location information"); + LLOG_INFO("configuration change for %s", iff->name); } + goto redo_set_port; +} + +struct lldpd_interface_list* +get_interfaces(int s) +{ + struct lldpd_interface_list *ifs; + if (ctl_msg_send_recv(s, GET_INTERFACES, NULL, NULL, (void **)&ifs, + &MARSHAL_INFO(lldpd_interface_list)) == -1) + fatalx("get_interfaces: unable to get the list of interfaces"); + return ifs; +} + +struct lldpd_hardware* +get_interface(int s, char *name) +{ + struct lldpd_hardware *h; + if (ctl_msg_send_recv(s, GET_INTERFACE, + name, &MARSHAL_INFO(string), + (void **)&h, &MARSHAL_INFO(lldpd_hardware)) == -1) + fatalx("get_interface: unable to get information for specified interface"); + return h; } -#endif int main(int argc, char *argv[]) { int ch, s, debug = 1; char * fmt = "plain"; -#define ACTION_SET_LOCATION (1 << 0) -#define ACTION_SET_POLICY (1 << 1) -#define ACTION_SET_POWER (1 << 2) -#define ACTION_SET_DOT3_POWER (1 << 3) int action = 0; /* @@ -881,20 +753,10 @@ main(int argc, char *argv[]) if ((s = ctl_connect(LLDPD_CTL_SOCKET)) == -1) fatalx("unable to connect to socket " LLDPD_CTL_SOCKET); -#ifdef ENABLE_LLDPMED - if (action & ACTION_SET_LOCATION) - set_location(s, argc, argv); - if (action & ACTION_SET_POLICY) - set_policy(s, argc, argv); - if (action & ACTION_SET_POWER) - set_power(s, argc, argv); -#endif -#ifdef ENABLE_DOT3 - if (action & ACTION_SET_DOT3_POWER) - set_dot3_power(s, argc, argv); -#endif if (!action) display_interfaces(s, fmt, argc, argv); + else + set_port(s, argc, argv, action); close(s); return 0; diff --git a/src/lldpd.h b/src/lldpd.h index ad9ce7da..74c14d98 100644 --- a/src/lldpd.h +++ b/src/lldpd.h @@ -23,6 +23,7 @@ #define _GNU_SOURCE 1 #include +#include #include #include #ifdef HAVE_SYS_TYPES_H @@ -76,25 +77,32 @@ struct lldpd_ppvid { u_int8_t p_cap_status; u_int16_t p_ppvid; }; -#define STRUCT_LLDPD_PPVID "(Lbw)" +MARSHAL_BEGIN(lldpd_ppvid) +MARSHAL_TQE(lldpd_ppvid, p_entries) +MARSHAL_END; struct lldpd_vlan { TAILQ_ENTRY(lldpd_vlan) v_entries; char *v_name; u_int16_t v_vid; }; -#define STRUCT_LLDPD_VLAN "(Lsw)" +MARSHAL_BEGIN(lldpd_vlan) +MARSHAL_TQE(lldpd_vlan, v_entries) +MARSHAL_STR(lldpd_vlan, v_name) +MARSHAL_END; struct lldpd_pi { TAILQ_ENTRY(lldpd_pi) p_entries; char *p_pi; int p_pi_len; }; -#define STRUCT_LLDPD_PI "(LC)" +MARSHAL_BEGIN(lldpd_pi) +MARSHAL_TQE(lldpd_pi, p_entries) +MARSHAL_FSTR(lldpd_pi, p_pi, p_pi_len) +MARSHAL_END; #endif #ifdef ENABLE_LLDPMED -#define STRUCT_LLDPD_MED_POLICY "(bbbwbb)" struct lldpd_med_policy { u_int8_t type; u_int8_t unknown; @@ -103,25 +111,27 @@ struct lldpd_med_policy { u_int8_t priority; u_int8_t dscp; }; +MARSHAL(lldpd_med_policy); -#define STRUCT_LLDPD_MED_LOC "(bC)" struct lldpd_med_loc { u_int8_t format; char *data; int data_len; }; +MARSHAL_BEGIN(lldpd_med_loc) +MARSHAL_FSTR(lldpd_med_loc, data, data_len) +MARSHAL_END; -#define STRUCT_LLDPD_MED_POWER "(bbbw)" struct lldpd_med_power { u_int8_t devicetype; /* PD or PSE */ u_int8_t source; u_int8_t priority; u_int16_t val; }; +MARSHAL(lldpd_med_power); #endif #ifdef ENABLE_DOT3 -#define STRUCT_LLDPD_DOT3_MACPHY "(bbww)" struct lldpd_dot3_macphy { u_int8_t autoneg_support; u_int8_t autoneg_enabled; @@ -129,7 +139,6 @@ struct lldpd_dot3_macphy { u_int16_t mau_type; }; -#define STRUCT_LLDPD_DOT3_POWER "(bbbbbbbbbww)" struct lldpd_dot3_power { u_int8_t devicetype; u_int8_t supported; @@ -144,6 +153,7 @@ struct lldpd_dot3_power { u_int16_t requested; u_int16_t allocated; }; +MARSHAL(lldpd_dot3_power); #endif struct lldpd_chassis { @@ -166,7 +176,6 @@ struct lldpd_chassis { u_int32_t c_mgmt_if; #ifdef ENABLE_LLDPMED -#define STRUCT_LLDPD_CHASSIS_MED "wbsssssss" u_int16_t c_med_cap_available; u_int8_t c_med_type; char *c_med_hw; @@ -176,12 +185,25 @@ struct lldpd_chassis { char *c_med_manuf; char *c_med_model; char *c_med_asset; -#else -#define STRUCT_LLDPD_CHASSIS_MED "" #endif }; -#define STRUCT_LLDPD_CHASSIS "(LwwbbCsswwwll" STRUCT_LLDPD_CHASSIS_MED ")" +MARSHAL_BEGIN(lldpd_chassis) +MARSHAL_TQE(lldpd_chassis, c_entries) +MARSHAL_FSTR(lldpd_chassis, c_id, c_id_len) +MARSHAL_STR(lldpd_chassis, c_name) +MARSHAL_STR(lldpd_chassis, c_descr) +#ifdef ENABLE_LLDPMED +MARSHAL_STR(lldpd_chassis, c_med_hw) +MARSHAL_STR(lldpd_chassis, c_med_fw) +MARSHAL_STR(lldpd_chassis, c_med_sw) +MARSHAL_STR(lldpd_chassis, c_med_sn) +MARSHAL_STR(lldpd_chassis, c_med_manuf) +MARSHAL_STR(lldpd_chassis, c_med_model) +MARSHAL_STR(lldpd_chassis, c_med_asset) +#endif +MARSHAL_END; + struct lldpd_port { TAILQ_ENTRY(lldpd_port) p_entries; @@ -199,52 +221,67 @@ struct lldpd_port { u_int8_t p_hidden_out:2; /* Considered as hidden for emission */ #ifdef ENABLE_DOT3 -#define STRUCT_LLDPD_PORT_DOT3 "l" STRUCT_LLDPD_DOT3_MACPHY STRUCT_LLDPD_DOT3_POWER /* Dot3 stuff */ u_int32_t p_aggregid; struct lldpd_dot3_macphy p_macphy; struct lldpd_dot3_power p_power; -#else -#define STRUCT_LLDPD_PORT_DOT3 "" #endif #ifdef ENABLE_LLDPMED -#define STRUCT_LLDPD_PORT_MED "w" \ - STRUCT_LLDPD_MED_POLICY \ - STRUCT_LLDPD_MED_POLICY \ - STRUCT_LLDPD_MED_POLICY \ - STRUCT_LLDPD_MED_POLICY \ - STRUCT_LLDPD_MED_POLICY \ - STRUCT_LLDPD_MED_POLICY \ - STRUCT_LLDPD_MED_POLICY \ - STRUCT_LLDPD_MED_POLICY \ - STRUCT_LLDPD_MED_LOC \ - STRUCT_LLDPD_MED_LOC \ - STRUCT_LLDPD_MED_LOC \ - STRUCT_LLDPD_MED_POWER u_int16_t p_med_cap_enabled; struct lldpd_med_policy p_med_policy[LLDPMED_APPTYPE_LAST]; struct lldpd_med_loc p_med_location[LLDPMED_LOCFORMAT_LAST]; struct lldpd_med_power p_med_power; -#else -#define STRUCT_LLDPD_PORT_MED "" #endif #ifdef ENABLE_DOT1 -#define STRUCT_LLDPD_PORT_DOT1 "wPPPPPP" u_int16_t p_pvid; TAILQ_HEAD(, lldpd_vlan) p_vlans; TAILQ_HEAD(, lldpd_ppvid) p_ppvids; TAILQ_HEAD(, lldpd_pi) p_pids; -#else -#define STRUCT_LLDPD_PORT_DOT1 "" #endif }; +MARSHAL_BEGIN(lldpd_port) +MARSHAL_TQE(lldpd_port, p_entries) +MARSHAL_POINTER(lldpd_port, lldpd_chassis, p_chassis) +MARSHAL_IGNORE(lldpd_port, p_lastframe) +MARSHAL_FSTR(lldpd_port, p_id, p_id_len) +MARSHAL_STR(lldpd_port, p_descr) +#ifdef ENABLE_LLDPMED +MARSHAL_SUBSTRUCT(lldpd_port, lldpd_med_loc, p_med_location[0]) +MARSHAL_SUBSTRUCT(lldpd_port, lldpd_med_loc, p_med_location[1]) +MARSHAL_SUBSTRUCT(lldpd_port, lldpd_med_loc, p_med_location[2]) +#endif +#ifdef ENABLE_DOT1 +MARSHAL_SUBTQ(lldpd_port, lldpd_vlan, p_vlans) +MARSHAL_SUBTQ(lldpd_port, lldpd_ppvid, p_ppvids) +MARSHAL_SUBTQ(lldpd_port, lldpd_pi, p_pids) +#endif +MARSHAL_END; -#define STRUCT_LLDPD_PORT "(LPttPbbCswb" \ - STRUCT_LLDPD_PORT_DOT3 \ - STRUCT_LLDPD_PORT_MED \ - STRUCT_LLDPD_PORT_DOT1 ")" +/* Used to modify some port related settings */ +struct lldpd_port_set { + char *ifname; +#ifdef ENABLE_LLDPMED + struct lldpd_med_policy *med_policy; + struct lldpd_med_loc *med_location; + struct lldpd_med_power *med_power; +#endif +#ifdef ENABLE_DOT3 + struct lldpd_dot3_power *dot3_power; +#endif +}; +MARSHAL_BEGIN(lldpd_port_set) +MARSHAL_STR(lldpd_port_set, ifname) +#ifdef ENABLE_LLDPMED +MARSHAL_POINTER(lldpd_port_set, lldpd_med_policy, med_policy) +MARSHAL_POINTER(lldpd_port_set, lldpd_med_loc, med_location) +MARSHAL_POINTER(lldpd_port_set, lldpd_med_power, med_power) +#endif +#ifdef ENABLE_DOT3 +MARSHAL_POINTER(lldpd_port_set, lldpd_dot3_power, dot3_power) +#endif +MARSHAL_END; struct lldpd_frame { int size; @@ -293,12 +330,25 @@ struct lldpd_hardware { struct lldpd_port h_lport; /* Port attached to this hardware port */ TAILQ_HEAD(, lldpd_port) h_rports; /* Remote ports */ }; +MARSHAL_BEGIN(lldpd_hardware) +MARSHAL_IGNORE(lldpd_hardware, h_entries.tqe_next) +MARSHAL_IGNORE(lldpd_hardware, h_entries.tqe_prev) +MARSHAL_IGNORE(lldpd_hardware, h_ops) +MARSHAL_IGNORE(lldpd_hardware, h_data) +MARSHAL_SUBSTRUCT(lldpd_hardware, lldpd_port, h_lport) +MARSHAL_SUBTQ(lldpd_hardware, lldpd_port, h_rports) +MARSHAL_END; struct lldpd_interface { TAILQ_ENTRY(lldpd_interface) next; char *name; }; -#define STRUCT_LLDPD_INTERFACE "(Ls)" +MARSHAL_BEGIN(lldpd_interface) +MARSHAL_TQE(lldpd_interface, next) +MARSHAL_STR(lldpd_interface, name) +MARSHAL_END; +TAILQ_HEAD(lldpd_interface_list, lldpd_interface); +MARSHAL_TQ(lldpd_interface_list, lldpd_interface); #define PROTO_SEND_SIG struct lldpd *, struct lldpd_hardware * #define PROTO_DECODE_SIG struct lldpd *, char *, int, struct lldpd_hardware *, struct lldpd_chassis **, struct lldpd_port ** @@ -382,35 +432,12 @@ struct lldpd { typedef void(*lldpd_ifhandlers)(struct lldpd *, struct ifaddrs *); enum hmsg_type { - HMSG_NONE, - HMSG_GET_INTERFACES, - HMSG_GET_NB_PORTS, - HMSG_GET_PORT, - HMSG_GET_CHASSIS, - HMSG_GET_VLANS, - HMSG_GET_PPVIDS, - HMSG_GET_PIDS, - HMSG_SET_LOCATION, - HMSG_SET_POLICY, - HMSG_SET_POWER, - HMSG_SET_DOT3_POWER, - HMSG_SHUTDOWN -}; - -struct hmsg_hdr { - enum hmsg_type type; - int16_t len; - pid_t pid; + NONE, + GET_INTERFACES, /* Get list of interfaces */ + GET_INTERFACE, /* Get all information related to an interface */ + SET_PORT, /* Set port-related information (location, power, policy) */ }; -struct hmsg { - struct hmsg_hdr hdr; - char data[]; -}; - -#define HMSG_HEADER_SIZE sizeof(struct hmsg_hdr) -#define MAX_HMSGSIZE 8192 - /* lldpd.c */ struct lldpd_hardware *lldpd_get_hardware(struct lldpd *, char *, int, struct lldpd_ops *); @@ -463,13 +490,10 @@ int ctl_create(char *); int ctl_connect(char *); void ctl_cleanup(char *); void ctl_accept(struct lldpd *, struct lldpd_callback *); -void ctl_msg_init(struct hmsg *, enum hmsg_type); -int ctl_msg_send(int, struct hmsg *); -int ctl_msg_recv(int, struct hmsg *); -int ctl_msg_pack_list(char *, void *, unsigned int, struct hmsg *, void **); -int ctl_msg_unpack_list(char *, void *, unsigned int, struct hmsg *, void **); -int ctl_msg_pack_structure(char *, void *, unsigned int, struct hmsg *, void **); -int ctl_msg_unpack_structure(char *, void *, unsigned int, struct hmsg *, void **); +int ctl_msg_send(int, enum hmsg_type, void *, size_t); +int ctl_msg_recv(int, enum hmsg_type *, void **); +int ctl_msg_send_recv(int, enum hmsg_type, + void *, struct marshal_info *, void **, struct marshal_info *); /* interfaces.c */ void lldpd_ifh_whitelist(struct lldpd *, struct ifaddrs *); @@ -515,19 +539,12 @@ void agent_priv_register_domain(void); /* client.c */ struct client_handle { enum hmsg_type type; - void (*handle)(struct lldpd*, struct hmsg*, struct hmsg*); + int (*handle)(struct lldpd*, enum hmsg_type *, + void *, int, void **); }; -void client_handle_client(struct lldpd *, struct lldpd_callback *, - char *, int); -void client_handle_none(struct lldpd *, struct hmsg *, - struct hmsg *); -void client_handle_get_interfaces(struct lldpd *, struct hmsg *, - struct hmsg *); -void client_handle_port_related(struct lldpd *, struct hmsg *, - struct hmsg *); -void client_handle_shutdown(struct lldpd *, struct hmsg *, - struct hmsg *); +int client_handle_client(struct lldpd *, struct lldpd_callback *, + enum hmsg_type, void *, int); /* priv.c */ void priv_init(char*); diff --git a/tests/Makefile.am b/tests/Makefile.am index 41c863eb..df67292b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,12 +1,9 @@ -TESTS = check_pack check_marshal check_lldp check_cdp check_sonmp check_edp check_ifaddrs +TESTS = check_marshal check_lldp check_cdp check_sonmp check_edp check_ifaddrs if HAVE_CHECK -check_pack_SOURCES = check_pack.c \ - $(top_builddir)/src/lldpd.h - check_marshal_SOURCES = check_marshal.c \ - $(top_builddir)/src/lldpd.h + $(top_builddir)/src/marshal.h check_lldp_SOURCES = check_lldp.c \ $(top_builddir)/src/lldpd.h \ diff --git a/tests/check_pack.c b/tests/check_pack.c deleted file mode 100644 index 7738524c..00000000 --- a/tests/check_pack.c +++ /dev/null @@ -1,735 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "../src/lldpd.h" - -struct hmsg *h = NULL; - -void -setup() -{ - h = (struct hmsg *)calloc(1, MAX_HMSGSIZE); - fail_unless(h != NULL); -} - -void teardown() -{ - free(h); h = NULL; -} - -START_TEST (test_pack_byte) -{ - /* Packing a single byte */ - char byte = 18; - void *p; - p = (char*)&h->data; - if (ctl_msg_pack_structure("b", &byte, sizeof(char), - h, &p) == -1) { - fail("unable to pack"); - return; - } - mark_point(); - p = (char*)&h->data; - if (ctl_msg_unpack_structure("b", &byte, sizeof(char), - h, &p) == -1) { - fail("unable to unpack"); - return; - } - ck_assert_int_eq(byte, 18); -} -END_TEST - -START_TEST (test_pack_word) -{ - /* Packing a single word */ - u_int16_t word = 7874; - void *p; - p = (char*)&h->data; - if (ctl_msg_pack_structure("w", &word, sizeof(u_int16_t), - h, &p) == -1) { - fail("unable to pack"); - return; - } - mark_point(); - p = (char*)&h->data; - if (ctl_msg_unpack_structure("w", &word, sizeof(u_int16_t), - h, &p) == -1) { - fail("unable to unpack"); - return; - } - ck_assert_int_eq(word, 7874); -} -END_TEST - -START_TEST (test_pack_long) -{ - /* Packing a single long */ - u_int32_t l = 14523657UL; - void *p; - p = (char*)&h->data; - if (ctl_msg_pack_structure("l", &l, sizeof(u_int32_t), - h, &p) == -1) { - fail("unable to pack"); - return; - } - mark_point(); - p = (char*)&h->data; - if (ctl_msg_unpack_structure("l", &l, sizeof(u_int32_t), - h, &p) == -1) { - fail("unable to unpack"); - return; - } - ck_assert_int_eq(l, 14523657UL); -} -END_TEST - -START_TEST (test_pack_time) -{ - /* Packing a single time_t */ - time_t t = time(NULL); - time_t t2; - void *p; - t2 = t; - p = (char*)&h->data; - if (ctl_msg_pack_structure("t", &t, sizeof(time_t), - h, &p) == -1) { - fail("unable to pack"); - return; - } - mark_point(); - p = (char*)&h->data; - if (ctl_msg_unpack_structure("t", &t, sizeof(time_t), - h, &p) == -1) { - fail("unable to unpack"); - return; - } - ck_assert_int_eq(t, t2); -} -END_TEST - -START_TEST (test_pack_string) -{ - /* Packing a single string */ - char *s = "My simple string"; - char *rs; - void *p; - p = (char*)&h->data; - if (ctl_msg_pack_structure("s", &s, sizeof(char *), - h, &p) == -1) { - fail("unable to pack"); - return; - } - mark_point(); - p = (char*)&h->data; - if (ctl_msg_unpack_structure("s", &rs, sizeof(char *), - h, &p) == -1) { - fail("unable to unpack"); - return; - } - ck_assert_str_eq(s, rs); - ck_assert_str_eq(rs, "My simple string"); - free(rs); -} -END_TEST - -START_TEST (test_pack_null_string) -{ - /* Packing a single empty string */ - char *s = ""; - char *rs; - void *p; - p = (char*)&h->data; - if (ctl_msg_pack_structure("s", &s, sizeof(char *), - h, &p) == -1) { - fail("unable to pack"); - return; - } - mark_point(); - p = (char*)&h->data; - if (ctl_msg_unpack_structure("s", &rs, sizeof(char *), - h, &p) == -1) { - fail("unable to unpack"); - return; - } - ck_assert_str_eq(s, rs); - ck_assert_int_eq(strlen(rs), 0); - free(rs); -} -END_TEST - -struct tpls { - char *s; - int l; -}; - -START_TEST (test_pack_len_string) -{ - /* Packing a single string with its length */ - struct tpls t; - void *p; - - t.s = "My string"; - t.l = strlen(t.s); - - p = (char*)&h->data; - if (ctl_msg_pack_structure("C", &t, sizeof(struct tpls), - h, &p) == -1) { - fail("unable to pack"); - return; - } - mark_point(); - p = (char*)&h->data; - if (ctl_msg_unpack_structure("C", &t, sizeof(struct tpls), - h, &p) == -1) { - fail("unable to unpack"); - return; - } - ck_assert_int_eq(t.l, strlen("My string")); - fail_unless(memcmp(t.s, "My string", t.l) == 0); - free(t.s); -} -END_TEST - -struct tps1 { - u_int8_t a; - u_int16_t b; - u_int32_t c; - u_int8_t d; - void *e; - u_int8_t f; - time_t g; -}; - -START_TEST (test_pack_structures1) -{ - /* Test padding */ - struct tps1 t; - void *p; - t.a = 129; - t.b = 37814; - t.c = 3456781258UL; - t.d = 14; - t.e = &t; - t.f = 47; - t.g = 1246799447UL; - - p = (char*)&h->data; - if (ctl_msg_pack_structure("bwlbPbt", &t, sizeof(struct tps1), - h, &p) == -1) { - fail("unable to pack"); - return; - } - mark_point(); - p = (char*)&h->data; - if (ctl_msg_unpack_structure("bwlbPbt", &t, sizeof(struct tps1), - h, &p) == -1) { - fail("unable to unpack"); - return; - } - ck_assert_int_eq(t.a, 129); - ck_assert_int_eq(t.b, 37814); - ck_assert_int_eq(t.c, 3456781258UL); - ck_assert_int_eq(t.d, 14); - ck_assert_int_eq(t.f, 47); - ck_assert_int_eq(t.g, 1246799447UL); -} -END_TEST - -struct tps2 { - u_int8_t a; - void *b; - u_int16_t c; - void *d; - u_int32_t e; - void *f; - time_t g; - void *h; - u_int8_t i; -}; - -START_TEST (test_pack_structures2) -{ - /* More padding */ - struct tps2 t; - void *p; - t.a = 129; - t.c = 37814; - t.e = 3456781258UL; - t.g = 1246799447; - t.i = 12; - - p = (char*)&h->data; - if (ctl_msg_pack_structure("bPwPlPtPb", &t, sizeof(struct tps2), - h, &p) == -1) { - fail("unable to pack"); - return; - } - mark_point(); - p = (char*)&h->data; - if (ctl_msg_unpack_structure("bPwPlPtPb", &t, sizeof(struct tps2), - h, &p) == -1) { - fail("unable to unpack"); - return; - } - ck_assert_int_eq(t.a, 129); - ck_assert_int_eq(t.c, 37814); - ck_assert_int_eq(t.e, 3456781258UL); - ck_assert_int_eq(t.g, 1246799447UL); - ck_assert_int_eq(t.i, 12); -} -END_TEST - -struct tps3 { - u_int8_t a; - char *b; - u_int16_t c; - char *d; - u_int32_t e; - char *f; - time_t g; - char *h; - u_int8_t i; - char *j; - int l; - u_int8_t k; - char *m; -}; - -START_TEST (test_pack_structures3) -{ - /* More padding, with strings */ - struct tps3 t; - void *p; - t.a = 129; - t.b = "First string"; - t.c = 37814; - t.d = "Second string"; - t.e = 3456781258UL; - t.f = "Third string"; - t.g = 1246799447UL; - t.h = "Fourth string"; - t.i = 12; - t.j = "Fifth string"; - t.l = strlen(t.j); - t.k = 89; - t.m = "Last string"; - - p = (char*)&h->data; - if (ctl_msg_pack_structure("bswslstsbCbs", &t, sizeof(struct tps3), - h, &p) == -1) { - fail("unable to pack"); - return; - } - mark_point(); - p = (char*)&h->data; - if (ctl_msg_unpack_structure("bswslstsbCbs", &t, sizeof(struct tps3), - h, &p) == -1) { - fail("unable to unpack"); - return; - } - ck_assert_int_eq(t.a, 129); - ck_assert_str_eq(t.b, "First string"); - ck_assert_int_eq(t.c, 37814); - ck_assert_str_eq(t.d, "Second string"); - ck_assert_int_eq(t.e, 3456781258UL); - ck_assert_str_eq(t.f, "Third string"); - ck_assert_int_eq(t.g, 1246799447UL); - ck_assert_str_eq(t.h, "Fourth string"); - ck_assert_int_eq(t.i, 12); - ck_assert_int_eq(t.l, strlen("Fifth string")); - fail_unless(memcmp(t.j, "Fifth string", t.l) == 0); - ck_assert_int_eq(t.k, 89); - ck_assert_str_eq(t.m, "Last string"); - free(t.b); free(t.d); free(t.f); free(t.h); free(t.j); free(t.m); -} -END_TEST - -struct tps4_1 { - u_int8_t a; - u_int16_t b; - u_int32_t c; - time_t d; - u_int8_t e; - void *f; - u_int8_t g; - char *h; - u_int8_t i; -}; -#define TPS41 "(bwltbPbsb)" - -struct tps4 { - u_int8_t a; - struct tps4_1 b; - u_int16_t c; - struct tps4_1 d; - u_int32_t e; - struct tps4_1 f; - void *g; - struct tps4_1 h; - struct tps4_1 i; - u_int8_t j; -}; -#define TPS4 "b" TPS41 "w" TPS41 "l" TPS41 "P" TPS41 TPS41 "b" - -START_TEST (test_pack_structures4) -{ - /* More padding, with substructures */ - struct tps4 t; - void *p; - t.a = 129; - t.b.a = 178; - t.b.b = 37894; - t.b.c = 345678914UL; - t.b.d = 345781741UL; - t.b.e = 74; - t.b.g = 78; - t.b.h = "First string"; - t.b.i = 230; - t.c = 37814; - t.d.a = t.b.a + 1; - t.d.b = t.b.b + 1; - t.d.c = t.b.c + 1; - t.d.d = t.b.d + 1; - t.d.e = t.b.e + 1; - t.d.g = t.b.g + 1; - t.d.h = "Second string"; - t.d.i = t.b.i + 1; - t.e = 3456781258UL; - t.f.a = t.b.a + 2; - t.f.b = t.b.b + 2; - t.f.c = t.b.c + 2; - t.f.d = t.b.d + 2; - t.f.e = t.b.e + 2; - t.f.g = t.b.g + 2; - t.f.h = "Third string"; - t.f.i = t.b.i + 2; - t.h.a = t.b.a + 3; - t.h.b = t.b.b + 3; - t.h.c = t.b.c + 3; - t.h.d = t.b.d + 3; - t.h.e = t.b.e + 3; - t.h.g = t.b.g + 3; - t.h.h = "Fourth string"; - t.h.i = t.b.i + 3; - t.i.a = t.b.a + 4; - t.i.b = t.b.b + 4; - t.i.c = t.b.c + 4; - t.i.d = t.b.d + 4; - t.i.e = t.b.e + 4; - t.i.g = t.b.g + 4; - t.i.h = "Fifth string"; - t.i.i = t.b.i + 4; - t.j = 12; - - p = (char*)&h->data; - if (ctl_msg_pack_structure(TPS4, &t, sizeof(struct tps4), - h, &p) == -1) { - fail("unable to pack"); - return; - } - mark_point(); - p = (char*)&h->data; - if (ctl_msg_unpack_structure(TPS4, &t, sizeof(struct tps4), - h, &p) == -1) { - fail("unable to unpack"); - return; - } - - ck_assert_int_eq(t.a, 129); - ck_assert_int_eq(t.b.a, 178); - ck_assert_int_eq(t.b.b, 37894); - ck_assert_int_eq(t.b.c, 345678914UL); - ck_assert_int_eq(t.b.d, 345781741UL); - ck_assert_int_eq(t.b.e, 74); - ck_assert_int_eq(t.b.g, 78); - ck_assert_str_eq(t.b.h, "First string"); - ck_assert_int_eq(t.b.i, 230); - ck_assert_int_eq(t.c, 37814); - ck_assert_int_eq(t.d.a, t.b.a + 1); - ck_assert_int_eq(t.d.b, t.b.b + 1); - ck_assert_int_eq(t.d.c, t.b.c + 1); - ck_assert_int_eq(t.d.d, t.b.d + 1); - ck_assert_int_eq(t.d.e, t.b.e + 1); - ck_assert_int_eq(t.d.g, t.b.g + 1); - ck_assert_str_eq(t.d.h, "Second string"); - ck_assert_int_eq(t.d.i, t.b.i + 1); - ck_assert_int_eq(t.e, 3456781258UL); - ck_assert_int_eq(t.f.a, t.b.a + 2); - ck_assert_int_eq(t.f.b, t.b.b + 2); - ck_assert_int_eq(t.f.c, t.b.c + 2); - ck_assert_int_eq(t.f.d, t.b.d + 2); - ck_assert_int_eq(t.f.e, t.b.e + 2); - ck_assert_int_eq(t.f.g, t.b.g + 2); - ck_assert_str_eq(t.f.h, "Third string"); - ck_assert_int_eq(t.f.i, t.b.i + 2); - ck_assert_int_eq(t.h.a, t.b.a + 3); - ck_assert_int_eq(t.h.b, t.b.b + 3); - ck_assert_int_eq(t.h.c, t.b.c + 3); - ck_assert_int_eq(t.h.d, t.b.d + 3); - ck_assert_int_eq(t.h.e, t.b.e + 3); - ck_assert_int_eq(t.h.g, t.b.g + 3); - fail_unless(strcmp(t.h.h, "Fourth string") == 0); - ck_assert_int_eq(t.h.i, t.b.i + 3); - ck_assert_int_eq(t.i.a, t.b.a + 4); - ck_assert_int_eq(t.i.b, t.b.b + 4); - ck_assert_int_eq(t.i.c, t.b.c + 4); - ck_assert_int_eq(t.i.d, t.b.d + 4); - ck_assert_int_eq(t.i.e, t.b.e + 4); - ck_assert_int_eq(t.i.g, t.b.g + 4); - ck_assert_str_eq(t.i.h, "Fifth string"); - ck_assert_int_eq(t.i.i, t.b.i + 4); - ck_assert_int_eq(t.j, 12); - free(t.i.h); free(t.h.h); free(t.f.h); free(t.d.h); free(t.b.h); -} -END_TEST - -struct tps51 { - u_int8_t a; - u_int16_t b; - u_int32_t c; - u_int8_t e; - time_t f; - u_int16_t g; - u_int8_t h; - u_int32_t i; - u_int16_t j; -}; -#define TPS51 "(bwlbtwblw)" - -struct tps52 { - u_int8_t a; - struct tps51 b; - u_int16_t c; - struct tps51 d; - u_int32_t e; - struct tps51 f; - struct tps51 g; - u_int8_t h; -}; -#define TPS52 "(b" TPS51 "w" TPS51 "l" TPS51 TPS51 "b)" - -struct tps53 { - u_int8_t a; - struct tps52 b; - u_int16_t c; - struct tps52 d; - u_int32_t e; - struct tps51 f; - struct tps52 g; - u_int8_t h; -}; -#define TPS53 "(b" TPS52 "w" TPS52 "l" TPS51 TPS52 "b)" - -struct tps5 { - u_int8_t a; - struct tps51 b; - u_int16_t c; - struct tps53 d; - u_int32_t e; - struct tps53 f; - struct tps53 g; - u_int8_t h; -}; -#define TPS5 "(b" TPS51 "w" TPS53 "l" TPS53 TPS53 "b)" - -START_TEST (test_pack_structures5) -{ - /* More padding, with recursive substructures */ - struct tps5 t; - struct tps5 tc; - int f, n; - void *p; - - f = open("/dev/urandom", O_RDONLY); - if (f == -1) { - fail("unable to open /dev/urandom"); - return; - } - n = read(f, &t, sizeof(struct tps5)); - if (n != sizeof(struct tps5)) { - fail("Should have read %d bytes from /dev/random but got %d", - sizeof(struct tps5), n); - close(f); - return; - } - memcpy(&tc, &t, sizeof(struct tps5)); - close(f); - - p = (char*)&h->data; - if (ctl_msg_pack_structure(TPS5, &t, sizeof(struct tps5), - h, &p) == -1) { - fail("unable to pack"); - return; - } - mark_point(); - p = (char*)&h->data; - if (ctl_msg_unpack_structure(TPS5, &t, sizeof(struct tps5), - h, &p) == -1) { - fail("unable to unpack"); - return; - } - - fail_unless(memcmp(&t, &tc, sizeof(struct tps5)) == 0); -} -END_TEST - -struct tpl { - TAILQ_ENTRY(tpl) next; - u_int16_t a; - u_int8_t b; - u_int32_t c; - char *e; - u_int8_t d; -}; -#define TPL "(Lwblsb)" - -START_TEST (test_pack_empty_list) -{ - TAILQ_HEAD(, tpl) l; - void *p; - - TAILQ_INIT(&l); - p = (char*)&h->data; - if (ctl_msg_pack_list(TPL, &l, sizeof(struct tpl), - h, &p) == -1) { - fail("unable to pack"); - return; - } - mark_point(); - p = (char*)&h->data; - if (ctl_msg_unpack_list(TPL, &l, sizeof(struct tpl), - h, &p) == -1) { - fail("unable to unpack"); - return; - } - - fail_unless(TAILQ_EMPTY(&l)); -} -END_TEST - -START_TEST (test_pack_list) -{ - TAILQ_HEAD(, tpl) l; - struct tpl tpl1, tpl2, tpl3; - struct tpl *tpl4; - void *p; - int count; - - TAILQ_INIT(&l); - tpl1.a = 47241; - tpl1.b = 147; - tpl1.c = 1474142364UL; - tpl1.d = 198; - tpl1.e = "First string"; - mark_point(); - TAILQ_INSERT_TAIL(&l, &tpl1, next); - tpl2.a = tpl1.a+1; - tpl2.b = tpl1.b+1; - tpl2.c = tpl1.c+1; - tpl2.d = tpl1.d+1; - tpl2.e = "Second string"; - mark_point(); - TAILQ_INSERT_TAIL(&l, &tpl2, next); - tpl3.a = tpl1.a+2; - tpl3.b = tpl1.b+2; - tpl3.c = tpl1.c+2; - tpl3.d = tpl1.d+2; - tpl3.e = "Last string"; - mark_point(); - TAILQ_INSERT_TAIL(&l, &tpl3, next); - - mark_point(); - p = (char*)&h->data; - if (ctl_msg_pack_list(TPL, &l, sizeof(struct tpl), - h, &p) == -1) { - fail("unable to pack"); - return; - } - mark_point(); - p = (char*)&h->data; - if (ctl_msg_unpack_list(TPL, &l, sizeof(struct tpl), - h, &p) == -1) { - fail("unable to unpack"); - return; - } - - count = 0; - TAILQ_FOREACH(tpl4, &l, next) { - mark_point(); - ck_assert_int_eq(tpl4->a, tpl1.a+count); - ck_assert_int_eq(tpl4->b, tpl1.b+count); - ck_assert_int_eq(tpl4->c, tpl1.c+count); - ck_assert_int_eq(tpl4->d, tpl1.d+count); - switch (count) { - case 0: - ck_assert_str_eq(tpl4->e, "First string"); - break; - case 1: - ck_assert_str_eq(tpl4->e, "Second string"); - break; - case 2: - ck_assert_str_eq(tpl4->e, "Last string"); - break; - default: - fail("Should not be there... List too long."); - break; - } - count++; - } - - ck_assert_int_eq(count, 3); -} -END_TEST - -Suite * -pack_suite(void) -{ - Suite *s = suite_create("Packing"); - - /* Single objects packing/unpacking */ - TCase *tc_core = tcase_create("Single objects"); - tcase_add_checked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, test_pack_byte); - tcase_add_test(tc_core, test_pack_word); - tcase_add_test(tc_core, test_pack_long); - tcase_add_test(tc_core, test_pack_time); - tcase_add_test(tc_core, test_pack_string); - tcase_add_test(tc_core, test_pack_null_string); - tcase_add_test(tc_core, test_pack_len_string); - suite_add_tcase(s, tc_core); - - /* Complex structure packing/unpacking */ - TCase *tc_structures = tcase_create("Structures"); - tcase_add_checked_fixture(tc_structures, setup, teardown); - tcase_add_test(tc_structures, test_pack_structures1); - tcase_add_test(tc_structures, test_pack_structures2); - tcase_add_test(tc_structures, test_pack_structures3); - tcase_add_test(tc_structures, test_pack_structures4); - tcase_add_test(tc_structures, test_pack_structures5); - suite_add_tcase(s, tc_structures); - - /* List packing/unpacking */ - TCase *tc_lists = tcase_create("Lists"); - tcase_add_checked_fixture(tc_lists, setup, teardown); - tcase_add_test(tc_lists, test_pack_empty_list); - tcase_add_test(tc_lists, test_pack_list); - suite_add_tcase(s, tc_lists); - - return s; -} - -int -main() -{ - int number_failed; - Suite *s = pack_suite (); - SRunner *sr = srunner_create (s); - srunner_run_all (sr, CK_ENV); - number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -}