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;
|
||||
uint8_t conn_addr[6];
|
||||
uint16_t conn_password_id;
|
||||
unsigned int conn_num;
|
||||
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;
|
||||
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->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_xchg_stop(dev->wdev_id);
|
||||
|
||||
@ -426,11 +471,117 @@ static const struct frame_xchg_prefix p2p_frame_pd_resp = {
|
||||
.len = 7,
|
||||
};
|
||||
|
||||
static void p2p_device_interface_create(struct p2p_device *dev)
|
||||
static void p2p_provision_connect(struct p2p_device *dev)
|
||||
{
|
||||
/* 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
l_dbus_property_complete_cb_t complete,
|
||||
struct l_dbus_message *message)
|
||||
@ -2395,13 +2555,28 @@ static void p2p_device_start_stop(struct p2p_device *dev,
|
||||
if (dev->enabled) {
|
||||
/*
|
||||
* 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);
|
||||
|
||||
l_queue_destroy(dev->peer_list, p2p_peer_put);
|
||||
dev->peer_list = NULL;
|
||||
if (!dev->conn_peer) {
|
||||
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