Closes #28354.
if (r < 0)
return r;
}
+
+ /* IEEE 802.1: VLAN ID */
+ if (memcmp(p, SD_LLDP_OUI_802_1_VLAN_ID, sizeof(SD_LLDP_OUI_802_1_VLAN_ID)) == 0) {
+ if (length != (sizeof(SD_LLDP_OUI_802_1_VLAN_ID) + sizeof(uint16_t)))
+ return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
+ "Found 802.1 VLAN ID TLV with wrong length, ignoring.");
+
+ n->has_port_vlan_id = true;
+ n->port_vlan_id = unaligned_read_be16(p + sizeof(SD_LLDP_OUI_802_1_VLAN_ID));
+ }
break;
}
return 0;
}
+int sd_lldp_neighbor_get_port_vlan_id(sd_lldp_neighbor *n, uint16_t *ret) {
+ assert_return(n, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (!n->has_port_vlan_id)
+ return -ENODATA;
+
+ *ret = n->port_vlan_id;
+ return 0;
+}
+
int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) {
assert_return(n, -EINVAL);
*system_name = NULL, *system_description = NULL;
uint16_t cc = 0;
bool valid_cc;
+ uint16_t vlanid = 0;
+ bool valid_vlanid;
assert(n);
assert(ret);
(void) sd_lldp_neighbor_get_system_description(n, &system_description);
valid_cc = sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0;
+ valid_vlanid = sd_lldp_neighbor_get_port_vlan_id(n, &vlanid) >= 0;
return sd_json_buildo(
ret,
JSON_BUILD_PAIR_STRING_NON_EMPTY("PortDescription", port_description),
JSON_BUILD_PAIR_STRING_NON_EMPTY("SystemName", system_name),
JSON_BUILD_PAIR_STRING_NON_EMPTY("SystemDescription", system_description),
- SD_JSON_BUILD_PAIR_CONDITION(valid_cc, "EnabledCapabilities", SD_JSON_BUILD_UNSIGNED(cc)));
+ SD_JSON_BUILD_PAIR_CONDITION(valid_cc, "EnabledCapabilities", SD_JSON_BUILD_UNSIGNED(cc)),
+ SD_JSON_BUILD_PAIR_CONDITION(valid_vlanid, "VlanID", SD_JSON_BUILD_UNSIGNED(vlanid)));
}
#include "sd-lldp-rx.h"
#include "fd-util.h"
+#include "json-util.h"
+#include "lldp-neighbor.h"
#include "lldp-network.h"
#include "tests.h"
assert_se(stop_lldp_rx(lldp_rx) == 0);
}
+static void test_receive_oui_vlanid_packet(sd_event *e) {
+ sd_lldp_rx *lldp_rx;
+ sd_lldp_neighbor **neighbors;
+ sd_json_variant *v;
+ _cleanup_(sd_json_variant_unrefp) sd_json_variant *neighbor_json = NULL;
+ static const uint8_t frame[] = {
+ /* Ethernet header */
+ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC */
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
+ 0x88, 0xcc, /* Ethertype */
+ /* LLDP mandatory TLVs */
+ 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
+ 0x03, 0x04, 0x05,
+ 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port TLV: interface name, "1/3" */
+ 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds */
+ /* LLDP optional TLVs */
+ 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x01, /* Port VLAN ID: 0x1234 */
+ 0x12, 0x34,
+ 0xfe, 0x07, 0x00, 0x80, 0xc2, 0x02, /* Port and protocol: flag 1, PPVID 0x7788 */
+ 0x01, 0x77, 0x88,
+ 0xfe, 0x0d, 0x00, 0x80, 0xc2, 0x03, /* VLAN Name: ID 0x1234, name "Vlan51" */
+ 0x12, 0x34, 0x06, 0x56, 0x6c, 0x61,
+ 0x6e, 0x35, 0x31,
+ 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x06, /* Management VID: 0x0102 */
+ 0x01, 0x02,
+ 0xfe, 0x09, 0x00, 0x80, 0xc2, 0x07, /* Link aggregation: status 1, ID 0x00140012 */
+ 0x01, 0x00, 0x14, 0x00, 0x12,
+ 0xfe, 0x07, 0x00, 0x12, 0x0f, 0x02, /* 802.3 Power via MDI: PSE, MDI enabled */
+ 0x07, 0x01, 0x00,
+ 0x00, 0x00 /* End of LLDPDU */
+ };
+ uint16_t vlanid;
+
+ lldp_rx_handler_calls = 0;
+ ASSERT_OK(start_lldp_rx(&lldp_rx, e, lldp_rx_handler, NULL));
+
+ ASSERT_OK_EQ_ERRNO(write(test_fd[1], frame, sizeof(frame)), (ssize_t)sizeof(frame));
+ ASSERT_OK(sd_event_run(e, 0));
+ ASSERT_EQ(lldp_rx_handler_calls, 1);
+ ASSERT_OK_EQ(sd_lldp_rx_get_neighbors(lldp_rx, &neighbors), 1);
+
+ ASSERT_OK(sd_lldp_neighbor_get_port_vlan_id(neighbors[0], &vlanid));
+ ASSERT_EQ(vlanid, 0x1234);
+
+ ASSERT_OK(lldp_neighbor_build_json(neighbors[0], &neighbor_json));
+ ASSERT_NOT_NULL(v = sd_json_variant_by_key(neighbor_json, "VlanID"));
+ ASSERT_EQ(sd_json_variant_type(v), SD_JSON_VARIANT_UNSIGNED);
+ ASSERT_EQ(sd_json_variant_unsigned(v), UINT64_C(0x1234));
+
+ sd_lldp_neighbor_unref(neighbors[0]);
+ free(neighbors);
+
+ ASSERT_OK(stop_lldp_rx(lldp_rx));
+}
+
int main(int argc, char *argv[]) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
test_receive_incomplete_packet(e);
test_receive_oui_packet(e);
test_multiple_neighbors_sorted(e);
+ test_receive_oui_vlanid_packet(e);
return 0;
}
const char *system_name;
const char *system_description;
uint16_t capabilities;
+ uint16_t vlan_id;
} LLDPNeighborInfo;
static const sd_json_dispatch_field lldp_neighbor_dispatch_table[] = {
{ "SystemName", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LLDPNeighborInfo, system_name), 0 },
{ "SystemDescription", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LLDPNeighborInfo, system_description), 0 },
{ "EnabledCapabilities", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(LLDPNeighborInfo, capabilities), 0 },
+ { "VlanID", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(LLDPNeighborInfo, vlan_id), 0 },
{},
};
SD_VARLINK_DEFINE_FIELD(PortDescription, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(SystemName, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(SystemDescription, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
- SD_VARLINK_DEFINE_FIELD(EnabledCapabilities, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
+ SD_VARLINK_DEFINE_FIELD(EnabledCapabilities, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+ SD_VARLINK_DEFINE_FIELD(VlanID, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
LLDPNeighborsByInterface,
int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret);
int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret);
int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret);
+int sd_lldp_neighbor_get_port_vlan_id(sd_lldp_neighbor *n, uint16_t *ret);
/* Low-level, iterative TLV access. This is for everything else, it iteratively goes through all available TLVs
* (including the ones covered with the calls above), and allows multiple TLVs for the same fields. */
SD_LLDP_SYSTEM_CAPABILITIES_SVLAN | \
SD_LLDP_SYSTEM_CAPABILITIES_TPMR))
-#define SD_LLDP_OUI_802_1 (const uint8_t[]) { 0x00, 0x80, 0xc2 }
+#define _SD_LLDP_OUI_802_1 0x00, 0x80, 0xc2
+#define SD_LLDP_OUI_802_1 (const uint8_t[]) { _SD_LLDP_OUI_802_1 }
+
+#define SD_LLDP_OUI_802_1_SUBTYPE_VLAN_ID 0x01
+#define SD_LLDP_OUI_802_1_VLAN_ID \
+ (const uint8_t[]) { _SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_VLAN_ID }
+
#define SD_LLDP_OUI_802_3 (const uint8_t[]) { 0x00, 0x12, 0x0f }
#define _SD_LLDP_OUI_IANA 0x00, 0x00, 0x5E