mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2025-01-03 10:32:33 +01:00
p2p: Create the P2P-Client interface
Once we've found the provisioning BSS create the P2P-Client interface that we're going to use for the actual provisioning and the final P2P connection.
This commit is contained in:
parent
d77fdd087b
commit
85f09d9318
185
src/p2p.c
185
src/p2p.c
@ -86,7 +86,11 @@ struct p2p_device {
|
|||||||
char *conn_pin;
|
char *conn_pin;
|
||||||
uint8_t conn_addr[6];
|
uint8_t conn_addr[6];
|
||||||
uint16_t conn_password_id;
|
uint16_t conn_password_id;
|
||||||
|
unsigned int conn_num;
|
||||||
struct scan_bss *conn_wsc_bss;
|
struct scan_bss *conn_wsc_bss;
|
||||||
|
struct netdev *conn_netdev;
|
||||||
|
uint32_t conn_netdev_watch_id;
|
||||||
|
uint32_t conn_new_intf_cmd_id;
|
||||||
|
|
||||||
struct l_timeout *config_timeout;
|
struct l_timeout *config_timeout;
|
||||||
unsigned long go_config_delay;
|
unsigned long go_config_delay;
|
||||||
@ -306,6 +310,47 @@ static void p2p_connection_reset(struct p2p_device *dev)
|
|||||||
l_timeout_remove(dev->config_timeout);
|
l_timeout_remove(dev->config_timeout);
|
||||||
l_timeout_remove(dev->go_neg_req_timeout);
|
l_timeout_remove(dev->go_neg_req_timeout);
|
||||||
|
|
||||||
|
if (dev->conn_new_intf_cmd_id)
|
||||||
|
/*
|
||||||
|
* Note this may result in the interface being created
|
||||||
|
* and unused, we don't have its ifindex or wdev_id here
|
||||||
|
* to be able to delete it. Could use a separate netlink
|
||||||
|
* socket for each connection or disallowing .Disconnect
|
||||||
|
* calls while this command runs.
|
||||||
|
*/
|
||||||
|
l_genl_family_cancel(dev->nl80211, dev->conn_new_intf_cmd_id);
|
||||||
|
|
||||||
|
if (dev->conn_netdev) {
|
||||||
|
struct l_genl_msg *msg;
|
||||||
|
uint64_t wdev_id = netdev_get_wdev_id(dev->conn_netdev);
|
||||||
|
|
||||||
|
msg = l_genl_msg_new(NL80211_CMD_DEL_INTERFACE);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_WDEV, 8, &wdev_id);
|
||||||
|
|
||||||
|
if (!l_genl_family_send(dev->nl80211, msg, NULL, NULL, NULL)) {
|
||||||
|
l_genl_msg_unref(msg);
|
||||||
|
l_error("Sending DEL_INTERFACE for %s failed",
|
||||||
|
netdev_get_name(dev->conn_netdev));
|
||||||
|
}
|
||||||
|
|
||||||
|
netdev_destroy(dev->conn_netdev);
|
||||||
|
dev->conn_netdev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Removing the netdev above makes sure that both the WSC connection
|
||||||
|
* and the final WPA2 connection (wsc.c and netdev.c) no longer need
|
||||||
|
* the bss so we can free it now -- if it wasn't freed as a result
|
||||||
|
* of wsc_enrollee_cancel or netdev_destroy triggering
|
||||||
|
* p2p_peer_provision_done in the first place.
|
||||||
|
*/
|
||||||
|
if (dev->conn_wsc_bss) {
|
||||||
|
scan_bss_free(dev->conn_wsc_bss);
|
||||||
|
dev->conn_wsc_bss = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
netdev_watch_remove(dev->conn_netdev_watch_id);
|
||||||
|
|
||||||
frame_watch_group_remove(dev->wdev_id, FRAME_GROUP_CONNECT);
|
frame_watch_group_remove(dev->wdev_id, FRAME_GROUP_CONNECT);
|
||||||
frame_xchg_stop(dev->wdev_id);
|
frame_xchg_stop(dev->wdev_id);
|
||||||
|
|
||||||
@ -426,11 +471,117 @@ static const struct frame_xchg_prefix p2p_frame_pd_resp = {
|
|||||||
.len = 7,
|
.len = 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void p2p_device_interface_create(struct p2p_device *dev)
|
static void p2p_provision_connect(struct p2p_device *dev)
|
||||||
{
|
{
|
||||||
/* TODO */
|
/* TODO */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void p2p_device_netdev_watch_destroy(void *user_data)
|
||||||
|
{
|
||||||
|
struct p2p_device *dev = user_data;
|
||||||
|
|
||||||
|
dev->conn_netdev_watch_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void p2p_device_netdev_notify(struct netdev *netdev,
|
||||||
|
enum netdev_watch_event event,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct p2p_device *dev = user_data;
|
||||||
|
|
||||||
|
if (dev->conn_netdev != netdev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case NETDEV_WATCH_EVENT_UP:
|
||||||
|
case NETDEV_WATCH_EVENT_NEW:
|
||||||
|
if (!dev->conn_wsc_bss || !netdev_get_is_up(netdev))
|
||||||
|
break;
|
||||||
|
|
||||||
|
p2p_provision_connect(dev);
|
||||||
|
break;
|
||||||
|
case NETDEV_WATCH_EVENT_DEL:
|
||||||
|
dev->conn_netdev = NULL;
|
||||||
|
/* Fall through */
|
||||||
|
case NETDEV_WATCH_EVENT_DOWN:
|
||||||
|
case NETDEV_WATCH_EVENT_ADDRESS_CHANGE:
|
||||||
|
p2p_connect_failed(dev);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void p2p_device_new_interface_cb(struct l_genl_msg *msg,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct p2p_device *dev = user_data;
|
||||||
|
|
||||||
|
l_debug("");
|
||||||
|
|
||||||
|
if (l_genl_msg_get_error(msg) < 0) {
|
||||||
|
l_error("NEW_INTERFACE failed: %s",
|
||||||
|
strerror(-l_genl_msg_get_error(msg)));
|
||||||
|
p2p_connect_failed(dev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the netdev so we don't have to parse the message ourselves */
|
||||||
|
dev->conn_netdev = netdev_create_from_genl(msg, dev->conn_addr);
|
||||||
|
if (!dev->conn_netdev) {
|
||||||
|
p2p_connect_failed(dev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register a watch for each connection rather than having one
|
||||||
|
* global watch. Each connection's watch will receive events
|
||||||
|
* related to all other connections too, and will check that its
|
||||||
|
* conn_netdev != netdev and exit immediately. This is not ideal
|
||||||
|
* but it's the same complexity (n^2) as that of one global watch
|
||||||
|
* that receives all events and iterates over p2p_device_list to
|
||||||
|
* find the connection.
|
||||||
|
*/
|
||||||
|
dev->conn_netdev_watch_id = netdev_watch_add(p2p_device_netdev_notify,
|
||||||
|
dev, p2p_device_netdev_watch_destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void p2p_device_new_interface_destroy(void *user_data)
|
||||||
|
{
|
||||||
|
struct p2p_device *dev = user_data;
|
||||||
|
|
||||||
|
dev->conn_new_intf_cmd_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void p2p_device_interface_create(struct p2p_device *dev)
|
||||||
|
{
|
||||||
|
uint32_t iftype = NL80211_IFTYPE_P2P_CLIENT;
|
||||||
|
char ifname[32];
|
||||||
|
uint32_t wiphy_id = dev->wdev_id >> 32;
|
||||||
|
struct l_genl_msg *msg;
|
||||||
|
|
||||||
|
snprintf(ifname, sizeof(ifname), "wlan%i-p2p-cl%i",
|
||||||
|
wiphy_id, dev->conn_num++);
|
||||||
|
l_debug("creating %s", ifname);
|
||||||
|
|
||||||
|
msg = l_genl_msg_new(NL80211_CMD_NEW_INTERFACE);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY, 4, &wiphy_id);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_IFTYPE, 4, &iftype);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_IFNAME,
|
||||||
|
strlen(ifname) + 1, ifname);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_4ADDR, 1, "\0");
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_SOCKET_OWNER, 0, "");
|
||||||
|
|
||||||
|
dev->conn_new_intf_cmd_id = l_genl_family_send(dev->nl80211, msg,
|
||||||
|
p2p_device_new_interface_cb, dev,
|
||||||
|
p2p_device_new_interface_destroy);
|
||||||
|
if (!dev->conn_new_intf_cmd_id) {
|
||||||
|
l_genl_msg_unref(msg);
|
||||||
|
l_error("Error sending NEW_INTERFACE for %s", ifname);
|
||||||
|
p2p_connect_failed(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void p2p_scan_destroy(void *user_data)
|
static void p2p_scan_destroy(void *user_data)
|
||||||
{
|
{
|
||||||
struct p2p_device *dev = user_data;
|
struct p2p_device *dev = user_data;
|
||||||
@ -2364,6 +2515,15 @@ static void p2p_device_enable_destroy(void *user_data)
|
|||||||
dev->start_stop_cmd_id = 0;
|
dev->start_stop_cmd_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool p2p_peer_remove_disconnected(void *peer, void *conn_peer)
|
||||||
|
{
|
||||||
|
if (peer == conn_peer)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
p2p_peer_put(peer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void p2p_device_start_stop(struct p2p_device *dev,
|
static void p2p_device_start_stop(struct p2p_device *dev,
|
||||||
l_dbus_property_complete_cb_t complete,
|
l_dbus_property_complete_cb_t complete,
|
||||||
struct l_dbus_message *message)
|
struct l_dbus_message *message)
|
||||||
@ -2395,13 +2555,28 @@ static void p2p_device_start_stop(struct p2p_device *dev,
|
|||||||
if (dev->enabled) {
|
if (dev->enabled) {
|
||||||
/*
|
/*
|
||||||
* Stopping the P2P device, drop all peers as we can't start
|
* Stopping the P2P device, drop all peers as we can't start
|
||||||
* new connections from now on.
|
* new connections from now on. Check if we have a connection
|
||||||
|
* being set up without a .conn_netdev and without
|
||||||
|
* .conn_wsc_bss -- this will mean the connection is still in
|
||||||
|
* the PD or GO Negotiation phase or inside the scan. Those
|
||||||
|
* phases happen on the device interface so the connection
|
||||||
|
* gets immediately aborted.
|
||||||
*/
|
*/
|
||||||
if (dev->conn_peer)
|
if (dev->conn_peer && !dev->conn_netdev && !dev->conn_wsc_bss)
|
||||||
p2p_connect_failed(dev);
|
p2p_connect_failed(dev);
|
||||||
|
|
||||||
l_queue_destroy(dev->peer_list, p2p_peer_put);
|
if (!dev->conn_peer) {
|
||||||
dev->peer_list = NULL;
|
l_queue_destroy(dev->peer_list, p2p_peer_put);
|
||||||
|
dev->peer_list = NULL;
|
||||||
|
} else
|
||||||
|
/*
|
||||||
|
* If the connection already depends on its own
|
||||||
|
* netdev only, we can let it continue until the user
|
||||||
|
* decides to disconnect.
|
||||||
|
*/
|
||||||
|
l_queue_foreach_remove(dev->peer_list,
|
||||||
|
p2p_peer_remove_disconnected,
|
||||||
|
dev->conn_peer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user