mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-11-25 17:59:25 +01:00
wiphy: Track regulatory domain changes
When a new wiphy is added query its regulatory domain and listen for nl80211 regulatory notifications to be able to provide current regulatory country code through the new wiphy_get_reg_domain_country().
This commit is contained in:
parent
0f3f0086ae
commit
b43e915b98
118
src/wiphy.c
118
src/wiphy.c
@ -52,6 +52,7 @@
|
||||
#include "src/common.h"
|
||||
#include "src/watchlist.h"
|
||||
#include "src/nl80211util.h"
|
||||
#include "src/nl80211cmd.h"
|
||||
|
||||
#define EXT_CAP_LEN 10
|
||||
|
||||
@ -60,6 +61,7 @@ static struct l_hwdb *hwdb;
|
||||
static char **whitelist_filter;
|
||||
static char **blacklist_filter;
|
||||
static int mac_randomize_bytes = 6;
|
||||
static char regdom_country[2];
|
||||
|
||||
struct wiphy {
|
||||
uint32_t id;
|
||||
@ -81,6 +83,8 @@ struct wiphy {
|
||||
uint8_t *iftype_extended_capabilities[NUM_NL80211_IFTYPES];
|
||||
uint8_t *supported_rates[NUM_NL80211_BANDS];
|
||||
uint8_t rm_enabled_capabilities[7]; /* 5 size max + header */
|
||||
struct l_genl_family *nl80211;
|
||||
char regdom_country[2];
|
||||
|
||||
bool support_scheduled_scan:1;
|
||||
bool support_rekey_offload:1;
|
||||
@ -227,6 +231,7 @@ static void wiphy_free(void *data)
|
||||
l_free(wiphy->model_str);
|
||||
l_free(wiphy->vendor_str);
|
||||
l_free(wiphy->driver_str);
|
||||
l_genl_family_free(wiphy->nl80211);
|
||||
l_free(wiphy);
|
||||
}
|
||||
|
||||
@ -562,6 +567,18 @@ const uint8_t *wiphy_get_supported_rates(struct wiphy *wiphy, unsigned int band,
|
||||
return wiphy->supported_rates[band];
|
||||
}
|
||||
|
||||
void wiphy_get_reg_domain_country(struct wiphy *wiphy, char *out)
|
||||
{
|
||||
char *country = wiphy->regdom_country;
|
||||
|
||||
if (!country[0])
|
||||
/* Wiphy uses the global regulatory domain */
|
||||
country = regdom_country;
|
||||
|
||||
out[0] = country[0];
|
||||
out[1] = country[1];
|
||||
}
|
||||
|
||||
uint32_t wiphy_state_watch_add(struct wiphy *wiphy,
|
||||
wiphy_state_watch_func_t func,
|
||||
void *user_data, wiphy_destroy_func_t destroy)
|
||||
@ -1046,9 +1063,11 @@ static void wiphy_register(struct wiphy *wiphy)
|
||||
struct wiphy *wiphy_create(uint32_t wiphy_id, const char *name)
|
||||
{
|
||||
struct wiphy *wiphy;
|
||||
struct l_genl *genl = iwd_get_genl();
|
||||
|
||||
wiphy = wiphy_new(wiphy_id);
|
||||
l_strlcpy(wiphy->name, name, sizeof(wiphy->name));
|
||||
wiphy->nl80211 = l_genl_family_new(genl, NL80211_GENL_NAME);
|
||||
l_queue_push_head(wiphy_list, wiphy);
|
||||
|
||||
if (!wiphy_is_managed(name))
|
||||
@ -1138,6 +1157,70 @@ static void wiphy_setup_rm_enabled_capabilities(struct wiphy *wiphy)
|
||||
*/
|
||||
}
|
||||
|
||||
static void wiphy_update_reg_domain(struct wiphy *wiphy, bool global,
|
||||
struct l_genl_msg *msg)
|
||||
{
|
||||
char *out_country;
|
||||
|
||||
if (global)
|
||||
/*
|
||||
* Leave @wiphy->regdom_country as all zeros to mean that it
|
||||
* uses the global @regdom_country, i.e. is not self-managed.
|
||||
*
|
||||
* Even if we're called because we queried a new wiphy's
|
||||
* reg domain, use the value we received here to update our
|
||||
* global @regdom_country in case this is the first opportunity
|
||||
* we have to update it -- possibly because this is the first
|
||||
* wiphy created (that is not self-managed anyway) and we
|
||||
* haven't received any REG_CHANGE events yet.
|
||||
*/
|
||||
out_country = regdom_country;
|
||||
else
|
||||
out_country = wiphy->regdom_country;
|
||||
|
||||
/*
|
||||
* Write the new country code or XX if the reg domain is not a
|
||||
* country domain.
|
||||
*/
|
||||
if (nl80211_parse_attrs(msg, NL80211_ATTR_REG_ALPHA2, out_country,
|
||||
NL80211_ATTR_UNSPEC) < 0)
|
||||
out_country[0] = out_country[1] = 'X';
|
||||
|
||||
l_debug("New reg domain country code for %s is %c%c",
|
||||
global ? "(global)" : wiphy->name,
|
||||
out_country[0], out_country[1]);
|
||||
}
|
||||
|
||||
static void wiphy_get_reg_cb(struct l_genl_msg *msg, void *user_data)
|
||||
{
|
||||
struct wiphy *wiphy = user_data;
|
||||
uint32_t tmp;
|
||||
bool global;
|
||||
|
||||
/*
|
||||
* NL80211_CMD_GET_REG contains an NL80211_ATTR_WIPHY iff the wiphy
|
||||
* uses a self-managed regulatory domain.
|
||||
*/
|
||||
global = nl80211_parse_attrs(msg, NL80211_ATTR_WIPHY, &tmp,
|
||||
NL80211_ATTR_UNSPEC) < 0;
|
||||
|
||||
wiphy_update_reg_domain(wiphy, global, msg);
|
||||
}
|
||||
|
||||
static void wiphy_get_reg_domain(struct wiphy *wiphy)
|
||||
{
|
||||
struct l_genl_msg *msg;
|
||||
|
||||
msg = l_genl_msg_new(NL80211_CMD_GET_REG);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY, 4, &wiphy->id);
|
||||
|
||||
if (!l_genl_family_send(wiphy->nl80211, msg, wiphy_get_reg_cb, wiphy,
|
||||
NULL)) {
|
||||
l_error("Error sending NL80211_CMD_GET_REG for %s", wiphy->name);
|
||||
l_genl_msg_unref(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void wiphy_create_complete(struct wiphy *wiphy)
|
||||
{
|
||||
wiphy_register(wiphy);
|
||||
@ -1152,6 +1235,7 @@ void wiphy_create_complete(struct wiphy *wiphy)
|
||||
|
||||
wiphy_set_station_capability_bits(wiphy);
|
||||
wiphy_setup_rm_enabled_capabilities(wiphy);
|
||||
wiphy_get_reg_domain(wiphy);
|
||||
|
||||
wiphy_print_basic_info(wiphy);
|
||||
}
|
||||
@ -1338,6 +1422,36 @@ static void setup_wiphy_interface(struct l_dbus_interface *interface)
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void wiphy_reg_notify(struct l_genl_msg *msg, void *user_data)
|
||||
{
|
||||
uint8_t cmd = l_genl_msg_get_command(msg);
|
||||
|
||||
l_debug("Notification of command %s(%u)",
|
||||
nl80211cmd_to_string(cmd), cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case NL80211_CMD_REG_CHANGE:
|
||||
wiphy_update_reg_domain(NULL, true, msg);
|
||||
break;
|
||||
case NL80211_CMD_WIPHY_REG_CHANGE:
|
||||
{
|
||||
uint32_t wiphy_id;
|
||||
struct wiphy *wiphy;
|
||||
|
||||
if (nl80211_parse_attrs(msg, NL80211_ATTR_WIPHY, &wiphy_id,
|
||||
NL80211_ATTR_UNSPEC) < 0)
|
||||
break;
|
||||
|
||||
wiphy = wiphy_find(wiphy_id);
|
||||
if (!wiphy)
|
||||
break;
|
||||
|
||||
wiphy_update_reg_domain(wiphy, false, msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int wiphy_init(void)
|
||||
{
|
||||
struct l_genl *genl = iwd_get_genl();
|
||||
@ -1388,6 +1502,10 @@ static int wiphy_init(void)
|
||||
" value: %s", s);
|
||||
}
|
||||
|
||||
if (!l_genl_family_register(nl80211, NL80211_MULTICAST_GROUP_REG,
|
||||
wiphy_reg_notify, NULL, NULL))
|
||||
l_error("Registering for regulatory notifications failed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,7 @@ const uint8_t *wiphy_get_permanent_address(struct wiphy *wiphy);
|
||||
const uint8_t *wiphy_get_extended_capabilities(struct wiphy *wiphy,
|
||||
uint32_t iftype);
|
||||
const uint8_t *wiphy_get_rm_enabled_capabilities(struct wiphy *wiphy);
|
||||
void wiphy_get_reg_domain_country(struct wiphy *wiphy, char *out);
|
||||
|
||||
void wiphy_generate_random_address(struct wiphy *wiphy, uint8_t addr[static 6]);
|
||||
void wiphy_generate_address_from_ssid(struct wiphy *wiphy, const char *ssid,
|
||||
|
Loading…
Reference in New Issue
Block a user