/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 | } |