2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 * Permission to use, copy, modify, and/or 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.
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.
23 #include <sys/types.h>
24 #include <sys/socket.h>
26 #include <arpa/inet.h>
28 TAILQ_HEAD(interfaces
, lldpd_interface
);
30 #define ntohll(x) (((u_int64_t)(ntohl((int)((x << 32) >> 32))) << 32) | \
31 (unsigned int)ntohl(((int)(x >> 32))))
32 #define htonll(x) ntohll(x)
39 static const struct value_string lldpd_protocol_map
[] = {
40 { LLDPD_MODE_LLDP
, "LLDP" },
41 { LLDPD_MODE_CDPV1
, "CDPv1"},
42 { LLDPD_MODE_CDPV2
, "CDPv2"},
43 { LLDPD_MODE_EDP
, "EDP" },
44 { LLDPD_MODE_FDP
, "FDP"},
45 { LLDPD_MODE_SONMP
, "SONMP"},
49 static const struct value_string chassis_id_subtype_map
[] = {
50 { LLDP_CHASSISID_SUBTYPE_IFNAME
, "ifname"},
51 { LLDP_CHASSISID_SUBTYPE_IFALIAS
, "ifalias" },
52 { LLDP_CHASSISID_SUBTYPE_LOCAL
, "local" },
53 { LLDP_CHASSISID_SUBTYPE_LLADDR
, "mac" },
54 { LLDP_CHASSISID_SUBTYPE_ADDR
, "ip" },
55 { LLDP_CHASSISID_SUBTYPE_PORT
, "unhandled" },
56 { LLDP_CHASSISID_SUBTYPE_CHASSIS
, "unhandled" },
60 static const struct value_string port_id_subtype_map
[] = {
61 { LLDP_PORTID_SUBTYPE_IFNAME
, "ifname"},
62 { LLDP_PORTID_SUBTYPE_IFALIAS
, "ifalias" },
63 { LLDP_PORTID_SUBTYPE_LOCAL
, "local" },
64 { LLDP_PORTID_SUBTYPE_LLADDR
, "mac" },
65 { LLDP_PORTID_SUBTYPE_ADDR
, "ip" },
66 { LLDP_PORTID_SUBTYPE_PORT
, "unhandled" },
67 { LLDP_PORTID_SUBTYPE_AGENTCID
, "unhandled" },
72 static const struct value_string chassis_med_type_map
[] = {
73 { LLDPMED_CLASS_I
, "Generic Endpoint (Class I)" },
74 { LLDPMED_CLASS_II
, "Media Endpoint (Class II)" },
75 { LLDPMED_CLASS_III
, "Communication Device Endpoint (Class III)" },
76 { LLDPMED_NETWORK_DEVICE
, "Network Connectivity Device" },
80 static const struct value_string lldpmed_capabilit_map
[] = {
81 {LLDPMED_CAP_CAP
, "Capabilities"},
82 {LLDPMED_CAP_POLICY
, "Policy"},
83 {LLDPMED_CAP_LOCATION
, "Location"},
84 {LLDPMED_CAP_MDI_PSE
, "MDI/PSE"},
85 {LLDPMED_CAP_MDI_PD
, "MDI/PD"},
86 {LLDPMED_CAP_IV
, "Inventory"},
90 static const struct value_string port_med_policy_map
[] = {
91 { LLDPMED_APPTYPE_VOICE
, "Voice"},
92 { LLDPMED_APPTYPE_VOICESIGNAL
, "Voice Signaling"},
93 { LLDPMED_APPTYPE_GUESTVOICE
, "Guest Voice"},
94 { LLDPMED_APPTYPE_GUESTVOICESIGNAL
, "Guest Voice Signaling"},
95 { LLDPMED_APPTYPE_SOFTPHONEVOICE
, "Softphone Voice"},
96 { LLDPMED_APPTYPE_VIDEOCONFERENCE
, "Video Conferencing"},
97 { LLDPMED_APPTYPE_VIDEOSTREAM
, "Streaming Video"},
98 { LLDPMED_APPTYPE_VIDEOSIGNAL
, "Video Signaling"},
102 static const struct value_string civic_address_type_values
[] = {
104 { 1, "National subdivisions" },
105 { 2, "County, parish, district" },
106 { 3, "City, township" },
107 { 4, "City division, borough, ward" },
108 { 5, "Neighborhood, block" },
110 { 16, "Leading street direction" },
111 { 17, "Trailing street suffix" },
112 { 18, "Street suffix" },
113 { 19, "House number" },
114 { 20, "House number suffix" },
115 { 21, "Landmark or vanity address" },
116 { 22, "Additional location info" },
118 { 24, "Postal/ZIP code" },
122 { 28, "Room number" },
123 { 29, "Place type" },
128 static const struct value_string civic_address_type_tags
[] = {
130 { 1, "country-subdivision" },
133 { 4, "city-division" },
137 { 17, "street-suffix" },
138 { 18, "street-suffix" },
140 { 20, "number-suffix" },
142 { 22, "additional" },
149 { 29, "place-type" },
154 static const struct value_string port_med_geoid_map
[] = {
161 static const struct value_string port_med_pow_devicetype_map
[] = {
162 { LLDPMED_POW_TYPE_PSE
, "PSE Device" },
163 { LLDPMED_POW_TYPE_PD
, "PD Device" },
167 static const struct value_string port_med_pow_source_map
[] = {
168 { LLDPMED_POW_SOURCE_PRIMARY
, "Primary Power Source" },
169 { LLDPMED_POW_SOURCE_BACKUP
, "Backup Power Source / Power Conservation Mode" },
170 { LLDPMED_POW_SOURCE_PSE
, "PSE" },
171 { LLDPMED_POW_SOURCE_LOCAL
, "Local"},
172 { LLDPMED_POW_SOURCE_BOTH
, "PSE + Local"},
176 static const struct value_string port_med_pow_priority_map
[] = {
177 { LLDPMED_POW_PRIO_CRITICAL
, "critical" },
178 { LLDPMED_POW_PRIO_HIGH
, "high" },
179 { LLDPMED_POW_PRIO_LOW
, "low" },
185 static const struct value_string operational_mau_type_values
[] = {
186 { 1, "AUI - no internal MAU, view from AUI" },
187 { 2, "10Base5 - thick coax MAU" },
188 { 3, "Foirl - FOIRL MAU" },
189 { 4, "10Base2 - thin coax MAU" },
190 { 5, "10BaseT - UTP MAU" },
191 { 6, "10BaseFP - passive fiber MAU" },
192 { 7, "10BaseFB - sync fiber MAU" },
193 { 8, "10BaseFL - async fiber MAU" },
194 { 9, "10Broad36 - broadband DTE MAU" },
195 { 10, "10BaseTHD - UTP MAU, half duplex mode" },
196 { 11, "10BaseTFD - UTP MAU, full duplex mode" },
197 { 12, "10BaseFLHD - async fiber MAU, half duplex mode" },
198 { 13, "10BaseFLDF - async fiber MAU, full duplex mode" },
199 { 14, "10BaseT4 - 4 pair category 3 UTP" },
200 { 15, "100BaseTXHD - 2 pair category 5 UTP, half duplex mode" },
201 { 16, "100BaseTXFD - 2 pair category 5 UTP, full duplex mode" },
202 { 17, "100BaseFXHD - X fiber over PMT, half duplex mode" },
203 { 18, "100BaseFXFD - X fiber over PMT, full duplex mode" },
204 { 19, "100BaseT2HD - 2 pair category 3 UTP, half duplex mode" },
205 { 20, "100BaseT2DF - 2 pair category 3 UTP, full duplex mode" },
206 { 21, "1000BaseXHD - PCS/PMA, unknown PMD, half duplex mode" },
207 { 22, "1000BaseXFD - PCS/PMA, unknown PMD, full duplex mode" },
208 { 23, "1000BaseLXHD - Fiber over long-wavelength laser, half duplex mode" },
209 { 24, "1000BaseLXFD - Fiber over long-wavelength laser, full duplex mode" },
210 { 25, "1000BaseSXHD - Fiber over short-wavelength laser, half duplex mode" },
211 { 26, "1000BaseSXFD - Fiber over short-wavelength laser, full duplex mode" },
212 { 27, "1000BaseCXHD - Copper over 150-Ohm balanced cable, half duplex mode" },
213 { 28, "1000BaseCXFD - Copper over 150-Ohm balanced cable, full duplex mode" },
214 { 29, "1000BaseTHD - Four-pair Category 5 UTP, half duplex mode" },
215 { 30, "1000BaseTFD - Four-pair Category 5 UTP, full duplex mode" },
216 { 31, "10GigBaseX - X PCS/PMA, unknown PMD." },
217 { 32, "10GigBaseLX4 - X fiber over WWDM optics" },
218 { 33, "10GigBaseR - R PCS/PMA, unknown PMD." },
219 { 34, "10GigBaseER - R fiber over 1550 nm optics" },
220 { 35, "10GigBaseLR - R fiber over 1310 nm optics" },
221 { 36, "10GigBaseSR - R fiber over 850 nm optics" },
222 { 37, "10GigBaseW - W PCS/PMA, unknown PMD." },
223 { 38, "10GigBaseEW - W fiber over 1550 nm optics" },
224 { 39, "10GigBaseLW - W fiber over 1310 nm optics" },
225 { 40, "10GigBaseSW - W fiber over 850 nm optics" },
226 { 41, "10GigBaseCX4 - X copper over 8 pair 100-Ohm balanced cable" },
227 { 42, "2BaseTL - Voice grade UTP copper, up to 2700m, optional PAF" },
228 { 43, "10PassTS - Voice grade UTP copper, up to 750m, optional PAF" },
229 { 44, "100BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" },
230 { 45, "100BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" },
231 { 46, "100BaseLX10 - Two single-mode fibers, long wavelength, 10km" },
232 { 47, "1000BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" },
233 { 48, "1000BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" },
234 { 49, "1000BaseLX10 - Two sigle-mode fiber, long wavelength, 10km" },
235 { 50, "1000BasePX10D - One single-mode fiber EPON OLT, 10km" },
236 { 51, "1000BasePX10U - One single-mode fiber EPON ONU, 10km" },
237 { 52, "1000BasePX20D - One single-mode fiber EPON OLT, 20km" },
238 { 53, "1000BasePX20U - One single-mode fiber EPON ONU, 20km" },
242 static const struct value_string port_dot3_power_devicetype_map
[] = {
243 { LLDP_DOT3_POWER_PSE
, "PSE" },
244 { LLDP_DOT3_POWER_PD
, "PD" },
248 static const struct value_string port_dot3_power_pairs_map
[] = {
249 { LLDP_DOT3_POWERPAIRS_SIGNAL
, "signal" },
250 { LLDP_DOT3_POWERPAIRS_SPARE
, "spare" },
254 static const struct value_string port_dot3_power_class_map
[] = {
263 static const struct value_string port_dot3_power_pse_source_map
[] = {
264 { LLDP_DOT3_POWER_SOURCE_BOTH
, "PSE + Local" },
265 { LLDP_DOT3_POWER_SOURCE_PSE
, "PSE" },
269 static const struct value_string port_dot3_power_pd_source_map
[] = {
270 { LLDP_DOT3_POWER_SOURCE_BACKUP
, "Backup source" },
271 { LLDP_DOT3_POWER_SOURCE_PRIMARY
, "Primary power source" },
275 static const struct value_string port_dot3_power_priority_map
[] = {
276 { LLDPMED_POW_PRIO_CRITICAL
, "critical" },
277 { LLDPMED_POW_PRIO_HIGH
, "high" },
278 { LLDPMED_POW_PRIO_LOW
, "low" },
283 static const struct value_string chassis_capability_map
[] = {
284 { LLDP_CAP_OTHER
, "Other" },
285 { LLDP_CAP_REPEATER
, "Repeater"},
286 { LLDP_CAP_BRIDGE
, "Bridge"},
287 { LLDP_CAP_ROUTER
, "Router"},
288 { LLDP_CAP_WLAN
, "Wlan"},
289 { LLDP_CAP_TELEPHONE
,"Telephone"},
290 { LLDP_CAP_DOCSIS
, "Docsis"},
291 { LLDP_CAP_STATION
, "Station"},
297 map_lookup(const struct value_string
* list
, int n
)
302 for( i
= 0; list
[i
].string
!= NULL
; i
++ ) {
303 if( list
[i
].value
== n
) {
304 return list
[i
].string
;
315 snprintf(buf
, sizeof(buf
), "%u", n
);
320 dump(void *data
, int size
, int max
, char sep
)
324 static char *buffer
= NULL
;
325 static char truncation
[] = "[...]";
329 len
= max
* 3 + sizeof(truncation
) + 1;
333 if ((buffer
= (char *)malloc(len
)) == NULL
)
336 for (i
= 0; (i
< size
) && (i
< max
); i
++)
337 sprintf(buffer
+ i
* 3, "%02x%c", *(u_int8_t
*)(data
+ i
), sep
);
339 sprintf(buffer
+ i
* 3, "%s", truncation
);
341 *(buffer
+ i
*3 - 1) = 0;
346 display_cap(struct writer
* w
, struct lldpd_chassis
*chassis
, u_int8_t bit
, char *symbol
)
348 if (chassis
->c_cap_available
& bit
) {
349 tag_start(w
, "capability", "Capability");
350 tag_attr (w
, "type", "", symbol
);
351 tag_attr (w
, "enabled", "", (chassis
->c_cap_enabled
& bit
)?"on":"off");
356 #ifdef ENABLE_LLDPMED
358 display_fixed_precision(u_int64_t value
, int intpart
, int floatpart
, int displaysign
, char ** res
)
361 u_int64_t tmp
= value
;
363 u_int32_t integer
= 0;
364 if (value
& (1ULL<<(intpart
+ floatpart
- 1))) {
369 integer
= (u_int32_t
)((tmp
&
370 (((1ULL << intpart
)-1) << floatpart
)) >> floatpart
);
371 tmp
= (tmp
& ((1<< floatpart
) - 1))*10000/(1ULL << floatpart
);
372 snprintf(buf
, sizeof(buf
),"%s%u.%04llu", displaysign
?(negative
?"-":"+"):"",
373 integer
, (unsigned long long int)tmp
);
381 display_latitude_or_longitude(struct writer
*w
, int option
, u_int64_t value
)
388 tag_start(w
, "lat", "Latitude");
390 tag_start(w
, "lon", "Longitude");
392 negative
= display_fixed_precision(value
, 9, 25, 0, &str
);
394 snprintf(buf
, sizeof(buf
), "%s %s", str
, negative
?" S":" N");
396 snprintf(buf
, sizeof(buf
), "%s %s", str
, negative
?" W":" E");
403 display_med_capability(struct writer
*w
, struct lldpd_chassis
*chassis
, int cap
)
405 if (chassis
->c_med_cap_available
& cap
) {
406 tag_start(w
, "capability", "Capability");
407 tag_attr(w
, "type", "",
408 map_lookup(lldpmed_capabilit_map
, cap
));
414 display_med(struct writer
*w
, struct lldpd_chassis
*chassis
, struct lldpd_port
*port
)
419 tag_start(w
, "lldp-med", "LLDP-MED");
421 tag_datatag(w
, "device-type", "Device Type",
422 map_lookup(chassis_med_type_map
, chassis
->c_med_type
));
424 display_med_capability(w
, chassis
, LLDPMED_CAP_CAP
);
425 display_med_capability(w
, chassis
, LLDPMED_CAP_POLICY
);
426 display_med_capability(w
, chassis
, LLDPMED_CAP_LOCATION
);
427 display_med_capability(w
, chassis
, LLDPMED_CAP_MDI_PSE
);
428 display_med_capability(w
, chassis
, LLDPMED_CAP_MDI_PD
);
429 display_med_capability(w
, chassis
, LLDPMED_CAP_IV
);
431 for (i
= 0; i
< LLDPMED_APPTYPE_LAST
; i
++) {
432 if (i
+1 == port
->p_med_policy
[i
].type
) {
433 tag_start(w
, "policy", "LLDP-MED Network Policy for");
434 tag_attr(w
, "apptype", "AppType",
435 u2str(port
->p_med_policy
[i
].type
));
436 tag_attr(w
, "defined", "Defined",
437 (port
->p_med_policy
[i
].unknown
)?"no":"yes");
439 tag_datatag(w
, "descr", "",
440 map_lookup(port_med_policy_map
, port
->p_med_policy
[i
].type
));
442 if (port
->p_med_policy
[i
].tagged
) {
443 tag_start(w
, "vlan", "VLAN");
444 if (port
->p_med_policy
[i
].vid
== 0) {
445 tag_attr(w
, "vid", "", "priority");
446 } else if (port
->p_med_policy
[i
].vid
== 4095) {
447 tag_attr(w
, "vid", "", "reserved");
449 tag_attr(w
, "vid", "",
450 u2str(port
->p_med_policy
[i
].vid
));
455 tag_datatag(w
, "priority", "Layer 2 Priority",
456 u2str(port
->p_med_policy
[i
].priority
));
458 tag_datatag(w
, "dscp", "DSCP Value",
459 u2str(port
->p_med_policy
[i
].dscp
));
464 for (i
= 0; i
< LLDPMED_LOCFORMAT_LAST
; i
++) {
465 if (i
+1 == port
->p_med_location
[i
].format
) {
466 tag_start(w
, "location", "LLDP-MED Location Identification");
468 switch(port
->p_med_location
[i
].format
) {
469 case LLDPMED_LOCFORMAT_COORD
:
470 tag_attr(w
, "type", "Type", "coordinates");
472 if (port
->p_med_location
[i
].data_len
!= 16) {
473 tag_datatag(w
, "error", "Error", "bad data length");
479 v
= *(u_int8_t
*)(port
->p_med_location
[i
].data
+ 15);
480 tag_attr(w
, "geoid", "Geoid",
481 map_lookup(port_med_geoid_map
,v
));
483 /* Latitude and longitude */
484 memcpy(&l
, port
->p_med_location
[i
].data
,
487 0x03FFFFFFFF000000ULL
) >> 24;
488 display_latitude_or_longitude(w
,0, l
);
489 memcpy(&l
, port
->p_med_location
[i
].data
+ 5,
492 0x03FFFFFFFF000000ULL
) >> 24;
493 display_latitude_or_longitude(w
,1, l
);
496 memcpy(&l
, port
->p_med_location
[i
].data
+ 10,
499 0x3FFFFFFF000000ULL
) >> 24;
500 display_fixed_precision(l
, 22, 8, 1, &s
);
502 tag_start(w
, "altitude", "Altitude");
503 switch ((*(u_int8_t
*)(port
->p_med_location
[i
].data
+
506 tag_attr(w
, "unit", "", "m");
509 tag_attr(w
, "unit", "", "floor");
512 tag_attr(w
, "unit", "", "unknown");
519 case LLDPMED_LOCFORMAT_CIVIC
:
520 tag_attr(w
, "type", "Type", "address");
522 if ((port
->p_med_location
[i
].data_len
< 3) ||
523 (port
->p_med_location
[i
].data_len
- 1 !=
524 *(u_int8_t
*)port
->p_med_location
[i
].data
)) {
525 tag_datatag(w
, "error", "Error", "bad data length");
527 int l
= 4, n
, catype
, calength
;
529 country
[0] = ((char *)port
->p_med_location
[i
].data
)[2];
530 country
[1] = ((char *)port
->p_med_location
[i
].data
)[3];
533 tag_datatag(w
, "country", "Country", country
);
536 p_med_location
[i
].data_len
- l
)) >= 2) {
537 catype
= *(u_int8_t
*)(port
->
538 p_med_location
[i
].data
+ l
);
539 calength
= *(u_int8_t
*)(port
->
540 p_med_location
[i
].data
+ l
+ 1);
541 if (n
< 2 + calength
) {
542 tag_datatag(w
, "error", "Error", "bad data length");
546 if ((value
= strndup((char *)(port
->
547 p_med_location
[i
].data
+ l
+ 2),
548 calength
)) == NULL
) {
549 fatalx("not enough memory");
553 map_lookup(civic_address_type_tags
,catype
),
554 map_lookup(civic_address_type_values
,catype
),
561 case LLDPMED_LOCFORMAT_ELIN
:
562 if ((value
= strndup((char *)(port
->
563 p_med_location
[i
].data
),
564 port
->p_med_location
[i
].data_len
)) == NULL
) {
565 fatalx( "not enough memory");
568 tag_attr(w
, "type", "Type", "elin");
569 tag_datatag(w
, "ecs", "ECS ELIN", value
);
573 tag_attr(w
, "type", "", "unknown");
574 tag_datatag(w
, "unknown", "Data",
575 dump(port
->p_med_location
[i
].data
,
576 port
->p_med_location
[i
].data_len
, 20, ' '));
581 if (port
->p_med_power
.devicetype
) {
582 tag_start(w
, "poe", "Extended Power-over-Ethernet");
584 tag_start(w
, "device-type", "Power Type & Source");
585 tag_data(w
, map_lookup(port_med_pow_devicetype_map
, port
->p_med_power
.devicetype
));
588 tag_start(w
, "source", "Power Source");
589 tag_data(w
, map_lookup(port_med_pow_source_map
, port
->p_med_power
.source
));
592 tag_start(w
, "priority", "Power Priority");
593 tag_data(w
, map_lookup(port_med_pow_priority_map
, port
->p_med_power
.priority
));
596 if(port
->p_med_power
.val
< 1024) {
597 tag_start(w
, "power", "Power Value");
598 tag_data(w
, u2str(port
->p_med_power
.val
* 100));
603 if (chassis
->c_med_hw
||
607 chassis
->c_med_manuf
||
608 chassis
->c_med_model
||
609 chassis
->c_med_asset
) {
610 tag_start(w
, "inventory", "Inventory");
612 if (chassis
->c_med_hw
)
613 tag_datatag(w
, "hardware", "Hardware Revision",
615 if (chassis
->c_med_sw
)
616 tag_datatag(w
, "software", "Software Revision",
618 if (chassis
->c_med_fw
)
619 tag_datatag(w
, "firmware", "Firmware Revision",
621 if (chassis
->c_med_sn
)
622 tag_datatag(w
, "serial", "Serial Number",
624 if (chassis
->c_med_manuf
)
625 tag_datatag(w
, "manufacturer", "Manufacturer",
626 chassis
->c_med_manuf
);
627 if (chassis
->c_med_model
)
628 tag_datatag(w
, "model", "Model",
629 chassis
->c_med_model
);
630 if (chassis
->c_med_asset
)
631 tag_datatag(w
, "asset", "Asset ID",
632 chassis
->c_med_asset
);
642 display_chassis(struct writer
* w
, struct lldpd_chassis
*chassis
)
646 struct lldpd_mgmt
*mgmt
;
647 char addrbuf
[INET6_ADDRSTRLEN
];
649 if ((cid
= (char *)malloc(chassis
->c_id_len
+ 1)) == NULL
)
651 memcpy(cid
, chassis
->c_id
, chassis
->c_id_len
);
652 cid
[chassis
->c_id_len
] = 0;
654 tag_start(w
, "chassis", "Chassis");
655 tag_start(w
, "id", "ChassisID");
656 tag_attr (w
, "type", "", map_lookup(chassis_id_subtype_map
, chassis
->c_id_subtype
));
658 switch (chassis
->c_id_subtype
) {
659 case LLDP_CHASSISID_SUBTYPE_IFNAME
:
660 case LLDP_CHASSISID_SUBTYPE_IFALIAS
:
661 case LLDP_CHASSISID_SUBTYPE_LOCAL
:
664 case LLDP_CHASSISID_SUBTYPE_LLADDR
:
665 tag_data(w
, dump(chassis
->c_id
, chassis
->c_id_len
, ETH_ALEN
, ':'));
667 case LLDP_CHASSISID_SUBTYPE_ADDR
:
668 if (*(u_int8_t
*)chassis
->c_id
== 1) {
669 memcpy(&ip
, chassis
->c_id
+ 1, sizeof(struct in_addr
));
670 tag_data(w
, inet_ntoa(ip
));
673 case LLDP_CHASSISID_SUBTYPE_PORT
:
674 case LLDP_CHASSISID_SUBTYPE_CHASSIS
:
676 tag_data(w
, dump(chassis
->c_id
, chassis
->c_id_len
, 16, ' '));
681 tag_datatag(w
, "name", "SysName", chassis
->c_name
);
682 tag_datatag(w
, "descr", "SysDescr", chassis
->c_descr
);
684 TAILQ_FOREACH(mgmt
, &chassis
->c_mgmt
, m_entries
) {
685 memset(addrbuf
, 0, sizeof(addrbuf
));
686 inet_ntop(lldpd_af(mgmt
->m_family
), &mgmt
->m_addr
, addrbuf
, sizeof(addrbuf
));
687 switch (mgmt
->m_family
) {
689 tag_datatag(w
, "mgmt-ip", "MgmtIP", addrbuf
);
692 tag_datatag(w
, "mgmt-ip6", "MgmtIPv6", addrbuf
);
697 display_cap(w
, chassis
, LLDP_CAP_OTHER
, "Other");
698 display_cap(w
, chassis
, LLDP_CAP_REPEATER
, "Repeater");
699 display_cap(w
, chassis
, LLDP_CAP_BRIDGE
, "Bridge");
700 display_cap(w
, chassis
, LLDP_CAP_ROUTER
, "Router");
701 display_cap(w
, chassis
, LLDP_CAP_WLAN
, "Wlan");
702 display_cap(w
, chassis
, LLDP_CAP_TELEPHONE
, "Tel");
703 display_cap(w
, chassis
, LLDP_CAP_DOCSIS
, "Docsis");
704 display_cap(w
, chassis
, LLDP_CAP_STATION
, "Station");
711 display_autoneg(struct writer
* w
, struct lldpd_port
*port
, int bithd
, int bitfd
, char *desc
)
713 if (!((port
->p_macphy
.autoneg_advertised
& bithd
) ||
714 (port
->p_macphy
.autoneg_advertised
& bitfd
)))
717 tag_start(w
, "advertised", "Adv");
718 tag_attr(w
, "type", "", desc
);
719 tag_attr(w
, "hd", "HD", (port
->p_macphy
.autoneg_advertised
& bithd
)?"yes":"no");
720 tag_attr(w
, "fd", "FD", (port
->p_macphy
.autoneg_advertised
)?"yes":"no");
726 display_port(struct writer
* w
, struct lldpd_port
*port
)
729 struct in_addr address
;
731 if ((pid
= (char *)malloc(port
->p_id_len
+ 1)) == NULL
)
733 memcpy(pid
, port
->p_id
, port
->p_id_len
);
734 pid
[port
->p_id_len
] = 0;
736 tag_start(w
, "port", "Port");
737 tag_start(w
, "id", "PortID");
738 tag_attr (w
, "type", "", map_lookup(port_id_subtype_map
, port
->p_id_subtype
));
740 switch (port
->p_id_subtype
) {
741 case LLDP_PORTID_SUBTYPE_IFNAME
:
742 case LLDP_PORTID_SUBTYPE_IFALIAS
:
743 case LLDP_PORTID_SUBTYPE_LOCAL
:
746 case LLDP_PORTID_SUBTYPE_LLADDR
:
747 tag_data(w
, dump(port
->p_id
, port
->p_id_len
, ETH_ALEN
, ':'));
749 case LLDP_PORTID_SUBTYPE_ADDR
:
750 if (*(u_int8_t
*)port
->p_id
== 1) {
751 memcpy(&address
, port
->p_id
+ 1,
752 sizeof(struct in_addr
));
753 tag_data(w
, inet_ntoa(address
));
756 case LLDP_PORTID_SUBTYPE_PORT
:
757 case LLDP_PORTID_SUBTYPE_AGENTCID
:
759 tag_data(w
, dump(port
->p_id
, port
->p_id_len
, 16, ' '));
764 tag_datatag(w
, "descr", "PortDescr", port
->p_descr
);
768 tag_datatag(w
, "mfs", "MFS", u2str(port
->p_mfs
));
770 if (port
->p_aggregid
)
771 tag_datatag(w
, "aggregation", " Port is aggregated. PortAggregID",
772 u2str(port
->p_aggregid
));
774 if (port
->p_macphy
.autoneg_support
|| port
->p_macphy
.autoneg_enabled
||
775 port
->p_macphy
.mau_type
) {
776 tag_start(w
, "auto-negotiation", "PMD autoneg");
777 tag_attr (w
, "supported", "supported",
778 port
->p_macphy
.autoneg_support
?"yes":"no");
779 tag_attr (w
, "enabled", "enabled",
780 port
->p_macphy
.autoneg_enabled
?"yes":"no");
782 if (port
->p_macphy
.autoneg_enabled
) {
783 display_autoneg(w
, port
, LLDP_DOT3_LINK_AUTONEG_10BASE_T
,
784 LLDP_DOT3_LINK_AUTONEG_10BASET_FD
,
786 display_autoneg(w
, port
, LLDP_DOT3_LINK_AUTONEG_100BASE_TX
,
787 LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD
,
789 display_autoneg(w
, port
, LLDP_DOT3_LINK_AUTONEG_100BASE_T2
,
790 LLDP_DOT3_LINK_AUTONEG_100BASE_T2FD
,
792 display_autoneg(w
, port
, LLDP_DOT3_LINK_AUTONEG_1000BASE_X
,
793 LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD
,
795 display_autoneg(w
, port
, LLDP_DOT3_LINK_AUTONEG_1000BASE_T
,
796 LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD
,
799 tag_datatag(w
, "current", "MAU oper type",
800 map_lookup(operational_mau_type_values
, port
->p_macphy
.mau_type
));
803 if (port
->p_power
.devicetype
) {
804 tag_start(w
, "power", "MDI Power");
805 tag_attr(w
, "supported", "supported",
806 port
->p_power
.supported
?"yes":"no");
807 tag_attr(w
, "enabled", "enabled",
808 port
->p_power
.enabled
?"yes":"no");
809 tag_attr(w
, "paircontrol", "pair control",
810 port
->p_power
.paircontrol
?"yes":"no");
811 tag_start(w
, "device-type", "Device type");
812 tag_data(w
, map_lookup(port_dot3_power_devicetype_map
,
813 port
->p_power
.devicetype
));
815 tag_start(w
, "pairs", "Power pairs");
816 tag_data(w
, map_lookup(port_dot3_power_pairs_map
,
817 port
->p_power
.pairs
));
819 tag_start(w
, "class", "Class");
820 tag_data(w
, map_lookup(port_dot3_power_class_map
,
821 port
->p_power
.class));
825 if (port
->p_power
.powertype
!= LLDP_DOT3_POWER_8023AT_OFF
) {
826 tag_start(w
, "power-type", "Power type");
827 tag_data(w
, u2str(port
->p_power
.powertype
));
830 tag_start(w
, "source", "Power Source");
831 tag_data(w
, map_lookup(
832 (port
->p_power
.devicetype
== LLDP_DOT3_POWER_PSE
)?
833 port_dot3_power_pse_source_map
:
834 port_dot3_power_pd_source_map
,
835 port
->p_power
.source
));
838 tag_start(w
, "priority", "Power Priority");
839 tag_data(w
, map_lookup(port_dot3_power_priority_map
,
840 port
->p_power
.priority
));
843 tag_start(w
, "requested", "PD requested power Value");
844 tag_data(w
, u2str(port
->p_power
.requested
* 100));
847 tag_start(w
, "allocated", "PSE allocated power Value");
848 tag_data(w
, u2str(port
->p_power
.allocated
* 100));
860 display_vlans(struct writer
*w
, struct lldpd_port
*port
)
863 struct lldpd_vlan
*vlan
;
864 TAILQ_FOREACH(vlan
, &port
->p_vlans
, v_entries
) {
865 if (port
->p_pvid
== vlan
->v_vid
)
868 tag_start(w
, "vlan", "VLAN");
869 tag_attr(w
, "vlan-id", "", u2str(vlan
->v_vid
));
870 if (port
->p_pvid
== vlan
->v_vid
)
871 tag_attr(w
, "pvid", "pvid", "yes");
872 tag_data(w
, vlan
->v_name
);
875 if (!foundpvid
&& port
->p_pvid
) {
876 tag_start(w
, "vlan", "VLAN");
877 tag_attr(w
, "vlan-id", "", u2str(port
->p_pvid
));
878 tag_attr(w
, "pvid", "pvid", "yes");
884 display_ppvids(struct writer
*w
, struct lldpd_port
*port
)
886 struct lldpd_ppvid
*ppvid
;
887 TAILQ_FOREACH(ppvid
, &port
->p_ppvids
, p_entries
) {
888 tag_start(w
, "ppvid", "PPVID");
890 tag_attr(w
, "value", "", u2str(ppvid
->p_ppvid
));
891 tag_attr(w
, "supported", "supported",
892 (ppvid
->p_cap_status
& LLDPD_PPVID_CAP_SUPPORTED
)?"yes":"no");
893 tag_attr(w
, "enabled", "enabled",
894 (ppvid
->p_cap_status
& LLDPD_PPVID_CAP_ENABLED
)?"yes":"no");
900 display_pids(struct writer
*w
, struct lldpd_port
*port
)
904 TAILQ_FOREACH(pi
, &port
->p_pids
, p_entries
) {
905 if (!pi
->p_pi_len
) continue;
906 tag_start(w
, "pi", "PI");
907 /* Convert to hex for display */
908 if ((hex
= malloc(pi
->p_pi_len
* 2 + 1)) == NULL
)
910 for (int i
= 0; i
< pi
->p_pi_len
; i
++)
911 snprintf(hex
+ 2*i
, 3, "%02X", (unsigned char)pi
->p_pi
[i
]);
920 display_age(struct lldpd_port
*port
)
922 static char sage
[30];
923 int age
= (int)(time(NULL
) - port
->p_lastchange
);
924 if (snprintf(sage
, sizeof(sage
),
925 "%d day%s, %02d:%02d:%02d",
927 (age
/ (60*60*24) > 1)?"s":"",
928 (age
/ (60*60)) % 24,
930 age
% 60) >= sizeof(sage
))
937 display_interfaces(int s
, const char * fmt
, int hidden
, int argc
, char *argv
[])
941 if ( strcmp(fmt
,"plain") == 0 ) {
942 w
= txt_init( stdout
);
943 } else if (strcmp(fmt
, "keyvalue") == 0) {
944 w
= kv_init( stdout
);
947 else if ( strcmp(fmt
,"xml") == 0 ) {
948 w
= xml_init( stdout
);
952 w
= txt_init( stdout
);
956 memset(sep
, '-', 79);
959 struct lldpd_interface
*iff
;
960 struct lldpd_interface_list
*ifs
= get_interfaces(s
);
961 tag_start(w
, "lldp", "LLDP neighbors");
963 TAILQ_FOREACH(iff
, ifs
, next
) {
965 for (i
= optind
; i
< argc
; i
++)
966 if (strncmp(argv
[i
], iff
->name
, IFNAMSIZ
) == 0)
972 struct lldpd_port
*port
;
973 struct lldpd_chassis
*chassis
;
974 struct lldpd_hardware
*hardware
= get_interface(s
, iff
->name
);
975 if (TAILQ_EMPTY(&hardware
->h_rports
))
977 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
) {
978 if (!hidden
&& SMART_HIDDEN(port
)) continue;
979 chassis
= port
->p_chassis
;
981 tag_start(w
, "interface", "Interface");
982 tag_attr(w
, "name", "", iff
->name
);
983 tag_attr(w
, "via" , "via", map_lookup(lldpd_protocol_map
, port
->p_protocol
));
984 tag_attr(w
, "rid" , "RID", u2str(chassis
->c_index
));
985 tag_attr(w
, "age" , "Time", display_age(port
));
987 display_chassis(w
,chassis
);
988 display_port(w
, port
);
990 if (!TAILQ_EMPTY(&port
->p_vlans
) || port
->p_pvid
) {
991 display_vlans(w
, port
);
993 if (!TAILQ_EMPTY(&port
->p_ppvids
)) {
994 display_ppvids(w
, port
);
996 if (!TAILQ_EMPTY(&port
->p_pids
)) {
997 display_pids(w
, port
);
1000 #ifdef ENABLE_LLDPMED
1001 if (port
->p_med_cap_enabled
) {
1002 display_med(w
, chassis
, port
);
1005 tag_end(w
); /* interface */