diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index 3465726c83..1dc6410ce8 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -841,6 +841,10 @@ typedef enum /*< flags >*/ { #define NM_LLDP_ATTR_IEEE_802_1_PVID "ieee-802-1-pvid" #define NM_LLDP_ATTR_IEEE_802_1_PPVID "ieee-802-1-ppvid" #define NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS "ieee-802-1-ppvid-flags" +#define NM_LLDP_ATTR_IEEE_802_1_VLANS "ieee-802-1-vlans" + +/* These are deprecated in favor of NM_LLDP_ATTR_IEEE_802_1_VLANS, + * which can report multiple VLANs */ #define NM_LLDP_ATTR_IEEE_802_1_VID "ieee-802-1-vid" #define NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME "ieee-802-1-vlan-name" diff --git a/src/devices/nm-lldp-listener.c b/src/devices/nm-lldp-listener.c index 55170985d9..f5b435ccfd 100644 --- a/src/devices/nm-lldp-listener.c +++ b/src/devices/nm-lldp-listener.c @@ -58,6 +58,7 @@ typedef enum { LLDP_ATTR_ID_IEEE_802_1_PPVID_FLAGS, LLDP_ATTR_ID_IEEE_802_1_VID, LLDP_ATTR_ID_IEEE_802_1_VLAN_NAME, + LLDP_ATTR_ID_IEEE_802_1_VLANS, _LLDP_ATTR_ID_COUNT, } LldpAttrId; @@ -174,6 +175,7 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_lldp_attr_id_to_name, LldpAttrId, NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_IEEE_802_1_PPVID_FLAGS, NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS), NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_IEEE_802_1_VID, NM_LLDP_ATTR_IEEE_802_1_VID), NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_IEEE_802_1_VLAN_NAME, NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME), + NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_IEEE_802_1_VLANS, NM_LLDP_ATTR_IEEE_802_1_VLANS), NM_UTILS_LOOKUP_ITEM_IGNORE (_LLDP_ATTR_ID_COUNT), ); @@ -189,6 +191,7 @@ _NM_UTILS_LOOKUP_DEFINE (static, _lldp_attr_id_to_type, LldpAttrId, LldpAttrType NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_IEEE_802_1_PPVID_FLAGS, LLDP_ATTR_TYPE_UINT32), NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_IEEE_802_1_VID, LLDP_ATTR_TYPE_UINT32), NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_IEEE_802_1_VLAN_NAME, LLDP_ATTR_TYPE_STRING), + NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_IEEE_802_1_VLANS, LLDP_ATTR_TYPE_ARRAY_OF_VARDICTS), NM_UTILS_LOOKUP_ITEM_IGNORE (_LLDP_ATTR_ID_COUNT), ); @@ -208,13 +211,8 @@ _lldp_attr_set_str (LldpAttrData *pdata, LldpAttrId attr_id, const char *v_strin } static void -_lldp_attr_set_str_ptr (LldpAttrData *pdata, LldpAttrId attr_id, const void *str, gsize len) +_lldp_attr_take_str_ptr (LldpAttrData *pdata, LldpAttrId attr_id, char *str) { - const char *s = str; - const char *tmp; - gsize len0 = len; - gs_free char *str_free = NULL; - nm_assert (pdata); nm_assert (_lldp_attr_id_to_type (attr_id) == LLDP_ATTR_TYPE_STRING); @@ -225,23 +223,7 @@ _lldp_attr_set_str_ptr (LldpAttrData *pdata, LldpAttrId attr_id, const void *str return; pdata->attr_type = LLDP_ATTR_TYPE_STRING; - - /* truncate at first NUL, including removing trailing NULs*/ - tmp = memchr (s, '\0', len); - if (tmp) - len = tmp - s; - - if (!len) { - pdata->v_string = g_strdup (""); - return; - } - - if (len0 <= len || s[len] != '\0') { - /* hmpf, g_strescape needs a trailing NUL. Need to clone */ - s = str_free = g_strndup (s, len); - } - - pdata->v_string = g_strescape (s, NULL); + pdata->v_string = str; } static void @@ -637,6 +619,10 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error) break; case SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME: { int l; + GVariantDict dict; + guint32 vid; + const char *name; + char *name_to_free; if (len <= 3) continue; @@ -647,10 +633,21 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error) if (l > 32) continue; - _lldp_attr_set_uint32 (neigh->attrs, LLDP_ATTR_ID_IEEE_802_1_VID, - unaligned_read_be16 (&data8[0])); - _lldp_attr_set_str_ptr (neigh->attrs, LLDP_ATTR_ID_IEEE_802_1_VLAN_NAME, - &data8[3], l); + name = nm_utils_buf_utf8safe_escape (&data8[3], l, 0, &name_to_free); + vid = unaligned_read_be16 (&data8[0]); + + g_variant_dict_init (&dict, NULL); + g_variant_dict_insert (&dict, "vid", "u", vid); + g_variant_dict_insert (&dict, "name", "s", name); + + _lldp_attr_add_vardict (neigh->attrs, + LLDP_ATTR_ID_IEEE_802_1_VLANS, + g_variant_dict_end (&dict)); + + _lldp_attr_set_uint32 (neigh->attrs, LLDP_ATTR_ID_IEEE_802_1_VID, vid); + _lldp_attr_take_str_ptr (neigh->attrs, + LLDP_ATTR_ID_IEEE_802_1_VLAN_NAME, + name_to_free ?: g_strdup (name)); break; } default: diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c index e045d29928..6bea1ed75e 100644 --- a/src/devices/tests/test-lldp.c +++ b/src/devices/tests/test-lldp.c @@ -234,6 +234,7 @@ _test_recv_data1_check (GMainLoop *loop, NMLldpListener *listener) GVariant *neighbors, *attr, *child; gs_unref_variant GVariant *neighbor = NULL; guint v_uint = 0; + const char *v_str = NULL; neighbors = nm_lldp_listener_get_neighbors (listener); nmtst_assert_variant_is_of_type (neighbors, G_VARIANT_TYPE ("aa{sv}")); @@ -243,7 +244,7 @@ _test_recv_data1_check (GMainLoop *loop, NMLldpListener *listener) SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS, "00:01:30:F9:AD:A0", SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME, "1/1"); g_assert (neighbor); - g_assert_cmpint (g_variant_n_children (neighbor), ==, 4 + 11); + g_assert_cmpint (g_variant_n_children (neighbor), ==, 4 + 12); attr = g_variant_lookup_value (neighbor, NM_LLDP_ATTR_DESTINATION, G_VARIANT_TYPE_STRING); nmtst_assert_variant_string (attr, NM_LLDP_DEST_NEAREST_BRIDGE); @@ -312,6 +313,18 @@ _test_recv_data1_check (GMainLoop *loop, NMLldpListener *listener) nmtst_assert_variant_uint32 (attr, 488); nm_clear_g_variant (&attr); + /* new VLAN attributes */ + attr = g_variant_lookup_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_VLANS, G_VARIANT_TYPE ("aa{sv}")); + g_assert_cmpuint (g_variant_n_children (attr), ==, 1); + child = g_variant_get_child_value (attr, 0); + g_assert (child); + g_variant_lookup (child, "vid", "u", &v_uint); + g_assert_cmpint (v_uint, ==, 488); + g_variant_lookup (child, "name", "&s", &v_str); + g_assert_cmpstr (v_str, ==, "v2-0488-03-0505"); + nm_clear_g_variant (&child); + nm_clear_g_variant (&attr); + /* unsupported: IEEE 802.1 - Protocol Identity */ } diff --git a/tools/test-networkmanager-service.py b/tools/test-networkmanager-service.py index fe680fa215..ddf92c0a27 100755 --- a/tools/test-networkmanager-service.py +++ b/tools/test-networkmanager-service.py @@ -741,7 +741,17 @@ class Device(ExportedObj): 'system-name': dbus.String('test2.example.com'), 'system-description': dbus.String('Test system #2'), 'system-capabilities': dbus.UInt32(2047), - 'destination': dbus.String('nearest-non-tpmr-bridge') + 'destination': dbus.String('nearest-non-tpmr-bridge'), + 'ieee-802-1-vlans': dbus.Array([ + dbus.Dictionary({ + 'vid': dbus.UInt32(80), + 'name': dbus.String('vlan80'), + }, signature = 'sv'), + dbus.Dictionary({ + 'vid': dbus.UInt32(4000), + 'name': dbus.String('My VLAN'), + }, signature = 'sv'), + ]), }), dbus.Dictionary({ 'chassis-id-type': dbus.UInt32(6),