nl80211: Handle CH_SWITCH event
Some drivers may independently decide to switch channels. Handle this by updating the hostapd and wpa_supplicant AP and GO configuration. Signed-hostap: Thomas Pedersen <c_tpeder@qca.qualcomm.com>
This commit is contained in:
parent
e7381b8473
commit
1b487b8b1e
8 changed files with 122 additions and 1 deletions
|
@ -26,6 +26,7 @@
|
||||||
#include "wps_hostapd.h"
|
#include "wps_hostapd.h"
|
||||||
#include "ap_drv_ops.h"
|
#include "ap_drv_ops.h"
|
||||||
#include "ap_config.h"
|
#include "ap_config.h"
|
||||||
|
#include "hw_features.h"
|
||||||
|
|
||||||
|
|
||||||
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||||
|
@ -273,6 +274,31 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||||
|
int offset)
|
||||||
|
{
|
||||||
|
int channel;
|
||||||
|
|
||||||
|
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_INFO, "driver had channel switch: "
|
||||||
|
"freq=%d, ht=%d, offset=%d", freq, ht, offset);
|
||||||
|
|
||||||
|
hapd->iface->freq = freq;
|
||||||
|
|
||||||
|
channel = hostapd_hw_get_channel(hapd, freq);
|
||||||
|
if (!channel) {
|
||||||
|
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_WARNING, "driver switched to "
|
||||||
|
"bad channel!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hapd->iconf->channel = channel;
|
||||||
|
hapd->iconf->ieee80211n = ht;
|
||||||
|
hapd->iconf->secondary_channel = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
|
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
|
||||||
const u8 *bssid, const u8 *ie, size_t ie_len,
|
const u8 *bssid, const u8 *ie, size_t ie_len,
|
||||||
int ssi_signal)
|
int ssi_signal)
|
||||||
|
@ -590,6 +616,13 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
hostapd_rx_action(hapd, &data->rx_action);
|
hostapd_rx_action(hapd, &data->rx_action);
|
||||||
break;
|
break;
|
||||||
#endif /* NEED_AP_MLME */
|
#endif /* NEED_AP_MLME */
|
||||||
|
case EVENT_CH_SWITCH:
|
||||||
|
if (!data)
|
||||||
|
break;
|
||||||
|
hostapd_event_ch_switch(hapd, data->ch_switch.freq,
|
||||||
|
data->ch_switch.ht_enabled,
|
||||||
|
data->ch_switch.ch_offset);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
|
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -283,5 +283,7 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
|
||||||
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
|
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
|
||||||
const u8 *bssid, const u8 *ie, size_t ie_len,
|
const u8 *bssid, const u8 *ie, size_t ie_len,
|
||||||
int ssi_signal);
|
int ssi_signal);
|
||||||
|
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||||
|
int offset);
|
||||||
|
|
||||||
#endif /* HOSTAPD_H */
|
#endif /* HOSTAPD_H */
|
||||||
|
|
|
@ -2978,7 +2978,14 @@ enum wpa_event_type {
|
||||||
/**
|
/**
|
||||||
* EVENT_EAPOL_TX_STATUS - notify of EAPOL TX status
|
* EVENT_EAPOL_TX_STATUS - notify of EAPOL TX status
|
||||||
*/
|
*/
|
||||||
EVENT_EAPOL_TX_STATUS
|
EVENT_EAPOL_TX_STATUS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EVENT_CH_SWITCH - AP or GO decided to switch channels
|
||||||
|
*
|
||||||
|
* Described in wpa_event_data.ch_switch
|
||||||
|
* */
|
||||||
|
EVENT_CH_SWITCH
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -3573,6 +3580,18 @@ union wpa_event_data {
|
||||||
int data_len;
|
int data_len;
|
||||||
int ack;
|
int ack;
|
||||||
} eapol_tx_status;
|
} eapol_tx_status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct ch_switch
|
||||||
|
* @freq: Frequency of new channel in MHz
|
||||||
|
* @ht_enabled: Whether this is an HT channel
|
||||||
|
* @ch_offset: Secondary channel offset
|
||||||
|
*/
|
||||||
|
struct ch_switch {
|
||||||
|
int freq;
|
||||||
|
int ht_enabled;
|
||||||
|
int ch_offset;
|
||||||
|
} ch_switch;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -77,6 +77,7 @@ const char * event_to_string(enum wpa_event_type event)
|
||||||
E2S(SCHED_SCAN_STOPPED);
|
E2S(SCHED_SCAN_STOPPED);
|
||||||
E2S(DRIVER_CLIENT_POLL_OK);
|
E2S(DRIVER_CLIENT_POLL_OK);
|
||||||
E2S(EAPOL_TX_STATUS);
|
E2S(EAPOL_TX_STATUS);
|
||||||
|
E2S(CH_SWITCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
|
|
|
@ -1196,6 +1196,40 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
|
||||||
|
struct nlattr *freq, struct nlattr *type)
|
||||||
|
{
|
||||||
|
union wpa_event_data data;
|
||||||
|
int ht_enabled = 1;
|
||||||
|
int chan_offset = 0;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
|
||||||
|
|
||||||
|
if (!freq || !type)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (nla_get_u32(type)) {
|
||||||
|
case NL80211_CHAN_NO_HT:
|
||||||
|
ht_enabled = 0;
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_HT20:
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_HT40PLUS:
|
||||||
|
chan_offset = 1;
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_HT40MINUS:
|
||||||
|
chan_offset = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.ch_switch.freq = nla_get_u32(freq);
|
||||||
|
data.ch_switch.ht_enabled = ht_enabled;
|
||||||
|
data.ch_switch.ch_offset = chan_offset;
|
||||||
|
|
||||||
|
wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
|
static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
|
||||||
enum nl80211_commands cmd, struct nlattr *addr)
|
enum nl80211_commands cmd, struct nlattr *addr)
|
||||||
{
|
{
|
||||||
|
@ -2116,6 +2150,10 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
|
||||||
tb[NL80211_ATTR_REQ_IE],
|
tb[NL80211_ATTR_REQ_IE],
|
||||||
tb[NL80211_ATTR_RESP_IE]);
|
tb[NL80211_ATTR_RESP_IE]);
|
||||||
break;
|
break;
|
||||||
|
case NL80211_CMD_CH_SWITCH_NOTIFY:
|
||||||
|
mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
|
||||||
|
tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
|
||||||
|
break;
|
||||||
case NL80211_CMD_DISCONNECT:
|
case NL80211_CMD_DISCONNECT:
|
||||||
mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
|
mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
|
||||||
tb[NL80211_ATTR_MAC],
|
tb[NL80211_ATTR_MAC],
|
||||||
|
|
|
@ -957,6 +957,17 @@ int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
|
||||||
|
int offset)
|
||||||
|
{
|
||||||
|
if (!wpa_s->ap_iface)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wpa_s->assoc_freq = freq;
|
||||||
|
hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
|
int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
|
||||||
const u8 *addr)
|
const u8 *addr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -49,5 +49,7 @@ int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s);
|
||||||
int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
|
int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
|
||||||
const u8 *addr);
|
const u8 *addr);
|
||||||
void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
|
void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
|
||||||
|
void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
|
||||||
|
int offset);
|
||||||
|
|
||||||
#endif /* AP_H */
|
#endif /* AP_H */
|
||||||
|
|
|
@ -2407,6 +2407,21 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
|
ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
|
||||||
data->rx_from_unknown.wds);
|
data->rx_from_unknown.wds);
|
||||||
break;
|
break;
|
||||||
|
case EVENT_CH_SWITCH:
|
||||||
|
if (!data)
|
||||||
|
break;
|
||||||
|
if (!wpa_s->ap_iface) {
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG, "AP: Ignore channel switch "
|
||||||
|
"event in non-AP mode");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_AP
|
||||||
|
wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
|
||||||
|
data->ch_switch.ht_enabled,
|
||||||
|
data->ch_switch.ch_offset);
|
||||||
|
#endif /* CONFIG_AP */
|
||||||
|
break;
|
||||||
case EVENT_RX_MGMT: {
|
case EVENT_RX_MGMT: {
|
||||||
u16 fc, stype;
|
u16 fc, stype;
|
||||||
const struct ieee80211_mgmt *mgmt;
|
const struct ieee80211_mgmt *mgmt;
|
||||||
|
|
Loading…
Reference in a new issue