]>
Commit | Line | Data |
---|---|---|
a552a72e VB |
1 | /* |
2 | * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx> | |
3 | * | |
4 | * Permission to use, copy, modify, and distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | */ | |
16 | ||
17 | #include "lldpd.h" | |
18 | ||
8888d191 | 19 | static struct client_handle client_handles[] = { |
a552a72e VB |
20 | { HMSG_NONE, client_handle_none }, |
21 | { HMSG_GET_INTERFACES, client_handle_get_interfaces }, | |
84853b92 | 22 | { HMSG_GET_NB_PORTS, client_handle_port_related }, |
740593ff | 23 | { HMSG_GET_PORT, client_handle_port_related }, |
84853b92 | 24 | { HMSG_GET_CHASSIS, client_handle_port_related }, |
740593ff VB |
25 | #ifdef ENABLE_LLDPMED |
26 | { HMSG_SET_LOCATION, client_handle_port_related }, | |
86f24df3 | 27 | { HMSG_SET_POLICY, client_handle_port_related }, |
009ddd23 | 28 | { HMSG_SET_POWER, client_handle_port_related }, |
740593ff | 29 | #endif |
a1347cd8 | 30 | #ifdef ENABLE_DOT1 |
740593ff | 31 | { HMSG_GET_VLANS, client_handle_port_related }, |
a1347cd8 | 32 | #endif |
a552a72e VB |
33 | { HMSG_SHUTDOWN, client_handle_shutdown }, |
34 | { 0, NULL } }; | |
35 | ||
36 | void | |
77d7090e | 37 | client_handle_client(struct lldpd *cfg, struct lldpd_callback *callback, |
a552a72e VB |
38 | char *buffer, int n) |
39 | { | |
40 | struct hmsg *h; /* Reception */ | |
41 | struct hmsg *t; /* Sending */ | |
42 | struct client_handle *ch; | |
43 | ||
44 | if (n < sizeof(struct hmsg_hdr)) { | |
45 | LLOG_WARNX("too short message request received"); | |
46 | return; | |
47 | } | |
48 | h = (struct hmsg *)buffer; | |
49 | n -= sizeof(struct hmsg_hdr); | |
50 | if (n != h->hdr.len) { | |
51 | LLOG_WARNX("incorrect message size received from %d", | |
52 | h->hdr.pid); | |
53 | return; | |
54 | } | |
55 | ||
740593ff | 56 | if ((t = (struct hmsg*)malloc(MAX_HMSGSIZE)) == NULL) { |
a552a72e VB |
57 | LLOG_WARNX("unable to allocate memory to answer to %d", |
58 | h->hdr.pid); | |
59 | return; | |
60 | } | |
61 | ctl_msg_init(t, h->hdr.type); | |
62 | for (ch = client_handles; ch->handle != NULL; ch++) { | |
63 | if (ch->type == h->hdr.type) { | |
64 | ch->handle(cfg, h, t); | |
65 | if (t->hdr.len == -1) { | |
66 | t->hdr.len = 0; | |
67 | t->hdr.type = HMSG_NONE; | |
68 | } | |
77d7090e | 69 | if (ctl_msg_send(callback->fd, t) == -1) |
a552a72e VB |
70 | LLOG_WARN("unable to send answer to client %d", |
71 | h->hdr.pid); | |
72 | free(t); | |
73 | return; | |
74 | } | |
75 | } | |
76 | ||
77 | LLOG_WARNX("unknown message request (%d) received from %d", | |
78 | h->hdr.type, h->hdr.pid); | |
79 | free(t); | |
80 | return; | |
81 | } | |
82 | ||
83 | void | |
84 | client_handle_shutdown(struct lldpd *cfg, struct hmsg *r, struct hmsg *s) | |
85 | { | |
86 | LLOG_INFO("received shutdown request from client %d", | |
87 | r->hdr.pid); | |
88 | exit(0); | |
89 | } | |
90 | ||
91 | void | |
92 | client_handle_none(struct lldpd *cfg, struct hmsg *r, struct hmsg *s) | |
93 | { | |
94 | LLOG_INFO("received noop request from client %d", | |
95 | r->hdr.pid); | |
96 | s->hdr.len = -1; | |
97 | } | |
98 | ||
99 | void | |
100 | client_handle_get_interfaces(struct lldpd *cfg, struct hmsg *r, struct hmsg *s) | |
101 | { | |
102 | struct lldpd_interface *iff, *iff_next; | |
103 | struct lldpd_hardware *hardware; | |
104 | void *p; | |
105 | ||
106 | /* Build the list of interfaces */ | |
107 | TAILQ_HEAD(, lldpd_interface) ifs; | |
108 | TAILQ_INIT(&ifs); | |
109 | TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) { | |
110 | if ((iff = (struct lldpd_interface*)malloc(sizeof( | |
111 | struct lldpd_interface))) == NULL) | |
112 | fatal(NULL); | |
113 | iff->name = hardware->h_ifname; | |
114 | TAILQ_INSERT_TAIL(&ifs, iff, next); | |
115 | } | |
116 | ||
117 | p = &s->data; | |
118 | if (ctl_msg_pack_list(STRUCT_LLDPD_INTERFACE, &ifs, | |
119 | sizeof(struct lldpd_interface), s, &p) == -1) { | |
120 | LLOG_WARNX("unable to pack list of interfaces"); | |
121 | s->hdr.len = -1; | |
122 | } | |
123 | ||
124 | /* Free the temporary list */ | |
125 | for (iff = TAILQ_FIRST(&ifs); | |
126 | iff != NULL; | |
127 | iff = iff_next) { | |
128 | iff_next = TAILQ_NEXT(iff, next); | |
129 | TAILQ_REMOVE(&ifs, iff, next); | |
130 | free(iff); | |
131 | } | |
132 | } | |
133 | ||
134 | void | |
740593ff | 135 | client_handle_port_related(struct lldpd *cfg, struct hmsg *r, struct hmsg *s) |
a552a72e VB |
136 | { |
137 | char *ifname; | |
138 | struct lldpd_hardware *hardware; | |
84853b92 | 139 | struct lldpd_port *port; |
a552a72e | 140 | void *p; |
740593ff | 141 | int i; |
a552a72e VB |
142 | |
143 | ifname = (char*)(&r->data); | |
740593ff VB |
144 | if ((r->hdr.len < IFNAMSIZ) || (ifname[IFNAMSIZ - 1] != 0)) { |
145 | LLOG_WARNX("bad message format for get port related message (%d)", | |
146 | r->hdr.type); | |
a552a72e VB |
147 | s->hdr.len = -1; |
148 | return; | |
149 | } | |
150 | TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) { | |
151 | if (strncmp(ifname, hardware->h_ifname, IFNAMSIZ) == 0) { | |
a552a72e | 152 | switch (r->hdr.type) { |
740593ff VB |
153 | #ifdef ENABLE_LLDPMED |
154 | case HMSG_SET_LOCATION: | |
155 | p = (char*)&r->data + IFNAMSIZ; | |
156 | for (i=0; i < LLDPMED_LOCFORMAT_LAST; i++) { | |
157 | free(hardware->h_lport.p_med_location[i].data); | |
158 | hardware->h_lport.p_med_location[i].data = NULL; | |
159 | hardware->h_lport.p_med_location[i].format = 0; | |
160 | } | |
161 | if (ctl_msg_unpack_structure(STRUCT_LLDPD_MED_LOC | |
162 | STRUCT_LLDPD_MED_LOC STRUCT_LLDPD_MED_LOC, | |
163 | hardware->h_lport.p_med_location, | |
164 | 3*sizeof(struct lldpd_med_loc), r, &p) == -1) { | |
165 | LLOG_WARNX("unable to set location for %s", ifname); | |
166 | s->hdr.len = -1; | |
167 | return; | |
168 | } | |
169 | hardware->h_lport.p_med_cap_enabled |= LLDPMED_CAP_LOCATION; | |
170 | break; | |
86f24df3 VB |
171 | case HMSG_SET_POLICY: |
172 | p = (char*)&r->data + IFNAMSIZ; | |
173 | for (i=0; i < LLDPMED_APPTYPE_LAST; i++) { | |
174 | hardware->h_lport.p_med_policy[i].type = 0; | |
175 | hardware->h_lport.p_med_policy[i].unknown = 0; | |
176 | hardware->h_lport.p_med_policy[i].tagged = 0; | |
177 | hardware->h_lport.p_med_policy[i].vid = 0; | |
178 | hardware->h_lport.p_med_policy[i].priority = 0; | |
179 | hardware->h_lport.p_med_policy[i].dscp = 0; | |
180 | } | |
181 | if (ctl_msg_unpack_structure( | |
182 | STRUCT_LLDPD_MED_POLICY | |
183 | STRUCT_LLDPD_MED_POLICY | |
184 | STRUCT_LLDPD_MED_POLICY | |
185 | STRUCT_LLDPD_MED_POLICY | |
186 | STRUCT_LLDPD_MED_POLICY | |
187 | STRUCT_LLDPD_MED_POLICY | |
188 | STRUCT_LLDPD_MED_POLICY | |
189 | STRUCT_LLDPD_MED_POLICY, | |
190 | hardware->h_lport.p_med_policy, | |
191 | 8*sizeof(struct lldpd_med_policy), | |
192 | r, &p) == -1) { | |
193 | LLOG_WARNX("unable to set network policy for %s", ifname); | |
194 | s->hdr.len = -1; | |
195 | return; | |
196 | } | |
197 | hardware->h_lport.p_med_cap_enabled |= | |
198 | LLDPMED_CAP_POLICY; | |
199 | break; | |
009ddd23 VB |
200 | case HMSG_SET_POWER: |
201 | p = (char*)&r->data + IFNAMSIZ; | |
202 | memset(&hardware->h_lport.p_med_power, 0, | |
203 | sizeof(struct lldpd_med_power)); | |
204 | if (ctl_msg_unpack_structure(STRUCT_LLDPD_MED_POWER, | |
205 | &hardware->h_lport.p_med_power, | |
206 | sizeof(struct lldpd_med_power), | |
207 | r, &p) == -1) { | |
208 | LLOG_WARNX("unable to set POE-MDI for %s", | |
209 | ifname); | |
210 | s->hdr.len = -1; | |
211 | return; | |
212 | } | |
213 | hardware->h_lport.p_med_cap_enabled &= ~( | |
214 | LLDPMED_CAP_MDI_PD | LLDPMED_CAP_MDI_PSE); | |
215 | switch (hardware->h_lport.p_med_power.devicetype) | |
216 | { | |
217 | case LLDPMED_POW_TYPE_PSE: | |
218 | hardware->h_lport.p_med_cap_enabled |= | |
219 | LLDPMED_CAP_MDI_PSE; | |
220 | break; | |
221 | case LLDPMED_POW_TYPE_PD: | |
222 | hardware->h_lport.p_med_cap_enabled |= | |
223 | LLDPMED_CAP_MDI_PD; | |
224 | break; | |
225 | } | |
226 | break; | |
740593ff | 227 | #endif |
84853b92 VB |
228 | case HMSG_GET_NB_PORTS: |
229 | p = &s->data; | |
230 | i = 0; | |
42b39485 VB |
231 | TAILQ_FOREACH(port, &hardware->h_rports, p_entries) { |
232 | if (SMART_HIDDEN(cfg, port)) continue; | |
233 | i++; | |
234 | } | |
84853b92 VB |
235 | memcpy(p, &i, sizeof(int)); |
236 | s->hdr.len = sizeof(int); | |
237 | break; | |
a552a72e | 238 | case HMSG_GET_VLANS: |
84853b92 VB |
239 | case HMSG_GET_PORT: |
240 | case HMSG_GET_CHASSIS: | |
241 | /* We read the index which is right after the interface name */ | |
242 | if (r->hdr.len < IFNAMSIZ + sizeof(int)) { | |
243 | LLOG_WARNX("too short message format for get " | |
244 | "port related message (%d)", r->hdr.type); | |
a552a72e VB |
245 | s->hdr.len = -1; |
246 | return; | |
247 | } | |
84853b92 VB |
248 | p = (char*)&r->data + IFNAMSIZ; |
249 | memcpy(&i, p, sizeof(int)); | |
250 | p = &s->data; | |
42b39485 VB |
251 | TAILQ_FOREACH(port, &hardware->h_rports, p_entries) { |
252 | if (SMART_HIDDEN(cfg, port)) continue; | |
253 | if (i-- == 0) break; | |
254 | } | |
84853b92 VB |
255 | if (!port) { |
256 | LLOG_INFO("out of range index requested for port " | |
257 | "related information on interface %s for %d", | |
258 | ifname, r->hdr.pid); | |
a552a72e VB |
259 | s->hdr.len = -1; |
260 | return; | |
261 | } | |
84853b92 VB |
262 | p = (char*)&s->data; |
263 | switch (r->hdr.type) { | |
264 | #ifdef ENABLE_DOT1 | |
265 | case HMSG_GET_VLANS: | |
266 | if (ctl_msg_pack_list(STRUCT_LLDPD_VLAN, | |
267 | &port->p_vlans, | |
268 | sizeof(struct lldpd_vlan), s, &p) == -1) { | |
269 | LLOG_WARNX("unable to send vlans information for " | |
270 | "interface %s for %d", ifname, r->hdr.pid); | |
271 | s->hdr.len = -1; | |
272 | return; | |
273 | } | |
274 | break; | |
275 | #endif | |
276 | case HMSG_GET_PORT: | |
277 | if (ctl_msg_pack_structure(STRUCT_LLDPD_PORT, | |
278 | port, | |
279 | sizeof(struct lldpd_port), s, &p) == -1) { | |
280 | LLOG_WARNX("unable to send port information for " | |
281 | "interface %s for %d", ifname, r->hdr.pid); | |
282 | s->hdr.len = -1; | |
283 | return; | |
284 | } | |
285 | break; | |
286 | case HMSG_GET_CHASSIS: | |
287 | if (ctl_msg_pack_structure(STRUCT_LLDPD_CHASSIS, | |
288 | port->p_chassis, | |
289 | sizeof(struct lldpd_chassis), s, &p) == -1) { | |
290 | LLOG_WARNX("unable to send chassis information " | |
291 | "for interface %s for %d", | |
292 | ifname, r->hdr.pid); | |
293 | s->hdr.len = -1; | |
294 | return; | |
295 | } | |
296 | break; | |
297 | default: | |
298 | LLOG_WARNX("don't know what to do"); | |
a552a72e VB |
299 | s->hdr.len = -1; |
300 | return; | |
301 | } | |
302 | break; | |
303 | default: | |
304 | LLOG_WARNX("don't know what to do"); | |
305 | s->hdr.len = -1; | |
306 | return; | |
307 | } | |
308 | return; | |
309 | } | |
310 | } | |
311 | LLOG_WARNX("requested interface %s by %d was not found", | |
312 | ifname, r->hdr.pid); | |
313 | s->hdr.len = -1; | |
314 | return; | |
315 | } |