3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-12-22 21:22:37 +01:00

station: create StationDiagnostic interface

This interface sits aside the regular station interface but
provides low level connection details for diagnostic and
testing purposes.
This commit is contained in:
James Prestwood 2021-01-14 12:54:40 -08:00 committed by Denis Kenzior
parent a0aa6fecb4
commit a17e5e0f7f

View File

@ -77,6 +77,7 @@ struct station {
struct l_dbus_message *hidden_pending; struct l_dbus_message *hidden_pending;
struct l_dbus_message *disconnect_pending; struct l_dbus_message *disconnect_pending;
struct l_dbus_message *scan_pending; struct l_dbus_message *scan_pending;
struct l_dbus_message *get_station_pending;
struct signal_agent *signal_agent; struct signal_agent *signal_agent;
uint32_t dbus_scan_id; uint32_t dbus_scan_id;
uint32_t quick_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), l_dbus_object_add_interface(dbus, netdev_get_path(netdev),
IWD_STATION_INTERFACE, station); IWD_STATION_INTERFACE, station);
l_dbus_object_add_interface(dbus, netdev_get_path(netdev),
IWD_STATION_DIAGNOSTIC_INTERFACE,
station);
if (netconfig_enabled) if (netconfig_enabled)
station->netconfig = netconfig_new(netdev_get_ifindex(netdev)); station->netconfig = netconfig_new(netdev_get_ifindex(netdev));
@ -3455,6 +3459,150 @@ static void station_destroy_interface(void *user_data)
station_free(station); 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, static void station_netdev_watch(struct netdev *netdev,
enum netdev_watch_event event, void *userdata) 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, l_dbus_register_interface(dbus_get_bus(), IWD_STATION_INTERFACE,
station_setup_interface, station_setup_interface,
station_destroy_interface, false); 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", if (!l_settings_get_uint(iwd_get_config(), "General",
"ManagementFrameProtection", "ManagementFrameProtection",
@ -3521,6 +3674,8 @@ static int station_init(void)
static void station_exit(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); l_dbus_unregister_interface(dbus_get_bus(), IWD_STATION_INTERFACE);
netdev_watch_remove(netdev_watch); netdev_watch_remove(netdev_watch);
l_queue_destroy(station_list, NULL); l_queue_destroy(station_list, NULL);