]>
Commit | Line | Data |
---|---|---|
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" | |
19 | ||
f6d20631 VB |
20 | static int |
21 | client_handle_none(struct lldpd *cfg, enum hmsg_type *type, | |
4e90a9e0 | 22 | void *input, int input_len, void **output, int *subscribed) |
a552a72e | 23 | { |
f6d20631 VB |
24 | LLOG_INFO("received noop request from client"); |
25 | *type = NONE; | |
26 | return 0; | |
a552a72e VB |
27 | } |
28 | ||
8729d69f VB |
29 | /* Return the global configuration */ |
30 | static int | |
31 | client_handle_get_configuration(struct lldpd *cfg, enum hmsg_type *type, | |
32 | void *input, int input_len, void **output, int *subscribed) | |
33 | { | |
34 | ssize_t output_len; | |
35 | output_len = marshal_serialize(lldpd_config, &cfg->g_config, output); | |
36 | if (output_len <= 0) { | |
37 | output_len = 0; | |
38 | *type = NONE; | |
39 | } | |
40 | return output_len; | |
41 | } | |
42 | ||
47287a61 VB |
43 | /* Change the global configuration */ |
44 | static int | |
45 | client_handle_set_configuration(struct lldpd *cfg, enum hmsg_type *type, | |
46 | void *input, int input_len, void **output, int *subscribed) | |
47 | { | |
48 | struct lldpd_config *config; | |
49 | ||
50 | /* Get the proposed configuration. */ | |
51 | if (marshal_unserialize(lldpd_config, input, input_len, &config) <= 0) { | |
52 | *type = NONE; | |
53 | return 0; | |
54 | } | |
55 | ||
56 | /* What needs to be done? Currently, we only support setting the | |
57 | * transmit delay. */ | |
8843f168 VB |
58 | if (config->c_tx_interval > 0) { |
59 | cfg->g_config.c_tx_interval = config->c_tx_interval; | |
47287a61 | 60 | } |
8843f168 | 61 | if (config->c_tx_interval < 0) { |
47287a61 VB |
62 | LLOG_DEBUG("client asked for immediate retransmission"); |
63 | levent_send_now(cfg); | |
64 | } | |
65 | ||
66 | lldpd_config_cleanup(config); | |
67 | ||
68 | return 0; | |
69 | } | |
70 | ||
f6d20631 VB |
71 | /* Return the list of interfaces. |
72 | Input: nothing. | |
73 | Output: list of interface names (lldpd_interface_list) | |
74 | */ | |
75 | static int | |
76 | client_handle_get_interfaces(struct lldpd *cfg, enum hmsg_type *type, | |
4e90a9e0 | 77 | void *input, int input_len, void **output, int *subscribed) |
a552a72e VB |
78 | { |
79 | struct lldpd_interface *iff, *iff_next; | |
80 | struct lldpd_hardware *hardware; | |
5fd6695c | 81 | int output_len; |
a552a72e VB |
82 | |
83 | /* Build the list of interfaces */ | |
f6d20631 | 84 | struct lldpd_interface_list ifs; |
a552a72e VB |
85 | TAILQ_INIT(&ifs); |
86 | TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) { | |
87 | if ((iff = (struct lldpd_interface*)malloc(sizeof( | |
88 | struct lldpd_interface))) == NULL) | |
89 | fatal(NULL); | |
90 | iff->name = hardware->h_ifname; | |
91 | TAILQ_INSERT_TAIL(&ifs, iff, next); | |
92 | } | |
93 | ||
5fd6695c | 94 | output_len = marshal_serialize(lldpd_interface_list, &ifs, output); |
f6d20631 VB |
95 | if (output_len <= 0) { |
96 | output_len = 0; | |
97 | *type = NONE; | |
a552a72e VB |
98 | } |
99 | ||
100 | /* Free the temporary list */ | |
101 | for (iff = TAILQ_FIRST(&ifs); | |
102 | iff != NULL; | |
103 | iff = iff_next) { | |
104 | iff_next = TAILQ_NEXT(iff, next); | |
105 | TAILQ_REMOVE(&ifs, iff, next); | |
106 | free(iff); | |
107 | } | |
f6d20631 VB |
108 | |
109 | return output_len; | |
a552a72e VB |
110 | } |
111 | ||
f6d20631 VB |
112 | /* Return all available information related to an interface |
113 | Input: name of the interface (serialized) | |
114 | Output: Information about the interface (lldpd_hardware) | |
115 | */ | |
116 | static int | |
117 | client_handle_get_interface(struct lldpd *cfg, enum hmsg_type *type, | |
4e90a9e0 | 118 | void *input, int input_len, void **output, int *subscribed) |
a552a72e | 119 | { |
f6d20631 | 120 | char *name; |
5fd6695c VB |
121 | struct lldpd_hardware *hardware; |
122 | ||
123 | /* Get name of the interface */ | |
f6d20631 VB |
124 | if (marshal_unserialize(string, input, input_len, &name) <= 0) { |
125 | *type = NONE; | |
126 | return 0; | |
127 | } | |
128 | ||
129 | /* Search appropriate hardware */ | |
f6d20631 VB |
130 | TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) |
131 | if (!strcmp(hardware->h_ifname, name)) { | |
132 | int output_len = marshal_serialize(lldpd_hardware, hardware, output); | |
133 | free(name); | |
134 | if (output_len <= 0) { | |
135 | *type = NONE; | |
136 | free(name); | |
137 | return 0; | |
138 | } | |
139 | return output_len; | |
140 | } | |
141 | ||
142 | free(name); | |
143 | LLOG_WARNX("no interface %s found", name); | |
144 | *type = NONE; | |
145 | return 0; | |
146 | } | |
147 | ||
148 | /* Set some port related settings (policy, location, power) | |
149 | Input: name of the interface, policy/location/power setting to be modified | |
150 | Output: nothing | |
151 | */ | |
152 | static int | |
153 | client_handle_set_port(struct lldpd *cfg, enum hmsg_type *type, | |
4e90a9e0 | 154 | void *input, int input_len, void **output, int *subscribed) |
f6d20631 VB |
155 | { |
156 | int ret = 0; | |
5fd6695c VB |
157 | struct lldpd_port_set *set = NULL; |
158 | struct lldpd_hardware *hardware = NULL; | |
2a836f02 | 159 | #ifdef ENABLE_LLDPMED |
5fd6695c | 160 | struct lldpd_med_loc *loc = NULL; |
2a836f02 | 161 | #endif |
a552a72e | 162 | |
f6d20631 VB |
163 | if (marshal_unserialize(lldpd_port_set, input, input_len, &set) <= 0) { |
164 | *type = NONE; | |
165 | return 0; | |
a552a72e | 166 | } |
f6d20631 VB |
167 | if (!set->ifname) { |
168 | LLOG_WARNX("no interface provided"); | |
169 | goto set_port_finished; | |
170 | } | |
171 | ||
172 | /* Search the appropriate hardware */ | |
f6d20631 VB |
173 | TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) |
174 | if (!strcmp(hardware->h_ifname, set->ifname)) { | |
175 | struct lldpd_port *port = &hardware->h_lport; | |
4b292b55 | 176 | (void)port; |
740593ff | 177 | #ifdef ENABLE_LLDPMED |
f6d20631 | 178 | if (set->med_policy && set->med_policy->type > 0) { |
4b292b55 | 179 | if (set->med_policy->type > LLDP_MED_APPTYPE_LAST) { |
f6d20631 VB |
180 | LLOG_WARNX("invalid policy provided: %d", |
181 | set->med_policy->type); | |
182 | goto set_port_finished; | |
183 | } | |
184 | memcpy(&port->p_med_policy[set->med_policy->type - 1], | |
185 | set->med_policy, sizeof(struct lldpd_med_policy)); | |
4b292b55 | 186 | port->p_med_cap_enabled |= LLDP_MED_CAP_POLICY; |
f6d20631 VB |
187 | } |
188 | if (set->med_location && set->med_location->format > 0) { | |
4b292b55 VB |
189 | char *newdata = NULL; |
190 | if (set->med_location->format > LLDP_MED_LOCFORMAT_LAST) { | |
f6d20631 VB |
191 | LLOG_WARNX("invalid location format provided: %d", |
192 | set->med_location->format); | |
193 | goto set_port_finished; | |
194 | } | |
5fd6695c | 195 | loc = \ |
f6d20631 VB |
196 | &port->p_med_location[set->med_location->format - 1]; |
197 | free(loc->data); | |
198 | memcpy(loc, set->med_location, sizeof(struct lldpd_med_loc)); | |
4b292b55 VB |
199 | if (!loc->data || !(newdata = malloc(loc->data_len))) loc->data_len = 0; |
200 | if (newdata) memcpy(newdata, loc->data, loc->data_len); | |
201 | loc->data = newdata; | |
202 | port->p_med_cap_enabled |= LLDP_MED_CAP_LOCATION; | |
f6d20631 VB |
203 | } |
204 | if (set->med_power) { | |
205 | memcpy(&port->p_med_power, set->med_power, | |
206 | sizeof(struct lldpd_med_power)); | |
207 | switch (set->med_power->devicetype) { | |
4b292b55 VB |
208 | case LLDP_MED_POW_TYPE_PD: |
209 | port->p_med_cap_enabled |= LLDP_MED_CAP_MDI_PD; | |
210 | port->p_med_cap_enabled &= ~LLDP_MED_CAP_MDI_PSE; | |
f6d20631 | 211 | break; |
4b292b55 VB |
212 | case LLDP_MED_POW_TYPE_PSE: |
213 | port->p_med_cap_enabled |= LLDP_MED_CAP_MDI_PSE; | |
214 | port->p_med_cap_enabled &= ~LLDP_MED_CAP_MDI_PD; | |
f6d20631 VB |
215 | break; |
216 | } | |
217 | } | |
42ee7382 VB |
218 | #endif |
219 | #ifdef ENABLE_DOT3 | |
f6d20631 VB |
220 | if (set->dot3_power) |
221 | memcpy(&port->p_power, set->dot3_power, | |
222 | sizeof(struct lldpd_dot3_power)); | |
740593ff | 223 | #endif |
f6d20631 VB |
224 | ret = 1; |
225 | break; | |
226 | } | |
227 | ||
228 | if (ret == 0) | |
229 | LLOG_WARN("no interface %s found", set->ifname); | |
230 | ||
231 | set_port_finished: | |
232 | if (!ret) *type = NONE; | |
233 | free(set->ifname); | |
4b292b55 | 234 | #ifdef ENABLE_LLDPMED |
f6d20631 VB |
235 | free(set->med_policy); |
236 | if (set->med_location) free(set->med_location->data); | |
237 | free(set->med_location); | |
238 | free(set->med_power); | |
84853b92 | 239 | #endif |
f6d20631 VB |
240 | #ifdef ENABLE_DOT3 |
241 | free(set->dot3_power); | |
242 | #endif | |
243 | return 0; | |
244 | } | |
245 | ||
4e90a9e0 VB |
246 | /* Register subscribtion to neighbor changes */ |
247 | static int | |
248 | client_handle_subscribe(struct lldpd *cfg, enum hmsg_type *type, | |
249 | void *input, int input_len, void **output, int *subscribed) | |
250 | { | |
251 | *subscribed = 1; | |
252 | return 0; | |
253 | } | |
254 | ||
255 | struct client_handle { | |
256 | enum hmsg_type type; | |
257 | int (*handle)(struct lldpd*, enum hmsg_type *, | |
258 | void *, int, void **, int *); | |
259 | }; | |
260 | ||
f6d20631 | 261 | static struct client_handle client_handles[] = { |
4e90a9e0 | 262 | { NONE, client_handle_none }, |
8729d69f | 263 | { GET_CONFIG, client_handle_get_configuration }, |
47287a61 | 264 | { SET_CONFIG, client_handle_set_configuration }, |
4e90a9e0 VB |
265 | { GET_INTERFACES, client_handle_get_interfaces }, |
266 | { GET_INTERFACE, client_handle_get_interface }, | |
267 | { SET_PORT, client_handle_set_port }, | |
268 | { SUBSCRIBE, client_handle_subscribe }, | |
269 | { 0, NULL } }; | |
f6d20631 VB |
270 | |
271 | int | |
e0478a46 VB |
272 | client_handle_client(struct lldpd *cfg, |
273 | ssize_t(*send)(void *, int, void *, size_t), | |
274 | void *out, | |
4e90a9e0 VB |
275 | enum hmsg_type type, void *buffer, size_t n, |
276 | int *subscribed) | |
f6d20631 VB |
277 | { |
278 | struct client_handle *ch; | |
e0478a46 | 279 | void *answer; size_t len, sent; |
f6d20631 VB |
280 | for (ch = client_handles; ch->handle != NULL; ch++) { |
281 | if (ch->type == type) { | |
282 | answer = NULL; len = 0; | |
4e90a9e0 VB |
283 | len = ch->handle(cfg, &type, buffer, n, &answer, |
284 | subscribed); | |
e0478a46 | 285 | sent = send(out, type, answer, len); |
f6d20631 VB |
286 | free(answer); |
287 | return sent; | |
a552a72e VB |
288 | } |
289 | } | |
e0478a46 | 290 | |
f6d20631 VB |
291 | LLOG_WARNX("unknown message request (%d) received", |
292 | type); | |
293 | return -1; | |
a552a72e | 294 | } |