Add a wpa_supplicant ctrl_iface event for regdom changes
CTRL-EVENT-REGDOM-CHANGE event provides an external notification of regulatory domain (and any driver channel list) changes. Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
150fd0b2b5
commit
142817b2f9
4 changed files with 123 additions and 30 deletions
|
@ -66,6 +66,8 @@ extern "C" {
|
|||
#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
|
||||
/** Change in the signal level was reported by the driver */
|
||||
#define WPA_EVENT_SIGNAL_CHANGE "CTRL-EVENT-SIGNAL-CHANGE "
|
||||
/** Regulatory domain channel */
|
||||
#define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE "
|
||||
|
||||
/** RSN IBSS 4-way handshakes completed with specified peer */
|
||||
#define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED "
|
||||
|
|
|
@ -50,6 +50,14 @@ enum reg_change_initiator {
|
|||
REGDOM_BEACON_HINT,
|
||||
};
|
||||
|
||||
enum reg_type {
|
||||
REGDOM_TYPE_UNKNOWN,
|
||||
REGDOM_TYPE_COUNTRY,
|
||||
REGDOM_TYPE_WORLD,
|
||||
REGDOM_TYPE_CUSTOM_WORLD,
|
||||
REGDOM_TYPE_INTERSECTION,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hostapd_channel_data - Channel information
|
||||
*/
|
||||
|
@ -3851,9 +3859,13 @@ union wpa_event_data {
|
|||
/**
|
||||
* channel_list_changed - Data for EVENT_CHANNEL_LIST_CHANGED
|
||||
* @initiator: Initiator of the regulatory change
|
||||
* @type: Regulatory change type
|
||||
* @alpha2: Country code (or "" if not available)
|
||||
*/
|
||||
struct channel_list_changed {
|
||||
enum reg_change_initiator initiator;
|
||||
enum reg_type type;
|
||||
char alpha2[3];
|
||||
} channel_list_changed;
|
||||
|
||||
/**
|
||||
|
|
|
@ -2889,6 +2889,69 @@ static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
|
|||
}
|
||||
|
||||
|
||||
static void nl80211_reg_change_event(struct wpa_driver_nl80211_data *drv,
|
||||
struct nlattr *tb[])
|
||||
{
|
||||
union wpa_event_data data;
|
||||
enum nl80211_reg_initiator init;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
|
||||
|
||||
if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
|
||||
return;
|
||||
|
||||
os_memset(&data, 0, sizeof(data));
|
||||
init = nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]);
|
||||
wpa_printf(MSG_DEBUG, " * initiator=%d", init);
|
||||
switch (init) {
|
||||
case NL80211_REGDOM_SET_BY_CORE:
|
||||
data.channel_list_changed.initiator = REGDOM_SET_BY_CORE;
|
||||
break;
|
||||
case NL80211_REGDOM_SET_BY_USER:
|
||||
data.channel_list_changed.initiator = REGDOM_SET_BY_USER;
|
||||
break;
|
||||
case NL80211_REGDOM_SET_BY_DRIVER:
|
||||
data.channel_list_changed.initiator = REGDOM_SET_BY_DRIVER;
|
||||
break;
|
||||
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
|
||||
data.channel_list_changed.initiator = REGDOM_SET_BY_COUNTRY_IE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tb[NL80211_ATTR_REG_TYPE]) {
|
||||
enum nl80211_reg_type type;
|
||||
type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]);
|
||||
wpa_printf(MSG_DEBUG, " * type=%d", type);
|
||||
switch (type) {
|
||||
case NL80211_REGDOM_TYPE_COUNTRY:
|
||||
data.channel_list_changed.type = REGDOM_TYPE_COUNTRY;
|
||||
break;
|
||||
case NL80211_REGDOM_TYPE_WORLD:
|
||||
data.channel_list_changed.type = REGDOM_TYPE_WORLD;
|
||||
break;
|
||||
case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
|
||||
data.channel_list_changed.type =
|
||||
REGDOM_TYPE_CUSTOM_WORLD;
|
||||
break;
|
||||
case NL80211_REGDOM_TYPE_INTERSECTION:
|
||||
data.channel_list_changed.type =
|
||||
REGDOM_TYPE_INTERSECTION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tb[NL80211_ATTR_REG_ALPHA2]) {
|
||||
os_strlcpy(data.channel_list_changed.alpha2,
|
||||
nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]),
|
||||
sizeof(data.channel_list_changed.alpha2));
|
||||
wpa_printf(MSG_DEBUG, " * alpha2=%s",
|
||||
data.channel_list_changed.alpha2);
|
||||
}
|
||||
|
||||
wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data);
|
||||
}
|
||||
|
||||
|
||||
static void do_process_drv_event(struct i802_bss *bss, int cmd,
|
||||
struct nlattr **tb)
|
||||
{
|
||||
|
@ -3008,34 +3071,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
|
|||
nl80211_cqm_event(drv, tb);
|
||||
break;
|
||||
case NL80211_CMD_REG_CHANGE:
|
||||
wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
|
||||
if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
|
||||
break;
|
||||
os_memset(&data, 0, sizeof(data));
|
||||
switch (nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])) {
|
||||
case NL80211_REGDOM_SET_BY_CORE:
|
||||
data.channel_list_changed.initiator =
|
||||
REGDOM_SET_BY_CORE;
|
||||
break;
|
||||
case NL80211_REGDOM_SET_BY_USER:
|
||||
data.channel_list_changed.initiator =
|
||||
REGDOM_SET_BY_USER;
|
||||
break;
|
||||
case NL80211_REGDOM_SET_BY_DRIVER:
|
||||
data.channel_list_changed.initiator =
|
||||
REGDOM_SET_BY_DRIVER;
|
||||
break;
|
||||
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
|
||||
data.channel_list_changed.initiator =
|
||||
REGDOM_SET_BY_COUNTRY_IE;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "nl80211: Unknown reg change initiator %d received",
|
||||
nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]));
|
||||
break;
|
||||
}
|
||||
wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
|
||||
&data);
|
||||
nl80211_reg_change_event(drv, tb);
|
||||
break;
|
||||
case NL80211_CMD_REG_BEACON_HINT:
|
||||
wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
|
||||
|
|
|
@ -2720,10 +2720,52 @@ static void wpas_event_deauth(struct wpa_supplicant *wpa_s,
|
|||
}
|
||||
|
||||
|
||||
static void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s)
|
||||
static const char * reg_init_str(enum reg_change_initiator init)
|
||||
{
|
||||
switch (init) {
|
||||
case REGDOM_SET_BY_CORE:
|
||||
return "CORE";
|
||||
case REGDOM_SET_BY_USER:
|
||||
return "USER";
|
||||
case REGDOM_SET_BY_DRIVER:
|
||||
return "DRIVER";
|
||||
case REGDOM_SET_BY_COUNTRY_IE:
|
||||
return "COUNTRY_IE";
|
||||
case REGDOM_BEACON_HINT:
|
||||
return "BEACON_HINT";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
|
||||
static const char * reg_type_str(enum reg_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case REGDOM_TYPE_UNKNOWN:
|
||||
return "UNKNOWN";
|
||||
case REGDOM_TYPE_COUNTRY:
|
||||
return "COUNTRY";
|
||||
case REGDOM_TYPE_WORLD:
|
||||
return "WORLD";
|
||||
case REGDOM_TYPE_CUSTOM_WORLD:
|
||||
return "CUSTOM_WORLD";
|
||||
case REGDOM_TYPE_INTERSECTION:
|
||||
return "INTERSECTION";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
|
||||
static void wpa_supplicant_update_channel_list(
|
||||
struct wpa_supplicant *wpa_s, struct channel_list_changed *info)
|
||||
{
|
||||
struct wpa_supplicant *ifs;
|
||||
|
||||
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s",
|
||||
reg_init_str(info->type), reg_type_str(info->type),
|
||||
info->alpha2[0] ? " alpha2=" : "",
|
||||
info->alpha2[0] ? info->alpha2 : "");
|
||||
|
||||
if (wpa_s->drv_priv == NULL)
|
||||
return; /* Ignore event during drv initialization */
|
||||
|
||||
|
@ -3326,7 +3368,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
|||
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
|
||||
break;
|
||||
case EVENT_CHANNEL_LIST_CHANGED:
|
||||
wpa_supplicant_update_channel_list(wpa_s);
|
||||
wpa_supplicant_update_channel_list(
|
||||
wpa_s, &data->channel_list_changed);
|
||||
break;
|
||||
case EVENT_INTERFACE_UNAVAILABLE:
|
||||
#ifdef CONFIG_P2P
|
||||
|
|
Loading…
Reference in a new issue