Coverage Report

Created: 2026-03-14 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/lldpd/src/daemon/client.c
Line
Count
Source
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
#include <sys/param.h>
22
#include <sys/utsname.h>
23
24
static ssize_t
25
client_handle_none(struct lldpd *cfg, enum hmsg_type *type, void *input, int input_len,
26
    void **output, int *subscribed)
27
0
{
28
0
  log_info("rpc", "received noop request from client");
29
0
  *type = NONE;
30
0
  return 0;
31
0
}
32
33
/* Return the global configuration */
34
static ssize_t
35
client_handle_get_configuration(struct lldpd *cfg, enum hmsg_type *type, void *input,
36
    int input_len, void **output, int *subscribed)
37
0
{
38
0
  ssize_t output_len;
39
0
  log_debug("rpc", "client requested configuration");
40
0
  output_len = lldpd_config_serialize(&cfg->g_config, output);
41
0
  if (output_len <= 0) {
42
0
    output_len = 0;
43
0
    *type = NONE;
44
0
  }
45
0
  return output_len;
46
0
}
47
48
static char *
49
xstrdup(const char *str)
50
0
{
51
0
  if (!str) return NULL;
52
0
  return strdup(str);
53
0
}
54
55
/* Change the global configuration */
56
static ssize_t
57
client_handle_set_configuration(struct lldpd *cfg, enum hmsg_type *type, void *input,
58
    int input_len, void **output, int *subscribed)
59
0
{
60
0
  struct lldpd_config *config;
61
62
0
  log_debug("rpc", "client request a change in configuration");
63
  /* Get the proposed configuration. */
64
0
  if (lldpd_config_unserialize(input, input_len, &config) <= 0) {
65
0
    *type = NONE;
66
0
    return 0;
67
0
  }
68
69
0
#define CHANGED(w) (config->w != cfg->g_config.w)
70
0
#define CHANGED_STR(w)               \
71
0
  (!(config->w == cfg->g_config.w || \
72
0
      (config->w && cfg->g_config.w && !strcmp(config->w, cfg->g_config.w))))
73
74
  /* What needs to be done? Transmit delay? */
75
0
  if (CHANGED(c_tx_interval) && config->c_tx_interval != 0) {
76
0
    if (config->c_tx_interval < 0) {
77
0
      log_debug("rpc", "client asked for immediate retransmission");
78
0
    } else if (config->c_tx_interval <= 3600 * 1000) {
79
0
      log_debug("rpc", "client change transmit interval to %d ms",
80
0
          config->c_tx_interval);
81
0
      cfg->g_config.c_tx_interval = config->c_tx_interval;
82
0
      cfg->g_config.c_ttl =
83
0
          cfg->g_config.c_tx_interval * cfg->g_config.c_tx_hold;
84
0
      cfg->g_config.c_ttl =
85
0
          MIN((cfg->g_config.c_ttl + 999) / 1000, 65535);
86
0
    }
87
0
    levent_send_now(cfg);
88
0
  }
89
0
  if (CHANGED(c_tx_hold) && config->c_tx_hold > 0 && config->c_tx_hold <= 100) {
90
0
    log_debug("rpc", "client change transmit hold to %d",
91
0
        config->c_tx_hold);
92
0
    cfg->g_config.c_tx_hold = config->c_tx_hold;
93
0
    cfg->g_config.c_ttl =
94
0
        cfg->g_config.c_tx_interval * cfg->g_config.c_tx_hold;
95
0
    cfg->g_config.c_ttl = MIN((cfg->g_config.c_ttl + 999) / 1000, 65535);
96
0
  }
97
0
  if (CHANGED(c_max_neighbors) && config->c_max_neighbors > 0) {
98
0
    log_debug("rpc", "client change maximum neighbors to %d",
99
0
        config->c_max_neighbors);
100
0
    cfg->g_config.c_max_neighbors = config->c_max_neighbors;
101
0
  }
102
0
  if (CHANGED(c_lldp_portid_type) &&
103
0
      config->c_lldp_portid_type > LLDP_PORTID_SUBTYPE_UNKNOWN &&
104
0
      config->c_lldp_portid_type <= LLDP_PORTID_SUBTYPE_MAX) {
105
0
    log_debug("rpc", "change lldp portid tlv subtype to %d",
106
0
        config->c_lldp_portid_type);
107
0
    cfg->g_config.c_lldp_portid_type = config->c_lldp_portid_type;
108
0
    levent_update_now(cfg);
109
0
  }
110
0
  if (CHANGED(c_lldp_agent_type) &&
111
0
      config->c_lldp_agent_type > LLDP_AGENT_TYPE_UNKNOWN &&
112
0
      config->c_lldp_agent_type <= LLDP_AGENT_TYPE_MAX) {
113
0
    log_debug("rpc", "change lldp agent type to %d",
114
0
        config->c_lldp_agent_type);
115
0
    cfg->g_config.c_lldp_agent_type = config->c_lldp_agent_type;
116
0
    levent_update_now(cfg);
117
0
  }
118
0
  if (CHANGED(c_lldp_portdescr_type) &&
119
0
      config->c_lldp_portdescr_type >= LLDP_PORTDESCR_SRC_AUTO &&
120
0
      config->c_lldp_portdescr_type <= LLDP_PORTDESCR_SRC_MAX) {
121
0
    log_debug("rpc", "change lldp port description source to %d",
122
0
        config->c_lldp_portdescr_type);
123
0
    cfg->g_config.c_lldp_portdescr_type = config->c_lldp_portdescr_type;
124
0
    levent_update_now(cfg);
125
0
  }
126
  /* Pause/resume */
127
0
  if (CHANGED(c_paused)) {
128
0
    log_debug("rpc", "client asked to %s lldpd",
129
0
        config->c_paused ? "pause" : "resume");
130
0
    cfg->g_config.c_paused = config->c_paused;
131
0
    levent_send_now(cfg);
132
0
  }
133
134
0
  if (CHANGED(c_enable_fast_start)) {
135
0
    cfg->g_config.c_enable_fast_start = config->c_enable_fast_start;
136
0
    log_debug("rpc", "client asked to %s fast start",
137
0
        cfg->g_config.c_enable_fast_start ? "enable" : "disable");
138
0
  }
139
0
  if (CHANGED(c_tx_fast_interval) && config->c_tx_fast_interval > 0) {
140
0
    log_debug("rpc", "change fast interval to %d",
141
0
        config->c_tx_fast_interval);
142
0
    cfg->g_config.c_tx_fast_interval = config->c_tx_fast_interval;
143
0
  }
144
0
  if (CHANGED_STR(c_iface_pattern)) {
145
0
    log_debug("rpc", "change interface pattern to %s",
146
0
        config->c_iface_pattern ? config->c_iface_pattern : "(NULL)");
147
0
    free(cfg->g_config.c_iface_pattern);
148
0
    cfg->g_config.c_iface_pattern = xstrdup(config->c_iface_pattern);
149
0
    levent_update_now(cfg);
150
0
  }
151
0
  if (CHANGED_STR(c_perm_ifaces)) {
152
0
    log_debug("rpc", "change permanent interface pattern to %s",
153
0
        config->c_perm_ifaces ? config->c_perm_ifaces : "(NULL)");
154
0
    free(cfg->g_config.c_perm_ifaces);
155
0
    cfg->g_config.c_perm_ifaces = xstrdup(config->c_perm_ifaces);
156
0
    levent_update_now(cfg);
157
0
  }
158
0
  if (CHANGED_STR(c_mgmt_pattern)) {
159
0
    log_debug("rpc", "change management pattern to %s",
160
0
        config->c_mgmt_pattern ? config->c_mgmt_pattern : "(NULL)");
161
0
    free(cfg->g_config.c_mgmt_pattern);
162
0
    cfg->g_config.c_mgmt_pattern = xstrdup(config->c_mgmt_pattern);
163
0
    levent_update_now(cfg);
164
0
  }
165
0
  if (CHANGED_STR(c_cid_string)) {
166
0
    log_debug("rpc", "change chassis ID string to %s",
167
0
        config->c_cid_string ? config->c_cid_string : "(NULL)");
168
0
    free(cfg->g_config.c_cid_string);
169
0
    cfg->g_config.c_cid_string = xstrdup(config->c_cid_string);
170
0
    free(LOCAL_CHASSIS(cfg)->c_id);
171
0
    LOCAL_CHASSIS(cfg)->c_id = NULL;
172
0
    lldpd_update_localchassis(cfg);
173
0
    levent_update_now(cfg);
174
0
  }
175
0
  if (CHANGED_STR(c_description)) {
176
0
    log_debug("rpc", "change chassis description to %s",
177
0
        config->c_description ? config->c_description : "(NULL)");
178
0
    free(cfg->g_config.c_description);
179
0
    cfg->g_config.c_description = xstrdup(config->c_description);
180
0
    lldpd_update_localchassis(cfg);
181
0
    levent_update_now(cfg);
182
0
  }
183
0
  if (CHANGED_STR(c_platform)) {
184
0
    log_debug("rpc", "change platform description to %s",
185
0
        config->c_platform ? config->c_platform : "(NULL)");
186
0
    free(cfg->g_config.c_platform);
187
0
    cfg->g_config.c_platform = xstrdup(config->c_platform);
188
0
    lldpd_update_localchassis(cfg);
189
0
    levent_update_now(cfg);
190
0
  }
191
0
  if (CHANGED_STR(c_hostname)) {
192
0
    log_debug("rpc", "change system name to %s",
193
0
        config->c_hostname ? config->c_hostname : "(NULL)");
194
0
    free(cfg->g_config.c_hostname);
195
0
    cfg->g_config.c_hostname = xstrdup(config->c_hostname);
196
0
    lldpd_update_localchassis(cfg);
197
0
    levent_update_now(cfg);
198
0
  }
199
0
  if (CHANGED(c_set_ifdescr)) {
200
0
    log_debug("rpc",
201
0
        "%s setting of interface description based on discovered neighbors",
202
0
        config->c_set_ifdescr ? "enable" : "disable");
203
0
    cfg->g_config.c_set_ifdescr = config->c_set_ifdescr;
204
0
    levent_update_now(cfg);
205
0
  }
206
0
  if (CHANGED(c_promisc)) {
207
0
    log_debug("rpc", "%s promiscuous mode on managed interfaces",
208
0
        config->c_promisc ? "enable" : "disable");
209
0
    cfg->g_config.c_promisc = config->c_promisc;
210
0
    levent_update_now(cfg);
211
0
  }
212
0
  if (CHANGED(c_cap_advertise)) {
213
0
    log_debug("rpc", "%s chassis capabilities advertisement",
214
0
        config->c_cap_advertise ? "enable" : "disable");
215
0
    cfg->g_config.c_cap_advertise = config->c_cap_advertise;
216
0
    levent_update_now(cfg);
217
0
  }
218
0
  if (CHANGED(c_cap_override)) {
219
0
    log_debug("rpc", "%s chassis capabilities override",
220
0
        config->c_cap_override ? "enable" : "disable");
221
0
    cfg->g_config.c_cap_override = config->c_cap_override;
222
0
    levent_update_now(cfg);
223
0
  }
224
0
  if (CHANGED(c_mgmt_advertise)) {
225
0
    log_debug("rpc", "%s management addresses advertisement",
226
0
        config->c_mgmt_advertise ? "enable" : "disable");
227
0
    cfg->g_config.c_mgmt_advertise = config->c_mgmt_advertise;
228
0
    levent_update_now(cfg);
229
0
  }
230
0
  if (CHANGED(c_bond_slave_src_mac_type)) {
231
0
    if (config->c_bond_slave_src_mac_type >
232
0
      LLDP_BOND_SLAVE_SRC_MAC_TYPE_UNKNOWN &&
233
0
        config->c_bond_slave_src_mac_type <=
234
0
      LLDP_BOND_SLAVE_SRC_MAC_TYPE_MAX) {
235
0
      log_debug("rpc", "change bond src mac type to %d",
236
0
          config->c_bond_slave_src_mac_type);
237
0
      cfg->g_config.c_bond_slave_src_mac_type =
238
0
          config->c_bond_slave_src_mac_type;
239
0
    } else {
240
0
      log_info("rpc", "Invalid bond slave src mac type: %d\n",
241
0
          config->c_bond_slave_src_mac_type);
242
0
    }
243
0
  }
244
245
0
  lldpd_config_cleanup(config);
246
0
  free(config);
247
248
0
  return 0;
249
0
}
250
251
/* Return the list of interfaces.
252
   Input:  nothing.
253
   Output: list of interface names (lldpd_interface_list)
254
*/
255
static ssize_t
256
client_handle_get_interfaces(struct lldpd *cfg, enum hmsg_type *type, void *input,
257
    int input_len, void **output, int *subscribed)
258
0
{
259
0
  struct lldpd_interface *iff, *iff_next;
260
0
  struct lldpd_hardware *hardware;
261
0
  ssize_t output_len;
262
263
  /* Build the list of interfaces */
264
0
  struct lldpd_interface_list ifs;
265
266
0
  log_debug("rpc", "client request the list of interfaces");
267
0
  TAILQ_INIT(&ifs);
268
0
  TAILQ_FOREACH (hardware, &cfg->g_hardware, h_entries) {
269
0
    if ((iff = (struct lldpd_interface *)malloc(
270
0
       sizeof(struct lldpd_interface))) == NULL)
271
0
      fatal("rpc", NULL);
272
0
    iff->name = hardware->h_ifname;
273
0
    iff->alias = hardware->h_ifalias;
274
0
    TAILQ_INSERT_TAIL(&ifs, iff, next);
275
0
  }
276
277
0
  output_len = lldpd_interface_list_serialize(&ifs, output);
278
0
  if (output_len <= 0) {
279
0
    output_len = 0;
280
0
    *type = NONE;
281
0
  }
282
283
  /* Free the temporary list */
284
0
  for (iff = TAILQ_FIRST(&ifs); iff != NULL; iff = iff_next) {
285
0
    iff_next = TAILQ_NEXT(iff, next);
286
0
    TAILQ_REMOVE(&ifs, iff, next);
287
0
    free(iff);
288
0
  }
289
290
0
  return output_len;
291
0
}
292
293
/**
294
 * Set local chassis info
295
 * Input: chassis object
296
 * Output: updated chassis object
297
 */
298
static ssize_t
299
client_handle_set_local_chassis(struct lldpd *cfg, enum hmsg_type *type, void *input,
300
    int input_len, void **output, int *subscribed)
301
0
{
302
0
  struct lldpd_chassis *chassis = NULL;
303
0
  struct lldpd_chassis *local_chassis = NULL;
304
0
#ifdef ENABLE_LLDPMED
305
0
  struct utsname un;
306
0
#endif
307
308
0
  log_debug("rpc", "client request a change in chassis configuration");
309
0
  if (lldpd_chassis_unserialize(input, input_len, &chassis) <= 0) {
310
0
    *type = NONE;
311
0
    return 0;
312
0
  }
313
314
0
  local_chassis = LOCAL_CHASSIS(cfg);
315
316
0
#ifdef ENABLE_LLDPMED
317
0
  free(local_chassis->c_med_hw);
318
0
  local_chassis->c_med_hw =
319
0
      (!chassis->c_med_hw) ? dmi_hw() : strdup(chassis->c_med_hw);
320
321
  // Follows lldpd.c - only set sw if advertising is enabled
322
0
  if (cfg->g_config.c_advertise_version) {
323
0
    free(local_chassis->c_med_sw);
324
325
0
    if (!chassis->c_med_sw) {
326
0
      if (uname(&un) < 0) {
327
0
        log_warn("rpc",
328
0
            "Could not get default uname. Will continue anyway.");
329
0
        local_chassis->c_med_sw = NULL;
330
0
      } else {
331
0
        local_chassis->c_med_sw = strdup(un.release);
332
0
      }
333
0
    } else {
334
0
      local_chassis->c_med_sw = strdup(chassis->c_med_sw);
335
0
    }
336
0
  }
337
338
0
  free(local_chassis->c_med_fw);
339
0
  local_chassis->c_med_fw =
340
0
      (!chassis->c_med_fw) ? dmi_fw() : strdup(chassis->c_med_fw);
341
342
0
  free(local_chassis->c_med_sn);
343
0
  local_chassis->c_med_sn =
344
0
      (!chassis->c_med_sn) ? dmi_sn() : strdup(chassis->c_med_sn);
345
346
0
  free(local_chassis->c_med_manuf);
347
0
  local_chassis->c_med_manuf =
348
0
      (!chassis->c_med_manuf) ? dmi_manuf() : strdup(chassis->c_med_manuf);
349
350
0
  free(local_chassis->c_med_model);
351
0
  local_chassis->c_med_model =
352
0
      (!chassis->c_med_model) ? dmi_model() : strdup(chassis->c_med_model);
353
354
0
  free(local_chassis->c_med_asset);
355
0
  local_chassis->c_med_asset =
356
0
      (!chassis->c_med_asset) ? dmi_asset() : strdup(chassis->c_med_asset);
357
0
#endif
358
359
0
  if (chassis->c_cap_enabled != local_chassis->c_cap_enabled) {
360
0
    local_chassis->c_cap_enabled = chassis->c_cap_enabled;
361
0
    log_debug("rpc", "change capabilities enabled to: %d",
362
0
        local_chassis->c_cap_enabled);
363
0
  }
364
365
0
#ifdef ENABLE_LLDPMED
366
0
  log_debug("rpc", "change hardware-revision to: %s", local_chassis->c_med_hw);
367
0
  log_debug("rpc", "change software-revision to: %s", local_chassis->c_med_sw);
368
0
  log_debug("rpc", "change firmware-revision to: %s", local_chassis->c_med_fw);
369
0
  log_debug("rpc", "change serial-number to: %s", local_chassis->c_med_sn);
370
0
  log_debug("rpc", "change manufacturer to: %s", local_chassis->c_med_manuf);
371
0
  log_debug("rpc", "change model to: %s", local_chassis->c_med_model);
372
0
  log_debug("rpc", "change asset to: %s", local_chassis->c_med_asset);
373
0
#endif
374
375
0
  lldpd_chassis_cleanup(chassis, 1);
376
377
0
  ssize_t output_len = lldpd_chassis_serialize(local_chassis, output);
378
0
  if (output_len <= 0) {
379
0
    *type = NONE;
380
0
    return 0;
381
0
  }
382
383
0
  return output_len;
384
0
}
385
386
/* Return the local chassis.
387
   Input:  nothing.
388
   Output: local chassis (lldpd_chassis)
389
*/
390
static ssize_t
391
client_handle_get_local_chassis(struct lldpd *cfg, enum hmsg_type *type, void *input,
392
    int input_len, void **output, int *subscribed)
393
0
{
394
0
  struct lldpd_chassis *chassis = LOCAL_CHASSIS(cfg);
395
0
  ssize_t output_len;
396
397
0
  log_debug("rpc", "client request the local chassis");
398
0
  output_len = lldpd_chassis_serialize(chassis, output);
399
0
  if (output_len <= 0) {
400
0
    output_len = 0;
401
0
    *type = NONE;
402
0
  }
403
404
0
  return output_len;
405
0
}
406
407
/* Return all available information related to an interface
408
   Input:  name of the interface (serialized)
409
   Output: Information about the interface (lldpd_hardware)
410
*/
411
static ssize_t
412
client_handle_get_interface(struct lldpd *cfg, enum hmsg_type *type, void *input,
413
    int input_len, void **output, int *subscribed)
414
0
{
415
0
  char *name;
416
0
  struct lldpd_hardware *hardware;
417
0
  void *p;
418
419
  /* Get name of the interface */
420
0
  if (marshal_unserialize(string, input, input_len, &p) <= 0) {
421
0
    *type = NONE;
422
0
    return 0;
423
0
  }
424
0
  name = p;
425
426
  /* Search appropriate hardware */
427
0
  log_debug("rpc", "client request interface %s", name);
428
0
  TAILQ_FOREACH (hardware, &cfg->g_hardware, h_entries)
429
0
    if (!strcmp(hardware->h_ifname, name)) {
430
0
      ssize_t output_len = lldpd_hardware_serialize(hardware, output);
431
0
      free(name);
432
0
      if (output_len <= 0) {
433
0
        *type = NONE;
434
0
        return 0;
435
0
      }
436
0
      return output_len;
437
0
    }
438
439
0
  log_warnx("rpc", "no interface %s found", name);
440
0
  free(name);
441
0
  *type = NONE;
442
0
  return 0;
443
0
}
444
445
/* Return all available information related to an interface
446
   Input:  name of the interface (serialized)
447
   Output: Information about the interface (lldpd_hardware)
448
*/
449
static ssize_t
450
client_handle_get_default_port(struct lldpd *cfg, enum hmsg_type *type, void *input,
451
    int input_len, void **output, int *subscribed)
452
0
{
453
0
  log_debug("rpc", "client request the default local port");
454
0
  ssize_t output_len = lldpd_port_serialize(cfg->g_default_local_port, output);
455
0
  if (output_len <= 0) {
456
0
    *type = NONE;
457
0
    return 0;
458
0
  }
459
0
  return output_len;
460
0
}
461
462
static int
463
_client_handle_set_port(struct lldpd *cfg, struct lldpd_port *port,
464
    struct lldpd_port_set *set)
465
0
{
466
0
#ifdef ENABLE_LLDPMED
467
0
  struct lldpd_med_loc *loc = NULL;
468
0
#endif
469
0
  if (set->local_id) {
470
0
    log_debug("rpc", "requested change to Port ID");
471
0
    free(port->p_id);
472
0
    port->p_id = strdup(set->local_id);
473
0
    port->p_id_len = strlen(set->local_id);
474
0
    port->p_id_subtype = LLDP_PORTID_SUBTYPE_LOCAL;
475
0
    port->p_descr_force = 0;
476
0
  }
477
0
  if (set->local_descr) {
478
0
    log_debug("rpc", "requested change to Port Description");
479
0
    free(port->p_descr);
480
0
    port->p_descr = strdup(set->local_descr);
481
0
    port->p_descr_force = 1;
482
0
  }
483
0
  switch (set->rxtx) {
484
0
  case LLDPD_RXTX_TXONLY:
485
0
    log_debug("rpc", "requested TX only mode");
486
0
    port->p_disable_rx = 1;
487
0
    port->p_disable_tx = 0;
488
0
    break;
489
0
  case LLDPD_RXTX_RXONLY:
490
0
    log_debug("rpc", "requested RX only mode");
491
0
    port->p_disable_rx = 0;
492
0
    port->p_disable_tx = 1;
493
0
    break;
494
0
  case LLDPD_RXTX_BOTH:
495
0
    log_debug("rpc", "requested RX/TX mode");
496
0
    port->p_disable_rx = port->p_disable_tx = 0;
497
0
    break;
498
0
  case LLDPD_RXTX_DISABLED:
499
0
    log_debug("rpc", "requested disabled mode");
500
0
    port->p_disable_rx = port->p_disable_tx = 1;
501
0
    break;
502
0
  }
503
0
  if (set->vlan_tx_enabled > -1) {
504
0
    port->p_vlan_tx_enabled = set->vlan_tx_enabled;
505
0
    port->p_vlan_tx_tag = set->vlan_tx_tag;
506
0
  }
507
0
  if (set->vlan_advertise_pattern) {
508
0
    log_debug("rpc", "requested change to VLAN advertise pattern");
509
0
    free(port->p_vlan_advertise_pattern);
510
0
    port->p_vlan_advertise_pattern = strdup(set->vlan_advertise_pattern);
511
0
  }
512
0
#ifdef ENABLE_LLDPMED
513
0
  if (set->med_policy && set->med_policy->type > 0) {
514
0
    log_debug("rpc", "requested change to MED policy");
515
0
    if (set->med_policy->type > LLDP_MED_APPTYPE_LAST) {
516
0
      log_warnx("rpc", "invalid policy provided: %d",
517
0
          set->med_policy->type);
518
0
      return -1;
519
0
    }
520
0
    memcpy(&port->p_med_policy[set->med_policy->type - 1], set->med_policy,
521
0
        sizeof(struct lldpd_med_policy));
522
0
    port->p_med_cap_enabled |= LLDP_MED_CAP_POLICY;
523
0
  }
524
0
  if (set->med_location && set->med_location->format > 0) {
525
0
    char *newdata = NULL;
526
0
    log_debug("rpc", "requested change to MED location");
527
0
    if (set->med_location->format > LLDP_MED_LOCFORMAT_LAST) {
528
0
      log_warnx("rpc", "invalid location format provided: %d",
529
0
          set->med_location->format);
530
0
      return -1;
531
0
    }
532
0
    loc = &port->p_med_location[set->med_location->format - 1];
533
0
    free(loc->data);
534
0
    memcpy(loc, set->med_location, sizeof(struct lldpd_med_loc));
535
0
    if (!loc->data || !(newdata = malloc(loc->data_len))) loc->data_len = 0;
536
0
    if (newdata) memcpy(newdata, loc->data, loc->data_len);
537
0
    loc->data = newdata;
538
0
    port->p_med_cap_enabled |= LLDP_MED_CAP_LOCATION;
539
0
  }
540
0
  if (set->med_power) {
541
0
    log_debug("rpc", "requested change to MED power");
542
0
    memcpy(&port->p_med_power, set->med_power,
543
0
        sizeof(struct lldpd_med_power));
544
0
    switch (set->med_power->devicetype) {
545
0
    case LLDP_MED_POW_TYPE_PD:
546
0
      port->p_med_cap_enabled |= LLDP_MED_CAP_MDI_PD;
547
0
      port->p_med_cap_enabled &= ~LLDP_MED_CAP_MDI_PSE;
548
0
      break;
549
0
    case LLDP_MED_POW_TYPE_PSE:
550
0
      port->p_med_cap_enabled |= LLDP_MED_CAP_MDI_PSE;
551
0
      port->p_med_cap_enabled &= ~LLDP_MED_CAP_MDI_PD;
552
0
      break;
553
0
    }
554
0
  }
555
0
#endif
556
0
#ifdef ENABLE_DOT3
557
0
  if (set->dot3_power) {
558
0
    log_debug("rpc", "requested change to Dot3 power");
559
0
    memcpy(&port->p_power, set->dot3_power,
560
0
        sizeof(struct lldpd_dot3_power));
561
0
  }
562
0
#endif
563
0
#ifdef ENABLE_CUSTOM
564
0
  if (set->custom_list_clear) {
565
0
    log_debug("rpc", "requested custom TLVs clear");
566
0
    lldpd_custom_list_cleanup(port);
567
0
  } else {
568
0
    if (set->custom) {
569
0
      log_info("rpc",
570
0
          "custom TLV op %s oui %02x:%02x:%02x subtype %x",
571
0
          (set->custom_tlv_op == CUSTOM_TLV_REMOVE)  ? "remove" :
572
0
        (set->custom_tlv_op == CUSTOM_TLV_ADD) ? "add" :
573
0
                   "replace",
574
0
          set->custom->oui[0], set->custom->oui[1],
575
0
          set->custom->oui[2], set->custom->subtype);
576
0
      switch (set->custom_tlv_op) {
577
0
      case CUSTOM_TLV_REMOVE:
578
0
        lldpd_custom_tlv_cleanup(port, set->custom);
579
0
        break;
580
0
      case CUSTOM_TLV_ADD:
581
0
        lldpd_custom_tlv_add(port, set->custom);
582
0
        break;
583
0
      case CUSTOM_TLV_REPLACE:
584
0
      default:
585
0
        lldpd_custom_tlv_cleanup(port, set->custom);
586
0
        lldpd_custom_tlv_add(port, set->custom);
587
0
        break;
588
0
      }
589
0
    }
590
0
  }
591
0
#endif
592
0
  return 0;
593
0
}
594
595
/* Set some port related settings (policy, location, power)
596
   Input: name of the interface, policy/location/power setting to be modified
597
   Output: nothing
598
*/
599
static ssize_t
600
client_handle_set_port(struct lldpd *cfg, enum hmsg_type *type, void *input,
601
    int input_len, void **output, int *subscribed)
602
0
{
603
0
  int ret = 0;
604
0
  struct lldpd_port_set *set = NULL;
605
0
  struct lldpd_hardware *hardware = NULL;
606
607
0
  if (lldpd_port_set_unserialize(input, input_len, &set) <= 0) {
608
0
    *type = NONE;
609
0
    return 0;
610
0
  }
611
0
  if (!set->ifname) {
612
0
    log_warnx("rpc", "no interface provided");
613
0
    goto set_port_finished;
614
0
  }
615
616
  /* Search the appropriate hardware */
617
0
  if (strlen(set->ifname) == 0) {
618
0
    log_debug("rpc", "client request change to default port");
619
0
    if (_client_handle_set_port(cfg, cfg->g_default_local_port, set) == -1)
620
0
      goto set_port_finished;
621
0
    ret = 1;
622
0
  } else {
623
0
    log_debug("rpc", "client request change to port %s", set->ifname);
624
0
    TAILQ_FOREACH (hardware, &cfg->g_hardware, h_entries) {
625
0
      if (!strcmp(hardware->h_ifname, set->ifname)) {
626
0
        struct lldpd_port *port = &hardware->h_lport;
627
0
        if (_client_handle_set_port(cfg, port, set) == -1)
628
0
          goto set_port_finished;
629
0
        ret = 1;
630
0
        break;
631
0
      }
632
0
    }
633
0
  }
634
635
0
  if (ret == 0)
636
0
    log_warn("rpc", "no interface %s found", set->ifname);
637
0
  else
638
0
    levent_update_now(cfg);
639
640
0
set_port_finished:
641
0
  if (!ret) *type = NONE;
642
0
  free(set->ifname);
643
0
  free(set->local_id);
644
0
  free(set->local_descr);
645
0
#ifdef ENABLE_LLDPMED
646
0
  free(set->med_policy);
647
0
  if (set->med_location) free(set->med_location->data);
648
0
  free(set->med_location);
649
0
  free(set->med_power);
650
0
#endif
651
0
#ifdef ENABLE_DOT3
652
0
  free(set->dot3_power);
653
0
#endif
654
0
#ifdef ENABLE_CUSTOM
655
0
  if (set->custom) {
656
0
    free(set->custom->oui_info);
657
0
    free(set->custom);
658
0
  }
659
0
#endif
660
0
  free(set);
661
0
  return 0;
662
0
}
663
664
/* Register subscribtion to neighbor changes */
665
static ssize_t
666
client_handle_subscribe(struct lldpd *cfg, enum hmsg_type *type, void *input,
667
    int input_len, void **output, int *subscribed)
668
0
{
669
0
  log_debug("rpc", "client subscribe to changes");
670
0
  *subscribed = 1;
671
0
  return 0;
672
0
}
673
674
struct client_handle {
675
  enum hmsg_type type;
676
  const char *name;
677
  ssize_t (
678
      *handle)(struct lldpd *, enum hmsg_type *, void *, int, void **, int *);
679
};
680
681
static struct client_handle client_handles[] = { { NONE, "None", client_handle_none },
682
  { GET_CONFIG, "Get configuration", client_handle_get_configuration },
683
  { SET_CONFIG, "Set configuration", client_handle_set_configuration },
684
  { GET_INTERFACES, "Get interfaces", client_handle_get_interfaces },
685
  { GET_INTERFACE, "Get interface", client_handle_get_interface },
686
  { GET_DEFAULT_PORT, "Get default port", client_handle_get_default_port },
687
  { SET_CHASSIS, "Set local chassis", client_handle_set_local_chassis },
688
  { GET_CHASSIS, "Get local chassis", client_handle_get_local_chassis },
689
  { SET_PORT, "Set port", client_handle_set_port },
690
  { SUBSCRIBE, "Subscribe", client_handle_subscribe }, { 0, NULL } };
691
692
int
693
client_handle_client(struct lldpd *cfg, ssize_t (*send)(void *, int, void *, size_t),
694
    void *out, enum hmsg_type type, void *buffer, size_t n, int *subscribed)
695
0
{
696
0
  struct client_handle *ch;
697
0
  void *answer;
698
0
  ssize_t len, sent;
699
700
0
  log_debug("rpc", "handle client request");
701
0
  for (ch = client_handles; ch->handle != NULL; ch++) {
702
0
    if (ch->type == type) {
703
0
      TRACE(LLDPD_CLIENT_REQUEST(ch->name));
704
0
      answer = NULL;
705
0
      len = ch->handle(cfg, &type, buffer, n, &answer, subscribed);
706
0
      sent = send(out, type, answer, len);
707
0
      free(answer);
708
0
      return sent;
709
0
    }
710
0
  }
711
712
0
  log_warnx("rpc", "unknown message request (%d) received", type);
713
0
  return -1;
714
0
}