p2p: Add device enable/disable logic

Implement the Enabled property on device interface.  The P2P device is
currently disabled on startup but automatically enabling the P2P device
can be considered.
This commit is contained in:
Andrew Zaborowski 2020-04-23 18:24:33 +02:00 committed by Denis Kenzior
parent ff65e1fd9a
commit 59cc1e27c2
1 changed files with 126 additions and 0 deletions

126
src/p2p.c
View File

@ -58,12 +58,18 @@
struct p2p_device {
uint64_t wdev_id;
uint8_t addr[6];
struct l_genl_family *nl80211;
struct wiphy *wiphy;
unsigned int connections_left;
struct p2p_capability_attr capability;
struct p2p_device_info_attr device_info;
uint32_t start_stop_cmd_id;
l_dbus_property_complete_cb_t pending_complete;
struct l_dbus_message *pending_message;
struct l_queue *peer_list;
bool enabled : 1;
};
struct p2p_peer {
@ -123,6 +129,74 @@ static void p2p_peer_put(void *user_data)
p2p_peer_free(peer);
}
static void p2p_device_enable_cb(struct l_genl_msg *msg, void *user_data)
{
struct p2p_device *dev = user_data;
int error = l_genl_msg_get_error(msg);
struct l_dbus_message *message = dev->pending_message;
l_debug("START/STOP_P2P_DEVICE: %s (%i)", strerror(-error), -error);
if (error)
goto done;
dev->enabled = !dev->enabled;
done:
dev->pending_complete(dbus_get_bus(), message,
error ? dbus_error_failed(message) :
NULL);
dev->pending_message = NULL;
dev->pending_complete = NULL;
if (!error)
l_dbus_property_changed(dbus_get_bus(),
p2p_device_get_path(dev),
IWD_P2P_INTERFACE, "Enabled");
}
static void p2p_device_enable_destroy(void *user_data)
{
struct p2p_device *dev = user_data;
dev->start_stop_cmd_id = 0;
}
static void p2p_device_start_stop(struct p2p_device *dev,
l_dbus_property_complete_cb_t complete,
struct l_dbus_message *message)
{
struct l_genl_msg *cmd;
if (!dev->enabled)
cmd = l_genl_msg_new_sized(NL80211_CMD_START_P2P_DEVICE, 16);
else
cmd = l_genl_msg_new_sized(NL80211_CMD_STOP_P2P_DEVICE, 16);
l_genl_msg_append_attr(cmd, NL80211_ATTR_WDEV, 8, &dev->wdev_id);
dev->start_stop_cmd_id = l_genl_family_send(dev->nl80211, cmd,
p2p_device_enable_cb, dev,
p2p_device_enable_destroy);
if (!dev->start_stop_cmd_id) {
l_genl_msg_unref(cmd);
complete(dbus_get_bus(), message, dbus_error_failed(message));
return;
}
dev->pending_message = message;
dev->pending_complete = complete;
if (dev->enabled) {
/*
* Stopping the P2P device, drop all peers as we can't start
* new connections from now on.
*/
l_queue_destroy(dev->peer_list, p2p_peer_put);
dev->peer_list = NULL;
}
}
#define P2P_SUPPORTED_METHODS ( \
WSC_CONFIGURATION_METHOD_LABEL | \
WSC_CONFIGURATION_METHOD_KEYPAD | \
@ -213,6 +287,7 @@ struct p2p_device *p2p_device_update_from_genl(struct l_genl_msg *msg,
dev = l_new(struct p2p_device, 1);
dev->wdev_id = *wdev_id;
memcpy(dev->addr, ifaddr, ETH_ALEN);
dev->nl80211 = l_genl_family_new(iwd_get_genl(), NL80211_GENL_NAME);
dev->wiphy = wiphy;
gethostname(hostname, sizeof(hostname));
dev->connections_left = 1;
@ -303,8 +378,19 @@ static void p2p_device_free(void *user_data)
{
struct p2p_device *dev = user_data;
if (dev->pending_message) {
struct l_dbus_message *reply =
dbus_error_aborted(dev->pending_message);
dev->pending_complete(dbus_get_bus(),
dev->pending_message, reply);
dev->pending_message = NULL;
dev->pending_complete = NULL;
}
l_dbus_unregister_object(dbus_get_bus(), p2p_device_get_path(dev));
l_queue_destroy(dev->peer_list, p2p_peer_put);
l_genl_family_free(dev->nl80211); /* Cancels dev->start_stop_cmd_id */
l_free(dev);
}
@ -317,6 +403,43 @@ bool p2p_device_destroy(struct p2p_device *dev)
return true;
}
static bool p2p_device_get_enabled(struct l_dbus *dbus,
struct l_dbus_message *message,
struct l_dbus_message_builder *builder,
void *user_data)
{
struct p2p_device *dev = user_data;
bool enabled = dev->enabled;
l_dbus_message_builder_append_basic(builder, 'b', &enabled);
return true;
}
static struct l_dbus_message *p2p_device_set_enabled(struct l_dbus *dbus,
struct l_dbus_message *message,
struct l_dbus_message_iter *new_value,
l_dbus_property_complete_cb_t complete,
void *user_data)
{
struct p2p_device *dev = user_data;
bool new_enabled;
if (!l_dbus_message_iter_get_variant(new_value, "b", &new_enabled))
return dbus_error_invalid_args(message);
if (dev->start_stop_cmd_id || dev->pending_message)
return dbus_error_busy(message);
if (dev->enabled == new_enabled) {
complete(dbus, message, NULL);
return NULL;
}
p2p_device_start_stop(dev, complete, message);
return NULL;
}
static bool p2p_device_get_name(struct l_dbus *dbus,
struct l_dbus_message *message,
struct l_dbus_message_builder *builder,
@ -414,6 +537,9 @@ static struct l_dbus_message *p2p_device_get_peers(struct l_dbus *dbus,
static void p2p_interface_setup(struct l_dbus_interface *interface)
{
l_dbus_interface_property(interface, "Enabled", 0, "b",
p2p_device_get_enabled,
p2p_device_set_enabled);
l_dbus_interface_property(interface, "Name", 0, "s",
p2p_device_get_name,
p2p_device_set_name);