1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include "lldpd.h"
19 #include "trace.h"
20
21 static ssize_t
client_handle_none(struct lldpd * cfg,enum hmsg_type * type,void * input,int input_len,void ** output,int * subscribed)22 client_handle_none(struct lldpd *cfg, enum hmsg_type *type,
23 void *input, int input_len, void **output, int *subscribed)
24 {
25 log_info("rpc", "received noop request from client");
26 *type = NONE;
27 return 0;
28 }
29
30 /* Return the global configuration */
31 static ssize_t
client_handle_get_configuration(struct lldpd * cfg,enum hmsg_type * type,void * input,int input_len,void ** output,int * subscribed)32 client_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;
36 log_debug("rpc", "client requested configuration");
37 output_len = lldpd_config_serialize(&cfg->g_config, output);
38 if (output_len <= 0) {
39 output_len = 0;
40 *type = NONE;
41 }
42 return output_len;
43 }
44
45 static char*
xstrdup(const char * str)46 xstrdup(const char *str)
47 {
48 if (!str) return NULL;
49 return strdup(str);
50 }
51
52 /* Change the global configuration */
53 static ssize_t
client_handle_set_configuration(struct lldpd * cfg,enum hmsg_type * type,void * input,int input_len,void ** output,int * subscribed)54 client_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
59 log_debug("rpc", "client request a change in configuration");
60 /* Get the proposed configuration. */
61 if (lldpd_config_unserialize(input, input_len, &config) <= 0) {
62 *type = NONE;
63 return 0;
64 }
65
66 #define CHANGED(w) (config->w != cfg->g_config.w)
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))))
69
70 /* What needs to be done? Transmit delay? */
71 if (CHANGED(c_tx_interval) && config->c_tx_interval != 0) {
72 if (config->c_tx_interval < 0) {
73 log_debug("rpc", "client asked for immediate retransmission");
74 } else {
75 log_debug("rpc", "client change transmit interval to %d ms",
76 config->c_tx_interval);
77 cfg->g_config.c_tx_interval = config->c_tx_interval;
78 cfg->g_config.c_ttl = cfg->g_config.c_tx_interval *
79 cfg->g_config.c_tx_hold;
80 cfg->g_config.c_ttl = (cfg->g_config.c_ttl + 999) / 1000;
81 }
82 levent_send_now(cfg);
83 }
84 if (CHANGED(c_tx_hold) && config->c_tx_hold > 0) {
85 log_debug("rpc", "client change transmit hold to %d",
86 config->c_tx_hold);
87 cfg->g_config.c_tx_hold = config->c_tx_hold;
88 cfg->g_config.c_ttl = cfg->g_config.c_tx_interval *
89 cfg->g_config.c_tx_hold;
90 cfg->g_config.c_ttl = (cfg->g_config.c_ttl + 999) / 1000;
91 }
92 if (CHANGED(c_max_neighbors) && config->c_max_neighbors > 0) {
93 log_debug("rpc", "client change maximum neighbors to %d",
94 config->c_max_neighbors);
95 cfg->g_config.c_max_neighbors = config->c_max_neighbors;
96 }
97 if (CHANGED(c_lldp_portid_type) &&
98 config->c_lldp_portid_type > LLDP_PORTID_SUBTYPE_UNKNOWN &&
99 config->c_lldp_portid_type <= LLDP_PORTID_SUBTYPE_MAX) {
100 log_debug("rpc", "change lldp portid tlv subtype to %d",
101 config->c_lldp_portid_type);
102 cfg->g_config.c_lldp_portid_type = config->c_lldp_portid_type;
103 levent_update_now(cfg);
104 }
105 if (CHANGED(c_lldp_agent_type) &&
106 config->c_lldp_agent_type > LLDP_AGENT_TYPE_UNKNOWN &&
107 config->c_lldp_agent_type <= LLDP_AGENT_TYPE_MAX) {
108 log_debug("rpc", "change lldp agent type to %d",
109 config->c_lldp_agent_type);
110 cfg->g_config.c_lldp_agent_type = config->c_lldp_agent_type;
111 levent_update_now(cfg);
112 }
113 /* Pause/resume */
114 if (CHANGED(c_paused)) {
115 log_debug("rpc", "client asked to %s lldpd",
116 config->c_paused?"pause":"resume");
117 cfg->g_config.c_paused = config->c_paused;
118 levent_send_now(cfg);
119 }
120
121 #ifdef ENABLE_LLDPMED
122 if (CHANGED(c_enable_fast_start)) {
123 cfg->g_config.c_enable_fast_start = config->c_enable_fast_start;
124 log_debug("rpc", "client asked to %s fast start",
125 cfg->g_config.c_enable_fast_start?"enable":"disable");
126 }
127 if (CHANGED(c_tx_fast_interval) &&
128 config->c_tx_fast_interval > 0) {
129 log_debug("rpc", "change fast interval to %d", config->c_tx_fast_interval);
130 cfg->g_config.c_tx_fast_interval = config->c_tx_fast_interval;
131 }
132 #endif
133 if (CHANGED_STR(c_iface_pattern)) {
134 log_debug("rpc", "change interface pattern to %s",
135 config->c_iface_pattern?config->c_iface_pattern:"(NULL)");
136 free(cfg->g_config.c_iface_pattern);
137 cfg->g_config.c_iface_pattern = xstrdup(config->c_iface_pattern);
138 levent_update_now(cfg);
139 }
140 if (CHANGED_STR(c_perm_ifaces)) {
141 log_debug("rpc", "change permanent interface pattern to %s",
142 config->c_perm_ifaces?config->c_perm_ifaces:"(NULL)");
143 free(cfg->g_config.c_perm_ifaces);
144 cfg->g_config.c_perm_ifaces = xstrdup(config->c_perm_ifaces);
145 levent_update_now(cfg);
146 }
147 if (CHANGED_STR(c_mgmt_pattern)) {
148 log_debug("rpc", "change management pattern to %s",
149 config->c_mgmt_pattern?config->c_mgmt_pattern:"(NULL)");
150 free(cfg->g_config.c_mgmt_pattern);
151 cfg->g_config.c_mgmt_pattern = xstrdup(config->c_mgmt_pattern);
152 levent_update_now(cfg);
153 }
154 if (CHANGED_STR(c_cid_string)) {
155 log_debug("rpc", "change chassis ID string to %s",
156 config->c_cid_string?config->c_cid_string:"(NULL)");
157 free(cfg->g_config.c_cid_string);
158 cfg->g_config.c_cid_string = xstrdup(config->c_cid_string);
159 free(LOCAL_CHASSIS(cfg)->c_id);
160 LOCAL_CHASSIS(cfg)->c_id = NULL;
161 lldpd_update_localchassis(cfg);
162 levent_update_now(cfg);
163 }
164 if (CHANGED_STR(c_description)) {
165 log_debug("rpc", "change chassis description to %s",
166 config->c_description?config->c_description:"(NULL)");
167 free(cfg->g_config.c_description);
168 cfg->g_config.c_description = xstrdup(config->c_description);
169 lldpd_update_localchassis(cfg);
170 levent_update_now(cfg);
171 }
172 if (CHANGED_STR(c_platform)) {
173 log_debug("rpc", "change platform description to %s",
174 config->c_platform?config->c_platform:"(NULL)");
175 free(cfg->g_config.c_platform);
176 cfg->g_config.c_platform = xstrdup(config->c_platform);
177 lldpd_update_localchassis(cfg);
178 levent_update_now(cfg);
179 }
180 if (CHANGED_STR(c_hostname)) {
181 log_debug("rpc", "change system name to %s",
182 config->c_hostname?config->c_hostname:"(NULL)");
183 free(cfg->g_config.c_hostname);
184 cfg->g_config.c_hostname = xstrdup(config->c_hostname);
185 lldpd_update_localchassis(cfg);
186 levent_update_now(cfg);
187 }
188 if (CHANGED(c_set_ifdescr)) {
189 log_debug("rpc", "%s setting of interface description based on discovered neighbors",
190 config->c_set_ifdescr?"enable":"disable");
191 cfg->g_config.c_set_ifdescr = config->c_set_ifdescr;
192 levent_update_now(cfg);
193 }
194 if (CHANGED(c_promisc)) {
195 log_debug("rpc", "%s promiscuous mode on managed interfaces",
196 config->c_promisc?"enable":"disable");
197 cfg->g_config.c_promisc = config->c_promisc;
198 levent_update_now(cfg);
199 }
200 if (CHANGED(c_cap_advertise)) {
201 log_debug("rpc", "%s chassis capabilities advertisement",
202 config->c_cap_advertise?"enable":"disable");
203 cfg->g_config.c_cap_advertise = config->c_cap_advertise;
204 levent_update_now(cfg);
205 }
206 if (CHANGED(c_mgmt_advertise)) {
207 log_debug("rpc", "%s management addresses advertisement",
208 config->c_mgmt_advertise?"enable":"disable");
209 cfg->g_config.c_mgmt_advertise = config->c_mgmt_advertise;
210 levent_update_now(cfg);
211 }
212 if (CHANGED(c_bond_slave_src_mac_type)) {
213 if (config->c_bond_slave_src_mac_type >
214 LLDP_BOND_SLAVE_SRC_MAC_TYPE_UNKNOWN &&
215 config->c_bond_slave_src_mac_type <=
216 LLDP_BOND_SLAVE_SRC_MAC_TYPE_MAX) {
217 log_debug("rpc", "change bond src mac type to %d",
218 config->c_bond_slave_src_mac_type);
219 cfg->g_config.c_bond_slave_src_mac_type =
220 config->c_bond_slave_src_mac_type;
221 } else {
222 log_info("rpc", "Invalid bond slave src mac type: %d\n",
223 config->c_bond_slave_src_mac_type);
224 }
225 }
226
227 lldpd_config_cleanup(config);
228 free(config);
229
230 return 0;
231 }
232
233 /* Return the list of interfaces.
234 Input: nothing.
235 Output: list of interface names (lldpd_interface_list)
236 */
237 static ssize_t
client_handle_get_interfaces(struct lldpd * cfg,enum hmsg_type * type,void * input,int input_len,void ** output,int * subscribed)238 client_handle_get_interfaces(struct lldpd *cfg, enum hmsg_type *type,
239 void *input, int input_len, void **output, int *subscribed)
240 {
241 struct lldpd_interface *iff, *iff_next;
242 struct lldpd_hardware *hardware;
243 ssize_t output_len;
244
245 /* Build the list of interfaces */
246 struct lldpd_interface_list ifs;
247
248 log_debug("rpc", "client request the list of interfaces");
249 TAILQ_INIT(&ifs);
250 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
251 if ((iff = (struct lldpd_interface*)malloc(sizeof(
252 struct lldpd_interface))) == NULL)
253 fatal("rpc", NULL);
254 iff->name = hardware->h_ifname;
255 TAILQ_INSERT_TAIL(&ifs, iff, next);
256 }
257
258 output_len = lldpd_interface_list_serialize(&ifs, output);
259 if (output_len <= 0) {
260 output_len = 0;
261 *type = NONE;
262 }
263
264 /* Free the temporary list */
265 for (iff = TAILQ_FIRST(&ifs);
266 iff != NULL;
267 iff = iff_next) {
268 iff_next = TAILQ_NEXT(iff, next);
269 TAILQ_REMOVE(&ifs, iff, next);
270 free(iff);
271 }
272
273 return output_len;
274 }
275
276 /* Return the local chassis.
277 Input: nothing.
278 Output: local chassis (lldpd_chassis)
279 */
280 static ssize_t
client_handle_get_local_chassis(struct lldpd * cfg,enum hmsg_type * type,void * input,int input_len,void ** output,int * subscribed)281 client_handle_get_local_chassis(struct lldpd *cfg, enum hmsg_type *type,
282 void *input, int input_len, void **output, int *subscribed)
283 {
284 struct lldpd_chassis *chassis = LOCAL_CHASSIS(cfg);
285 ssize_t output_len;
286
287 log_debug("rpc", "client request the local chassis");
288 output_len = lldpd_chassis_serialize(chassis, output);
289 if (output_len <= 0) {
290 output_len = 0;
291 *type = NONE;
292 }
293
294 return output_len;
295 }
296
297 /* Return all available information related to an interface
298 Input: name of the interface (serialized)
299 Output: Information about the interface (lldpd_hardware)
300 */
301 static ssize_t
client_handle_get_interface(struct lldpd * cfg,enum hmsg_type * type,void * input,int input_len,void ** output,int * subscribed)302 client_handle_get_interface(struct lldpd *cfg, enum hmsg_type *type,
303 void *input, int input_len, void **output, int *subscribed)
304 {
305 char *name;
306 struct lldpd_hardware *hardware;
307 void *p;
308
309 /* Get name of the interface */
310 if (marshal_unserialize(string, input, input_len, &p) <= 0) {
311 *type = NONE;
312 return 0;
313 }
314 name = p;
315
316 /* Search appropriate hardware */
317 log_debug("rpc", "client request interface %s", name);
318 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
319 if (!strcmp(hardware->h_ifname, name)) {
320 ssize_t output_len = lldpd_hardware_serialize(hardware, output);
321 free(name);
322 if (output_len <= 0) {
323 *type = NONE;
324 return 0;
325 }
326 return output_len;
327 }
328
329 log_warnx("rpc", "no interface %s found", name);
330 free(name);
331 *type = NONE;
332 return 0;
333 }
334
335 /* Return all available information related to an interface
336 Input: name of the interface (serialized)
337 Output: Information about the interface (lldpd_hardware)
338 */
339 static ssize_t
client_handle_get_default_port(struct lldpd * cfg,enum hmsg_type * type,void * input,int input_len,void ** output,int * subscribed)340 client_handle_get_default_port(struct lldpd *cfg, enum hmsg_type *type,
341 void *input, int input_len, void **output, int *subscribed)
342 {
343 log_debug("rpc", "client request the default local port");
344 ssize_t output_len = lldpd_port_serialize(cfg->g_default_local_port, output);
345 if (output_len <= 0) {
346 *type = NONE;
347 return 0;
348 }
349 return output_len;
350 }
351
352 static int
_client_handle_set_port(struct lldpd * cfg,struct lldpd_port * port,struct lldpd_port_set * set)353 _client_handle_set_port(struct lldpd *cfg,
354 struct lldpd_port *port, struct lldpd_port_set *set)
355 {
356 #ifdef ENABLE_LLDPMED
357 struct lldpd_med_loc *loc = NULL;
358 #endif
359 if (set->local_id) {
360 log_debug("rpc", "requested change to Port ID");
361 free(port->p_id);
362 port->p_id = strdup(set->local_id);
363 port->p_id_len = strlen(set->local_id);
364 port->p_id_subtype = LLDP_PORTID_SUBTYPE_LOCAL;
365 port->p_descr_force = 0;
366 }
367 if (set->local_descr) {
368 log_debug("rpc", "requested change to Port Description");
369 free(port->p_descr);
370 port->p_descr = strdup(set->local_descr);
371 port->p_descr_force = 1;
372 }
373 switch (set->rxtx) {
374 case LLDPD_RXTX_TXONLY:
375 log_debug("rpc", "requested TX only mode");
376 port->p_disable_rx = 1;
377 port->p_disable_tx = 0;
378 break;
379 case LLDPD_RXTX_RXONLY:
380 log_debug("rpc", "requested RX only mode");
381 port->p_disable_rx = 0;
382 port->p_disable_tx = 1;
383 break;
384 case LLDPD_RXTX_BOTH:
385 log_debug("rpc", "requested RX/TX mode");
386 port->p_disable_rx = port->p_disable_tx = 0;
387 break;
388 case LLDPD_RXTX_DISABLED:
389 log_debug("rpc", "requested disabled mode");
390 port->p_disable_rx = port->p_disable_tx = 1;
391 break;
392 }
393 if (set->vlan_tx_enabled >= -1) {
394 port->p_vlan_tx_enabled = set->vlan_tx_enabled;
395 port->p_vlan_tx_tag = set->vlan_tx_tag;
396 }
397 #ifdef ENABLE_LLDPMED
398 if (set->med_policy && set->med_policy->type > 0) {
399 log_debug("rpc", "requested change to MED policy");
400 if (set->med_policy->type > LLDP_MED_APPTYPE_LAST) {
401 log_warnx("rpc", "invalid policy provided: %d",
402 set->med_policy->type);
403 return -1;
404 }
405 memcpy(&port->p_med_policy[set->med_policy->type - 1],
406 set->med_policy, sizeof(struct lldpd_med_policy));
407 port->p_med_cap_enabled |= LLDP_MED_CAP_POLICY;
408 }
409 if (set->med_location && set->med_location->format > 0) {
410 char *newdata = NULL;
411 log_debug("rpc", "requested change to MED location");
412 if (set->med_location->format > LLDP_MED_LOCFORMAT_LAST) {
413 log_warnx("rpc", "invalid location format provided: %d",
414 set->med_location->format);
415 return -1;
416 }
417 loc = \
418 &port->p_med_location[set->med_location->format - 1];
419 free(loc->data);
420 memcpy(loc, set->med_location, sizeof(struct lldpd_med_loc));
421 if (!loc->data || !(newdata = malloc(loc->data_len))) loc->data_len = 0;
422 if (newdata) memcpy(newdata, loc->data, loc->data_len);
423 loc->data = newdata;
424 port->p_med_cap_enabled |= LLDP_MED_CAP_LOCATION;
425 }
426 if (set->med_power) {
427 log_debug("rpc", "requested change to MED power");
428 memcpy(&port->p_med_power, set->med_power,
429 sizeof(struct lldpd_med_power));
430 switch (set->med_power->devicetype) {
431 case LLDP_MED_POW_TYPE_PD:
432 port->p_med_cap_enabled |= LLDP_MED_CAP_MDI_PD;
433 port->p_med_cap_enabled &= ~LLDP_MED_CAP_MDI_PSE;
434 break;
435 case LLDP_MED_POW_TYPE_PSE:
436 port->p_med_cap_enabled |= LLDP_MED_CAP_MDI_PSE;
437 port->p_med_cap_enabled &= ~LLDP_MED_CAP_MDI_PD;
438 break;
439 }
440 }
441 #endif
442 #ifdef ENABLE_DOT3
443 if (set->dot3_power) {
444 log_debug("rpc", "requested change to Dot3 power");
445 memcpy(&port->p_power, set->dot3_power,
446 sizeof(struct lldpd_dot3_power));
447 }
448 #endif
449 #ifdef ENABLE_CUSTOM
450 if (set->custom_list_clear) {
451 log_debug("rpc", "requested custom TLVs clear");
452 lldpd_custom_list_cleanup(port);
453 } else {
454 if (set->custom) {
455 log_info("rpc", "custom TLV op %s oui %02x:%02x:%02x subtype %x",
456 (set->custom_tlv_op == CUSTOM_TLV_REMOVE)?"remove":
457 (set->custom_tlv_op == CUSTOM_TLV_ADD)?"add":
458 "replace",
459 set->custom->oui[0],
460 set->custom->oui[1],
461 set->custom->oui[2],
462 set->custom->subtype);
463 switch (set->custom_tlv_op) {
464 case CUSTOM_TLV_REMOVE:
465 lldpd_custom_tlv_cleanup(port, set->custom);
466 break;
467 case CUSTOM_TLV_ADD:
468 lldpd_custom_tlv_add(port, set->custom);
469 break;
470 case CUSTOM_TLV_REPLACE:
471 default:
472 lldpd_custom_tlv_cleanup(port, set->custom);
473 lldpd_custom_tlv_add(port, set->custom);
474 break;
475 }
476 }
477 }
478 #endif
479 return 0;
480 }
481
482 /* Set some port related settings (policy, location, power)
483 Input: name of the interface, policy/location/power setting to be modified
484 Output: nothing
485 */
486 static ssize_t
client_handle_set_port(struct lldpd * cfg,enum hmsg_type * type,void * input,int input_len,void ** output,int * subscribed)487 client_handle_set_port(struct lldpd *cfg, enum hmsg_type *type,
488 void *input, int input_len, void **output, int *subscribed)
489 {
490 int ret = 0;
491 struct lldpd_port_set *set = NULL;
492 struct lldpd_hardware *hardware = NULL;
493
494 if (lldpd_port_set_unserialize(input, input_len, &set) <= 0) {
495 *type = NONE;
496 return 0;
497 }
498 if (!set->ifname) {
499 log_warnx("rpc", "no interface provided");
500 goto set_port_finished;
501 }
502
503 /* Search the appropriate hardware */
504 if (strlen(set->ifname) == 0) {
505 log_debug("rpc", "client request change to default port");
506 if (_client_handle_set_port(cfg, cfg->g_default_local_port, set) == -1)
507 goto set_port_finished;
508 ret = 1;
509 } else {
510 log_debug("rpc", "client request change to port %s", set->ifname);
511 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
512 if (!strcmp(hardware->h_ifname, set->ifname)) {
513 struct lldpd_port *port = &hardware->h_lport;
514 if (_client_handle_set_port(cfg, port, set) == -1)
515 goto set_port_finished;
516 ret = 1;
517 break;
518 }
519 }
520 }
521
522 if (ret == 0)
523 log_warn("rpc", "no interface %s found", set->ifname);
524 else
525 levent_update_now(cfg);
526
527 set_port_finished:
528 if (!ret) *type = NONE;
529 free(set->ifname);
530 free(set->local_id);
531 free(set->local_descr);
532 #ifdef ENABLE_LLDPMED
533 free(set->med_policy);
534 if (set->med_location) free(set->med_location->data);
535 free(set->med_location);
536 free(set->med_power);
537 #endif
538 #ifdef ENABLE_DOT3
539 free(set->dot3_power);
540 #endif
541 #ifdef ENABLE_CUSTOM
542 if (set->custom) {
543 free(set->custom->oui_info);
544 free(set->custom);
545 }
546 #endif
547 free(set);
548 return 0;
549 }
550
551 /* Register subscribtion to neighbor changes */
552 static ssize_t
client_handle_subscribe(struct lldpd * cfg,enum hmsg_type * type,void * input,int input_len,void ** output,int * subscribed)553 client_handle_subscribe(struct lldpd *cfg, enum hmsg_type *type,
554 void *input, int input_len, void **output, int *subscribed)
555 {
556 log_debug("rpc", "client subscribe to changes");
557 *subscribed = 1;
558 return 0;
559 }
560
561 struct client_handle {
562 enum hmsg_type type;
563 const char *name;
564 ssize_t (*handle)(struct lldpd*, enum hmsg_type *,
565 void *, int, void **, int *);
566 };
567
568 static struct client_handle client_handles[] = {
569 { NONE, "None", client_handle_none },
570 { GET_CONFIG, "Get configuration", client_handle_get_configuration },
571 { SET_CONFIG, "Set configuration", client_handle_set_configuration },
572 { GET_INTERFACES, "Get interfaces", client_handle_get_interfaces },
573 { GET_INTERFACE, "Get interface", client_handle_get_interface },
574 { GET_DEFAULT_PORT, "Get default port", client_handle_get_default_port },
575 { GET_CHASSIS, "Get local chassis", client_handle_get_local_chassis },
576 { SET_PORT, "Set port", client_handle_set_port },
577 { SUBSCRIBE, "Subscribe", client_handle_subscribe },
578 { 0, NULL } };
579
580 int
client_handle_client(struct lldpd * cfg,ssize_t (* send)(void *,int,void *,size_t),void * out,enum hmsg_type type,void * buffer,size_t n,int * subscribed)581 client_handle_client(struct lldpd *cfg,
582 ssize_t(*send)(void *, int, void *, size_t),
583 void *out,
584 enum hmsg_type type, void *buffer, size_t n,
585 int *subscribed)
586 {
587 struct client_handle *ch;
588 void *answer; ssize_t len, sent;
589
590 log_debug("rpc", "handle client request");
591 for (ch = client_handles; ch->handle != NULL; ch++) {
592 if (ch->type == type) {
593 TRACE(LLDPD_CLIENT_REQUEST(ch->name));
594 answer = NULL;
595 len = ch->handle(cfg, &type, buffer, n, &answer,
596 subscribed);
597 sent = send(out, type, answer, len);
598 free(answer);
599 return sent;
600 }
601 }
602
603 log_warnx("rpc", "unknown message request (%d) received",
604 type);
605 return -1;
606 }
607