3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-10-04 02:18:49 +02:00

manager: Create/destroy P2P devices

Create a P2P device interface along with the station interface when
setting up a wiphy and handle the interface being removed.
This commit is contained in:
Andrew Zaborowski 2020-04-03 18:14:16 +02:00 committed by Denis Kenzior
parent 326a8cd6ee
commit 358d0ca201

View File

@ -42,6 +42,7 @@
#include "src/util.h" #include "src/util.h"
#include "src/common.h" #include "src/common.h"
#include "src/nl80211cmd.h" #include "src/nl80211cmd.h"
#include "src/p2p.h"
static struct l_genl_family *nl80211 = NULL; static struct l_genl_family *nl80211 = NULL;
static char **whitelist_filter; static char **whitelist_filter;
@ -125,7 +126,8 @@ static bool manager_use_default(struct wiphy_setup_state *state)
return true; return true;
} }
static void manager_new_interface_cb(struct l_genl_msg *msg, void *user_data) static void manager_new_station_interface_cb(struct l_genl_msg *msg,
void *user_data)
{ {
struct wiphy_setup_state *state = user_data; struct wiphy_setup_state *state = user_data;
uint8_t addr_buf[6]; uint8_t addr_buf[6];
@ -170,6 +172,25 @@ static void manager_new_interface_cb(struct l_genl_msg *msg, void *user_data)
netdev_create_from_genl(msg, addr); netdev_create_from_genl(msg, addr);
} }
static void manager_new_p2p_interface_cb(struct l_genl_msg *msg,
void *user_data)
{
struct wiphy_setup_state *state = user_data;
l_debug("");
if (state->aborted)
return;
if (l_genl_msg_get_error(msg) < 0) {
l_error("NEW_INTERFACE failed for p2p-device: %s",
strerror(-l_genl_msg_get_error(msg)));
return;
}
p2p_device_update_from_genl(msg, true);
}
static void manager_new_interface_done(void *user_data) static void manager_new_interface_done(void *user_data)
{ {
struct wiphy_setup_state *state = user_data; struct wiphy_setup_state *state = user_data;
@ -184,7 +205,7 @@ static void manager_create_interfaces(struct wiphy_setup_state *state)
{ {
struct l_genl_msg *msg; struct l_genl_msg *msg;
char ifname[10]; char ifname[10];
uint32_t iftype = NL80211_IFTYPE_STATION; uint32_t iftype;
unsigned cmd_id; unsigned cmd_id;
if (state->aborted) if (state->aborted)
@ -192,19 +213,26 @@ static void manager_create_interfaces(struct wiphy_setup_state *state)
if (state->use_default) { if (state->use_default) {
manager_use_default(state); manager_use_default(state);
return;
/*
* Some drivers don't let us touch the default interface
* but still allow us to create/destroy P2P interfaces, so
* give it a chance.
*/
goto try_create_p2p;
} }
/* /*
* Current policy: we maintain one netdev per wiphy for station, * Current policy: we maintain one netdev per wiphy for station,
* AP and Ad-Hoc modes, one optional p2p-device and zero or more * AP and Ad-Hoc modes, one optional p2p-device and zero or more
* p2p-GOs or p2p-clients. The P2P-related interfaces will be * p2p-GOs or p2p-clients. The P2P-client/GO interfaces will be
* created on request. * created on request.
*/ */
/* To be improved */ /* To be improved */
snprintf(ifname, sizeof(ifname), "wlan%i", (int) state->id); snprintf(ifname, sizeof(ifname), "wlan%i", (int) state->id);
l_debug("creating %s", ifname); l_debug("creating %s", ifname);
iftype = NL80211_IFTYPE_STATION;
msg = l_genl_msg_new(NL80211_CMD_NEW_INTERFACE); msg = l_genl_msg_new(NL80211_CMD_NEW_INTERFACE);
l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY, 4, &state->id); l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY, 4, &state->id);
@ -226,7 +254,48 @@ static void manager_create_interfaces(struct wiphy_setup_state *state)
} }
cmd_id = l_genl_family_send(nl80211, msg, cmd_id = l_genl_family_send(nl80211, msg,
manager_new_interface_cb, state, manager_new_station_interface_cb, state,
manager_new_interface_done);
if (!cmd_id) {
l_error("Error sending NEW_INTERFACE for %s", ifname);
return;
}
state->pending_cmd_count++;
try_create_p2p:
/*
* Require the MAC on create feature so we can send our desired
* interface address during GO Negotiation before actually creating
* the local Client/GO interface. Could be worked around if needed.
*/
if (!wiphy_supports_iftype(state->wiphy, NL80211_IFTYPE_P2P_DEVICE) ||
!wiphy_supports_iftype(state->wiphy,
NL80211_IFTYPE_P2P_CLIENT) ||
!wiphy_has_feature(state->wiphy,
NL80211_FEATURE_MAC_ON_CREATE))
return;
/*
* Use wlan%i-p2p for now. We might want to use
* <default_interface's_name>-p2p here (in case state->use_default
* is true) but the risk is that we'd go over the interface name
* length limit.
*/
snprintf(ifname, sizeof(ifname), "wlan%i-p2p", (int) state->id);
l_debug("creating %s", ifname);
iftype = NL80211_IFTYPE_P2P_DEVICE;
msg = l_genl_msg_new(NL80211_CMD_NEW_INTERFACE);
l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY, 4, &state->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, "");
cmd_id = l_genl_family_send(nl80211, msg,
manager_new_p2p_interface_cb, state,
manager_new_interface_done); manager_new_interface_done);
if (!cmd_id) { if (!cmd_id) {
@ -378,17 +447,6 @@ static struct wiphy_setup_state *manager_find_pending(uint32_t id)
L_UINT_TO_PTR(id)); L_UINT_TO_PTR(id));
} }
static uint32_t manager_parse_ifindex(struct l_genl_msg *msg)
{
uint32_t ifindex;
if (nl80211_parse_attrs(msg, NL80211_ATTR_IFINDEX, &ifindex,
NL80211_ATTR_UNSPEC) < 0)
return -1;
return ifindex;
}
static uint32_t manager_parse_wiphy_id(struct l_genl_msg *msg) static uint32_t manager_parse_wiphy_id(struct l_genl_msg *msg)
{ {
uint32_t wiphy; uint32_t wiphy;
@ -593,7 +651,6 @@ static int manager_wiphy_filtered_dump(uint32_t wiphy_id,
static void manager_config_notify(struct l_genl_msg *msg, void *user_data) static void manager_config_notify(struct l_genl_msg *msg, void *user_data)
{ {
uint8_t cmd; uint8_t cmd;
struct netdev *netdev;
uint32_t wiphy_id; uint32_t wiphy_id;
struct wiphy_setup_state *state; struct wiphy_setup_state *state;
@ -692,13 +749,36 @@ static void manager_config_notify(struct l_genl_msg *msg, void *user_data)
return; return;
case NL80211_CMD_DEL_INTERFACE: case NL80211_CMD_DEL_INTERFACE:
netdev = netdev_find(manager_parse_ifindex(msg)); {
if (!netdev) uint32_t ifindex;
return;
if (nl80211_parse_attrs(msg, NL80211_ATTR_IFINDEX, &ifindex,
NL80211_ATTR_UNSPEC) < 0) {
uint64_t wdev_id;
struct p2p_device *p2p_device;
if (nl80211_parse_attrs(msg, NL80211_ATTR_WDEV,
&wdev_id,
NL80211_ATTR_UNSPEC) < 0)
return;
p2p_device = p2p_device_find(wdev_id);
if (!p2p_device)
return;
p2p_device_destroy(p2p_device);
} else {
struct netdev *netdev = netdev_find(ifindex);
if (!netdev)
return;
netdev_destroy(netdev);
}
netdev_destroy(netdev);
return; return;
} }
}
} }
static int manager_init(void) static int manager_init(void)