]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/daemon/client.c
lldpctl: add a "-w" option to watch neighbor changes
[thirdparty/lldpd.git] / src / daemon / client.c
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
20 static int
21 client_handle_none(struct lldpd *cfg, enum hmsg_type *type,
22 void *input, int input_len, void **output, int *subscribed)
23 {
24 LLOG_INFO("received noop request from client");
25 *type = NONE;
26 return 0;
27 }
28
29 /* Return the list of interfaces.
30 Input: nothing.
31 Output: list of interface names (lldpd_interface_list)
32 */
33 static int
34 client_handle_get_interfaces(struct lldpd *cfg, enum hmsg_type *type,
35 void *input, int input_len, void **output, int *subscribed)
36 {
37 struct lldpd_interface *iff, *iff_next;
38 struct lldpd_hardware *hardware;
39 int output_len;
40
41 /* Build the list of interfaces */
42 struct lldpd_interface_list ifs;
43 TAILQ_INIT(&ifs);
44 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
45 if ((iff = (struct lldpd_interface*)malloc(sizeof(
46 struct lldpd_interface))) == NULL)
47 fatal(NULL);
48 iff->name = hardware->h_ifname;
49 TAILQ_INSERT_TAIL(&ifs, iff, next);
50 }
51
52 output_len = marshal_serialize(lldpd_interface_list, &ifs, output);
53 if (output_len <= 0) {
54 output_len = 0;
55 *type = NONE;
56 }
57
58 /* Free the temporary list */
59 for (iff = TAILQ_FIRST(&ifs);
60 iff != NULL;
61 iff = iff_next) {
62 iff_next = TAILQ_NEXT(iff, next);
63 TAILQ_REMOVE(&ifs, iff, next);
64 free(iff);
65 }
66
67 return output_len;
68 }
69
70 /* Return all available information related to an interface
71 Input: name of the interface (serialized)
72 Output: Information about the interface (lldpd_hardware)
73 */
74 static int
75 client_handle_get_interface(struct lldpd *cfg, enum hmsg_type *type,
76 void *input, int input_len, void **output, int *subscribed)
77 {
78 char *name;
79 struct lldpd_hardware *hardware;
80
81 /* Get name of the interface */
82 if (marshal_unserialize(string, input, input_len, &name) <= 0) {
83 *type = NONE;
84 return 0;
85 }
86
87 /* Search appropriate hardware */
88 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
89 if (!strcmp(hardware->h_ifname, name)) {
90 int output_len = marshal_serialize(lldpd_hardware, hardware, output);
91 free(name);
92 if (output_len <= 0) {
93 *type = NONE;
94 free(name);
95 return 0;
96 }
97 return output_len;
98 }
99
100 free(name);
101 LLOG_WARNX("no interface %s found", name);
102 *type = NONE;
103 return 0;
104 }
105
106 /* Set some port related settings (policy, location, power)
107 Input: name of the interface, policy/location/power setting to be modified
108 Output: nothing
109 */
110 static int
111 client_handle_set_port(struct lldpd *cfg, enum hmsg_type *type,
112 void *input, int input_len, void **output, int *subscribed)
113 {
114 int ret = 0;
115 struct lldpd_port_set *set = NULL;
116 struct lldpd_hardware *hardware = NULL;
117 #ifdef ENABLE_LLDPMED
118 struct lldpd_med_loc *loc = NULL;
119 #endif
120
121 if (marshal_unserialize(lldpd_port_set, input, input_len, &set) <= 0) {
122 *type = NONE;
123 return 0;
124 }
125 if (!set->ifname) {
126 LLOG_WARNX("no interface provided");
127 goto set_port_finished;
128 }
129
130 /* Search the appropriate hardware */
131 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
132 if (!strcmp(hardware->h_ifname, set->ifname)) {
133 struct lldpd_port *port = &hardware->h_lport;
134 (void)port;
135 #ifdef ENABLE_LLDPMED
136 if (set->med_policy && set->med_policy->type > 0) {
137 if (set->med_policy->type > LLDP_MED_APPTYPE_LAST) {
138 LLOG_WARNX("invalid policy provided: %d",
139 set->med_policy->type);
140 goto set_port_finished;
141 }
142 memcpy(&port->p_med_policy[set->med_policy->type - 1],
143 set->med_policy, sizeof(struct lldpd_med_policy));
144 port->p_med_cap_enabled |= LLDP_MED_CAP_POLICY;
145 }
146 if (set->med_location && set->med_location->format > 0) {
147 char *newdata = NULL;
148 if (set->med_location->format > LLDP_MED_LOCFORMAT_LAST) {
149 LLOG_WARNX("invalid location format provided: %d",
150 set->med_location->format);
151 goto set_port_finished;
152 }
153 loc = \
154 &port->p_med_location[set->med_location->format - 1];
155 free(loc->data);
156 memcpy(loc, set->med_location, sizeof(struct lldpd_med_loc));
157 if (!loc->data || !(newdata = malloc(loc->data_len))) loc->data_len = 0;
158 if (newdata) memcpy(newdata, loc->data, loc->data_len);
159 loc->data = newdata;
160 port->p_med_cap_enabled |= LLDP_MED_CAP_LOCATION;
161 }
162 if (set->med_power) {
163 memcpy(&port->p_med_power, set->med_power,
164 sizeof(struct lldpd_med_power));
165 switch (set->med_power->devicetype) {
166 case LLDP_MED_POW_TYPE_PD:
167 port->p_med_cap_enabled |= LLDP_MED_CAP_MDI_PD;
168 port->p_med_cap_enabled &= ~LLDP_MED_CAP_MDI_PSE;
169 break;
170 case LLDP_MED_POW_TYPE_PSE:
171 port->p_med_cap_enabled |= LLDP_MED_CAP_MDI_PSE;
172 port->p_med_cap_enabled &= ~LLDP_MED_CAP_MDI_PD;
173 break;
174 }
175 }
176 #endif
177 #ifdef ENABLE_DOT3
178 if (set->dot3_power)
179 memcpy(&port->p_power, set->dot3_power,
180 sizeof(struct lldpd_dot3_power));
181 #endif
182 ret = 1;
183 break;
184 }
185
186 if (ret == 0)
187 LLOG_WARN("no interface %s found", set->ifname);
188
189 set_port_finished:
190 if (!ret) *type = NONE;
191 free(set->ifname);
192 #ifdef ENABLE_LLDPMED
193 free(set->med_policy);
194 if (set->med_location) free(set->med_location->data);
195 free(set->med_location);
196 free(set->med_power);
197 #endif
198 #ifdef ENABLE_DOT3
199 free(set->dot3_power);
200 #endif
201 return 0;
202 }
203
204 /* Register subscribtion to neighbor changes */
205 static int
206 client_handle_subscribe(struct lldpd *cfg, enum hmsg_type *type,
207 void *input, int input_len, void **output, int *subscribed)
208 {
209 *subscribed = 1;
210 return 0;
211 }
212
213 struct client_handle {
214 enum hmsg_type type;
215 int (*handle)(struct lldpd*, enum hmsg_type *,
216 void *, int, void **, int *);
217 };
218
219 static struct client_handle client_handles[] = {
220 { NONE, client_handle_none },
221 { GET_INTERFACES, client_handle_get_interfaces },
222 { GET_INTERFACE, client_handle_get_interface },
223 { SET_PORT, client_handle_set_port },
224 { SUBSCRIBE, client_handle_subscribe },
225 { 0, NULL } };
226
227 int
228 client_handle_client(struct lldpd *cfg,
229 ssize_t(*send)(void *, int, void *, size_t),
230 void *out,
231 enum hmsg_type type, void *buffer, size_t n,
232 int *subscribed)
233 {
234 struct client_handle *ch;
235 void *answer; size_t len, sent;
236 for (ch = client_handles; ch->handle != NULL; ch++) {
237 if (ch->type == type) {
238 answer = NULL; len = 0;
239 len = ch->handle(cfg, &type, buffer, n, &answer,
240 subscribed);
241 sent = send(out, type, answer, len);
242 free(answer);
243 return sent;
244 }
245 }
246
247 LLOG_WARNX("unknown message request (%d) received",
248 type);
249 return -1;
250 }