mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2025-01-03 10:32:33 +01:00
manager: dump wiphy/iface on NEW_WIPHY
A NEW_WIPHY event may not always contain all the information about a given phy, but GET_WIPHY will. In order to get everything we must mimic the behavior done during initalization and dump both wiphy and interfaces when a NEW_WIPHY comes in. Now, any NEW_WIPHY event will initialize a wiphy, but then do a GET_WIPHY/GET_INTERFACE to obtain all the information. Because of this we can ignore any NEW_INTERFACE notifications since we are dumping the interface anyways. Once some kernel changes get merged we wont need to do this anymore so long as the 'full' NEW_WIPHY feature is supported.
This commit is contained in:
parent
b3ccabea9e
commit
95f1fb1663
228
src/manager.c
228
src/manager.c
@ -49,7 +49,6 @@ static bool randomize;
|
|||||||
struct wiphy_setup_state {
|
struct wiphy_setup_state {
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
struct wiphy *wiphy;
|
struct wiphy *wiphy;
|
||||||
struct l_timeout *setup_timeout;
|
|
||||||
unsigned int pending_cmd_count;
|
unsigned int pending_cmd_count;
|
||||||
bool aborted;
|
bool aborted;
|
||||||
|
|
||||||
@ -85,9 +84,6 @@ static void wiphy_setup_state_free(void *data)
|
|||||||
{
|
{
|
||||||
struct wiphy_setup_state *state = data;
|
struct wiphy_setup_state *state = data;
|
||||||
|
|
||||||
if (state->setup_timeout)
|
|
||||||
l_timeout_remove(state->setup_timeout);
|
|
||||||
|
|
||||||
if (state->default_if_msg)
|
if (state->default_if_msg)
|
||||||
l_genl_msg_unref(state->default_if_msg);
|
l_genl_msg_unref(state->default_if_msg);
|
||||||
|
|
||||||
@ -375,47 +371,6 @@ static void manager_get_interface_cb(struct l_genl_msg *msg, void *user_data)
|
|||||||
state->pending_cmd_count++;
|
state->pending_cmd_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void manager_wiphy_dump_interfaces(struct wiphy_setup_state *state)
|
|
||||||
{
|
|
||||||
struct l_genl_msg *msg;
|
|
||||||
unsigned cmd_id;
|
|
||||||
|
|
||||||
if (state->setup_timeout) {
|
|
||||||
l_timeout_remove(state->setup_timeout);
|
|
||||||
state->setup_timeout = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* As the first step after new wiphy is detected we will query
|
|
||||||
* the initial interface setup, delete the default interfaces
|
|
||||||
* and create interfaces for our own use with NL80211_ATTR_SOCKET_OWNER
|
|
||||||
* on them. After that if new interfaces are created outside of
|
|
||||||
* IWD, or removed outside of IWD, we don't touch them and will
|
|
||||||
* try to minimally adapt to handle the removals correctly. It's
|
|
||||||
* a very unlikely situation in any case but it wouldn't make
|
|
||||||
* sense to try to continually enforce our setup fighting against
|
|
||||||
* some other process, and it wouldn't make sense to try to
|
|
||||||
* manage and use additional interfaces beyond the one or two
|
|
||||||
* we need for our operations.
|
|
||||||
*/
|
|
||||||
|
|
||||||
msg = l_genl_msg_new(NL80211_CMD_GET_INTERFACE);
|
|
||||||
l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY, 4, &state->id);
|
|
||||||
cmd_id = l_genl_family_dump(nl80211, msg,
|
|
||||||
manager_get_interface_cb, state,
|
|
||||||
manager_setup_cmd_done);
|
|
||||||
|
|
||||||
if (!cmd_id) {
|
|
||||||
l_error("Querying interface information for wiphy %u failed",
|
|
||||||
(unsigned int) state->id);
|
|
||||||
wiphy_setup_state_destroy(state);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
l_debug("");
|
|
||||||
state->pending_cmd_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct wiphy_setup_state *manager_rx_cmd_new_wiphy(
|
static struct wiphy_setup_state *manager_rx_cmd_new_wiphy(
|
||||||
struct l_genl_msg *msg)
|
struct l_genl_msg *msg)
|
||||||
{
|
{
|
||||||
@ -492,32 +447,6 @@ done:
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void manager_wiphy_setup_timeout(struct l_timeout *timeout,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
struct wiphy_setup_state *state = user_data;
|
|
||||||
|
|
||||||
manager_wiphy_dump_interfaces(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void manager_new_wiphy_event(struct l_genl_msg *msg)
|
|
||||||
{
|
|
||||||
struct wiphy_setup_state *state;
|
|
||||||
|
|
||||||
if (!pending_wiphys)
|
|
||||||
return;
|
|
||||||
|
|
||||||
state = manager_rx_cmd_new_wiphy(msg);
|
|
||||||
if (!state)
|
|
||||||
return;
|
|
||||||
|
|
||||||
wiphy_create_complete(state->wiphy);
|
|
||||||
|
|
||||||
/* Setup a timer just in case a default interface is not created */
|
|
||||||
state->setup_timeout = l_timeout_create(1, manager_wiphy_setup_timeout,
|
|
||||||
state, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool manager_wiphy_state_match(const void *a, const void *b)
|
static bool manager_wiphy_state_match(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
const struct wiphy_setup_state *state = a;
|
const struct wiphy_setup_state *state = a;
|
||||||
@ -593,56 +522,6 @@ static void manager_del_wiphy_event(struct l_genl_msg *msg)
|
|||||||
wiphy_destroy(wiphy);
|
wiphy_destroy(wiphy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void manager_config_notify(struct l_genl_msg *msg, void *user_data)
|
|
||||||
{
|
|
||||||
uint8_t cmd;
|
|
||||||
struct wiphy_setup_state *state;
|
|
||||||
struct l_genl_attr attr;
|
|
||||||
struct netdev *netdev;
|
|
||||||
|
|
||||||
cmd = l_genl_msg_get_command(msg);
|
|
||||||
|
|
||||||
l_debug("Notification of command %s(%u)",
|
|
||||||
nl80211cmd_to_string(cmd), cmd);
|
|
||||||
|
|
||||||
switch (cmd) {
|
|
||||||
case NL80211_CMD_NEW_WIPHY:
|
|
||||||
manager_new_wiphy_event(msg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NL80211_CMD_DEL_WIPHY:
|
|
||||||
manager_del_wiphy_event(msg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NL80211_CMD_NEW_INTERFACE:
|
|
||||||
/*
|
|
||||||
* If we have a NEW_INTERFACE for a freshly detected wiphy
|
|
||||||
* assume we can now query for the default or pre-created
|
|
||||||
* interfaces, remove any we don't need and create our own.
|
|
||||||
*/
|
|
||||||
if (!l_genl_attr_init(&attr, msg))
|
|
||||||
break;
|
|
||||||
|
|
||||||
state = manager_find_pending(manager_parse_wiphy_id(&attr));
|
|
||||||
if (!state || !state->setup_timeout)
|
|
||||||
break;
|
|
||||||
|
|
||||||
manager_wiphy_dump_interfaces(state);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NL80211_CMD_DEL_INTERFACE:
|
|
||||||
if (!l_genl_attr_init(&attr, msg))
|
|
||||||
break;
|
|
||||||
|
|
||||||
netdev = netdev_find(manager_parse_ifindex(&attr));
|
|
||||||
if (!netdev)
|
|
||||||
break;
|
|
||||||
|
|
||||||
netdev_destroy(netdev);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void manager_interface_dump_callback(struct l_genl_msg *msg,
|
static void manager_interface_dump_callback(struct l_genl_msg *msg,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
@ -655,7 +534,7 @@ static void manager_interface_dump_callback(struct l_genl_msg *msg,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
state = manager_find_pending(manager_parse_wiphy_id(&attr));
|
state = manager_find_pending(manager_parse_wiphy_id(&attr));
|
||||||
if (!state || state->setup_timeout)
|
if (!state)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
manager_get_interface_cb(msg, state);
|
manager_get_interface_cb(msg, state);
|
||||||
@ -665,10 +544,6 @@ static bool manager_check_create_interfaces(const void *a, const void *b)
|
|||||||
{
|
{
|
||||||
struct wiphy_setup_state *state = (void *) a;
|
struct wiphy_setup_state *state = (void *) a;
|
||||||
|
|
||||||
/* phy might have been detected after the initial dump */
|
|
||||||
if (state->setup_timeout)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
wiphy_create_complete(state->wiphy);
|
wiphy_create_complete(state->wiphy);
|
||||||
|
|
||||||
if (state->pending_cmd_count)
|
if (state->pending_cmd_count)
|
||||||
@ -697,6 +572,107 @@ static void manager_wiphy_dump_callback(struct l_genl_msg *msg, void *user_data)
|
|||||||
manager_rx_cmd_new_wiphy(msg);
|
manager_rx_cmd_new_wiphy(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void manager_new_wiphy_event(struct l_genl_msg *msg)
|
||||||
|
{
|
||||||
|
struct l_genl_attr attr;
|
||||||
|
unsigned int wiphy_cmd_id;
|
||||||
|
unsigned int iface_cmd_id;
|
||||||
|
uint32_t wiphy_id;
|
||||||
|
|
||||||
|
if (!pending_wiphys)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!l_genl_attr_init(&attr, msg))
|
||||||
|
return;
|
||||||
|
|
||||||
|
wiphy_id = manager_parse_wiphy_id(&attr);
|
||||||
|
/*
|
||||||
|
* Until fixed, a NEW_WIPHY event will not include all the information
|
||||||
|
* that may be available, but a dump will. Because of this we do both
|
||||||
|
* GET_WIPHY/GET_INTERFACE, same as we would during initalization.
|
||||||
|
*/
|
||||||
|
msg = l_genl_msg_new_sized(NL80211_CMD_GET_WIPHY, 128);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP, 0, NULL);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY, 4, &wiphy_id);
|
||||||
|
|
||||||
|
wiphy_cmd_id = l_genl_family_dump(nl80211, msg,
|
||||||
|
manager_wiphy_dump_callback,
|
||||||
|
NULL, NULL);
|
||||||
|
if (!wiphy_cmd_id) {
|
||||||
|
l_error("Could not dump wiphy %u", wiphy_id);
|
||||||
|
l_genl_msg_unref(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As the first step after new wiphy is detected we will query
|
||||||
|
* the initial interface setup, delete the default interfaces
|
||||||
|
* and create interfaces for our own use with NL80211_ATTR_SOCKET_OWNER
|
||||||
|
* on them. After that if new interfaces are created outside of
|
||||||
|
* IWD, or removed outside of IWD, we don't touch them and will
|
||||||
|
* try to minimally adapt to handle the removals correctly. It's
|
||||||
|
* a very unlikely situation in any case but it wouldn't make
|
||||||
|
* sense to try to continually enforce our setup fighting against
|
||||||
|
* some other process, and it wouldn't make sense to try to
|
||||||
|
* manage and use additional interfaces beyond the one or two
|
||||||
|
* we need for our operations.
|
||||||
|
*/
|
||||||
|
msg = l_genl_msg_new(NL80211_CMD_GET_INTERFACE);
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY, 4, &wiphy_id);
|
||||||
|
|
||||||
|
iface_cmd_id = l_genl_family_dump(nl80211, msg,
|
||||||
|
manager_interface_dump_callback,
|
||||||
|
NULL, manager_interface_dump_done);
|
||||||
|
|
||||||
|
if (!iface_cmd_id) {
|
||||||
|
l_error("Could not dump interface for wiphy %u", wiphy_id);
|
||||||
|
l_genl_family_cancel(nl80211, wiphy_cmd_id);
|
||||||
|
l_genl_msg_unref(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void manager_config_notify(struct l_genl_msg *msg, void *user_data)
|
||||||
|
{
|
||||||
|
uint8_t cmd;
|
||||||
|
struct l_genl_attr attr;
|
||||||
|
struct netdev *netdev;
|
||||||
|
|
||||||
|
cmd = l_genl_msg_get_command(msg);
|
||||||
|
|
||||||
|
l_debug("Notification of command %s(%u)",
|
||||||
|
nl80211cmd_to_string(cmd), cmd);
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case NL80211_CMD_NEW_WIPHY:
|
||||||
|
manager_new_wiphy_event(msg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NL80211_CMD_DEL_WIPHY:
|
||||||
|
manager_del_wiphy_event(msg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NL80211_CMD_NEW_INTERFACE:
|
||||||
|
/*
|
||||||
|
* TODO: Until NEW_WIPHY contains all required information we
|
||||||
|
* are stuck always having to do a full dump. This specific
|
||||||
|
* interface must also be dumped, and this is taken care of
|
||||||
|
* in manager_new_wiphy_event.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NL80211_CMD_DEL_INTERFACE:
|
||||||
|
if (!l_genl_attr_init(&attr, msg))
|
||||||
|
break;
|
||||||
|
|
||||||
|
netdev = netdev_find(manager_parse_ifindex(&attr));
|
||||||
|
if (!netdev)
|
||||||
|
break;
|
||||||
|
|
||||||
|
netdev_destroy(netdev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool manager_init(struct l_genl_family *in,
|
bool manager_init(struct l_genl_family *in,
|
||||||
const char *if_whitelist, const char *if_blacklist)
|
const char *if_whitelist, const char *if_blacklist)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user