diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index c2ad09ae26..2e127c40b8 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -843,6 +843,10 @@ typedef enum /*< flags >*/ { #define NM_LLDP_ATTR_IEEE_802_1_VLANS "ieee-802-1-vlans" #define NM_LLDP_ATTR_IEEE_802_1_PPVIDS "ieee-802-1-ppvids" +#define NM_LLDP_ATTR_IEEE_802_3_MAC_PHY_CONF "ieee-802-3-mac-phy-conf" +#define NM_LLDP_ATTR_IEEE_802_3_POWER_VIA_MDI "ieee-802-3-power-via-mdi" +#define NM_LLDP_ATTR_IEEE_802_3_MAX_FRAME_SIZE "ieee-802-3-max-frame-size" + /* 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" diff --git a/src/devices/nm-lldp-listener.c b/src/devices/nm-lldp-listener.c index b4709fe7eb..da52d90c31 100644 --- a/src/devices/nm-lldp-listener.c +++ b/src/devices/nm-lldp-listener.c @@ -42,6 +42,7 @@ typedef enum { LLDP_ATTR_TYPE_NONE, LLDP_ATTR_TYPE_UINT32, LLDP_ATTR_TYPE_STRING, + LLDP_ATTR_TYPE_VARDICT, LLDP_ATTR_TYPE_ARRAY_OF_VARDICTS, } LldpAttrType; @@ -60,6 +61,9 @@ typedef enum { 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_IEEE_802_3_MAC_PHY_CONF, + LLDP_ATTR_ID_IEEE_802_3_POWER_VIA_MDI, + LLDP_ATTR_ID_IEEE_802_3_MAX_FRAME_SIZE, _LLDP_ATTR_ID_COUNT, } LldpAttrId; @@ -68,6 +72,7 @@ typedef struct { union { guint32 v_uint32; char *v_string; + GVariant *v_variant; CList v_variant_list; }; } LldpAttrData; @@ -178,6 +183,9 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_lldp_attr_id_to_name, LldpAttrId, 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_STR_ITEM (LLDP_ATTR_ID_IEEE_802_3_MAC_PHY_CONF, NM_LLDP_ATTR_IEEE_802_3_MAC_PHY_CONF), + NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_IEEE_802_3_POWER_VIA_MDI, NM_LLDP_ATTR_IEEE_802_3_POWER_VIA_MDI), + NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_IEEE_802_3_MAX_FRAME_SIZE,NM_LLDP_ATTR_IEEE_802_3_MAX_FRAME_SIZE), NM_UTILS_LOOKUP_ITEM_IGNORE (_LLDP_ATTR_ID_COUNT), ); @@ -195,6 +203,9 @@ _NM_UTILS_LOOKUP_DEFINE (static, _lldp_attr_id_to_type, LldpAttrId, LldpAttrType 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 (LLDP_ATTR_ID_IEEE_802_3_MAC_PHY_CONF, LLDP_ATTR_TYPE_VARDICT), + NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_IEEE_802_3_POWER_VIA_MDI, LLDP_ATTR_TYPE_VARDICT), + NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_IEEE_802_3_MAX_FRAME_SIZE, LLDP_ATTR_TYPE_UINT32), NM_UTILS_LOOKUP_ITEM_IGNORE (_LLDP_ATTR_ID_COUNT), ); @@ -244,6 +255,26 @@ _lldp_attr_set_uint32 (LldpAttrData *pdata, LldpAttrId attr_id, guint32 v_uint32 pdata->v_uint32 = v_uint32; } +static void +_lldp_attr_set_vardict (LldpAttrData *pdata, LldpAttrId attr_id, GVariant *variant) +{ + + nm_assert (pdata); + nm_assert (_lldp_attr_id_to_type (attr_id) == LLDP_ATTR_TYPE_VARDICT); + + pdata = &pdata[attr_id]; + + /* we ignore duplicate fields silently */ + if (pdata->attr_type != LLDP_ATTR_TYPE_NONE) { + if (g_variant_is_floating (variant)) + g_variant_unref (variant); + return; + } + + pdata->attr_type = LLDP_ATTR_TYPE_VARDICT; + pdata->v_variant = g_variant_ref_sink (variant); +} + static void _lldp_attr_add_vardict (LldpAttrData *pdata, LldpAttrId attr_id, GVariant *variant) { @@ -319,6 +350,9 @@ lldp_neighbor_free (LldpNeighbor *neighbor) case LLDP_ATTR_TYPE_STRING: g_free (neighbor->attrs[attr_id].v_string); break; + case LLDP_ATTR_TYPE_VARDICT: + g_variant_unref (neighbor->attrs[attr_id].v_variant); + break; case LLDP_ATTR_TYPE_ARRAY_OF_VARDICTS: nm_c_list_elem_free_all (&neighbor->attrs[attr_id].v_variant_list, (GDestroyNotify) g_variant_unref); @@ -577,14 +611,10 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error) goto out; } - if (!( memcmp (oui, SD_LLDP_OUI_802_1, sizeof (oui)) == 0 - && NM_IN_SET (subtype, - SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID, - SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID, - SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME))) + if ( memcmp (oui, SD_LLDP_OUI_802_1, sizeof (oui)) != 0 + && memcmp (oui, SD_LLDP_OUI_802_3, sizeof (oui)) != 0) continue; - /* skip over leading TLV, OUI and subtype */ #ifdef WITH_MORE_ASSERTS { @@ -603,8 +633,7 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error) data8 += 6; len -= 6; - /*if (memcmp (oui, SD_LLDP_OUI_802_1, sizeof (oui)) == 0)*/ - { + if (memcmp (oui, SD_LLDP_OUI_802_1, sizeof (oui)) == 0) { GVariantDict dict; switch (subtype) { @@ -663,7 +692,44 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error) break; } default: - g_assert_not_reached (); + continue; + } + } else if (memcmp (oui, SD_LLDP_OUI_802_3, sizeof (oui)) == 0) { + GVariantDict dict; + + switch (subtype) { + case SD_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS: + if (len != 5) + continue; + + g_variant_dict_init (&dict, NULL); + g_variant_dict_insert (&dict, "autoneg", "u", (guint32) data8[0]); + g_variant_dict_insert (&dict, "pmd-autoneg-cap", "u", (guint32) unaligned_read_be16 (&data8[1])); + g_variant_dict_insert (&dict, "operational-mau-type", "u", (guint32) unaligned_read_be16 (&data8[3])); + + _lldp_attr_set_vardict (neigh->attrs, + LLDP_ATTR_ID_IEEE_802_3_MAC_PHY_CONF, + g_variant_dict_end (&dict)); + break; + case SD_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI: + if (len != 3) + continue; + + g_variant_dict_init (&dict, NULL); + g_variant_dict_insert (&dict, "mdi-power-support", "u", (guint32) data8[0]); + g_variant_dict_insert (&dict, "pse-power-pair", "u", (guint32) data8[1]); + g_variant_dict_insert (&dict, "power-class", "u", (guint32) data8[2]); + + _lldp_attr_set_vardict (neigh->attrs, + LLDP_ATTR_ID_IEEE_802_3_POWER_VIA_MDI, + g_variant_dict_end (&dict)); + break; + case SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE: + if (len != 2) + continue; + _lldp_attr_set_uint32 (neigh->attrs, LLDP_ATTR_ID_IEEE_802_3_MAX_FRAME_SIZE, + unaligned_read_be16 (data8)); + break; } } } while (sd_lldp_neighbor_tlv_next (neighbor_sd) > 0); @@ -728,6 +794,11 @@ lldp_neighbor_to_variant (LldpNeighbor *neigh) _lldp_attr_id_to_name (attr_id), g_variant_new_string (data->v_string)); break; + case LLDP_ATTR_TYPE_VARDICT: + g_variant_builder_add (&builder, "{sv}", + _lldp_attr_id_to_name (attr_id), + data->v_variant); + break; case LLDP_ATTR_TYPE_ARRAY_OF_VARDICTS: { NMCListElem *elem; GVariantBuilder builder2; diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c index edb26e762d..7b135f5886 100644 --- a/src/devices/tests/test-lldp.c +++ b/src/devices/tests/test-lldp.c @@ -244,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 + 13); + g_assert_cmpint (g_variant_n_children (neighbor), ==, 4 + 16); attr = g_variant_lookup_value (neighbor, NM_LLDP_ATTR_DESTINATION, G_VARIANT_TYPE_STRING); nmtst_assert_variant_string (attr, NM_LLDP_DEST_NEAREST_BRIDGE); @@ -287,10 +287,34 @@ _test_recv_data1_check (GMainLoop *loop, NMLldpListener *listener) nm_clear_g_variant (&child); nm_clear_g_variant (&attr); - /* unsupported: IEEE 802.3 - Power Via MDI */ - /* unsupported: IEEE 802.3 - MAC/PHY Configuration/Status */ + /* IEEE 802.3 - Power Via MDI */ + attr = g_variant_lookup_value (neighbor, NM_LLDP_ATTR_IEEE_802_3_POWER_VIA_MDI, G_VARIANT_TYPE_VARDICT); + g_assert (attr); + g_variant_lookup (attr, "mdi-power-support", "u", &v_uint); + g_assert_cmpint (v_uint, ==, 7); + g_variant_lookup (attr, "pse-power-pair", "u", &v_uint); + g_assert_cmpint (v_uint, ==, 1); + g_variant_lookup (attr, "power-class", "u", &v_uint); + g_assert_cmpint (v_uint, ==, 0); + nm_clear_g_variant (&attr); + + /* IEEE 802.3 - MAC/PHY Configuration/Status */ + attr = g_variant_lookup_value (neighbor, NM_LLDP_ATTR_IEEE_802_3_MAC_PHY_CONF, G_VARIANT_TYPE_VARDICT); + g_assert (attr); + g_variant_lookup (attr, "autoneg", "u", &v_uint); + g_assert_cmpint (v_uint, ==, 3); + g_variant_lookup (attr, "pmd-autoneg-cap", "u", &v_uint); + g_assert_cmpint (v_uint, ==, 0x6c00); + g_variant_lookup (attr, "operational-mau-type", "u", &v_uint); + g_assert_cmpint (v_uint, ==, 16); + nm_clear_g_variant (&attr); + /* unsupported: IEEE 802.3 - Link Aggregation */ - /* unsupported: IEEE 802.3 - Maximum Frame Size*/ + + /* Maximum Frame Size */ + attr = g_variant_lookup_value (neighbor, NM_LLDP_ATTR_IEEE_802_3_MAX_FRAME_SIZE, G_VARIANT_TYPE_UINT32); + nmtst_assert_variant_uint32 (attr, 1522); + nm_clear_g_variant (&attr); /* IEEE 802.1 - Port VLAN ID */ attr = g_variant_lookup_value (neighbor, NM_LLDP_ATTR_IEEE_802_1_PVID, G_VARIANT_TYPE_UINT32); diff --git a/tools/test-networkmanager-service.py b/tools/test-networkmanager-service.py index 7b31696106..c2d874f3f2 100755 --- a/tools/test-networkmanager-service.py +++ b/tools/test-networkmanager-service.py @@ -762,6 +762,7 @@ class Device(ExportedObj): 'flags': dbus.UInt32(0x31), }, signature = 'sv'), ]), + }), dbus.Dictionary({ 'chassis-id-type': dbus.UInt32(6), @@ -787,7 +788,17 @@ class Device(ExportedObj): 'interface-number': dbus.UInt32(1), 'interface-number-subtype': dbus.UInt32(2), }, signature = 'sv'), - ]) + ]), + 'ieee-802-3-mac-phy-conf': dbus.Dictionary({ + 'autoneg': dbus.UInt32(3), + 'pmd-autoneg-cap': dbus.UInt32(0xfe), + 'operational-mau-type': dbus.UInt32(5), + }, signature = 'sv'), + 'ieee-802-3-power-via-mdi': dbus.Dictionary({ + 'mdi-power-support': dbus.UInt32(7), + 'pse-power-pair': dbus.UInt32(6), + 'power-class': dbus.UInt32(1), + }, signature = 'sv'), }) ], 'a{sv}') }