]>
Commit | Line | Data |
---|---|---|
43c02e7b 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 | ||
19 | #include <stdio.h> | |
20 | #include <unistd.h> | |
21 | #include <errno.h> | |
22 | #include <sys/types.h> | |
23 | #include <sys/socket.h> | |
24 | #include <sys/un.h> | |
25 | #include <arpa/inet.h> | |
26 | ||
8888d191 | 27 | static void usage(void); |
43c02e7b VB |
28 | |
29 | TAILQ_HEAD(interfaces, lldpd_interface); | |
a1347cd8 | 30 | #ifdef ENABLE_DOT1 |
43c02e7b | 31 | TAILQ_HEAD(vlans, lldpd_vlan); |
a1347cd8 | 32 | #endif |
43c02e7b | 33 | |
650cae58 VB |
34 | #define ntohll(x) (((u_int64_t)(ntohl((int)((x << 32) >> 32))) << 32) | \ |
35 | (unsigned int)ntohl(((int)(x >> 32)))) | |
36 | #define htonll(x) ntohll(x) | |
37 | ||
38 | ||
43c02e7b VB |
39 | struct value_string { |
40 | int value; | |
41 | char *string; | |
42 | }; | |
43 | ||
650cae58 VB |
44 | #ifdef ENABLE_LLDPMED |
45 | static const struct value_string civic_address_type_values[] = { | |
46 | { 0, "Language" }, | |
47 | { 1, "National subdivisions" }, | |
48 | { 2, "County, parish, district" }, | |
49 | { 3, "City, township" }, | |
50 | { 4, "City division, borough, ward" }, | |
51 | { 5, "Neighborhood, block" }, | |
52 | { 6, "Street" }, | |
53 | { 16, "Leading street direction" }, | |
54 | { 17, "Trailing street suffix" }, | |
55 | { 18, "Street suffix" }, | |
56 | { 19, "House number" }, | |
57 | { 20, "House number suffix" }, | |
58 | { 21, "Landmark or vanity address" }, | |
59 | { 22, "Additional location info" }, | |
60 | { 23, "Name" }, | |
61 | { 24, "Postal/ZIP code" }, | |
62 | { 25, "Building" }, | |
63 | { 26, "Unit" }, | |
64 | { 27, "Floor" }, | |
65 | { 28, "Room number" }, | |
66 | { 29, "Place type" }, | |
67 | { 128, "Script" }, | |
68 | { 0, NULL } | |
69 | }; | |
70 | #endif | |
71 | ||
a1347cd8 | 72 | #ifdef ENABLE_DOT3 |
43c02e7b VB |
73 | static const struct value_string operational_mau_type_values[] = { |
74 | { 1, "AUI - no internal MAU, view from AUI" }, | |
75 | { 2, "10Base5 - thick coax MAU" }, | |
76 | { 3, "Foirl - FOIRL MAU" }, | |
77 | { 4, "10Base2 - thin coax MAU" }, | |
78 | { 5, "10BaseT - UTP MAU" }, | |
79 | { 6, "10BaseFP - passive fiber MAU" }, | |
80 | { 7, "10BaseFB - sync fiber MAU" }, | |
81 | { 8, "10BaseFL - async fiber MAU" }, | |
82 | { 9, "10Broad36 - broadband DTE MAU" }, | |
83 | { 10, "10BaseTHD - UTP MAU, half duplex mode" }, | |
84 | { 11, "10BaseTFD - UTP MAU, full duplex mode" }, | |
85 | { 12, "10BaseFLHD - async fiber MAU, half duplex mode" }, | |
86 | { 13, "10BaseFLDF - async fiber MAU, full duplex mode" }, | |
87 | { 14, "10BaseT4 - 4 pair category 3 UTP" }, | |
88 | { 15, "100BaseTXHD - 2 pair category 5 UTP, half duplex mode" }, | |
89 | { 16, "100BaseTXFD - 2 pair category 5 UTP, full duplex mode" }, | |
90 | { 17, "100BaseFXHD - X fiber over PMT, half duplex mode" }, | |
91 | { 18, "100BaseFXFD - X fiber over PMT, full duplex mode" }, | |
92 | { 19, "100BaseT2HD - 2 pair category 3 UTP, half duplex mode" }, | |
93 | { 20, "100BaseT2DF - 2 pair category 3 UTP, full duplex mode" }, | |
94 | { 21, "1000BaseXHD - PCS/PMA, unknown PMD, half duplex mode" }, | |
95 | { 22, "1000BaseXFD - PCS/PMA, unknown PMD, full duplex mode" }, | |
96 | { 23, "1000BaseLXHD - Fiber over long-wavelength laser, half duplex mode" }, | |
97 | { 24, "1000BaseLXFD - Fiber over long-wavelength laser, full duplex mode" }, | |
98 | { 25, "1000BaseSXHD - Fiber over short-wavelength laser, half duplex mode" }, | |
99 | { 26, "1000BaseSXFD - Fiber over short-wavelength laser, full duplex mode" }, | |
100 | { 27, "1000BaseCXHD - Copper over 150-Ohm balanced cable, half duplex mode" }, | |
101 | { 28, "1000BaseCXFD - Copper over 150-Ohm balanced cable, full duplex mode" }, | |
102 | { 29, "1000BaseTHD - Four-pair Category 5 UTP, half duplex mode" }, | |
103 | { 30, "1000BaseTFD - Four-pair Category 5 UTP, full duplex mode" }, | |
104 | { 31, "10GigBaseX - X PCS/PMA, unknown PMD." }, | |
105 | { 32, "10GigBaseLX4 - X fiber over WWDM optics" }, | |
106 | { 33, "10GigBaseR - R PCS/PMA, unknown PMD." }, | |
107 | { 34, "10GigBaseER - R fiber over 1550 nm optics" }, | |
108 | { 35, "10GigBaseLR - R fiber over 1310 nm optics" }, | |
109 | { 36, "10GigBaseSR - R fiber over 850 nm optics" }, | |
110 | { 37, "10GigBaseW - W PCS/PMA, unknown PMD." }, | |
111 | { 38, "10GigBaseEW - W fiber over 1550 nm optics" }, | |
112 | { 39, "10GigBaseLW - W fiber over 1310 nm optics" }, | |
113 | { 40, "10GigBaseSW - W fiber over 850 nm optics" }, | |
4b7f39b1 VB |
114 | { 41, "10GigBaseCX4 - X copper over 8 pair 100-Ohm balanced cable" }, |
115 | { 42, "2BaseTL - Voice grade UTP copper, up to 2700m, optional PAF" }, | |
116 | { 43, "10PassTS - Voice grade UTP copper, up to 750m, optional PAF" }, | |
117 | { 44, "100BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" }, | |
118 | { 45, "100BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" }, | |
119 | { 46, "100BaseLX10 - Two single-mode fibers, long wavelength, 10km" }, | |
120 | { 47, "1000BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" }, | |
121 | { 48, "1000BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" }, | |
122 | { 49, "1000BaseLX10 - Two sigle-mode fiber, long wavelength, 10km" }, | |
123 | { 50, "1000BasePX10D - One single-mode fiber EPON OLT, 10km" }, | |
124 | { 51, "1000BasePX10U - One single-mode fiber EPON ONU, 10km" }, | |
125 | { 52, "1000BasePX20D - One single-mode fiber EPON OLT, 20km" }, | |
126 | { 53, "1000BasePX20U - One single-mode fiber EPON ONU, 20km" }, | |
43c02e7b VB |
127 | { 0, NULL } |
128 | }; | |
a1347cd8 | 129 | #endif |
43c02e7b | 130 | |
8888d191 | 131 | static void |
43c02e7b VB |
132 | usage(void) |
133 | { | |
134 | extern const char *__progname; | |
135 | ||
740593ff VB |
136 | fprintf(stderr, "usage: %s [options]\n", __progname); |
137 | fprintf(stderr, "see manual page lldpctl(8) for more information\n"); | |
43c02e7b VB |
138 | exit(1); |
139 | } | |
140 | ||
141 | static char* | |
142 | dump(void *data, int size, int max, char sep) | |
143 | { | |
144 | int i; | |
145 | size_t len; | |
146 | static char *buffer = NULL; | |
147 | static char truncation[] = "[...]"; | |
148 | ||
149 | free(buffer); | |
150 | if (size > max) | |
151 | len = max * 3 + sizeof(truncation) + 1; | |
152 | else | |
153 | len = size * 3; | |
154 | ||
155 | if ((buffer = (char *)malloc(len)) == NULL) | |
156 | fatal(NULL); | |
157 | ||
158 | for (i = 0; (i < size) && (i < max); i++) | |
159 | sprintf(buffer + i * 3, "%02x%c", *(u_int8_t*)(data + i), sep); | |
160 | if (size > max) | |
161 | sprintf(buffer + i * 3, "%s", truncation); | |
162 | else | |
163 | *(buffer + i*3 - 1) = 0; | |
164 | return buffer; | |
165 | } | |
166 | ||
167 | ||
8888d191 | 168 | static void |
43c02e7b VB |
169 | get_interfaces(int s, struct interfaces *ifs) |
170 | { | |
171 | void *p; | |
172 | struct hmsg *h; | |
173 | ||
174 | if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) | |
175 | fatal(NULL); | |
176 | ctl_msg_init(h, HMSG_GET_INTERFACES); | |
177 | if (ctl_msg_send(s, h) == -1) | |
178 | fatalx("get_interfaces: unable to send request"); | |
179 | if (ctl_msg_recv(s, h) == -1) | |
180 | fatalx("get_interfaces: unable to receive answer"); | |
181 | if (h->hdr.type != HMSG_GET_INTERFACES) | |
182 | fatalx("get_interfaces: unknown answer type received"); | |
183 | p = &h->data; | |
184 | if (ctl_msg_unpack_list(STRUCT_LLDPD_INTERFACE, | |
185 | ifs, sizeof(struct lldpd_interface), h, &p) == -1) | |
186 | fatalx("get_interfaces: unable to retrieve the list of interfaces"); | |
187 | } | |
188 | ||
a1347cd8 | 189 | #ifdef ENABLE_DOT1 |
8888d191 | 190 | static int |
84853b92 | 191 | get_vlans(int s, struct vlans *vls, char *interface, int nb) |
43c02e7b VB |
192 | { |
193 | void *p; | |
194 | struct hmsg *h; | |
195 | ||
196 | if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) | |
197 | fatal(NULL); | |
198 | ctl_msg_init(h, HMSG_GET_VLANS); | |
740593ff | 199 | strlcpy((char *)&h->data, interface, IFNAMSIZ); |
84853b92 VB |
200 | memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int)); |
201 | h->hdr.len += IFNAMSIZ + sizeof(int); | |
43c02e7b VB |
202 | if (ctl_msg_send(s, h) == -1) |
203 | fatalx("get_vlans: unable to send request"); | |
204 | if (ctl_msg_recv(s, h) == -1) | |
205 | fatalx("get_vlans: unable to receive answer"); | |
206 | if (h->hdr.type != HMSG_GET_VLANS) | |
207 | fatalx("get_vlans: unknown answer type received"); | |
208 | p = &h->data; | |
209 | if (ctl_msg_unpack_list(STRUCT_LLDPD_VLAN, | |
210 | vls, sizeof(struct lldpd_vlan), h, &p) == -1) | |
211 | fatalx("get_vlans: unable to retrieve the list of vlans"); | |
212 | return 1; | |
213 | } | |
a1347cd8 | 214 | #endif |
43c02e7b | 215 | |
8888d191 | 216 | static int |
84853b92 | 217 | get_chassis(int s, struct lldpd_chassis *chassis, char *interface, int nb) |
43c02e7b VB |
218 | { |
219 | struct hmsg *h; | |
220 | void *p; | |
221 | ||
222 | if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) | |
223 | fatal(NULL); | |
224 | ctl_msg_init(h, HMSG_GET_CHASSIS); | |
740593ff | 225 | strlcpy((char *)&h->data, interface, IFNAMSIZ); |
84853b92 VB |
226 | memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int)); |
227 | h->hdr.len += IFNAMSIZ + sizeof(int); | |
43c02e7b VB |
228 | if (ctl_msg_send(s, h) == -1) |
229 | fatalx("get_chassis: unable to send request to get chassis"); | |
230 | if (ctl_msg_recv(s, h) == -1) | |
231 | fatalx("get_chassis: unable to receive answer to get chassis"); | |
232 | if (h->hdr.type == HMSG_NONE) | |
233 | /* No chassis */ | |
234 | return -1; | |
235 | p = &h->data; | |
236 | if (ctl_msg_unpack_structure(STRUCT_LLDPD_CHASSIS, | |
237 | chassis, sizeof(struct lldpd_chassis), h, &p) == -1) { | |
238 | LLOG_WARNX("unable to retrieve chassis for %s", interface); | |
239 | fatalx("get_chassis: abort"); | |
240 | } | |
241 | return 1; | |
242 | } | |
243 | ||
8888d191 | 244 | static int |
84853b92 | 245 | get_port(int s, struct lldpd_port *port, char *interface, int nb) |
43c02e7b VB |
246 | { |
247 | struct hmsg *h; | |
248 | void *p; | |
249 | ||
250 | if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) | |
251 | fatal(NULL); | |
252 | ctl_msg_init(h, HMSG_GET_PORT); | |
740593ff | 253 | strlcpy((char *)&h->data, interface, IFNAMSIZ); |
84853b92 VB |
254 | memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int)); |
255 | h->hdr.len += IFNAMSIZ + sizeof(int); | |
43c02e7b VB |
256 | if (ctl_msg_send(s, h) == -1) |
257 | fatalx("get_port: unable to send request to get port"); | |
258 | if (ctl_msg_recv(s, h) == -1) | |
259 | fatalx("get_port: unable to receive answer to get port"); | |
260 | if (h->hdr.type == HMSG_NONE) | |
261 | /* No port */ | |
262 | return -1; | |
263 | p = &h->data; | |
264 | if (ctl_msg_unpack_structure(STRUCT_LLDPD_PORT, | |
265 | port, sizeof(struct lldpd_port), h, &p) == -1) { | |
266 | LLOG_WARNX("unable to retrieve port information for %s", | |
267 | interface); | |
268 | fatalx("get_chassis: abort"); | |
269 | } | |
270 | return 1; | |
271 | } | |
272 | ||
84853b92 VB |
273 | static int |
274 | get_nb_port(int s, char *interface) | |
275 | { | |
276 | struct hmsg *h; | |
277 | int nb; | |
278 | ||
279 | if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) | |
280 | fatal(NULL); | |
281 | ctl_msg_init(h, HMSG_GET_NB_PORTS); | |
282 | strlcpy((char *)&h->data, interface, IFNAMSIZ); | |
283 | h->hdr.len += IFNAMSIZ; | |
284 | if (ctl_msg_send(s, h) == -1) | |
285 | fatalx("get_nb_port: unable to send request to get number of ports"); | |
286 | if (ctl_msg_recv(s, h) == -1) | |
287 | fatalx("get_nb_port: unable to receive answer to get number of ports"); | |
288 | if (h->hdr.type == HMSG_NONE) | |
289 | return -1; | |
290 | if (h->hdr.len != sizeof(int)) | |
291 | fatalx("get_nb_port: bad message length"); | |
292 | memcpy(&nb, &h->data, sizeof(int)); | |
293 | return nb; | |
294 | } | |
295 | ||
8888d191 | 296 | static void |
43c02e7b VB |
297 | display_cap(struct lldpd_chassis *chassis, u_int8_t bit, char *symbol) |
298 | { | |
299 | if (chassis->c_cap_available & bit) | |
300 | printf("%s(%c) ", symbol, | |
301 | (chassis->c_cap_enabled & bit)?'E':'d'); | |
302 | } | |
303 | ||
8888d191 | 304 | static void |
43c02e7b VB |
305 | pretty_print(char *string) |
306 | { | |
307 | char *s = NULL; | |
f0bd3505 | 308 | if (((s = strchr(string, '\n')) == NULL) && (strlen(string) < 60)) { |
43c02e7b VB |
309 | printf("%s\n", string); |
310 | return; | |
311 | } else | |
312 | printf("\n"); | |
313 | while (s != NULL) { | |
314 | *s = '\0'; | |
315 | printf(" %s\n", string); | |
316 | *s = '\n'; | |
317 | string = s + 1; | |
f0bd3505 | 318 | s = strchr(string, '\n'); |
43c02e7b VB |
319 | } |
320 | printf(" %s\n", string); | |
321 | } | |
322 | ||
6772b237 | 323 | #ifdef ENABLE_LLDPMED |
8888d191 | 324 | static int |
1e379fe3 | 325 | display_fixed_precision(u_int64_t value, int intpart, int floatpart, int displaysign) |
650cae58 | 326 | { |
650cae58 VB |
327 | u_int64_t tmp = value; |
328 | int negative = 0; | |
329 | u_int32_t integer = 0; | |
115ff55c | 330 | if (value & (1ULL<<(intpart + floatpart - 1))) { |
650cae58 VB |
331 | negative = 1; |
332 | tmp = ~value; | |
333 | tmp += 1; | |
334 | } | |
1e379fe3 VB |
335 | integer = (u_int32_t)((tmp & |
336 | (((1ULL << intpart)-1) << floatpart)) >> floatpart); | |
337 | tmp = (tmp & ((1<< floatpart) - 1))*10000/(1ULL << floatpart); | |
338 | printf("%s%u.%04llu", displaysign?(negative?"-":"+"):"", | |
339 | integer, (unsigned long long int)tmp); | |
340 | return negative; | |
341 | } | |
342 | ||
8888d191 | 343 | static void |
1e379fe3 VB |
344 | display_latitude_or_longitude(int option, u_int64_t value) |
345 | { | |
346 | int negative; | |
347 | negative = display_fixed_precision(value, 9, 25, 0); | |
348 | if (option == 0) | |
349 | printf("%s", negative?" South":" North"); | |
350 | else | |
351 | printf("%s", negative?" West":" East"); | |
650cae58 VB |
352 | } |
353 | ||
8888d191 | 354 | static void |
740593ff | 355 | display_med(struct lldpd_chassis *chassis, struct lldpd_port *port) |
6772b237 | 356 | { |
e3a44efb | 357 | int i; |
650cae58 | 358 | char *value; |
efe3f9b0 | 359 | printf(" LLDP-MED Device Type: "); |
6772b237 VB |
360 | switch (chassis->c_med_type) { |
361 | case LLDPMED_CLASS_I: | |
362 | printf("Generic Endpoint (Class I)"); | |
363 | break; | |
364 | case LLDPMED_CLASS_II: | |
365 | printf("Media Endpoint (Class II)"); | |
366 | break; | |
367 | case LLDPMED_CLASS_III: | |
368 | printf("Communication Device Endpoint (Class III)"); | |
369 | break; | |
370 | case LLDPMED_NETWORK_DEVICE: | |
371 | printf("Network Connectivity Device"); | |
372 | break; | |
373 | default: | |
374 | printf("Unknown (%d)", chassis->c_med_type); | |
375 | break; | |
376 | } | |
efe3f9b0 | 377 | printf("\n LLDP-MED Capabilities:"); |
4982b864 | 378 | if (chassis->c_med_cap_available & LLDPMED_CAP_CAP) |
6772b237 | 379 | printf(" Capabilities"); |
4982b864 | 380 | if (chassis->c_med_cap_available & LLDPMED_CAP_POLICY) |
6772b237 | 381 | printf(" Policy"); |
4982b864 | 382 | if (chassis->c_med_cap_available & LLDPMED_CAP_LOCATION) |
6772b237 | 383 | printf(" Location"); |
4982b864 | 384 | if (chassis->c_med_cap_available & LLDPMED_CAP_MDI_PSE) |
a49b3a79 | 385 | printf(" MDI/PSE"); |
4982b864 | 386 | if (chassis->c_med_cap_available & LLDPMED_CAP_MDI_PD) |
a49b3a79 | 387 | printf(" MDI/PD"); |
4982b864 | 388 | if (chassis->c_med_cap_available & LLDPMED_CAP_IV) |
6772b237 VB |
389 | printf(" Inventory"); |
390 | printf("\n"); | |
e3a44efb | 391 | for (i = 0; i < LLDPMED_APPTYPE_LAST; i++) { |
740593ff | 392 | if (i+1 == port->p_med_policy[i].type) { |
e3a44efb | 393 | printf(" LLDP-MED Network Policy for "); |
740593ff | 394 | switch(port->p_med_policy[i].type) { |
e3a44efb VB |
395 | case LLDPMED_APPTYPE_VOICE: |
396 | printf("Voice"); | |
397 | break; | |
398 | case LLDPMED_APPTYPE_VOICESIGNAL: | |
399 | printf("Voice Signaling"); | |
400 | break; | |
401 | case LLDPMED_APPTYPE_GUESTVOICE: | |
402 | printf("Guest Voice"); | |
403 | break; | |
404 | case LLDPMED_APPTYPE_GUESTVOICESIGNAL: | |
405 | printf("Guest Voice Signaling"); | |
406 | break; | |
407 | case LLDPMED_APPTYPE_SOFTPHONEVOICE: | |
408 | printf("Softphone Voice"); | |
409 | break; | |
410 | case LLDPMED_APPTYPE_VIDEOCONFERENCE: | |
411 | printf("Video Conferencing"); | |
412 | break; | |
413 | case LLDPMED_APPTYPE_VIDEOSTREAM: | |
414 | printf("Streaming Video"); | |
415 | break; | |
416 | case LLDPMED_APPTYPE_VIDEOSIGNAL: | |
417 | printf("Video Signaling"); | |
418 | break; | |
419 | default: | |
420 | printf("Reserved"); | |
421 | } | |
422 | printf(":\n Policy: "); | |
740593ff | 423 | if (port->p_med_policy[i].unknown) { |
e3a44efb VB |
424 | printf("unknown, "); |
425 | } else { | |
426 | printf("defined, "); | |
427 | } | |
740593ff | 428 | if (!port->p_med_policy[i].tagged) { |
e3a44efb VB |
429 | printf("un"); |
430 | } | |
431 | printf("tagged"); | |
432 | printf("\n VLAN ID: "); | |
740593ff | 433 | if (port->p_med_policy[i].vid == 0) { |
e3a44efb | 434 | printf("Priority Tagged"); |
740593ff | 435 | } else if (port->p_med_policy[i].vid == 4095) { |
e3a44efb VB |
436 | printf("reserved"); |
437 | } else { | |
740593ff | 438 | printf("%u", port->p_med_policy[i].vid); |
e3a44efb VB |
439 | } |
440 | printf("\n Layer 2 Priority: "); | |
740593ff | 441 | printf("%u", port->p_med_policy[i].priority); |
e3a44efb | 442 | printf("\n DSCP Value: "); |
740593ff | 443 | printf("%u\n", port->p_med_policy[i].dscp); |
efe3f9b0 | 444 | } |
efe3f9b0 | 445 | } |
e3a44efb | 446 | for (i = 0; i < LLDPMED_LOCFORMAT_LAST; i++) { |
740593ff | 447 | if (i+1 == port->p_med_location[i].format) { |
e3a44efb | 448 | printf(" LLDP-MED Location Identification: "); |
740593ff | 449 | switch(port->p_med_location[i].format) { |
e3a44efb | 450 | case LLDPMED_LOCFORMAT_COORD: |
1e379fe3 | 451 | printf("\n Coordinate-based data: "); |
740593ff | 452 | if (port->p_med_location[i].data_len != 16) |
650cae58 VB |
453 | printf("bad data length"); |
454 | else { | |
455 | u_int64_t l; | |
1e379fe3 VB |
456 | |
457 | /* Latitude and longitude */ | |
3d1337f3 VB |
458 | memcpy(&l, port->p_med_location[i].data, |
459 | sizeof(u_int64_t)); | |
460 | l = (ntohll(l) & | |
0d83ebae | 461 | 0x03FFFFFFFF000000ULL) >> 24; |
650cae58 VB |
462 | display_latitude_or_longitude(0, l); |
463 | printf(", "); | |
3d1337f3 VB |
464 | memcpy(&l, port->p_med_location[i].data + 5, |
465 | sizeof(u_int64_t)); | |
466 | l = (ntohll(l) & | |
0d83ebae | 467 | 0x03FFFFFFFF000000ULL) >> 24; |
650cae58 | 468 | display_latitude_or_longitude(1, l); |
1e379fe3 VB |
469 | |
470 | /* Altitude */ | |
471 | printf(", "); | |
3d1337f3 VB |
472 | memcpy(&l, port->p_med_location[i].data + 10, |
473 | sizeof(u_int64_t)); | |
474 | l = (ntohll(l) & | |
1e379fe3 VB |
475 | 0x3FFFFFFF000000ULL) >> 24; |
476 | display_fixed_precision(l, 22, 8, 1); | |
740593ff | 477 | switch ((*(u_int8_t*)(port->p_med_location[i].data + |
1e379fe3 VB |
478 | 10)) & 0xf0) { |
479 | case (1 << 4): | |
480 | printf(" meters"); break; | |
481 | case (2 << 4): | |
482 | printf(" floors"); break; | |
483 | default: | |
484 | printf(" (unknown)"); | |
485 | } | |
486 | ||
487 | /* Datum */ | |
740593ff | 488 | switch (*(u_int8_t*)(port->p_med_location[i].data + |
1e379fe3 VB |
489 | 15)) { |
490 | case 1: | |
491 | printf(", WGS84"); break; | |
492 | case 2: | |
493 | printf(", NAD83"); break; | |
494 | case 3: | |
495 | printf(", NAD83/MLLW"); break; | |
496 | } | |
650cae58 | 497 | } |
e3a44efb VB |
498 | break; |
499 | case LLDPMED_LOCFORMAT_CIVIC: | |
650cae58 | 500 | printf("Civic address: "); |
740593ff VB |
501 | if ((port->p_med_location[i].data_len < 3) || |
502 | (port->p_med_location[i].data_len - 1 != | |
503 | *(u_int8_t*)port->p_med_location[i].data)) | |
650cae58 VB |
504 | printf("bad data length"); |
505 | else { | |
506 | int l = 4, n, catype, calength, j = 0; | |
507 | printf("\n%28s: %c%c", "Country", | |
740593ff VB |
508 | ((char *)port->p_med_location[i].data)[2], |
509 | ((char *)port->p_med_location[i].data)[3]); | |
510 | while ((n = (port-> | |
511 | p_med_location[i].data_len - l)) >= 2) { | |
512 | catype = *(u_int8_t*)(port-> | |
513 | p_med_location[i].data + l); | |
514 | calength = *(u_int8_t*)(port-> | |
515 | p_med_location[i].data + l + 1); | |
650cae58 VB |
516 | if (n < 2 + calength) { |
517 | printf("bad data length"); | |
518 | break; | |
519 | } | |
520 | for (j = 0; | |
521 | civic_address_type_values[j].string != NULL; | |
522 | j++) { | |
523 | if (civic_address_type_values[j].value == | |
524 | catype) | |
525 | break; | |
526 | } | |
527 | if (civic_address_type_values[j].string == NULL) { | |
528 | printf("unknown type %d", catype); | |
529 | break; | |
530 | } | |
740593ff VB |
531 | if ((value = strndup((char *)(port-> |
532 | p_med_location[i].data + l + 2), | |
650cae58 VB |
533 | calength)) == NULL) { |
534 | printf("not enough memory"); | |
535 | break; | |
536 | } | |
537 | printf("\n%28s: %s", | |
538 | civic_address_type_values[j].string, | |
539 | value); | |
540 | free(value); | |
541 | l += 2 + calength; | |
542 | } | |
543 | } | |
e3a44efb VB |
544 | break; |
545 | case LLDPMED_LOCFORMAT_ELIN: | |
740593ff VB |
546 | if ((value = strndup((char *)(port-> |
547 | p_med_location[i].data), | |
548 | port->p_med_location[i].data_len)) == NULL) { | |
650cae58 VB |
549 | printf("not enough memory"); |
550 | break; | |
551 | } | |
552 | printf("ECS ELIN: %s", value); | |
553 | free(value); | |
e3a44efb VB |
554 | break; |
555 | default: | |
556 | printf("unknown location data format: \n %s", | |
740593ff VB |
557 | dump(port->p_med_location[i].data, |
558 | port->p_med_location[i].data_len, 20, ' ')); | |
e3a44efb VB |
559 | } |
560 | printf("\n"); | |
efe3f9b0 | 561 | } |
efe3f9b0 | 562 | } |
740593ff | 563 | if (port->p_med_pow_devicetype) { |
efe3f9b0 VB |
564 | printf(" LLDP-MED Extended Power-over-Ethernet:\n"); |
565 | printf(" Power Type & Source: "); | |
740593ff | 566 | switch (port->p_med_pow_devicetype) { |
994812b9 | 567 | case LLDPMED_POW_TYPE_PSE: |
efe3f9b0 | 568 | printf("PSE Device"); |
994812b9 VB |
569 | break; |
570 | case LLDPMED_POW_TYPE_PD: | |
efe3f9b0 | 571 | printf("PD Device"); |
994812b9 VB |
572 | break; |
573 | default: | |
efe3f9b0 VB |
574 | printf("reserved"); |
575 | } | |
740593ff | 576 | switch (port->p_med_pow_source) { |
994812b9 VB |
577 | case LLDPMED_POW_SOURCE_UNKNOWN: |
578 | case LLDPMED_POW_SOURCE_RESERVED: | |
579 | printf(", unknown"); break; | |
580 | case LLDPMED_POW_SOURCE_PRIMARY: | |
581 | printf(", Primary Power Source"); | |
582 | break; | |
583 | case LLDPMED_POW_SOURCE_BACKUP: | |
584 | printf(", Backup Power Source / Power Conservation Mode"); | |
585 | break; | |
586 | case LLDPMED_POW_SOURCE_PSE: | |
587 | printf(", PSE"); break; | |
588 | case LLDPMED_POW_SOURCE_LOCAL: | |
589 | printf(", local"); break; | |
590 | case LLDPMED_POW_SOURCE_BOTH: | |
591 | printf(", PSE & local"); | |
592 | break; | |
593 | } | |
e3a44efb | 594 | printf("\n Power Priority: "); |
740593ff | 595 | switch (port->p_med_pow_priority) { |
994812b9 VB |
596 | case LLDPMED_POW_PRIO_CRITICAL: |
597 | printf("critical"); break; | |
598 | case LLDPMED_POW_PRIO_HIGH: | |
599 | printf("high"); break; | |
600 | case LLDPMED_POW_PRIO_LOW: | |
601 | printf("low"); break; | |
602 | default: | |
efe3f9b0 | 603 | printf("unknown"); |
efe3f9b0 | 604 | } |
e3a44efb | 605 | printf("\n Power Value: "); |
740593ff VB |
606 | if(port->p_med_pow_val < 1024) { |
607 | printf("%u mW", port->p_med_pow_val * 100); | |
efe3f9b0 VB |
608 | } else { |
609 | printf("reserved"); | |
610 | } | |
228fcecd | 611 | printf("\n"); |
efe3f9b0 | 612 | } |
6772b237 VB |
613 | if (chassis->c_med_hw || |
614 | chassis->c_med_sw || | |
615 | chassis->c_med_fw || | |
616 | chassis->c_med_sn || | |
617 | chassis->c_med_manuf || | |
618 | chassis->c_med_model || | |
619 | chassis->c_med_asset) { | |
620 | printf(" LLDP-MED Inventory:\n"); | |
621 | if (chassis->c_med_hw) | |
622 | printf(" Hardware Revision: %s\n", chassis->c_med_hw); | |
623 | if (chassis->c_med_sw) | |
624 | printf(" Software Revision: %s\n", chassis->c_med_sw); | |
625 | if (chassis->c_med_fw) | |
626 | printf(" Firmware Revision: %s\n", chassis->c_med_fw); | |
627 | if (chassis->c_med_sn) | |
628 | printf(" Serial Number: %s\n", chassis->c_med_sn); | |
629 | if (chassis->c_med_manuf) | |
630 | printf(" Manufacturer: %s\n", | |
631 | chassis->c_med_manuf); | |
632 | if (chassis->c_med_model) | |
633 | printf(" Model: %s\n", | |
634 | chassis->c_med_model); | |
635 | if (chassis->c_med_asset) | |
636 | printf(" Asset ID: %s\n", | |
637 | chassis->c_med_asset); | |
638 | } | |
639 | } | |
640 | #endif | |
641 | ||
8888d191 | 642 | static void |
43c02e7b VB |
643 | display_chassis(struct lldpd_chassis *chassis) |
644 | { | |
645 | char *cid; | |
646 | if ((cid = (char *)malloc(chassis->c_id_len + 1)) == NULL) | |
647 | fatal(NULL); | |
648 | memcpy(cid, chassis->c_id, chassis->c_id_len); | |
649 | cid[chassis->c_id_len] = 0; | |
650 | switch (chassis->c_id_subtype) { | |
651 | case LLDP_CHASSISID_SUBTYPE_IFNAME: | |
652 | printf(" ChassisID: %s (ifName)\n", cid); | |
653 | break; | |
654 | case LLDP_CHASSISID_SUBTYPE_IFALIAS: | |
655 | printf(" ChassisID: %s (ifAlias)\n", cid); | |
656 | break; | |
657 | case LLDP_CHASSISID_SUBTYPE_LOCAL: | |
658 | printf(" ChassisID: %s (local)\n", cid); | |
659 | break; | |
660 | case LLDP_CHASSISID_SUBTYPE_LLADDR: | |
661 | printf(" ChassisID: %s (MAC)\n", | |
662 | dump(chassis->c_id, chassis->c_id_len, ETH_ALEN, ':')); | |
663 | break; | |
664 | case LLDP_CHASSISID_SUBTYPE_ADDR: | |
665 | if (*(u_int8_t*)chassis->c_id == 1) { | |
666 | printf(" ChassisID: %s (IP)\n", | |
667 | inet_ntoa(*(struct in_addr*)(chassis->c_id + | |
668 | 1))); | |
669 | break; | |
670 | } | |
671 | case LLDP_CHASSISID_SUBTYPE_PORT: | |
672 | case LLDP_CHASSISID_SUBTYPE_CHASSIS: | |
673 | default: | |
674 | printf(" ChassisID: %s (unhandled type)\n", | |
675 | dump(chassis->c_id, chassis->c_id_len, 16, ' ')); | |
676 | } | |
677 | printf(" SysName: %s\n", chassis->c_name); | |
678 | printf(" SysDescr: "); pretty_print(chassis->c_descr); | |
a806f67a VB |
679 | if (chassis->c_mgmt.s_addr != INADDR_ANY) |
680 | printf(" MgmtIP: %s\n", inet_ntoa(chassis->c_mgmt)); | |
43c02e7b VB |
681 | printf(" Caps: "); |
682 | display_cap(chassis, LLDP_CAP_OTHER, "Other"); | |
683 | display_cap(chassis, LLDP_CAP_REPEATER, "Repeater"); | |
684 | display_cap(chassis, LLDP_CAP_BRIDGE, "Bridge"); | |
45e96f2e | 685 | display_cap(chassis, LLDP_CAP_ROUTER, "Router"); |
43c02e7b VB |
686 | display_cap(chassis, LLDP_CAP_WLAN, "Wlan"); |
687 | display_cap(chassis, LLDP_CAP_TELEPHONE, "Tel"); | |
688 | display_cap(chassis, LLDP_CAP_DOCSIS, "Docsis"); | |
689 | display_cap(chassis, LLDP_CAP_STATION, "Station"); | |
690 | printf("\n"); | |
691 | } | |
692 | ||
a1347cd8 | 693 | #ifdef ENABLE_DOT3 |
8888d191 | 694 | static void |
43c02e7b VB |
695 | display_autoneg(struct lldpd_port *port, int bithd, int bitfd, char *desc) |
696 | { | |
697 | if (!((port->p_autoneg_advertised & bithd) || | |
698 | (port->p_autoneg_advertised & bitfd))) | |
699 | return; | |
700 | printf("%s ", desc); | |
701 | if (port->p_autoneg_advertised & bithd) { | |
702 | printf("(HD"); | |
703 | if (port->p_autoneg_advertised & bitfd) { | |
704 | printf(", FD) "); | |
705 | return; | |
706 | } | |
707 | printf(") "); | |
708 | return; | |
709 | } | |
710 | printf("(FD) "); | |
711 | } | |
a1347cd8 | 712 | #endif |
43c02e7b | 713 | |
8888d191 | 714 | static void |
43c02e7b VB |
715 | display_port(struct lldpd_port *port) |
716 | { | |
717 | char *pid; | |
3d1337f3 | 718 | struct in_addr address; |
a1347cd8 | 719 | #ifdef ENABLE_DOT3 |
43c02e7b | 720 | int i; |
a1347cd8 | 721 | #endif |
43c02e7b VB |
722 | |
723 | if ((pid = (char *)malloc(port->p_id_len + 1)) == NULL) | |
724 | fatal(NULL); | |
725 | memcpy(pid, port->p_id, port->p_id_len); | |
726 | pid[port->p_id_len] = 0; | |
727 | switch (port->p_id_subtype) { | |
728 | case LLDP_PORTID_SUBTYPE_IFNAME: | |
729 | printf(" PortID: %s (ifName)\n", pid); | |
730 | break; | |
731 | case LLDP_PORTID_SUBTYPE_IFALIAS: | |
732 | printf(" PortID: %s (ifAlias)\n", pid); | |
733 | break; | |
734 | case LLDP_PORTID_SUBTYPE_LOCAL: | |
735 | printf(" PortID: %s (local)\n", pid); | |
736 | break; | |
737 | case LLDP_PORTID_SUBTYPE_LLADDR: | |
738 | printf(" PortID: %s (MAC)\n", | |
739 | dump(port->p_id, port->p_id_len, ETH_ALEN, ':')); | |
740 | break; | |
741 | case LLDP_PORTID_SUBTYPE_ADDR: | |
742 | if (*(u_int8_t*)port->p_id == 1) { | |
3d1337f3 VB |
743 | memcpy(&address, port->p_id + 1, |
744 | sizeof(struct in_addr)); | |
43c02e7b | 745 | printf(" PortID: %s (IP)\n", |
3d1337f3 | 746 | inet_ntoa(address)); |
43c02e7b VB |
747 | break; |
748 | } | |
749 | case LLDP_PORTID_SUBTYPE_PORT: | |
750 | case LLDP_PORTID_SUBTYPE_AGENTCID: | |
751 | default: | |
752 | printf(" ChassisID: %s (unhandled type)\n", | |
753 | dump(port->p_id, port->p_id_len, 16, ' ')); | |
754 | } | |
755 | printf(" PortDescr: "); pretty_print(port->p_descr); | |
a1347cd8 | 756 | #ifdef ENABLE_DOT3 |
548109b2 | 757 | if (port->p_mfs) |
748e05df | 758 | printf(" MFS: %d bytes\n", port->p_mfs); |
43c02e7b VB |
759 | if (port->p_aggregid) |
760 | printf("\n Port is aggregated. PortAggregID: %d\n", | |
761 | port->p_aggregid); | |
762 | ||
a9e9242e VB |
763 | if (port->p_autoneg_support || port->p_autoneg_enabled || |
764 | port->p_mau_type) { | |
765 | printf("\n Autoneg: %ssupported/%senabled\n", | |
766 | port->p_autoneg_support?"":"not ", | |
767 | port->p_autoneg_enabled?"":"not "); | |
768 | if (port->p_autoneg_enabled) { | |
769 | printf(" PMD autoneg: "); | |
770 | display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_10BASE_T, | |
771 | LLDP_DOT3_LINK_AUTONEG_10BASET_FD, | |
772 | "10Base-T"); | |
773 | display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_100BASE_TX, | |
774 | LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD, | |
775 | "100Base-T"); | |
776 | display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_100BASE_T2, | |
777 | LLDP_DOT3_LINK_AUTONEG_100BASE_T2FD, | |
778 | "100Base-T2"); | |
779 | display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_1000BASE_X, | |
780 | LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD, | |
781 | "100Base-X"); | |
782 | display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_1000BASE_T, | |
783 | LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD, | |
784 | "1000Base-T"); | |
785 | printf("\n"); | |
786 | } | |
787 | printf(" MAU oper type: "); | |
788 | for (i = 0; operational_mau_type_values[i].value != 0; i++) { | |
789 | if (operational_mau_type_values[i].value == | |
790 | port->p_mau_type) { | |
791 | printf("%s\n", operational_mau_type_values[i].string); | |
792 | break; | |
793 | } | |
43c02e7b | 794 | } |
a9e9242e VB |
795 | if (operational_mau_type_values[i].value == 0) |
796 | printf("unknown (%d)\n", port->p_mau_type); | |
43c02e7b | 797 | } |
a1347cd8 | 798 | #endif |
43c02e7b VB |
799 | } |
800 | ||
a1347cd8 | 801 | #ifdef ENABLE_DOT1 |
8888d191 | 802 | static void |
43c02e7b VB |
803 | display_vlans(struct lldpd_port *port) |
804 | { | |
805 | int i = 0; | |
806 | struct lldpd_vlan *vlan; | |
807 | TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) | |
75b3469d VB |
808 | printf(" %cVLAN %4d: %-20s%c", |
809 | (port->p_pvid == vlan->v_vid)?'*':' ', | |
810 | vlan->v_vid, vlan->v_name, | |
43c02e7b VB |
811 | (i++ % 2) ? '\n' : ' '); |
812 | if (i % 2) | |
813 | printf("\n"); | |
814 | } | |
a1347cd8 | 815 | #endif |
43c02e7b | 816 | |
8888d191 | 817 | static void |
740593ff | 818 | display_interfaces(int s, int argc, char *argv[]) |
43c02e7b | 819 | { |
84853b92 | 820 | int i, nb; |
43c02e7b | 821 | struct interfaces ifs; |
a1347cd8 | 822 | #ifdef ENABLE_DOT1 |
43c02e7b | 823 | struct vlans vls; |
a1347cd8 | 824 | #endif |
43c02e7b VB |
825 | struct lldpd_interface *iff; |
826 | struct lldpd_chassis chassis; | |
827 | struct lldpd_port port; | |
828 | char sep[80]; | |
740593ff | 829 | |
43c02e7b VB |
830 | memset(sep, '-', 79); |
831 | sep[79] = 0; | |
43c02e7b | 832 | get_interfaces(s, &ifs); |
740593ff | 833 | |
43c02e7b VB |
834 | printf("%s\n", sep); |
835 | printf(" LLDP neighbors\n"); | |
836 | printf("%s\n", sep); | |
837 | TAILQ_FOREACH(iff, &ifs, next) { | |
ccea83b2 VB |
838 | if (optind < argc) { |
839 | for (i = optind; i < argc; i++) | |
840 | if (strncmp(argv[i], iff->name, IFNAMSIZ) == 0) | |
841 | break; | |
842 | if (i == argc) | |
843 | continue; | |
844 | } | |
84853b92 VB |
845 | nb = get_nb_port(s, iff->name); |
846 | for (i = 0; i < nb; i++) { | |
847 | if (!((get_chassis(s, &chassis, iff->name, i) != -1) && | |
848 | (get_port(s, &port, iff->name, i) != -1))) | |
849 | continue; | |
850 | printf("Interface: %s (via ", iff->name); | |
851 | switch (port.p_protocol) { | |
852 | case (LLDPD_MODE_LLDP): printf("LLDP"); break; | |
853 | case (LLDPD_MODE_CDPV1): printf("CDPv1"); break; | |
854 | case (LLDPD_MODE_CDPV2): printf("CDPv2"); break; | |
855 | case (LLDPD_MODE_EDP): printf("EDP"); break; | |
856 | case (LLDPD_MODE_FDP): printf("FDP"); break; | |
857 | case (LLDPD_MODE_SONMP): printf("SONMP"); break; | |
858 | default: printf("unknown protocol"); break; | |
859 | } | |
860 | printf(") - RID: %d\n", chassis.c_index); | |
43c02e7b VB |
861 | display_chassis(&chassis); |
862 | printf("\n"); | |
863 | display_port(&port); | |
a1347cd8 | 864 | #ifdef ENABLE_DOT1 |
84853b92 | 865 | if (get_vlans(s, &vls, iff->name, i) != -1) { |
43c02e7b VB |
866 | memcpy(&port.p_vlans, &vls, sizeof(struct vlans)); |
867 | if (!TAILQ_EMPTY(&port.p_vlans)) { | |
868 | printf("\n"); | |
869 | display_vlans(&port); | |
870 | } | |
871 | } | |
a1347cd8 | 872 | #endif |
6772b237 | 873 | #ifdef ENABLE_LLDPMED |
740593ff | 874 | if (port.p_med_cap_enabled) { |
6772b237 | 875 | printf("\n"); |
740593ff | 876 | display_med(&chassis, &port); |
6772b237 VB |
877 | } |
878 | #endif | |
43c02e7b VB |
879 | printf("%s\n", sep); |
880 | } | |
881 | } | |
740593ff VB |
882 | } |
883 | ||
884 | #ifdef ENABLE_LLDPMED | |
8888d191 | 885 | static int |
740593ff VB |
886 | lldpd_parse_location(struct lldpd_port *port, const char *location) |
887 | { | |
888 | char *l, *e, *s, *data, *n; | |
889 | double ll, altitude; | |
890 | u_int32_t intpart, floatpart; | |
891 | int type = 0, i; | |
892 | ||
893 | if (strlen(location) == 0) | |
894 | return 0; | |
895 | if ((l = strdup(location)) == NULL) | |
896 | fatal(NULL); | |
897 | s = l; | |
f0bd3505 | 898 | if ((e = strchr(s, ':')) == NULL) |
740593ff VB |
899 | goto invalid_location; |
900 | *e = '\0'; | |
901 | type = atoi(s); | |
902 | switch (type) { | |
903 | case LLDPMED_LOCFORMAT_COORD: | |
904 | /* Coordinates */ | |
905 | if ((port->p_med_location[0].data = | |
906 | (char *)malloc(16)) == NULL) | |
907 | fatal(NULL); | |
908 | port->p_med_location[0].data_len = 16; | |
909 | port->p_med_location[0].format = LLDPMED_LOCFORMAT_COORD; | |
910 | data = port->p_med_location[0].data; | |
911 | ||
912 | /* Latitude and longitude */ | |
913 | for (i = 0; i < 2; i++) { | |
914 | s = e+1; | |
f0bd3505 | 915 | if ((e = strchr(s, ':')) == NULL) |
740593ff VB |
916 | goto invalid_location; |
917 | *e = '\0'; | |
918 | ll = atof(s); | |
919 | s = e + 1; | |
f0bd3505 | 920 | if ((e = strchr(s, ':')) == NULL) |
740593ff VB |
921 | goto invalid_location; |
922 | *e = '\0'; | |
923 | intpart = (int)ll; | |
924 | floatpart = (ll - intpart) * (1 << 25); | |
925 | if (((i == 0) && (*s == 'S')) || | |
926 | ((i == 1) && (*s == 'W'))) { | |
927 | intpart = ~intpart; | |
928 | intpart += 1; | |
929 | floatpart = ~floatpart; | |
930 | floatpart += 1; | |
931 | } else if (((i == 0) && (*s != 'N')) || | |
932 | ((i == 1) && (*s != 'E'))) | |
933 | goto invalid_location; | |
934 | *(u_int8_t *)data = (6 << 2) | /* Precision */ | |
935 | ((intpart & 0x180) >> 7); /* Int part 2 bits */ | |
936 | data++; | |
937 | *(u_int8_t *)data = (((intpart & 0x7f) << 1) | /* Int part 7 bits */ | |
938 | ((floatpart & 0x1000000) >> 24)); /* Float part 1 bit */ | |
939 | data++; | |
940 | *(u_int8_t *)data = (floatpart & 0xff0000) >> 16; /* 8 bits */ | |
941 | data++; | |
942 | *(u_int8_t *)data = (floatpart & 0xff00) >> 8; /* 8 bits */ | |
943 | data++; | |
944 | *(u_int8_t *)data = (floatpart & 0xff); /* 8 bits */ | |
945 | data++; | |
946 | } | |
947 | ||
948 | /* Altitude */ | |
949 | s = e+1; | |
f0bd3505 | 950 | if ((e = strchr(s, ':')) == NULL) |
740593ff VB |
951 | goto invalid_location; |
952 | *e = '\0'; | |
953 | altitude = atof(s); | |
954 | s = e+1; | |
f0bd3505 | 955 | if ((e = strchr(s, ':')) == NULL) |
740593ff VB |
956 | goto invalid_location; |
957 | *e = '\0'; | |
958 | if (altitude < 0) { | |
959 | intpart = -(int)altitude; | |
960 | floatpart = (-(altitude + intpart)) * (1 << 8); | |
961 | intpart = ~intpart; intpart += 1; | |
962 | floatpart = ~floatpart; floatpart += 1; | |
963 | } else { | |
964 | intpart = (int)altitude; | |
965 | floatpart = (altitude - intpart) * (1 << 8); | |
966 | } | |
967 | if ((*s != 'm') && (*s != 'f')) | |
968 | goto invalid_location; | |
969 | *(u_int8_t *)data = ((((*s == 'm')?1:2) << 4) | /* Type 4 bits */ | |
970 | 0); /* Precision 4 bits */ | |
971 | data++; | |
972 | *(u_int8_t *)data = ((6 << 6) | /* Precision 2 bits */ | |
973 | ((intpart & 0x3f0000) >> 16)); /* Int 6 bits */ | |
974 | data++; | |
975 | *(u_int8_t *)data = (intpart & 0xff00) >> 8; /* Int 8 bits */ | |
976 | data++; | |
977 | *(u_int8_t *)data = intpart & 0xff; /* Int 8 bits */ | |
978 | data++; | |
979 | *(u_int8_t *)data = floatpart & 0xff; /* Float 8 bits */ | |
980 | data++; | |
981 | ||
982 | /* Datum */ | |
983 | s = e + 1; | |
f0bd3505 | 984 | if (strchr(s, ':') != NULL) |
740593ff VB |
985 | goto invalid_location; |
986 | *(u_int8_t *)data = atoi(s); | |
987 | break; | |
988 | case LLDPMED_LOCFORMAT_CIVIC: | |
989 | /* Civic address */ | |
990 | port->p_med_location[1].data_len = 4; | |
991 | s = e+1; | |
f0bd3505 | 992 | if ((s = strchr(s, ':')) == NULL) |
740593ff VB |
993 | goto invalid_location; |
994 | s = s+1; | |
995 | do { | |
f0bd3505 | 996 | if ((s = strchr(s, ':')) == NULL) |
740593ff VB |
997 | break; |
998 | s = s+1; | |
999 | /* s is the beginning of the word */ | |
f0bd3505 | 1000 | if ((n = strchr(s, ':')) == NULL) |
740593ff VB |
1001 | n = s + strlen(s); |
1002 | /* n is the end of the word */ | |
1003 | port->p_med_location[1].data_len += (n - s) + 2; | |
f0bd3505 | 1004 | if ((s = strchr(s, ':')) == NULL) |
740593ff VB |
1005 | break; |
1006 | s = s+1; | |
1007 | } while (1); | |
1008 | s = e+1; | |
1009 | if ((port->p_med_location[1].data = | |
1010 | (char *)malloc(port->p_med_location[1].data_len)) == | |
1011 | NULL) | |
1012 | fatal(NULL); | |
1013 | port->p_med_location[1].format = LLDPMED_LOCFORMAT_CIVIC; | |
1014 | data = port->p_med_location[1].data; | |
1015 | *(u_int8_t *)data = port->p_med_location[1].data_len - 1; | |
1016 | data++; | |
1017 | *(u_int8_t *)data = 2; /* Client location */ | |
1018 | data++; | |
f0bd3505 | 1019 | if ((e = strchr(s, ':')) == NULL) |
740593ff VB |
1020 | goto invalid_location; |
1021 | if ((e - s) != 2) | |
1022 | goto invalid_location; | |
1023 | memcpy(data, s, 2); /* Country code */ | |
1024 | data += 2; | |
1025 | while (*e != '\0') { | |
1026 | s=e+1; | |
f0bd3505 | 1027 | if ((e = strchr(s, ':')) == NULL) |
740593ff VB |
1028 | goto invalid_location; |
1029 | *e = '\0'; | |
1030 | *(u_int8_t *)data = atoi(s); | |
1031 | data++; | |
1032 | s=e+1; | |
f0bd3505 | 1033 | if ((e = strchr(s, ':')) == NULL) |
740593ff VB |
1034 | e = s + strlen(s); |
1035 | *(u_int8_t *)data = e - s; | |
1036 | data++; | |
1037 | memcpy(data, s, e-s); | |
1038 | data += e-s; | |
1039 | } | |
1040 | break; | |
1041 | case LLDPMED_LOCFORMAT_ELIN: | |
1042 | s = e+1; | |
1043 | port->p_med_location[2].data_len = strlen(s); | |
1044 | if ((port->p_med_location[2].data = | |
1045 | (char *)malloc(strlen(s))) == NULL) | |
1046 | fatal(NULL); | |
1047 | port->p_med_location[2].format = LLDPMED_LOCFORMAT_ELIN; | |
1048 | strcpy(port->p_med_location[2].data, s); | |
1049 | break; | |
1050 | default: | |
1051 | type = 0; | |
1052 | goto invalid_location; | |
1053 | } | |
1054 | ||
1055 | port->p_med_cap_enabled |= LLDPMED_CAP_LOCATION; | |
1056 | return 0; | |
1057 | invalid_location: | |
1058 | LLOG_WARNX("the format of the location is invalid (%s)", | |
1059 | location); | |
1060 | if (type) { | |
1061 | free(port->p_med_location[type-1].data); | |
1062 | memset(&port->p_med_location[type-1], 0, | |
1063 | sizeof(struct lldpd_med_loc)); | |
1064 | } | |
1065 | free(l); | |
1066 | return -1; | |
1067 | } | |
1068 | ||
8888d191 | 1069 | static void |
740593ff VB |
1070 | set_location(int s, int argc, char *argv[]) |
1071 | { | |
1072 | int i, ch; | |
1073 | struct interfaces ifs; | |
1074 | struct lldpd_interface *iff; | |
1075 | struct lldpd_port port; | |
1076 | void *p; | |
1077 | struct hmsg *h; | |
1078 | ||
1079 | if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL) | |
1080 | fatal(NULL); | |
1081 | ||
1082 | memset(&port, 0, sizeof(struct lldpd_port)); | |
1083 | optind = 1; | |
1084 | while ((ch = getopt(argc, argv, "dL:")) != -1) { | |
1085 | switch (ch) { | |
1086 | case 'L': | |
1087 | if ((lldpd_parse_location(&port, optarg)) == -1) | |
1088 | fatalx("incorrect location"); | |
1089 | break; | |
1090 | } | |
1091 | } | |
1092 | ||
1093 | get_interfaces(s, &ifs); | |
1094 | TAILQ_FOREACH(iff, &ifs, next) { | |
1095 | if (optind < argc) { | |
1096 | for (i = optind; i < argc; i++) | |
1097 | if (strncmp(argv[i], iff->name, IFNAMSIZ) == 0) | |
1098 | break; | |
1099 | if (i == argc) | |
1100 | continue; | |
1101 | } | |
1102 | ||
1103 | ctl_msg_init(h, HMSG_SET_LOCATION); | |
1104 | strlcpy((char *)&h->data, iff->name, IFNAMSIZ); | |
1105 | h->hdr.len += IFNAMSIZ; | |
1106 | p = (char*)&h->data + IFNAMSIZ; | |
1107 | if (ctl_msg_pack_structure(STRUCT_LLDPD_MED_LOC | |
1108 | STRUCT_LLDPD_MED_LOC STRUCT_LLDPD_MED_LOC, | |
1109 | port.p_med_location, | |
1110 | 3*sizeof(struct lldpd_med_loc), h, &p) == -1) { | |
1111 | LLOG_WARNX("set_location: unable to set location for %s", iff->name); | |
1112 | fatalx("aborting"); | |
1113 | } | |
1114 | if (ctl_msg_send(s, h) == -1) | |
1115 | fatalx("set_location: unable to send request"); | |
1116 | if (ctl_msg_recv(s, h) == -1) | |
1117 | fatalx("set_location: unable to receive answer"); | |
1118 | if (h->hdr.type != HMSG_SET_LOCATION) | |
1119 | fatalx("set_location: unknown answer type received"); | |
1120 | LLOG_INFO("Location set succesfully for %s", iff->name); | |
1121 | } | |
1122 | } | |
1123 | #endif | |
1124 | ||
1125 | int | |
1126 | main(int argc, char *argv[]) | |
1127 | { | |
1128 | int ch, s, debug = 1; | |
1129 | #define ACTION_SET_LOCATION 1 | |
1130 | int action = 0; | |
43c02e7b | 1131 | |
740593ff VB |
1132 | /* |
1133 | * Get and parse command line options | |
1134 | */ | |
1135 | while ((ch = getopt(argc, argv, "dL:")) != -1) { | |
1136 | switch (ch) { | |
1137 | case 'd': | |
1138 | debug++; | |
1139 | break; | |
1140 | case 'L': | |
1141 | #ifdef ENABLE_LLDPMED | |
1142 | action = ACTION_SET_LOCATION; | |
1143 | #else | |
1144 | fprintf(stderr, "LLDP-MED support is not built-in\n"); | |
1145 | usage(); | |
1146 | #endif | |
1147 | break; | |
1148 | default: | |
1149 | usage(); | |
1150 | } | |
1151 | } | |
1152 | ||
1153 | log_init(debug); | |
43c02e7b | 1154 | |
740593ff VB |
1155 | if ((s = ctl_connect(LLDPD_CTL_SOCKET)) == -1) |
1156 | fatalx("unable to connect to socket " LLDPD_CTL_SOCKET); | |
1157 | ||
1158 | switch (action) { | |
1159 | #ifdef ENABLE_LLDPMED | |
1160 | case ACTION_SET_LOCATION: | |
1161 | set_location(s, argc, argv); | |
1162 | break; | |
1163 | #endif | |
1164 | default: | |
1165 | display_interfaces(s, argc, argv); | |
1166 | } | |
1167 | ||
1168 | close(s); | |
43c02e7b VB |
1169 | return 0; |
1170 | } |