nl80211: Specify CSA offsets in send_mlme() driver op

Some management frames contain CSA counters which should be updated by
kernel. Change driver op send_mlme() allowing to send a frame,
specifying an array of offsets to the CSA counters which should be
updated. For example, CSA offsets parameters should be specified when
sending Probe Response frames during CSA period.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
This commit is contained in:
Andrei Otcheretianski 2015-09-08 12:46:26 +03:00 committed by Jouni Malinen
parent c0d94d6118
commit 2d3943ce5b
7 changed files with 59 additions and 26 deletions

View file

@ -649,7 +649,19 @@ int hostapd_drv_send_mlme(struct hostapd_data *hapd,
{ {
if (hapd->driver == NULL || hapd->driver->send_mlme == NULL) if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
return 0; return 0;
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0); return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
NULL, 0);
}
int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
const void *msg, size_t len, int noack,
const u16 *csa_offs, size_t csa_offs_len)
{
if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
return 0;
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
csa_offs, csa_offs_len);
} }

View file

@ -88,6 +88,9 @@ int hostapd_drv_set_key(const char *ifname,
const u8 *key, size_t key_len); const u8 *key, size_t key_len);
int hostapd_drv_send_mlme(struct hostapd_data *hapd, int hostapd_drv_send_mlme(struct hostapd_data *hapd,
const void *msg, size_t len, int noack); const void *msg, size_t len, int noack);
int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
const void *msg, size_t len, int noack,
const u16 *csa_offs, size_t csa_offs_len);
int hostapd_drv_sta_deauth(struct hostapd_data *hapd, int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason); const u8 *addr, int reason);
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd, int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,

View file

@ -1965,10 +1965,13 @@ struct wpa_driver_ops {
* @noack: Do not wait for this frame to be acked (disable retries) * @noack: Do not wait for this frame to be acked (disable retries)
* @freq: Frequency (in MHz) to send the frame on, or 0 to let the * @freq: Frequency (in MHz) to send the frame on, or 0 to let the
* driver decide * driver decide
* @csa_offs: Array of CSA offsets or %NULL
* @csa_offs_len: Number of elements in csa_offs
* Returns: 0 on success, -1 on failure * Returns: 0 on success, -1 on failure
*/ */
int (*send_mlme)(void *priv, const u8 *data, size_t data_len, int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
int noack, unsigned int freq); int noack, unsigned int freq, const u16 *csa_offs,
size_t csa_offs_len);
/** /**
* update_ft_ies - Update FT (IEEE 802.11r) IEs * update_ft_ies - Update FT (IEEE 802.11r) IEs

View file

@ -1848,7 +1848,8 @@ static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) #if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len, static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
int noack, unsigned int freq) int noack, unsigned int freq,
const u16 *csa_offs, size_t csa_offs_len)
{ {
struct atheros_driver_data *drv = priv; struct atheros_driver_data *drv = priv;
u8 buf[1510]; u8 buf[1510];

View file

@ -258,7 +258,8 @@ static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr)
static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack, static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack,
unsigned int freq) unsigned int freq,
const u16 *csa_offs, size_t csa_offs_len)
{ {
struct hostap_driver_data *drv = priv; struct hostap_driver_data *drv = priv;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
@ -307,7 +308,7 @@ static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data,
pos += 2; pos += 2;
memcpy(pos, data, data_len); memcpy(pos, data, data_len);
res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0); res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0);
if (res < 0) { if (res < 0) {
wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - " wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
"failed: %d (%s)", "failed: %d (%s)",
@ -1045,7 +1046,7 @@ static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
memcpy(mgmt.bssid, own_addr, ETH_ALEN); memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code = host_to_le16(reason); mgmt.u.deauth.reason_code = host_to_le16(reason);
return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
sizeof(mgmt.u.deauth), 0, 0); sizeof(mgmt.u.deauth), 0, 0, NULL, 0);
} }
@ -1083,7 +1084,7 @@ static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
memcpy(mgmt.bssid, own_addr, ETH_ALEN); memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.disassoc.reason_code = host_to_le16(reason); mgmt.u.disassoc.reason_code = host_to_le16(reason);
return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
sizeof(mgmt.u.disassoc), 0, 0); sizeof(mgmt.u.disassoc), 0, 0, NULL, 0);
} }
@ -1161,7 +1162,7 @@ static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr,
os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0); hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0);
} }

View file

@ -176,7 +176,8 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
static int nl80211_send_frame_cmd(struct i802_bss *bss, static int nl80211_send_frame_cmd(struct i802_bss *bss,
unsigned int freq, unsigned int wait, unsigned int freq, unsigned int wait,
const u8 *buf, size_t buf_len, u64 *cookie, const u8 *buf, size_t buf_len, u64 *cookie,
int no_cck, int no_ack, int offchanok); int no_cck, int no_ack, int offchanok,
const u16 *csa_offs, size_t csa_offs_len);
static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
int report); int report);
@ -3093,7 +3094,9 @@ static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
const void *data, size_t len, const void *data, size_t len,
int encrypt, int noack, int encrypt, int noack,
unsigned int freq, int no_cck, unsigned int freq, int no_cck,
int offchanok, unsigned int wait_time) int offchanok, unsigned int wait_time,
const u16 *csa_offs,
size_t csa_offs_len)
{ {
struct wpa_driver_nl80211_data *drv = bss->drv; struct wpa_driver_nl80211_data *drv = bss->drv;
u64 cookie; u64 cookie;
@ -3119,7 +3122,8 @@ static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd"); wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd");
res = nl80211_send_frame_cmd(bss, freq, wait_time, data, len, res = nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
&cookie, no_cck, noack, offchanok); &cookie, no_cck, noack, offchanok,
csa_offs, csa_offs_len);
if (res == 0 && !noack) { if (res == 0 && !noack) {
const struct ieee80211_mgmt *mgmt; const struct ieee80211_mgmt *mgmt;
u16 fc; u16 fc;
@ -3145,7 +3149,9 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
size_t data_len, int noack, size_t data_len, int noack,
unsigned int freq, int no_cck, unsigned int freq, int no_cck,
int offchanok, int offchanok,
unsigned int wait_time) unsigned int wait_time,
const u16 *csa_offs,
size_t csa_offs_len)
{ {
struct wpa_driver_nl80211_data *drv = bss->drv; struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt *mgmt; struct ieee80211_mgmt *mgmt;
@ -3175,7 +3181,7 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
} }
return nl80211_send_frame_cmd(bss, freq, 0, return nl80211_send_frame_cmd(bss, freq, 0,
data, data_len, NULL, 1, noack, data, data_len, NULL, 1, noack,
1); 1, csa_offs, csa_offs_len);
} }
if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) { if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
@ -3189,7 +3195,8 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
wait_time, wait_time,
data, data_len, data, data_len,
&drv->send_action_cookie, &drv->send_action_cookie,
no_cck, noack, offchanok); no_cck, noack, offchanok,
csa_offs, csa_offs_len);
} }
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
@ -3209,7 +3216,8 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame"); wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame");
return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
noack, freq, no_cck, offchanok, noack, freq, no_cck, offchanok,
wait_time); wait_time, csa_offs,
csa_offs_len);
} }
@ -4248,7 +4256,7 @@ static int wpa_driver_nl80211_hapd_send_eapol(
memcpy(pos, data, data_len); memcpy(pos, data, data_len);
res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0, res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0,
0, 0, 0, 0); 0, 0, 0, 0, NULL, 0);
if (res < 0) { if (res < 0) {
wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - " wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
"failed: %d (%s)", "failed: %d (%s)",
@ -5439,7 +5447,7 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
IEEE80211_HDRLEN + IEEE80211_HDRLEN +
sizeof(mgmt.u.deauth), 0, 0, 0, 0, sizeof(mgmt.u.deauth), 0, 0, 0, 0,
0); 0, NULL, 0);
} }
@ -5466,7 +5474,7 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
IEEE80211_HDRLEN + IEEE80211_HDRLEN +
sizeof(mgmt.u.disassoc), 0, 0, 0, 0, sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
0); 0, NULL, 0);
} }
@ -6125,7 +6133,8 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
unsigned int freq, unsigned int wait, unsigned int freq, unsigned int wait,
const u8 *buf, size_t buf_len, const u8 *buf, size_t buf_len,
u64 *cookie_out, int no_cck, int no_ack, u64 *cookie_out, int no_cck, int no_ack,
int offchanok) int offchanok, const u16 *csa_offs,
size_t csa_offs_len)
{ {
struct wpa_driver_nl80211_data *drv = bss->drv; struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg; struct nl_msg *msg;
@ -6145,6 +6154,8 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) || nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) ||
(no_cck && nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE)) || (no_cck && nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE)) ||
(no_ack && nla_put_flag(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK)) || (no_ack && nla_put_flag(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK)) ||
(csa_offs && nla_put(msg, NL80211_ATTR_CSA_C_OFFSETS_TX,
csa_offs_len * sizeof(u16), csa_offs)) ||
nla_put(msg, NL80211_ATTR_FRAME, buf_len, buf)) nla_put(msg, NL80211_ATTR_FRAME, buf_len, buf))
goto fail; goto fail;
@ -6204,12 +6215,12 @@ static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
!drv->use_monitor)) !drv->use_monitor))
ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len, ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
0, freq, no_cck, 1, 0, freq, no_cck, 1,
wait_time); wait_time, NULL, 0);
else else
ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf, ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
24 + data_len, 24 + data_len,
&drv->send_action_cookie, &drv->send_action_cookie,
no_cck, 0, 1); no_cck, 0, 1, NULL, 0);
os_free(buf); os_free(buf);
return ret; return ret;
@ -6551,7 +6562,7 @@ static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
{ {
struct i802_bss *bss = priv; struct i802_bss *bss = priv;
return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0, return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0,
0, 0, 0, 0); 0, 0, 0, 0, NULL, 0);
} }
@ -6960,7 +6971,7 @@ static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0, if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
0, 0) < 0) 0, 0, NULL, 0) < 0)
wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to " wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
"send poll frame"); "send poll frame");
} }
@ -7280,11 +7291,13 @@ static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
static int driver_nl80211_send_mlme(void *priv, const u8 *data, static int driver_nl80211_send_mlme(void *priv, const u8 *data,
size_t data_len, int noack, size_t data_len, int noack,
unsigned int freq) unsigned int freq,
const u16 *csa_offs, size_t csa_offs_len)
{ {
struct i802_bss *bss = priv; struct i802_bss *bss = priv;
return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack, return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
freq, 0, 0, 0); freq, 0, 0, 0, csa_offs,
csa_offs_len);
} }

View file

@ -292,7 +292,7 @@ static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
if (wpa_s->driver->send_mlme) if (wpa_s->driver->send_mlme)
return wpa_s->driver->send_mlme(wpa_s->drv_priv, return wpa_s->driver->send_mlme(wpa_s->drv_priv,
data, data_len, noack, data, data_len, noack,
freq); freq, NULL, 0);
return -1; return -1;
} }