From 2212d76d08f3bc34c683aed1a6736325b841625c Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Sun, 21 Jun 2015 20:27:04 +0200 Subject: lldp: add reference counter to struct tlv_packet Add a reference counter to the tlv_packet structure so that it can be shared between multiple users and properly free'd when no longer in use. --- src/libsystemd-network/lldp-tlv.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/libsystemd-network/lldp-tlv.h') diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h index ce3334e115..f682997031 100644 --- a/src/libsystemd-network/lldp-tlv.h +++ b/src/libsystemd-network/lldp-tlv.h @@ -45,6 +45,8 @@ int tlv_section_new(tlv_section **ret); void tlv_section_free(tlv_section *ret); struct tlv_packet { + unsigned n_ref; + uint16_t type; uint16_t length; usec_t ts; @@ -61,10 +63,11 @@ struct tlv_packet { }; int tlv_packet_new(tlv_packet **ret); -void tlv_packet_free(tlv_packet *m); +tlv_packet *tlv_packet_ref(tlv_packet *m); +tlv_packet *tlv_packet_unref(tlv_packet *m); -DEFINE_TRIVIAL_CLEANUP_FUNC(tlv_packet*, tlv_packet_free); -#define _cleanup_tlv_packet_free_ _cleanup_(tlv_packet_freep) +DEFINE_TRIVIAL_CLEANUP_FUNC(tlv_packet*, tlv_packet_unref); +#define _cleanup_tlv_packet_free_ _cleanup_(tlv_packet_unrefp) int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type); int lldp_tlv_packet_close_container(tlv_packet *m); -- cgit v1.2.3-54-g00ecf From 176c355b43e616b61552566303ad59d5fd910333 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 10 Jul 2015 18:43:12 +0200 Subject: lldp: export opaque TLV type and accessor functions Export struct tlv_packet as a public opaque sd_lldp_packet type and make its accessor functions public. --- src/libsystemd-network/lldp-internal.c | 61 +++++++++++++++++----------------- src/libsystemd-network/lldp-internal.h | 8 ----- src/libsystemd-network/lldp-network.c | 2 +- src/libsystemd-network/lldp-tlv.c | 4 +-- src/libsystemd-network/lldp-tlv.h | 8 ++--- src/libsystemd-network/sd-lldp.c | 10 +++--- src/libsystemd-network/test-lldp.c | 4 +-- src/systemd/sd-lldp.h | 12 +++++++ 8 files changed, 57 insertions(+), 52 deletions(-) (limited to 'src/libsystemd-network/lldp-tlv.h') diff --git a/src/libsystemd-network/lldp-internal.c b/src/libsystemd-network/lldp-internal.c index 7695805946..762a1d2895 100644 --- a/src/libsystemd-network/lldp-internal.c +++ b/src/libsystemd-network/lldp-internal.c @@ -21,6 +21,7 @@ ***/ #include "lldp-internal.h" +#include "sd-lldp.h" /* We store maximum 1K chassis entries */ #define LLDP_MIB_MAX_CHASSIS 1024 @@ -28,10 +29,10 @@ /* Maximum Ports can be attached to any chassis */ #define LLDP_MIB_MAX_PORT_PER_CHASSIS 32 -int lldp_read_chassis_id(tlv_packet *tlv, - uint8_t *type, - uint8_t **data, - uint16_t *length) { +int sd_lldp_packet_read_chassis_id(tlv_packet *tlv, + uint8_t *type, + uint8_t **data, + uint16_t *length) { uint8_t subtype; int r; @@ -67,10 +68,10 @@ int lldp_read_chassis_id(tlv_packet *tlv, return r; } -int lldp_read_port_id(tlv_packet *tlv, - uint8_t *type, - uint8_t **data, - uint16_t *length) { +int sd_lldp_packet_read_port_id(tlv_packet *tlv, + uint8_t *type, + uint8_t **data, + uint16_t *length) { uint8_t subtype; char *s; int r; @@ -119,7 +120,7 @@ int lldp_read_port_id(tlv_packet *tlv, return r; } -int lldp_read_ttl(tlv_packet *tlv, uint16_t *ttl) { +int sd_lldp_packet_read_ttl(tlv_packet *tlv, uint16_t *ttl) { int r; assert_return(tlv, -EINVAL); @@ -136,9 +137,9 @@ int lldp_read_ttl(tlv_packet *tlv, uint16_t *ttl) { return r; } -int lldp_read_system_name(tlv_packet *tlv, - char **data, - uint16_t *length) { +int sd_lldp_packet_read_system_name(tlv_packet *tlv, + char **data, + uint16_t *length) { char *s; int r; @@ -160,9 +161,9 @@ int lldp_read_system_name(tlv_packet *tlv, return r; } -int lldp_read_system_description(tlv_packet *tlv, - char **data, - uint16_t *length) { +int sd_lldp_packet_read_system_description(tlv_packet *tlv, + char **data, + uint16_t *length) { char *s; int r; @@ -184,9 +185,9 @@ int lldp_read_system_description(tlv_packet *tlv, return r; } -int lldp_read_port_description(tlv_packet *tlv, - char **data, - uint16_t *length) { +int sd_lldp_packet_read_port_description(tlv_packet *tlv, + char **data, + uint16_t *length) { char *s; int r; @@ -208,7 +209,7 @@ int lldp_read_port_description(tlv_packet *tlv, return r; } -int lldp_read_system_capability(tlv_packet *tlv, uint16_t *data) { +int sd_lldp_packet_read_system_capability(tlv_packet *tlv, uint16_t *data) { int r; assert_return(tlv, -EINVAL); @@ -244,7 +245,7 @@ int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) { assert_return(c, -EINVAL); assert_return(tlv, -EINVAL); - r = lldp_read_port_id(tlv, &type, &data, &length); + r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); if (r < 0) return r; @@ -253,13 +254,13 @@ int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) { if ((p->type == type && p->length == length && !memcmp(p->data, data, p->length))) { - r = lldp_read_ttl(tlv, &ttl); + r = sd_lldp_packet_read_ttl(tlv, &ttl); if (r < 0) return r; p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic()); - tlv_packet_unref(p->packet); + sd_lldp_packet_unref(p->packet); p->packet = tlv; prioq_reshuffle(p->c->by_expiry, p, &p->prioq_idx); @@ -281,7 +282,7 @@ int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv) { assert_return(c, -EINVAL); assert_return(tlv, -EINVAL); - r = lldp_read_port_id(tlv, &type, &data, &length); + r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); if (r < 0) return r; @@ -312,11 +313,11 @@ int lldp_mib_add_objects(Prioq *by_expiry, assert_return(neighbour_mib, -EINVAL); assert_return(tlv, -EINVAL); - r = lldp_read_chassis_id(tlv, &subtype, &data, &length); + r = sd_lldp_packet_read_chassis_id(tlv, &subtype, &data, &length); if (r < 0) goto drop; - r = lldp_read_ttl(tlv, &ttl); + r = sd_lldp_packet_read_ttl(tlv, &ttl); if (r < 0) goto drop; @@ -401,7 +402,7 @@ int lldp_mib_add_objects(Prioq *by_expiry, return 0; drop: - tlv_packet_unref(tlv); + sd_lldp_packet_unref(tlv); if (new_chassis) hashmap_remove(neighbour_mib, &c->chassis_id); @@ -435,7 +436,7 @@ void lldp_neighbour_port_free(lldp_neighbour_port *p) { if(!p) return; - tlv_packet_unref(p->packet); + sd_lldp_packet_unref(p->packet); free(p->data); free(p); @@ -452,11 +453,11 @@ int lldp_neighbour_port_new(lldp_chassis *c, assert(tlv); - r = lldp_read_port_id(tlv, &type, &data, &length); + r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); if (r < 0) return r; - r = lldp_read_ttl(tlv, &ttl); + r = sd_lldp_packet_read_ttl(tlv, &ttl); if (r < 0) return r; @@ -505,7 +506,7 @@ int lldp_chassis_new(tlv_packet *tlv, assert(tlv); - r = lldp_read_chassis_id(tlv, &type, &data, &length); + r = sd_lldp_packet_read_chassis_id(tlv, &type, &data, &length); if (r < 0) return r; diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h index c61080828b..774562e171 100644 --- a/src/libsystemd-network/lldp-internal.h +++ b/src/libsystemd-network/lldp-internal.h @@ -86,13 +86,5 @@ int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv); int lldp_mib_add_objects(Prioq *by_expiry, Hashmap *neighbour_mib, tlv_packet *tlv); int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv); -int lldp_read_chassis_id(tlv_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length); -int lldp_read_port_id(tlv_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length); -int lldp_read_ttl(tlv_packet *tlv, uint16_t *ttl); -int lldp_read_system_name(tlv_packet *tlv, char **data, uint16_t *length); -int lldp_read_system_description(tlv_packet *tlv, char **data, uint16_t *length); -int lldp_read_system_capability(tlv_packet *tlv, uint16_t *data); -int lldp_read_port_description(tlv_packet *tlv, char **data, uint16_t *length); - int lldp_handle_packet(tlv_packet *m, uint16_t length); #define log_lldp(fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c index 664d2f7867..1c6dcae14d 100644 --- a/src/libsystemd-network/lldp-network.c +++ b/src/libsystemd-network/lldp-network.c @@ -84,7 +84,7 @@ int lldp_network_bind_raw_socket(int ifindex) { } int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_tlv_packet_free_ tlv_packet *packet = NULL; + _cleanup_lldp_packet_unref_ tlv_packet *packet = NULL; tlv_packet *p; uint16_t length; int r; diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c index 1370d217f4..700da2fde7 100644 --- a/src/libsystemd-network/lldp-tlv.c +++ b/src/libsystemd-network/lldp-tlv.c @@ -61,7 +61,7 @@ int tlv_packet_new(tlv_packet **ret) { return 0; } -tlv_packet *tlv_packet_ref(tlv_packet *m) { +tlv_packet *sd_lldp_packet_ref(tlv_packet *m) { if (!m) return NULL; @@ -72,7 +72,7 @@ tlv_packet *tlv_packet_ref(tlv_packet *m) { return m; } -tlv_packet *tlv_packet_unref(tlv_packet *m) { +tlv_packet *sd_lldp_packet_unref(tlv_packet *m) { tlv_section *s, *n; if (!m) diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h index f682997031..19509d3589 100644 --- a/src/libsystemd-network/lldp-tlv.h +++ b/src/libsystemd-network/lldp-tlv.h @@ -28,6 +28,8 @@ #include "lldp.h" #include "list.h" +#include "sd-lldp.h" + typedef struct tlv_packet tlv_packet; typedef struct tlv_section tlv_section; @@ -63,11 +65,9 @@ struct tlv_packet { }; int tlv_packet_new(tlv_packet **ret); -tlv_packet *tlv_packet_ref(tlv_packet *m); -tlv_packet *tlv_packet_unref(tlv_packet *m); -DEFINE_TRIVIAL_CLEANUP_FUNC(tlv_packet*, tlv_packet_unref); -#define _cleanup_tlv_packet_free_ _cleanup_(tlv_packet_unrefp) +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_lldp_packet*, sd_lldp_packet_unref); +#define _cleanup_lldp_packet_unref_ _cleanup_(sd_lldp_packet_unrefp) int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type); int lldp_tlv_packet_close_container(tlv_packet *m); diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 5a03ab4448..2b788e78cd 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -338,7 +338,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { lldp->statistics.stats_frames_in_errors_total ++; } - tlv_packet_unref(tlv); + sd_lldp_packet_unref(tlv); return 0; } @@ -455,7 +455,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { _cleanup_free_ char *s = NULL; char *k, *t; - r = lldp_read_chassis_id(p->packet, &type, &mac, &length); + r = sd_lldp_packet_read_chassis_id(p->packet, &type, &mac, &length); if (r < 0) continue; @@ -468,7 +468,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { goto fail; } - r = lldp_read_port_id(p->packet, &type, &port_id, &length); + r = sd_lldp_packet_read_port_id(p->packet, &type, &port_id, &length); if (r < 0) continue; @@ -513,7 +513,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { free(s); s = k; - r = lldp_read_system_name(p->packet, &k, &length); + r = sd_lldp_packet_read_system_name(p->packet, &k, &length); if (r < 0) k = strappend(s, "'_NAME=N/A' "); else { @@ -535,7 +535,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { free(s); s = k; - (void) lldp_read_system_capability(p->packet, &data); + (void) sd_lldp_packet_read_system_capability(p->packet, &data); sprintf(buf, "'_CAP=%x'", data); diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index 06545aee59..26f64347a7 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -38,7 +38,7 @@ static struct ether_addr mac_addr = { }; static int lldp_build_tlv_packet(tlv_packet **ret) { - _cleanup_tlv_packet_free_ tlv_packet *m = NULL; + _cleanup_lldp_packet_unref_ tlv_packet *m = NULL; const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR; struct ether_header ether = { .ether_type = htons(ETHERTYPE_LLDP), @@ -216,7 +216,7 @@ static int lldp_parse_tlv_packet(tlv_packet *m, int len) { } int main(int argc, char *argv[]) { - _cleanup_tlv_packet_free_ tlv_packet *tlv = NULL; + _cleanup_lldp_packet_unref_ tlv_packet *tlv = NULL; /* form a packet */ lldp_build_tlv_packet(&tlv); diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index 0680e526b0..efa76dacf7 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -29,6 +29,7 @@ enum { }; typedef struct sd_lldp sd_lldp; +typedef struct tlv_packet sd_lldp_packet; typedef void (*sd_lldp_cb_t)(sd_lldp *lldp, int event, void *userdata); @@ -43,3 +44,14 @@ int sd_lldp_detach_event(sd_lldp *lldp); int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata); int sd_lldp_save(sd_lldp *lldp, const char *file); + +int sd_lldp_packet_read_chassis_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length); +int sd_lldp_packet_read_port_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length); +int sd_lldp_packet_read_ttl(sd_lldp_packet *tlv, uint16_t *ttl); +int sd_lldp_packet_read_system_name(sd_lldp_packet *tlv, char **data, uint16_t *length); +int sd_lldp_packet_read_system_description(sd_lldp_packet *tlv, char **data, uint16_t *length); +int sd_lldp_packet_read_system_capability(sd_lldp_packet *tlv, uint16_t *data); +int sd_lldp_packet_read_port_description(sd_lldp_packet *tlv, char **data, uint16_t *length); + +sd_lldp_packet *sd_lldp_packet_ref(sd_lldp_packet *tlv); +sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv); -- cgit v1.2.3-54-g00ecf From 4fc6de5df31c81ae35e82ed91d0a2ee515edad41 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 27 Jul 2015 18:04:46 +0200 Subject: lldp: add sd_lldp_tlv_packet_get_destination_type() It can be useful to know the destination address of a LLDP frame because it determines the scope of propagation of the frame and thus this information be used to know whether the neighbor is connected to the same physical link. See clause 7.1 of IEEE Std 802.1AB-2009. --- src/libsystemd-network/lldp-tlv.c | 17 +++++++++++++++++ src/libsystemd-network/lldp-tlv.h | 4 ++++ src/libsystemd-network/test-lldp.c | 11 +++++++++++ src/systemd/sd-lldp.h | 8 ++++++++ 4 files changed, 40 insertions(+) (limited to 'src/libsystemd-network/lldp-tlv.h') diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c index 24f2606f31..996c5b8881 100644 --- a/src/libsystemd-network/lldp-tlv.c +++ b/src/libsystemd-network/lldp-tlv.c @@ -539,3 +539,20 @@ int sd_lldp_packet_read_system_capability(tlv_packet *tlv, uint16_t *data) { return r; } + +int sd_lldp_packet_get_destination_type(tlv_packet *tlv, int *dest) { + assert_return(tlv, -EINVAL); + assert_return(dest, -EINVAL); + + /* 802.1AB-2009, Table 7-1 */ + if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_BRIDGE, ETH_ALEN)) + *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE; + else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE, ETH_ALEN)) + *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE; + else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE, ETH_ALEN)) + *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE; + else + return -EINVAL; + + return 0; +} diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h index 19509d3589..5af06b40ca 100644 --- a/src/libsystemd-network/lldp-tlv.h +++ b/src/libsystemd-network/lldp-tlv.h @@ -43,6 +43,10 @@ struct tlv_section { LIST_FIELDS(tlv_section, section); }; +#define LLDP_MAC_NEAREST_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } +#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 } +#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 } + int tlv_section_new(tlv_section **ret); void tlv_section_free(tlv_section *ret); diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index 26f64347a7..294198a0b5 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -202,6 +202,15 @@ static int lldp_parse_ttl_tlv(tlv_packet *m) { return 0; } +static int lldp_get_destination_type(tlv_packet *m) { + int dest; + + assert_se(sd_lldp_packet_get_destination_type(m, &dest) >= 0); + assert_se(dest == SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE); + + return 0; +} + static int lldp_parse_tlv_packet(tlv_packet *m, int len) { uint8_t subtype; @@ -212,6 +221,8 @@ static int lldp_parse_tlv_packet(tlv_packet *m, int len) { assert_se(lldp_parse_ttl_tlv(m) >= 0); assert_se(lldp_parse_system_desc_tlv(m) >= 0); + assert_se(lldp_get_destination_type(m) >= 0); + return 0; } diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index e472cbece9..bf6dfc1ee0 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -28,6 +28,12 @@ enum { SD_LLDP_EVENT_UPDATE_INFO = 0, }; +enum { + SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE, + SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE, + SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE, +}; + typedef struct sd_lldp sd_lldp; typedef struct tlv_packet sd_lldp_packet; @@ -56,4 +62,6 @@ int sd_lldp_packet_read_port_description(sd_lldp_packet *tlv, char **data, uint1 sd_lldp_packet *sd_lldp_packet_ref(sd_lldp_packet *tlv); sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv); +int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest); + int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs); -- cgit v1.2.3-54-g00ecf From d8c89d6198651e34786bc78df26f313eede9918b Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 27 Jul 2015 23:37:07 +0200 Subject: lldp: add support for organizationally specific TLVs LLDP TLVs of type 127 are used to carry organizationally specific information and include additional fields to specify the OUI and subtype. Add support for parsing such fields and functions to access the most common IEEE 802.1 specific TLVs. --- src/libsystemd-network/lldp-tlv.c | 139 +++++++++++++++++++++++++++++++++++++- src/libsystemd-network/lldp-tlv.h | 5 ++ src/libsystemd-network/lldp.h | 13 ++++ src/libsystemd-network/sd-lldp.c | 2 +- src/systemd/sd-lldp.h | 7 ++ 5 files changed, 164 insertions(+), 2 deletions(-) (limited to 'src/libsystemd-network/lldp-tlv.h') diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c index b967f34a99..b3f0bfb1e9 100644 --- a/src/libsystemd-network/lldp-tlv.c +++ b/src/libsystemd-network/lldp-tlv.c @@ -277,7 +277,7 @@ int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) { p = m->pdu; - /* extract ethernet herader */ + /* extract ethernet header */ memcpy(&m->mac, p, ETH_ALEN); p += sizeof(struct ether_header); @@ -297,6 +297,17 @@ int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) { } p += 2; + + if (section->type == LLDP_TYPE_PRIVATE && + section->length >= LLDP_OUI_LEN + 1) { + section->oui = p; + p += LLDP_OUI_LEN; + section->subtype = *p++; + + section->length -= LLDP_OUI_LEN + 1; + l += LLDP_OUI_LEN + 1; + } + section->data = p; LIST_FIND_TAIL(section, m->sections, tail); @@ -313,6 +324,7 @@ int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type) { tlv_section *s; assert_return(m, -EINVAL); + assert_return(type != LLDP_TYPE_PRIVATE, -EINVAL); LIST_FOREACH(section, s, m->sections) if (s->type == type) @@ -331,6 +343,34 @@ int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type) { return 0; } +int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype) { + tlv_section *s; + + assert_return(m, -EINVAL); + assert_return(oui, -EINVAL); + + LIST_FOREACH(section, s, m->sections) { + if (s->type == LLDP_TYPE_PRIVATE && + s->oui && + s->subtype == subtype && + !memcmp(s->oui, oui, LLDP_OUI_LEN)) + break; + } + + if (!s) + return -1; + + m->container = s; + + m->container->read_pos = s->data; + if (!m->container->read_pos) { + m->container = 0; + return -1; + } + + return 0; +} + int lldp_tlv_packet_exit_container(tlv_packet *m) { assert_return(m, -EINVAL); @@ -495,6 +535,103 @@ int sd_lldp_packet_read_system_capability(tlv_packet *tlv, uint16_t *data) { return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_SYSTEM_CAPABILITIES, data); } +int sd_lldp_packet_read_port_vlan_id(tlv_packet *tlv, uint16_t *id) { + int r; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID); + if (r < 0) + goto out; + + r = tlv_packet_read_u16(tlv, id); + + (void) lldp_tlv_packet_exit_container(tlv); + + out: + return r; +} + +int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id) { + int r; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID); + if (r < 0) + goto out; + + r = tlv_packet_read_u8(tlv, flags); + if (r >= 0) + r = tlv_packet_read_u16(tlv, id); + + (void) lldp_tlv_packet_exit_container(tlv); + + out: + return r; +} + +int sd_lldp_packet_read_vlan_name(tlv_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length) { + int r; + uint8_t len = 0; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_VLAN_NAME); + if (r < 0) + goto out; + + r = tlv_packet_read_u16(tlv, vlan_id); + if (r >= 0) + r = tlv_packet_read_u8(tlv, &len); + if (r >= 0) + r = tlv_packet_read_string(tlv, name, length); + + if (r >= 0 && len < *length) + *length = len; + + (void) lldp_tlv_packet_exit_container(tlv); + + out: + return r; +} + +int sd_lldp_packet_read_management_vid(tlv_packet *tlv, uint16_t *id) { + int r; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID); + if (r < 0) + goto out; + + r = tlv_packet_read_u16(tlv, id); + + (void) lldp_tlv_packet_exit_container(tlv); + + out: + return r; +} + +int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id) { + int r; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION); + if (r < 0) + goto out; + + r = tlv_packet_read_u8(tlv, status); + if (r >= 0) + r = tlv_packet_read_u32(tlv, id); + + (void) lldp_tlv_packet_exit_container(tlv); + + out: + return r; +} + int sd_lldp_packet_get_destination_type(tlv_packet *tlv, int *dest) { assert_return(tlv, -EINVAL); assert_return(dest, -EINVAL); diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h index 5af06b40ca..2d2c776be6 100644 --- a/src/libsystemd-network/lldp-tlv.h +++ b/src/libsystemd-network/lldp-tlv.h @@ -33,9 +33,13 @@ typedef struct tlv_packet tlv_packet; typedef struct tlv_section tlv_section; +#define LLDP_OUI_LEN 3 + struct tlv_section { uint16_t type; uint16_t length; + uint8_t *oui; + uint8_t subtype; uint8_t *read_pos; uint8_t *data; @@ -83,6 +87,7 @@ int tlv_packet_append_u32(tlv_packet *m, uint32_t data); int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size); int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type); +int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype); int lldp_tlv_packet_exit_container(tlv_packet *m); int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length); diff --git a/src/libsystemd-network/lldp.h b/src/libsystemd-network/lldp.h index 5e4b283e26..19e5cc5f41 100644 --- a/src/libsystemd-network/lldp.h +++ b/src/libsystemd-network/lldp.h @@ -113,3 +113,16 @@ typedef enum LLDPMedCapability { LLDP_MED_CAPABILITY_MAX, LLDP_MED_CAPABILITY_INVALID = -1, } LLDPMedCapability; + +#define LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 } +#define LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f } + +enum { + LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID = 1, + LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID = 2, + LLDP_OUI_SUBTYPE_802_1_VLAN_NAME = 3, + LLDP_OUI_SUBTYPE_802_1_PROTOCOL_IDENTITY = 4, + LLDP_OUI_SUBTYPE_802_1_VID_USAGE_DIGEST = 5, + LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID = 6, + LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION = 7, +}; diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index a343370e96..7aa405a655 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -199,7 +199,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { goto out; } - /* skip type and lengh encoding */ + /* skip type and length encoding */ p += 2; q = p; diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index bf6dfc1ee0..308d42c6e9 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -59,6 +59,13 @@ int sd_lldp_packet_read_system_description(sd_lldp_packet *tlv, char **data, uin int sd_lldp_packet_read_system_capability(sd_lldp_packet *tlv, uint16_t *data); int sd_lldp_packet_read_port_description(sd_lldp_packet *tlv, char **data, uint16_t *length); +/* IEEE 802.1 organizationally specific TLVs */ +int sd_lldp_packet_read_port_vlan_id(sd_lldp_packet *tlv, uint16_t *id); +int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id); +int sd_lldp_packet_read_vlan_name(sd_lldp_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length); +int sd_lldp_packet_read_management_vid(sd_lldp_packet *tlv, uint16_t *id); +int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id); + sd_lldp_packet *sd_lldp_packet_ref(sd_lldp_packet *tlv); sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv); -- cgit v1.2.3-54-g00ecf