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

hwsim: Basic DBus interface to radio information

In daemon mode start a basic passive DBus interface to expose the
information on radios attached to mac80211_hwsim.  In this version
interfaces have objects of their own.  It might be simpler to only
show them as an array property on the radio object (array of pairs of
string, one string for address, one for name).
This commit is contained in:
Andrew Zaborowski 2017-03-08 13:33:19 +01:00 committed by Denis Kenzior
parent 5dc347ecb1
commit 315269fd23

View File

@ -35,6 +35,11 @@
#include "src/util.h" #include "src/util.h"
#include "src/storage.h" #include "src/storage.h"
#include "src/dbus.h"
#define HWSIM_RADIO_MANAGER_INTERFACE "net.connman.iwd.hwsim.RadioManager"
#define HWSIM_RADIO_INTERFACE "net.connman.iwd.hwsim.Radio"
#define HWSIM_INTERFACE_INTERFACE "net.connman.iwd.hwsim.Interface"
enum { enum {
HWSIM_CMD_UNSPEC, HWSIM_CMD_UNSPEC,
@ -91,6 +96,7 @@ static bool keep_radios_attr;
static bool no_vif_attr; static bool no_vif_attr;
static bool p2p_attr; static bool p2p_attr;
static const char *radio_name_attr; static const char *radio_name_attr;
static struct l_dbus *dbus;
static void do_debug(const char *str, void *user_data) static void do_debug(const char *str, void *user_data)
{ {
@ -245,7 +251,8 @@ struct radio_info_rec {
uint32_t wiphy_id; uint32_t wiphy_id;
char alpha2[2]; char alpha2[2];
bool p2p; bool p2p;
uint32_t regdom; bool custom_regdom;
uint32_t regdom_idx;
int channels; int channels;
uint8_t addrs[ETH_ALEN * 2]; uint8_t addrs[ETH_ALEN * 2];
char *name; char *name;
@ -309,6 +316,23 @@ static bool interface_info_match_id(const void *a, const void *b)
return rec->id == id; return rec->id == id;
} }
static const char *radio_get_path(const struct radio_info_rec *rec)
{
static char path[15];
snprintf(path, sizeof(path), "/radio%u", rec->id);
return path;
}
static const char *interface_get_path(const struct interface_info_rec *rec)
{
static char path[25];
snprintf(path, sizeof(path), "%s/%u",
radio_get_path(rec->radio_rec), rec->id);
return path;
}
static bool parse_addresses(const uint8_t *buf, size_t len, static bool parse_addresses(const uint8_t *buf, size_t len,
struct radio_info_rec *rec) struct radio_info_rec *rec)
{ {
@ -373,6 +397,9 @@ static void get_radio_callback(struct l_genl_msg *msg, void *user_data)
int bytes, consumed; int bytes, consumed;
unsigned int uintval; unsigned int uintval;
bool old; bool old;
struct radio_info_rec prev_rec;
bool name_change = false;
const char *path;
if (!l_genl_attr_init(&attr, msg)) if (!l_genl_attr_init(&attr, msg))
return; return;
@ -400,6 +427,12 @@ static void get_radio_callback(struct l_genl_msg *msg, void *user_data)
if (rec) { if (rec) {
old = true; old = true;
memcpy(&prev_rec, rec, sizeof(prev_rec));
if (strlen(rec->name) != name_len ||
memcmp(rec->name, name, name_len))
name_change = true;
l_free(rec->name); l_free(rec->name);
} else { } else {
old = false; old = false;
@ -438,7 +471,8 @@ static void get_radio_callback(struct l_genl_msg *msg, void *user_data)
if (len != 4) if (len != 4)
break; break;
rec->regdom = *(uint32_t *) data; rec->custom_regdom = true;
rec->regdom_idx = *(uint32_t *) data;
break; break;
} }
} }
@ -456,14 +490,14 @@ static void get_radio_callback(struct l_genl_msg *msg, void *user_data)
"/sys/class/ieee80211/%s/index", rec->name); "/sys/class/ieee80211/%s/index", rec->name);
if (bytes < 0) { if (bytes < 0) {
l_error("Error reading index for %s from sysfs", rec->name); l_error("Error reading index for %s from sysfs", rec->name);
goto free_radio; goto err_free_radio;
} }
file_buffer[bytes] = '\0'; file_buffer[bytes] = '\0';
if (sscanf((char *) file_buffer, "%u %n", &uintval, &consumed) != 1 || if (sscanf((char *) file_buffer, "%u %n", &uintval, &consumed) != 1 ||
consumed != bytes) { consumed != bytes) {
l_error("Error parsing index for %s from sysfs", rec->name); l_error("Error parsing index for %s from sysfs", rec->name);
goto free_radio; goto err_free_radio;
} }
rec->wiphy_id = uintval; rec->wiphy_id = uintval;
@ -472,11 +506,11 @@ static void get_radio_callback(struct l_genl_msg *msg, void *user_data)
"/sys/class/ieee80211/%s/addresses", rec->name); "/sys/class/ieee80211/%s/addresses", rec->name);
if (bytes < 0) { if (bytes < 0) {
l_error("Error reading addresses for %s from sysfs", rec->name); l_error("Error reading addresses for %s from sysfs", rec->name);
goto free_radio; goto err_free_radio;
} }
if (!parse_addresses(file_buffer, bytes, rec)) if (!parse_addresses(file_buffer, bytes, rec))
goto free_radio; goto err_free_radio;
if (!radio_info) if (!radio_info)
radio_info = l_queue_new(); radio_info = l_queue_new();
@ -484,11 +518,37 @@ static void get_radio_callback(struct l_genl_msg *msg, void *user_data)
if (!old) if (!old)
l_queue_push_tail(radio_info, rec); l_queue_push_tail(radio_info, rec);
/* TODO: Create DBus object */ path = radio_get_path(rec);
if (!old) {
/* Create Dbus object */
if (!l_dbus_object_add_interface(dbus, path,
HWSIM_RADIO_INTERFACE, rec))
l_info("Unable to add the %s interface to %s",
HWSIM_RADIO_INTERFACE, path);
if (!l_dbus_object_add_interface(dbus, path,
L_DBUS_INTERFACE_PROPERTIES,
NULL))
l_info("Unable to add the %s interface to %s",
L_DBUS_INTERFACE_PROPERTIES, path);
} else {
/* Emit property change events */
if (memcmp(prev_rec.addrs, rec->addrs, sizeof(rec->addrs)))
l_dbus_property_changed(dbus, path,
HWSIM_RADIO_INTERFACE,
"Addresses");
if (name_change)
l_dbus_property_changed(dbus, path,
HWSIM_RADIO_INTERFACE, "Name");
}
return; return;
free_radio: err_free_radio:
if (!old) if (!old)
radio_free(rec); radio_free(rec);
} }
@ -532,6 +592,9 @@ static void get_wiphy_callback(struct l_genl_msg *msg, void *user_data)
l_free(rec->name); l_free(rec->name);
rec->name = l_strndup(name, name_len); rec->name = l_strndup(name, name_len);
l_dbus_property_changed(dbus, radio_get_path(rec),
HWSIM_RADIO_INTERFACE, "Name");
} }
static void get_interface_callback(struct l_genl_msg *msg, void *user_data) static void get_interface_callback(struct l_genl_msg *msg, void *user_data)
@ -547,6 +610,9 @@ static void get_interface_callback(struct l_genl_msg *msg, void *user_data)
struct interface_info_rec *rec; struct interface_info_rec *rec;
struct radio_info_rec *radio_rec; struct radio_info_rec *radio_rec;
bool old; bool old;
const char *path;
struct interface_info_rec prev_rec;
bool name_change = false;
if (!l_genl_attr_init(&attr, msg)) if (!l_genl_attr_init(&attr, msg))
return; return;
@ -595,6 +661,12 @@ static void get_interface_callback(struct l_genl_msg *msg, void *user_data)
if (rec) { if (rec) {
old = true; old = true;
memcpy(&prev_rec, rec, sizeof(prev_rec));
if (strlen(rec->name) != ifname_len ||
memcmp(rec->name, ifname, ifname_len))
name_change = true;
l_free(rec->name); l_free(rec->name);
} else { } else {
old = false; old = false;
@ -614,7 +686,34 @@ static void get_interface_callback(struct l_genl_msg *msg, void *user_data)
if (!old) if (!old)
l_queue_push_tail(interface_info, rec); l_queue_push_tail(interface_info, rec);
/* TODO: Create DBus object */ path = interface_get_path(rec);
if (!old) {
/* Create Dbus object */
if (!l_dbus_object_add_interface(dbus, path,
HWSIM_INTERFACE_INTERFACE, rec))
l_info("Unable to add the %s interface to %s",
HWSIM_INTERFACE_INTERFACE, path);
if (!l_dbus_object_add_interface(dbus, path,
L_DBUS_INTERFACE_PROPERTIES,
NULL))
l_info("Unable to add the %s interface to %s",
L_DBUS_INTERFACE_PROPERTIES, path);
} else {
/* Emit property change events */
if (memcmp(prev_rec.addr, rec->addr, ETH_ALEN))
l_dbus_property_changed(dbus, path,
HWSIM_INTERFACE_INTERFACE,
"Addresses");
if (name_change)
l_dbus_property_changed(dbus, path,
HWSIM_INTERFACE_INTERFACE,
"Name");
}
} }
static bool interface_info_destroy_by_radio(void *data, void *user_data) static bool interface_info_destroy_by_radio(void *data, void *user_data)
@ -625,7 +724,7 @@ static bool interface_info_destroy_by_radio(void *data, void *user_data)
if (rec->radio_rec != radio_rec) if (rec->radio_rec != radio_rec)
return false; return false;
/* TODO: Drop DBus object */ l_dbus_unregister_object(dbus, interface_get_path(rec));
interface_free(rec); interface_free(rec);
@ -666,7 +765,7 @@ static void del_radio_event(struct l_genl_msg *msg)
l_queue_foreach_remove(interface_info, interface_info_destroy_by_radio, l_queue_foreach_remove(interface_info, interface_info_destroy_by_radio,
radio); radio);
/* TODO: Drop DBus object */ l_dbus_unregister_object(dbus, radio_get_path(radio));
radio_free(radio); radio_free(radio);
l_queue_remove(radio_info, radio); l_queue_remove(radio_info, radio);
@ -702,7 +801,7 @@ static void del_interface_event(struct l_genl_msg *msg)
if (!interface) if (!interface)
return; return;
/* TODO: Drop DBus object */ l_dbus_unregister_object(dbus, interface_get_path(interface));
interface_free(interface); interface_free(interface);
l_queue_remove(interface_info, interface); l_queue_remove(interface_info, interface);
@ -756,6 +855,218 @@ static void nl80211_config_notify(struct l_genl_msg *msg, void *user_data)
} }
} }
static void setup_radio_manager_interface(struct l_dbus_interface *interface)
{
}
static bool radio_property_get_name(struct l_dbus *dbus,
struct l_dbus_message *message,
struct l_dbus_message_builder *builder,
void *user_data)
{
const struct radio_info_rec *rec = user_data;
l_dbus_message_builder_append_basic(builder, 's', rec->name);
return true;
}
static bool radio_property_get_addresses(struct l_dbus *dbus,
struct l_dbus_message *message,
struct l_dbus_message_builder *builder,
void *user_data)
{
const struct radio_info_rec *rec = user_data;
unsigned int i;
l_dbus_message_builder_enter_array(builder, "s");
for (i = 0; i < sizeof(rec->addrs); i += ETH_ALEN) {
const char *str = util_address_to_string(rec->addrs + i);
l_dbus_message_builder_append_basic(builder, 's', str);
}
l_dbus_message_builder_leave_array(builder);
return true;
}
static bool radio_property_get_channels(struct l_dbus *dbus,
struct l_dbus_message *message,
struct l_dbus_message_builder *builder,
void *user_data)
{
const struct radio_info_rec *rec = user_data;
uint16_t val = rec->channels;
l_dbus_message_builder_append_basic(builder, 'q', &val);
return true;
}
static bool radio_property_get_alpha2(struct l_dbus *dbus,
struct l_dbus_message *message,
struct l_dbus_message_builder *builder,
void *user_data)
{
const struct radio_info_rec *rec = user_data;
if (rec->alpha2[0] == 0 || rec->alpha2[1] == 0)
return false;
l_dbus_message_builder_enter_struct(builder, "yy");
l_dbus_message_builder_append_basic(builder, 'y', &rec->alpha2[0]);
l_dbus_message_builder_append_basic(builder, 'y', &rec->alpha2[1]);
l_dbus_message_builder_leave_struct(builder);
return true;
}
static bool radio_property_get_p2p(struct l_dbus *dbus,
struct l_dbus_message *message,
struct l_dbus_message_builder *builder,
void *user_data)
{
const struct radio_info_rec *rec = user_data;
bool val = rec->p2p;
l_dbus_message_builder_append_basic(builder, 'b', &val);
return true;
}
static bool radio_property_get_regdom(struct l_dbus *dbus,
struct l_dbus_message *message,
struct l_dbus_message_builder *builder,
void *user_data)
{
const struct radio_info_rec *rec = user_data;
if (!rec->custom_regdom)
return false;
l_dbus_message_builder_append_basic(builder, 'u', &rec->regdom_idx);
return true;
}
static void setup_radio_interface(struct l_dbus_interface *interface)
{
l_dbus_interface_property(interface, "Name", 0, "s",
radio_property_get_name, NULL);
l_dbus_interface_property(interface, "Addresses", 0, "s",
radio_property_get_addresses, NULL);
l_dbus_interface_property(interface, "Channels", 0, "q",
radio_property_get_channels, NULL);
l_dbus_interface_property(interface, "Alpha2", 0, "(yy)",
radio_property_get_alpha2, NULL);
l_dbus_interface_property(interface, "P2PDevice", 0, "b",
radio_property_get_p2p, NULL);
l_dbus_interface_property(interface, "RegulatoryDomainIndex", 0, "u",
radio_property_get_regdom, NULL);
}
static bool interface_property_get_name(struct l_dbus *dbus,
struct l_dbus_message *message,
struct l_dbus_message_builder *builder,
void *user_data)
{
const struct interface_info_rec *rec = user_data;
l_dbus_message_builder_append_basic(builder, 's', rec->name);
return true;
}
static bool interface_property_get_address(struct l_dbus *dbus,
struct l_dbus_message *message,
struct l_dbus_message_builder *builder,
void *user_data)
{
const struct interface_info_rec *rec = user_data;
const char *str = util_address_to_string(rec->addr);
l_dbus_message_builder_append_basic(builder, 's', str);
return true;
}
static void setup_interface_interface(struct l_dbus_interface *interface)
{
l_dbus_interface_property(interface, "Name", 0, "s",
interface_property_get_name, NULL);
l_dbus_interface_property(interface, "Address", 0, "s",
interface_property_get_address, NULL);
}
static void request_name_callback(struct l_dbus *dbus, bool success,
bool queued, void *user_data)
{
if (!success)
l_error("Name request failed");
}
static void ready_callback(void *user_data)
{
l_dbus_name_acquire(dbus, "net.connman.iwd.hwsim", false, false, true,
request_name_callback, NULL);
if (!l_dbus_object_manager_enable(dbus))
l_info("Unable to register the ObjectManager");
}
static void disconnect_callback(void *user_data)
{
l_info("D-Bus disconnected, quitting...");
l_main_quit();
}
static bool setup_dbus_hwsim(void)
{
dbus = l_dbus_new_default(L_DBUS_SYSTEM_BUS);
if (!dbus) {
l_error("Unable to connect to Dbus");
return false;
}
if (!l_dbus_register_interface(dbus, HWSIM_RADIO_MANAGER_INTERFACE,
setup_radio_manager_interface,
NULL, false)) {
l_error("Unable to register the %s interface",
HWSIM_RADIO_MANAGER_INTERFACE);
return false;
}
if (!l_dbus_register_interface(dbus, HWSIM_RADIO_INTERFACE,
setup_radio_interface, NULL, false)) {
l_error("Unable to register the %s interface",
HWSIM_RADIO_INTERFACE);
return false;
}
if (!l_dbus_register_interface(dbus, HWSIM_INTERFACE_INTERFACE,
setup_interface_interface,
NULL, false)) {
l_error("Unable to register the %s interface",
HWSIM_INTERFACE_INTERFACE);
return false;
}
if (!l_dbus_object_add_interface(dbus, "/",
HWSIM_RADIO_MANAGER_INTERFACE,
NULL)) {
l_info("Unable to add the %s interface to /",
HWSIM_RADIO_MANAGER_INTERFACE);
return false;
}
l_dbus_set_ready_handler(dbus, ready_callback, dbus, NULL);
l_dbus_set_disconnect_handler(dbus, disconnect_callback, NULL, NULL);
return true;
}
static void get_radio_done_initial(void *user_data) static void get_radio_done_initial(void *user_data)
{ {
struct l_genl_msg *msg; struct l_genl_msg *msg;
@ -888,6 +1199,9 @@ static void hwsim_ready(void *user_data)
break; break;
case ACTION_NONE: case ACTION_NONE:
if (!setup_dbus_hwsim())
goto error;
l_genl_family_set_watches(nl80211, nl80211_ready, NULL, l_genl_family_set_watches(nl80211, nl80211_ready, NULL,
NULL, NULL); NULL, NULL);
@ -895,6 +1209,10 @@ static void hwsim_ready(void *user_data)
} }
return; return;
error:
exit_status = EXIT_FAILURE;
l_main_quit();
} }
static void hwsim_disappeared(void *user_data) static void hwsim_disappeared(void *user_data)
@ -1068,6 +1386,8 @@ int main(int argc, char *argv[])
l_genl_family_unref(nl80211); l_genl_family_unref(nl80211);
l_genl_unref(genl); l_genl_unref(genl);
l_dbus_destroy(dbus);
hwsim_radio_cache_cleanup(); hwsim_radio_cache_cleanup();
done: done: