static void test_receive_basic_packet(sd_event *e) { sd_lldp *lldp; sd_lldp_packet **packets; uint8_t type, *data; uint16_t length, ttl; int dest_type; char *str; 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: interface name, "1/3" */ 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds*/ /* LLDP optional TLVs */ 0x08, 0x04, 0x50, 0x6f, 0x72, 0x74, /* Port Description: "Port" */ 0x0a, 0x03, 0x53, 0x59, 0x53, /* System Name: "SYS" */ 0x0c, 0x04, 0x66, 0x6f, 0x6f, 0x00, /* System Description: "foo" (NULL-terminated) */ 0x00, 0x00 /* End Of LLDPDU */ }; lldp_handler_calls = 0; assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0); assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame)); sd_event_run(e, 0); assert_se(lldp_handler_calls == 1); assert_se(sd_lldp_get_packets(lldp, &packets) == 1); assert_se(sd_lldp_packet_read_chassis_id(packets[0], &type, &data, &length) == 0); assert_se(type == LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS); assert_se(length == ETH_ALEN); assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN)); assert_se(sd_lldp_packet_read_port_id(packets[0], &type, &data, &length) == 0); assert_se(type == LLDP_PORT_SUBTYPE_INTERFACE_NAME); assert_se(length == 3); assert_se(strneq((char *) data, "1/3", 3)); assert_se(sd_lldp_packet_read_port_description(packets[0], &str, &length) == 0); assert_se(length == 4); assert_se(strneq(str, "Port", 4)); assert_se(sd_lldp_packet_read_system_name(packets[0], &str, &length) == 0); assert_se(length == 3); assert_se(strneq(str, "SYS", 3)); assert_se(sd_lldp_packet_read_system_description(packets[0], &str, &length) == 0); assert_se(length == 4); /* This is the real length in the TLV packet */ assert_se(strneq(str, "foo", 3)); assert_se(sd_lldp_packet_read_ttl(packets[0], &ttl) == 0); assert_se(ttl == 120); assert_se(sd_lldp_packet_get_destination_type(packets[0], &dest_type) == 0); assert_se(dest_type == SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE); sd_lldp_packet_unref(packets[0]); free(packets); assert_se(stop_lldp(lldp) == 0); }
static void process_lldp_neighbors (NMLldpListener *self) { NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE (self); sd_lldp_packet **packets = NULL; GHashTable *hash; int num, i; num = sd_lldp_get_packets (priv->lldp_handle, &packets); if (num < 0) { nm_log_dbg (LOGD_DEVICE, "LLDP: error %d retrieving neighbor packets for %s", num, priv->iface); return; } hash = g_hash_table_new_full (lldp_neighbor_id_hash, lldp_neighbor_id_equal, lldp_neighbor_free, NULL); for (i = 0; packets && i < num; i++) { uint8_t chassis_id_type, port_id_type, *chassis_id, *port_id, data8; uint16_t chassis_id_len, port_id_len, len, data16; LLDPNeighbor *neigh; GValue *value; char *str; int r; if (i >= MAX_NEIGHBORS) goto next_packet; r = sd_lldp_packet_read_chassis_id (packets[i], &chassis_id_type, &chassis_id, &chassis_id_len); if (r < 0) goto next_packet; r = sd_lldp_packet_read_port_id (packets[i], &port_id_type, &port_id, &port_id_len); if (r < 0) goto next_packet; neigh = g_malloc0 (sizeof (LLDPNeighbor)); neigh->tlvs = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gvalue_destroy); neigh->chassis_id_type = chassis_id_type; neigh->port_id_type = port_id_type; sd_lldp_packet_get_destination_type (packets[i], &neigh->dest); if (chassis_id_len < 1) { lldp_neighbor_free (neigh); goto next_packet; } switch (chassis_id_type) { case LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS: case LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME: case LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED: case LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT: neigh->chassis_id = strndup ((char *) chassis_id, chassis_id_len); break; case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: neigh->chassis_id = nm_utils_hwaddr_ntoa (chassis_id, chassis_id_len); break; default: nm_log_dbg (LOGD_DEVICE, "LLDP: unsupported chassis ID type %d", chassis_id_type); lldp_neighbor_free (neigh); goto next_packet; } if (port_id_len < 1) { lldp_neighbor_free (neigh); goto next_packet; } switch (port_id_type) { case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: case LLDP_PORT_SUBTYPE_INTERFACE_NAME: case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: case LLDP_PORT_SUBTYPE_PORT_COMPONENT: neigh->port_id = strndup ((char *) port_id, port_id_len); break; case LLDP_PORT_SUBTYPE_MAC_ADDRESS: neigh->port_id = nm_utils_hwaddr_ntoa (port_id, port_id_len); break; default: nm_log_dbg (LOGD_DEVICE, "LLDP: unsupported port ID type %d", port_id_type); lldp_neighbor_free (neigh); goto next_packet; } if (sd_lldp_packet_read_port_description (packets[i], &str, &len) == 0) { value = gvalue_new_nstr (str, len); g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_PORT_DESCRIPTION, value); } if (sd_lldp_packet_read_system_name (packets[i], &str, &len) == 0) { value = gvalue_new_nstr (str, len); g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_SYSTEM_NAME, value); } if (sd_lldp_packet_read_system_description (packets[i], &str, &len) == 0) { value = gvalue_new_nstr (str, len); g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_SYSTEM_DESCRIPTION, value); } if (sd_lldp_packet_read_system_capability (packets[i], &data16) == 0) { value = gvalue_new_uint (data16); g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_SYSTEM_CAPABILITIES, value); } if (sd_lldp_packet_read_port_vlan_id (packets[i], &data16) == 0) { value = gvalue_new_uint (data16); g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PVID, value); } if (sd_lldp_packet_read_port_protocol_vlan_id (packets[i], &data8, &data16) == 0) { value = gvalue_new_uint (data16); g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PPVID, value); value = gvalue_new_uint (data8); g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS, value); } if (sd_lldp_packet_read_vlan_name (packets[i], &data16, &str, &len) == 0) { value = gvalue_new_uint (data16); g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_VID, value); value = gvalue_new_nstr (str, len); g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME, value); } nm_log_dbg (LOGD_DEVICE, "LLDP: new neigh: CHASSIS='%s' PORT='%s'", neigh->chassis_id, neigh->port_id); g_hash_table_add (hash, neigh); next_packet: sd_lldp_packet_unref (packets[i]); } g_free (packets); if (lldp_hash_table_equal (priv->lldp_neighbors, hash)) { g_hash_table_destroy (hash); } else { g_hash_table_destroy (priv->lldp_neighbors); priv->lldp_neighbors = hash; nm_clear_g_variant (&priv->variant); g_object_notify (G_OBJECT (self), NM_LLDP_LISTENER_NEIGHBORS); } /* Since the processing of the neighbor list is potentially * expensive when there are many neighbors, coalesce multiple * events arriving in short time. */ priv->timer = g_timeout_add_seconds (MIN_UPDATE_INTERVAL, lldp_timeout, self); priv->num_pending_events = 0; }