]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/daemon/client.c
daemon/lldpd.c: free() cfg at end of main function
[thirdparty/lldpd.git] / src / daemon / client.c
CommitLineData
4b292b55 1/* -*- mode: c; c-file-style: "openbsd" -*- */
a552a72e
VB
2/*
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 *
51434125 5 * Permission to use, copy, modify, and/or distribute this software for any
a552a72e
VB
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include "lldpd.h"
bdfe4193 19#include "trace.h"
a552a72e 20
324d73a3 21static ssize_t
f6d20631 22client_handle_none(struct lldpd *cfg, enum hmsg_type *type,
4e90a9e0 23 void *input, int input_len, void **output, int *subscribed)
a552a72e 24{
6f8925be 25 log_info("rpc", "received noop request from client");
f6d20631
VB
26 *type = NONE;
27 return 0;
a552a72e
VB
28}
29
8729d69f 30/* Return the global configuration */
324d73a3 31static ssize_t
8729d69f
VB
32client_handle_get_configuration(struct lldpd *cfg, enum hmsg_type *type,
33 void *input, int input_len, void **output, int *subscribed)
34{
35 ssize_t output_len;
6f8925be 36 log_debug("rpc", "client requested configuration");
985a4cb5 37 output_len = lldpd_config_serialize(&cfg->g_config, output);
8729d69f
VB
38 if (output_len <= 0) {
39 output_len = 0;
40 *type = NONE;
41 }
42 return output_len;
43}
44
6dd83015
VB
45static char*
46xstrdup(const char *str)
47{
48 if (!str) return NULL;
49 return strdup(str);
50}
51
47287a61 52/* Change the global configuration */
324d73a3 53static ssize_t
47287a61
VB
54client_handle_set_configuration(struct lldpd *cfg, enum hmsg_type *type,
55 void *input, int input_len, void **output, int *subscribed)
56{
57 struct lldpd_config *config;
58
6f8925be 59 log_debug("rpc", "client request a change in configuration");
47287a61 60 /* Get the proposed configuration. */
985a4cb5 61 if (lldpd_config_unserialize(input, input_len, &config) <= 0) {
47287a61
VB
62 *type = NONE;
63 return 0;
64 }
e4c51716
VB
65
66#define CHANGED(w) (config->w != cfg->g_config.w)
6dd83015
VB
67#define CHANGED_STR(w) (!(config->w == cfg->g_config.w || \
68 (config->w && cfg->g_config.w && !strcmp(config->w, cfg->g_config.w))))
e4c51716 69
e4ff3ed5 70 /* What needs to be done? Transmit delay? */
63b4f1ee 71 if (CHANGED(c_tx_interval) && config->c_tx_interval != 0) {
e4c51716
VB
72 if (config->c_tx_interval < 0) {
73 log_debug("rpc", "client asked for immediate retransmission");
74 levent_send_now(cfg);
75 } else {
63b4f1ee
VB
76 log_debug("rpc", "client change transmit interval to %d",
77 config->c_tx_interval);
78 cfg->g_config.c_tx_interval = config->c_tx_interval;
e4c51716
VB
79 LOCAL_CHASSIS(cfg)->c_ttl = cfg->g_config.c_tx_interval *
80 cfg->g_config.c_tx_hold;
81 }
82 }
63b4f1ee
VB
83 if (CHANGED(c_tx_hold) && config->c_tx_hold > 0) {
84 log_debug("rpc", "client change transmit hold to %d",
85 config->c_tx_hold);
86 cfg->g_config.c_tx_hold = config->c_tx_hold;
87 LOCAL_CHASSIS(cfg)->c_ttl = cfg->g_config.c_tx_interval *
88 cfg->g_config.c_tx_hold;
89 }
e4c51716
VB
90 if (CHANGED(c_lldp_portid_type) &&
91 config->c_lldp_portid_type > LLDP_PORTID_SUBTYPE_UNKNOWN &&
92 config->c_lldp_portid_type <= LLDP_PORTID_SUBTYPE_MAX) {
93 log_debug("rpc", "change lldp portid tlv subtype to %d",
94 config->c_lldp_portid_type);
95 cfg->g_config.c_lldp_portid_type = config->c_lldp_portid_type;
96 levent_update_now(cfg);
8fbd3195 97 }
e4ff3ed5 98 /* Pause/resume */
e4c51716 99 if (CHANGED(c_paused)) {
e4ff3ed5
VB
100 log_debug("rpc", "client asked to %s lldpd",
101 config->c_paused?"pause":"resume");
102 cfg->g_config.c_paused = config->c_paused;
103 levent_send_now(cfg);
104 }
47287a61 105
486a6133 106#ifdef ENABLE_LLDPMED
e4c51716
VB
107 if (CHANGED(c_enable_fast_start)) {
108 cfg->g_config.c_enable_fast_start = config->c_enable_fast_start;
486a6133
VB
109 log_debug("rpc", "client asked to %s fast start",
110 cfg->g_config.c_enable_fast_start?"enable":"disable");
111 }
e4c51716
VB
112 if (CHANGED(c_tx_fast_interval) &&
113 config->c_tx_fast_interval > 0) {
486a6133
VB
114 log_debug("rpc", "change fast interval to %d", config->c_tx_fast_interval);
115 cfg->g_config.c_tx_fast_interval = config->c_tx_fast_interval;
116 }
117#endif
e4c51716 118 if (CHANGED_STR(c_iface_pattern)) {
6dd83015
VB
119 log_debug("rpc", "change interface pattern to %s",
120 config->c_iface_pattern?config->c_iface_pattern:"(NULL)");
e26a25ca 121 free(cfg->g_config.c_iface_pattern);
6dd83015 122 cfg->g_config.c_iface_pattern = xstrdup(config->c_iface_pattern);
e681c859 123 levent_update_now(cfg);
346a0f69 124 }
e4c51716 125 if (CHANGED_STR(c_mgmt_pattern)) {
6dd83015
VB
126 log_debug("rpc", "change management pattern to %s",
127 config->c_mgmt_pattern?config->c_mgmt_pattern:"(NULL)");
622d14bb 128 free(cfg->g_config.c_mgmt_pattern);
6dd83015 129 cfg->g_config.c_mgmt_pattern = xstrdup(config->c_mgmt_pattern);
622d14bb
VB
130 levent_update_now(cfg);
131 }
e4c51716 132 if (CHANGED_STR(c_description)) {
6dd83015
VB
133 log_debug("rpc", "change chassis description to %s",
134 config->c_description?config->c_description:"(NULL)");
decaec0d 135 free(cfg->g_config.c_description);
6dd83015 136 cfg->g_config.c_description = xstrdup(config->c_description);
decaec0d
VB
137 levent_update_now(cfg);
138 }
e4c51716 139 if (CHANGED_STR(c_platform)) {
6dd83015
VB
140 log_debug("rpc", "change platform description to %s",
141 config->c_platform?config->c_platform:"(NULL)");
3f70e118 142 free(cfg->g_config.c_platform);
6dd83015 143 cfg->g_config.c_platform = xstrdup(config->c_platform);
3f70e118
VB
144 levent_update_now(cfg);
145 }
e4c51716 146 if (CHANGED_STR(c_hostname)) {
6dd83015
VB
147 log_debug("rpc", "change system name to %s",
148 config->c_hostname?config->c_hostname:"(NULL");
ce347d29 149 free(cfg->g_config.c_hostname);
6dd83015 150 cfg->g_config.c_hostname = xstrdup(config->c_hostname);
ce347d29
JJ
151 levent_update_now(cfg);
152 }
e4c51716 153 if (CHANGED(c_set_ifdescr)) {
bb37268d
VB
154 log_debug("rpc", "%s setting of interface description based on discovered neighbors",
155 config->c_set_ifdescr?"enable":"disable");
156 cfg->g_config.c_set_ifdescr = config->c_set_ifdescr;
157 levent_update_now(cfg);
158 }
e4c51716 159 if (CHANGED(c_promisc)) {
f84199dd
VB
160 log_debug("rpc", "%s promiscuous mode on managed interfaces",
161 config->c_promisc?"enable":"disable");
162 cfg->g_config.c_promisc = config->c_promisc;
163 levent_update_now(cfg);
164 }
e4c51716 165 if (CHANGED(c_bond_slave_src_mac_type)) {
5813918a
VB
166 if (config->c_bond_slave_src_mac_type >
167 LLDP_BOND_SLAVE_SRC_MAC_TYPE_UNKNOWN &&
168 config->c_bond_slave_src_mac_type <=
169 LLDP_BOND_SLAVE_SRC_MAC_TYPE_MAX) {
170 log_debug("rpc", "change bond src mac type to %d",
171 config->c_bond_slave_src_mac_type);
172 cfg->g_config.c_bond_slave_src_mac_type =
173 config->c_bond_slave_src_mac_type;
174 } else {
175 log_info("rpc", "Invalid bond slave src mac type: %d\n",
176 config->c_bond_slave_src_mac_type);
177 }
dfbd7185 178 }
486a6133 179
47287a61 180 lldpd_config_cleanup(config);
aba549a8 181 free(config);
47287a61
VB
182
183 return 0;
184}
185
f6d20631
VB
186/* Return the list of interfaces.
187 Input: nothing.
188 Output: list of interface names (lldpd_interface_list)
189*/
324d73a3 190static ssize_t
f6d20631 191client_handle_get_interfaces(struct lldpd *cfg, enum hmsg_type *type,
4e90a9e0 192 void *input, int input_len, void **output, int *subscribed)
a552a72e
VB
193{
194 struct lldpd_interface *iff, *iff_next;
195 struct lldpd_hardware *hardware;
324d73a3 196 ssize_t output_len;
a552a72e
VB
197
198 /* Build the list of interfaces */
f6d20631 199 struct lldpd_interface_list ifs;
6f8925be
VB
200
201 log_debug("rpc", "client request the list of interfaces");
a552a72e
VB
202 TAILQ_INIT(&ifs);
203 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
204 if ((iff = (struct lldpd_interface*)malloc(sizeof(
205 struct lldpd_interface))) == NULL)
6f8925be 206 fatal("rpc", NULL);
a552a72e
VB
207 iff->name = hardware->h_ifname;
208 TAILQ_INSERT_TAIL(&ifs, iff, next);
209 }
210
985a4cb5 211 output_len = lldpd_interface_list_serialize(&ifs, output);
f6d20631
VB
212 if (output_len <= 0) {
213 output_len = 0;
214 *type = NONE;
a552a72e
VB
215 }
216
217 /* Free the temporary list */
218 for (iff = TAILQ_FIRST(&ifs);
219 iff != NULL;
220 iff = iff_next) {
221 iff_next = TAILQ_NEXT(iff, next);
222 TAILQ_REMOVE(&ifs, iff, next);
223 free(iff);
224 }
f6d20631
VB
225
226 return output_len;
a552a72e
VB
227}
228
f6d20631
VB
229/* Return all available information related to an interface
230 Input: name of the interface (serialized)
231 Output: Information about the interface (lldpd_hardware)
232*/
324d73a3 233static ssize_t
f6d20631 234client_handle_get_interface(struct lldpd *cfg, enum hmsg_type *type,
4e90a9e0 235 void *input, int input_len, void **output, int *subscribed)
a552a72e 236{
f6d20631 237 char *name;
5fd6695c 238 struct lldpd_hardware *hardware;
a8da1864 239 void *p;
5fd6695c
VB
240
241 /* Get name of the interface */
a8da1864 242 if (marshal_unserialize(string, input, input_len, &p) <= 0) {
f6d20631
VB
243 *type = NONE;
244 return 0;
245 }
a8da1864 246 name = p;
f6d20631
VB
247
248 /* Search appropriate hardware */
6f8925be 249 log_debug("rpc", "client request interface %s", name);
f6d20631
VB
250 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
251 if (!strcmp(hardware->h_ifname, name)) {
324d73a3 252 ssize_t output_len = lldpd_hardware_serialize(hardware, output);
f6d20631
VB
253 free(name);
254 if (output_len <= 0) {
255 *type = NONE;
f6d20631
VB
256 return 0;
257 }
258 return output_len;
259 }
260
6f8925be 261 log_warnx("rpc", "no interface %s found", name);
e4dea55d 262 free(name);
f6d20631
VB
263 *type = NONE;
264 return 0;
265}
266
267/* Set some port related settings (policy, location, power)
268 Input: name of the interface, policy/location/power setting to be modified
269 Output: nothing
270*/
324d73a3 271static ssize_t
f6d20631 272client_handle_set_port(struct lldpd *cfg, enum hmsg_type *type,
4e90a9e0 273 void *input, int input_len, void **output, int *subscribed)
f6d20631
VB
274{
275 int ret = 0;
5fd6695c
VB
276 struct lldpd_port_set *set = NULL;
277 struct lldpd_hardware *hardware = NULL;
2a836f02 278#ifdef ENABLE_LLDPMED
5fd6695c 279 struct lldpd_med_loc *loc = NULL;
2a836f02 280#endif
a552a72e 281
985a4cb5 282 if (lldpd_port_set_unserialize(input, input_len, &set) <= 0) {
f6d20631
VB
283 *type = NONE;
284 return 0;
a552a72e 285 }
f6d20631 286 if (!set->ifname) {
6f8925be 287 log_warnx("rpc", "no interface provided");
f6d20631
VB
288 goto set_port_finished;
289 }
290
291 /* Search the appropriate hardware */
6f8925be 292 log_debug("rpc", "client request change to port %s", set->ifname);
f6d20631
VB
293 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
294 if (!strcmp(hardware->h_ifname, set->ifname)) {
295 struct lldpd_port *port = &hardware->h_lport;
8e46010c
AA
296 if (set->local_id) {
297 log_debug("rpc", "requested change to Port ID");
298 free(port->p_id);
299 port->p_id = strdup(set->local_id);
300 port->p_id_len = strlen(set->local_id);
301 port->p_id_subtype = LLDP_PORTID_SUBTYPE_LOCAL;
302 }
c267d0f2
AA
303 if (set->local_descr) {
304 log_debug("rpc", "requested change to Port Description");
305 free(port->p_descr);
306 port->p_descr = strdup(set->local_descr);
307 }
740593ff 308#ifdef ENABLE_LLDPMED
f6d20631 309 if (set->med_policy && set->med_policy->type > 0) {
6f8925be 310 log_debug("rpc", "requested change to MED policy");
4b292b55 311 if (set->med_policy->type > LLDP_MED_APPTYPE_LAST) {
6f8925be 312 log_warnx("rpc", "invalid policy provided: %d",
f6d20631
VB
313 set->med_policy->type);
314 goto set_port_finished;
315 }
316 memcpy(&port->p_med_policy[set->med_policy->type - 1],
317 set->med_policy, sizeof(struct lldpd_med_policy));
4b292b55 318 port->p_med_cap_enabled |= LLDP_MED_CAP_POLICY;
f6d20631
VB
319 }
320 if (set->med_location && set->med_location->format > 0) {
4b292b55 321 char *newdata = NULL;
6f8925be 322 log_debug("rpc", "requested change to MED location");
4b292b55 323 if (set->med_location->format > LLDP_MED_LOCFORMAT_LAST) {
6f8925be 324 log_warnx("rpc", "invalid location format provided: %d",
f6d20631
VB
325 set->med_location->format);
326 goto set_port_finished;
327 }
5fd6695c 328 loc = \
f6d20631
VB
329 &port->p_med_location[set->med_location->format - 1];
330 free(loc->data);
331 memcpy(loc, set->med_location, sizeof(struct lldpd_med_loc));
4b292b55
VB
332 if (!loc->data || !(newdata = malloc(loc->data_len))) loc->data_len = 0;
333 if (newdata) memcpy(newdata, loc->data, loc->data_len);
334 loc->data = newdata;
335 port->p_med_cap_enabled |= LLDP_MED_CAP_LOCATION;
f6d20631
VB
336 }
337 if (set->med_power) {
6f8925be 338 log_debug("rpc", "requested change to MED power");
f6d20631
VB
339 memcpy(&port->p_med_power, set->med_power,
340 sizeof(struct lldpd_med_power));
341 switch (set->med_power->devicetype) {
4b292b55
VB
342 case LLDP_MED_POW_TYPE_PD:
343 port->p_med_cap_enabled |= LLDP_MED_CAP_MDI_PD;
344 port->p_med_cap_enabled &= ~LLDP_MED_CAP_MDI_PSE;
f6d20631 345 break;
4b292b55
VB
346 case LLDP_MED_POW_TYPE_PSE:
347 port->p_med_cap_enabled |= LLDP_MED_CAP_MDI_PSE;
348 port->p_med_cap_enabled &= ~LLDP_MED_CAP_MDI_PD;
f6d20631
VB
349 break;
350 }
351 }
42ee7382
VB
352#endif
353#ifdef ENABLE_DOT3
6f8925be
VB
354 if (set->dot3_power) {
355 log_debug("rpc", "requested change to Dot3 power");
f6d20631
VB
356 memcpy(&port->p_power, set->dot3_power,
357 sizeof(struct lldpd_dot3_power));
6f8925be 358 }
740593ff 359#endif
f6d20631
VB
360 ret = 1;
361 break;
362 }
363
364 if (ret == 0)
6f8925be 365 log_warn("rpc", "no interface %s found", set->ifname);
bbd094f4
VB
366 else
367 levent_update_now(cfg);
f6d20631
VB
368
369set_port_finished:
370 if (!ret) *type = NONE;
371 free(set->ifname);
8e46010c 372 free(set->local_id);
c267d0f2 373 free(set->local_descr);
4b292b55 374#ifdef ENABLE_LLDPMED
f6d20631
VB
375 free(set->med_policy);
376 if (set->med_location) free(set->med_location->data);
377 free(set->med_location);
378 free(set->med_power);
84853b92 379#endif
f6d20631
VB
380#ifdef ENABLE_DOT3
381 free(set->dot3_power);
382#endif
383 return 0;
384}
385
4e90a9e0 386/* Register subscribtion to neighbor changes */
324d73a3 387static ssize_t
4e90a9e0
VB
388client_handle_subscribe(struct lldpd *cfg, enum hmsg_type *type,
389 void *input, int input_len, void **output, int *subscribed)
390{
6f8925be 391 log_debug("rpc", "client subscribe to changes");
4e90a9e0
VB
392 *subscribed = 1;
393 return 0;
394}
395
396struct client_handle {
397 enum hmsg_type type;
bdfe4193 398 const char *name;
324d73a3 399 ssize_t (*handle)(struct lldpd*, enum hmsg_type *,
4e90a9e0
VB
400 void *, int, void **, int *);
401};
402
f6d20631 403static struct client_handle client_handles[] = {
bdfe4193
VB
404 { NONE, "None", client_handle_none },
405 { GET_CONFIG, "Get configuration", client_handle_get_configuration },
406 { SET_CONFIG, "Set configuration", client_handle_set_configuration },
407 { GET_INTERFACES, "Get interfaces", client_handle_get_interfaces },
408 { GET_INTERFACE, "Get interface", client_handle_get_interface },
409 { SET_PORT, "Set port", client_handle_set_port },
410 { SUBSCRIBE, "Subscribe", client_handle_subscribe },
4e90a9e0 411 { 0, NULL } };
f6d20631
VB
412
413int
e0478a46
VB
414client_handle_client(struct lldpd *cfg,
415 ssize_t(*send)(void *, int, void *, size_t),
416 void *out,
4e90a9e0
VB
417 enum hmsg_type type, void *buffer, size_t n,
418 int *subscribed)
f6d20631
VB
419{
420 struct client_handle *ch;
324d73a3 421 void *answer; ssize_t len, sent;
6f8925be
VB
422
423 log_debug("rpc", "handle client request");
f6d20631
VB
424 for (ch = client_handles; ch->handle != NULL; ch++) {
425 if (ch->type == type) {
bdfe4193 426 TRACE(LLDPD_CLIENT_REQUEST(ch->name));
281a5cd4 427 answer = NULL;
4e90a9e0
VB
428 len = ch->handle(cfg, &type, buffer, n, &answer,
429 subscribed);
e0478a46 430 sent = send(out, type, answer, len);
f6d20631
VB
431 free(answer);
432 return sent;
a552a72e
VB
433 }
434 }
e0478a46 435
6f8925be 436 log_warnx("rpc", "unknown message request (%d) received",
f6d20631
VB
437 type);
438 return -1;
a552a72e 439}