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 "
|
#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
|
||||||
/** Change in the signal level was reported by the driver */
|
/** Change in the signal level was reported by the driver */
|
||||||
#define WPA_EVENT_SIGNAL_CHANGE "CTRL-EVENT-SIGNAL-CHANGE "
|
#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 */
|
/** RSN IBSS 4-way handshakes completed with specified peer */
|
||||||
#define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED "
|
#define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED "
|
||||||
|
|
|
@ -50,6 +50,14 @@ enum reg_change_initiator {
|
||||||
REGDOM_BEACON_HINT,
|
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
|
* struct hostapd_channel_data - Channel information
|
||||||
*/
|
*/
|
||||||
|
@ -3851,9 +3859,13 @@ union wpa_event_data {
|
||||||
/**
|
/**
|
||||||
* channel_list_changed - Data for EVENT_CHANNEL_LIST_CHANGED
|
* channel_list_changed - Data for EVENT_CHANNEL_LIST_CHANGED
|
||||||
* @initiator: Initiator of the regulatory change
|
* @initiator: Initiator of the regulatory change
|
||||||
|
* @type: Regulatory change type
|
||||||
|
* @alpha2: Country code (or "" if not available)
|
||||||
*/
|
*/
|
||||||
struct channel_list_changed {
|
struct channel_list_changed {
|
||||||
enum reg_change_initiator initiator;
|
enum reg_change_initiator initiator;
|
||||||
|
enum reg_type type;
|
||||||
|
char alpha2[3];
|
||||||
} channel_list_changed;
|
} 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,
|
static void do_process_drv_event(struct i802_bss *bss, int cmd,
|
||||||
struct nlattr **tb)
|
struct nlattr **tb)
|
||||||
{
|
{
|
||||||
|
@ -3008,34 +3071,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
|
||||||
nl80211_cqm_event(drv, tb);
|
nl80211_cqm_event(drv, tb);
|
||||||
break;
|
break;
|
||||||
case NL80211_CMD_REG_CHANGE:
|
case NL80211_CMD_REG_CHANGE:
|
||||||
wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
|
nl80211_reg_change_event(drv, tb);
|
||||||
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);
|
|
||||||
break;
|
break;
|
||||||
case NL80211_CMD_REG_BEACON_HINT:
|
case NL80211_CMD_REG_BEACON_HINT:
|
||||||
wpa_printf(MSG_DEBUG, "nl80211: Regulatory 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;
|
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)
|
if (wpa_s->drv_priv == NULL)
|
||||||
return; /* Ignore event during drv initialization */
|
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);
|
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
|
||||||
break;
|
break;
|
||||||
case EVENT_CHANNEL_LIST_CHANGED:
|
case EVENT_CHANNEL_LIST_CHANGED:
|
||||||
wpa_supplicant_update_channel_list(wpa_s);
|
wpa_supplicant_update_channel_list(
|
||||||
|
wpa_s, &data->channel_list_changed);
|
||||||
break;
|
break;
|
||||||
case EVENT_INTERFACE_UNAVAILABLE:
|
case EVENT_INTERFACE_UNAVAILABLE:
|
||||||
#ifdef CONFIG_P2P
|
#ifdef CONFIG_P2P
|
||||||
|
|
Loading…
Reference in a new issue