From a17e5e0f7fc7cc96d091e17cea9f6249c5ac679d Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Thu, 14 Jan 2021 12:54:40 -0800 Subject: [PATCH] station: create StationDiagnostic interface This interface sits aside the regular station interface but provides low level connection details for diagnostic and testing purposes. --- src/station.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/src/station.c b/src/station.c index 1e3706af..2b79aaa7 100644 --- a/src/station.c +++ b/src/station.c @@ -77,6 +77,7 @@ struct station { struct l_dbus_message *hidden_pending; struct l_dbus_message *disconnect_pending; struct l_dbus_message *scan_pending; + struct l_dbus_message *get_station_pending; struct signal_agent *signal_agent; uint32_t dbus_scan_id; uint32_t quick_scan_id; @@ -3333,6 +3334,9 @@ static struct station *station_create(struct netdev *netdev) l_dbus_object_add_interface(dbus, netdev_get_path(netdev), IWD_STATION_INTERFACE, station); + l_dbus_object_add_interface(dbus, netdev_get_path(netdev), + IWD_STATION_DIAGNOSTIC_INTERFACE, + station); if (netconfig_enabled) station->netconfig = netconfig_new(netdev_get_ifindex(netdev)); @@ -3455,6 +3459,150 @@ static void station_destroy_interface(void *user_data) station_free(station); } +static void station_get_diagnostic_cb(const struct netdev_station_info *info, + void *user_data) +{ + struct station *station = user_data; + struct l_dbus_message *reply; + struct l_dbus_message_builder *builder; + int16_t rssi; + + if (!info) { + reply = dbus_error_aborted(station->get_station_pending); + goto done; + } + + reply = l_dbus_message_new_method_return(station->get_station_pending); + + rssi = (int16_t)info->cur_rssi; + + builder = l_dbus_message_builder_new(reply); + + l_dbus_message_builder_enter_array(builder, "{sv}"); + + dbus_append_dict_basic(builder, "ConnectedBss", 's', + util_address_to_string(info->addr)); + + if (info->have_cur_rssi) + dbus_append_dict_basic(builder, "RSSI", 'n', &rssi); + + if (info->have_rx_mcs) { + switch (info->rx_mcs_type) { + case NETDEV_MCS_TYPE_HT: + dbus_append_dict_basic(builder, "RxMode", 's', + "802.11n"); + dbus_append_dict_basic(builder, "RxMCS", 'y', + &info->rx_mcs); + break; + case NETDEV_MCS_TYPE_VHT: + dbus_append_dict_basic(builder, "RxMode", 's', + "802.11ac"); + dbus_append_dict_basic(builder, "RxMCS", 'y', + &info->rx_mcs); + break; + case NETDEV_MCS_TYPE_HE: + dbus_append_dict_basic(builder, "RxMode", 's', + "802.11ax"); + dbus_append_dict_basic(builder, "RxMCS", 'y', + &info->rx_mcs); + break; + default: + break; + } + } + + if (info->have_tx_mcs) { + switch (info->tx_mcs_type) { + case NETDEV_MCS_TYPE_HT: + dbus_append_dict_basic(builder, "TxMode", 's', + "802.11n"); + dbus_append_dict_basic(builder, "TxMCS", 'y', + &info->tx_mcs); + break; + case NETDEV_MCS_TYPE_VHT: + dbus_append_dict_basic(builder, "TxMode", 's', + "802.11ac"); + dbus_append_dict_basic(builder, "TxMCS", 'y', + &info->tx_mcs); + break; + case NETDEV_MCS_TYPE_HE: + dbus_append_dict_basic(builder, "TxMode", 's', + "802.11ax"); + dbus_append_dict_basic(builder, "TxMCS", 'y', + &info->tx_mcs); + break; + default: + break; + } + } + + if (info->have_tx_bitrate) + dbus_append_dict_basic(builder, "TxBitrate", 'u', + &info->tx_bitrate); + + if (info->have_rx_bitrate) + dbus_append_dict_basic(builder, "RxBitrate", 'u', + &info->rx_bitrate); + + if (info->have_expected_throughput) + dbus_append_dict_basic(builder, "ExpectedThroughput", 'u', + &info->expected_throughput); + + l_dbus_message_builder_leave_array(builder); + l_dbus_message_builder_finalize(builder); + l_dbus_message_builder_destroy(builder); + +done: + dbus_pending_reply(&station->get_station_pending, reply); +} + +static void station_get_diagnostic_destroy(void *user_data) +{ + struct station *station = user_data; + struct l_dbus_message *reply; + + if (station->get_station_pending) { + reply = dbus_error_aborted(station->get_station_pending); + dbus_pending_reply(&station->get_station_pending, reply); + } +} + +static struct l_dbus_message *station_get_diagnostics(struct l_dbus *dbus, + struct l_dbus_message *message, + void *user_data) +{ + struct station *station = user_data; + int ret; + + /* + * At this time all values depend on a connected state. + */ + if (station->state != STATION_STATE_CONNECTED) + return dbus_error_not_connected(message); + + ret = netdev_get_current_station(station->netdev, + station_get_diagnostic_cb, station, + station_get_diagnostic_destroy); + if (ret < 0) + return dbus_error_from_errno(ret, message); + + station->get_station_pending = l_dbus_message_ref(message); + + return NULL; +} + +static void station_setup_diagnostic_interface( + struct l_dbus_interface *interface) +{ + l_dbus_interface_method(interface, "GetDiagnostics", 0, + station_get_diagnostics, "a{sv}", "", + "diagnostics"); +} + +static void station_destroy_diagnostic_interface(void *user_data) +{ +} + static void station_netdev_watch(struct netdev *netdev, enum netdev_watch_event event, void *userdata) { @@ -3483,6 +3631,11 @@ static int station_init(void) l_dbus_register_interface(dbus_get_bus(), IWD_STATION_INTERFACE, station_setup_interface, station_destroy_interface, false); + l_dbus_register_interface(dbus_get_bus(), + IWD_STATION_DIAGNOSTIC_INTERFACE, + station_setup_diagnostic_interface, + station_destroy_diagnostic_interface, + false); if (!l_settings_get_uint(iwd_get_config(), "General", "ManagementFrameProtection", @@ -3521,6 +3674,8 @@ static int station_init(void) static void station_exit(void) { + l_dbus_unregister_interface(dbus_get_bus(), + IWD_STATION_DIAGNOSTIC_INTERFACE); l_dbus_unregister_interface(dbus_get_bus(), IWD_STATION_INTERFACE); netdev_watch_remove(netdev_watch); l_queue_destroy(station_list, NULL);