Commit e78a287a authored by Arik Nemtsov's avatar Arik Nemtsov Committed by Luciano Coelho

wl12xx: Configure AP on BSS info change

Configure AP-specific beacon and probe response templates.
Start the AP when beaconing is enabled.

The wl1271_bss_info_changed() function has been split into AP/STA
specific handlers.
Signed-off-by: default avatarArik Nemtsov <arik@wizery.com>
Reviewed-by: default avatarLuciano Coelho <coelho@ti.com>
Signed-off-by: default avatarLuciano Coelho <coelho@ti.com>
parent beb6c880
...@@ -1843,7 +1843,7 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) ...@@ -1843,7 +1843,7 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return ret; return ret;
} }
static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb, static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
int offset) int offset)
{ {
u8 *ptr = skb->data + offset; u8 *ptr = skb->data + offset;
...@@ -1853,89 +1853,206 @@ static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb, ...@@ -1853,89 +1853,206 @@ static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
if (ptr[0] == WLAN_EID_SSID) { if (ptr[0] == WLAN_EID_SSID) {
wl->ssid_len = ptr[1]; wl->ssid_len = ptr[1];
memcpy(wl->ssid, ptr+2, wl->ssid_len); memcpy(wl->ssid, ptr+2, wl->ssid_len);
return; return 0;
} }
ptr += (ptr[1] + 2); ptr += (ptr[1] + 2);
} }
wl1271_error("No SSID in IEs!\n"); wl1271_error("No SSID in IEs!\n");
return -ENOENT;
} }
static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf, struct ieee80211_bss_conf *bss_conf,
u32 changed) u32 changed)
{ {
enum wl1271_cmd_ps_mode mode; int ret = 0;
struct wl1271 *wl = hw->priv;
struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
bool do_join = false;
bool set_assoc = false;
int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed"); if (changed & BSS_CHANGED_ERP_SLOT) {
if (bss_conf->use_short_slot)
ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
else
ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
if (ret < 0) {
wl1271_warning("Set slot time failed %d", ret);
goto out;
}
}
mutex_lock(&wl->mutex); if (changed & BSS_CHANGED_ERP_PREAMBLE) {
if (bss_conf->use_short_preamble)
wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
else
wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
}
if (unlikely(wl->state == WL1271_STATE_OFF)) if (changed & BSS_CHANGED_ERP_CTS_PROT) {
if (bss_conf->use_cts_prot)
ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
else
ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
if (ret < 0) {
wl1271_warning("Set ctsprotect failed %d", ret);
goto out; goto out;
}
}
ret = wl1271_ps_elp_wakeup(wl, false); out:
if (ret < 0) return ret;
goto out; }
static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changed)
{
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
int ret = 0;
if ((changed & BSS_CHANGED_BEACON_INT) && if ((changed & BSS_CHANGED_BEACON_INT)) {
(wl->bss_type == BSS_TYPE_IBSS)) { wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
bss_conf->beacon_int); bss_conf->beacon_int);
wl->beacon_int = bss_conf->beacon_int; wl->beacon_int = bss_conf->beacon_int;
do_join = true;
} }
if ((changed & BSS_CHANGED_BEACON) && if ((changed & BSS_CHANGED_BEACON)) {
(wl->bss_type == BSS_TYPE_IBSS)) {
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
if (beacon) {
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
int ieoffset = offsetof(struct ieee80211_mgmt, int ieoffset = offsetof(struct ieee80211_mgmt,
u.beacon.variable); u.beacon.variable);
struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
u16 tmpl_id;
if (!beacon)
goto out;
wl1271_ssid_set(wl, beacon, ieoffset); wl1271_debug(DEBUG_MASTER, "beacon updated");
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, ret = wl1271_ssid_set(wl, beacon, ieoffset);
if (ret < 0) {
dev_kfree_skb(beacon);
goto out;
}
tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
CMD_TEMPL_BEACON;
ret = wl1271_cmd_template_set(wl, tmpl_id,
beacon->data, beacon->data,
beacon->len, 0, beacon->len, 0,
wl1271_tx_min_rate_get(wl)); wl1271_tx_min_rate_get(wl));
if (ret < 0) { if (ret < 0) {
dev_kfree_skb(beacon); dev_kfree_skb(beacon);
goto out_sleep; goto out;
} }
hdr = (struct ieee80211_hdr *) beacon->data; hdr = (struct ieee80211_hdr *) beacon->data;
hdr->frame_control = cpu_to_le16( hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_PROBE_RESP); IEEE80211_STYPE_PROBE_RESP);
tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
CMD_TEMPL_PROBE_RESPONSE;
ret = wl1271_cmd_template_set(wl, ret = wl1271_cmd_template_set(wl,
CMD_TEMPL_PROBE_RESPONSE, tmpl_id,
beacon->data, beacon->data,
beacon->len, 0, beacon->len, 0,
wl1271_tx_min_rate_get(wl)); wl1271_tx_min_rate_get(wl));
dev_kfree_skb(beacon); dev_kfree_skb(beacon);
if (ret < 0) if (ret < 0)
goto out_sleep; goto out;
}
/* Need to update the SSID (for filtering etc) */ out:
do_join = true; return ret;
}
/* AP mode changes */
static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changed)
{
int ret = 0;
if ((changed & BSS_CHANGED_BASIC_RATES)) {
u32 rates = bss_conf->basic_rates;
struct conf_tx_rate_class mgmt_rc;
wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
wl->basic_rate = wl1271_tx_min_rate_get(wl);
wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
wl->basic_rate_set);
/* update the AP management rate policy with the new rates */
mgmt_rc.enabled_rates = wl->basic_rate_set;
mgmt_rc.long_retry_limit = 10;
mgmt_rc.short_retry_limit = 10;
mgmt_rc.aflags = 0;
ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
ACX_TX_AP_MODE_MGMT_RATE);
if (ret < 0) {
wl1271_error("AP mgmt policy change failed %d", ret);
goto out;
}
}
ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
if (ret < 0)
goto out;
if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
if (bss_conf->enable_beacon) {
if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
ret = wl1271_cmd_start_bss(wl);
if (ret < 0)
goto out;
set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
wl1271_debug(DEBUG_AP, "started AP");
} }
} else {
if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
ret = wl1271_cmd_stop_bss(wl);
if (ret < 0)
goto out;
clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
wl1271_debug(DEBUG_AP, "stopped AP");
}
}
}
ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
if (ret < 0)
goto out;
out:
return;
}
/* STA/IBSS mode changes */
static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changed)
{
bool do_join = false, set_assoc = false;
bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
int ret;
struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
if (is_ibss) {
ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
changed);
if (ret < 0)
goto out;
} }
if ((changed & BSS_CHANGED_BEACON_ENABLED) && if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
(wl->bss_type == BSS_TYPE_IBSS)) { do_join = true;
/* Need to update the SSID (for filtering etc) */
if ((changed & BSS_CHANGED_BEACON) && is_ibss)
do_join = true;
if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s", wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
bss_conf->enable_beacon ? "enabled" : "disabled"); bss_conf->enable_beacon ? "enabled" : "disabled");
...@@ -1946,7 +2063,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -1946,7 +2063,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
do_join = true; do_join = true;
} }
if (changed & BSS_CHANGED_CQM) { if ((changed & BSS_CHANGED_CQM)) {
bool enable = false; bool enable = false;
if (bss_conf->cqm_rssi_thold) if (bss_conf->cqm_rssi_thold)
enable = true; enable = true;
...@@ -1968,11 +2085,11 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -1968,11 +2085,11 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
ret = wl1271_cmd_build_null_data(wl); ret = wl1271_cmd_build_null_data(wl);
if (ret < 0) if (ret < 0)
goto out_sleep; goto out;
ret = wl1271_build_qos_null_data(wl); ret = wl1271_build_qos_null_data(wl);
if (ret < 0) if (ret < 0)
goto out_sleep; goto out;
/* filter out all packets not from this BSSID */ /* filter out all packets not from this BSSID */
wl1271_configure_filters(wl, 0); wl1271_configure_filters(wl, 0);
...@@ -1981,7 +2098,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -1981,7 +2098,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
do_join = true; do_join = true;
} }
if (changed & BSS_CHANGED_ASSOC) { if ((changed & BSS_CHANGED_ASSOC)) {
if (bss_conf->assoc) { if (bss_conf->assoc) {
u32 rates; u32 rates;
int ieoffset; int ieoffset;
...@@ -2000,7 +2117,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -2000,7 +2117,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
wl->basic_rate = wl1271_tx_min_rate_get(wl); wl->basic_rate = wl1271_tx_min_rate_get(wl);
ret = wl1271_acx_sta_rate_policies(wl); ret = wl1271_acx_sta_rate_policies(wl);
if (ret < 0) if (ret < 0)
goto out_sleep; goto out;
/* /*
* with wl1271, we don't need to update the * with wl1271, we don't need to update the
...@@ -2010,7 +2127,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -2010,7 +2127,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
*/ */
ret = wl1271_cmd_build_ps_poll(wl, wl->aid); ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
if (ret < 0) if (ret < 0)
goto out_sleep; goto out;
/* /*
* Get a template for hardware connection maintenance * Get a template for hardware connection maintenance
...@@ -2024,17 +2141,19 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -2024,17 +2141,19 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
/* enable the connection monitoring feature */ /* enable the connection monitoring feature */
ret = wl1271_acx_conn_monit_params(wl, true); ret = wl1271_acx_conn_monit_params(wl, true);
if (ret < 0) if (ret < 0)
goto out_sleep; goto out;
/* If we want to go in PSM but we're not there yet */ /* If we want to go in PSM but we're not there yet */
if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
!test_bit(WL1271_FLAG_PSM, &wl->flags)) { !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
enum wl1271_cmd_ps_mode mode;
mode = STATION_POWER_SAVE_MODE; mode = STATION_POWER_SAVE_MODE;
ret = wl1271_ps_set_mode(wl, mode, ret = wl1271_ps_set_mode(wl, mode,
wl->basic_rate, wl->basic_rate,
true); true);
if (ret < 0) if (ret < 0)
goto out_sleep; goto out;
} }
} else { } else {
/* use defaults when not associated */ /* use defaults when not associated */
...@@ -2054,7 +2173,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -2054,7 +2173,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
wl->basic_rate = wl1271_tx_min_rate_get(wl); wl->basic_rate = wl1271_tx_min_rate_get(wl);
ret = wl1271_acx_sta_rate_policies(wl); ret = wl1271_acx_sta_rate_policies(wl);
if (ret < 0) if (ret < 0)
goto out_sleep; goto out;
/* disable connection monitor features */ /* disable connection monitor features */
ret = wl1271_acx_conn_monit_params(wl, false); ret = wl1271_acx_conn_monit_params(wl, false);
...@@ -2062,43 +2181,17 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -2062,43 +2181,17 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
/* Disable the keep-alive feature */ /* Disable the keep-alive feature */
ret = wl1271_acx_keep_alive_mode(wl, false); ret = wl1271_acx_keep_alive_mode(wl, false);
if (ret < 0) if (ret < 0)
goto out_sleep; goto out;
/* restore the bssid filter and go to dummy bssid */ /* restore the bssid filter and go to dummy bssid */
wl1271_unjoin(wl); wl1271_unjoin(wl);
wl1271_dummy_join(wl); wl1271_dummy_join(wl);
} }
}
if (changed & BSS_CHANGED_ERP_SLOT) {
if (bss_conf->use_short_slot)
ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
else
ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
if (ret < 0) {
wl1271_warning("Set slot time failed %d", ret);
goto out_sleep;
}
}
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
if (bss_conf->use_short_preamble)
wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
else
wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
} }
if (changed & BSS_CHANGED_ERP_CTS_PROT) { ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
if (bss_conf->use_cts_prot) if (ret < 0)
ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE); goto out;
else
ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
if (ret < 0) {
wl1271_warning("Set ctsprotect failed %d", ret);
goto out_sleep;
}
}
/* /*
* Takes care of: New association with HT enable, * Takes care of: New association with HT enable,
...@@ -2110,13 +2203,13 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -2110,13 +2203,13 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true); ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
if (ret < 0) { if (ret < 0) {
wl1271_warning("Set ht cap true failed %d", ret); wl1271_warning("Set ht cap true failed %d", ret);
goto out_sleep; goto out;
} }
ret = wl1271_acx_set_ht_information(wl, ret = wl1271_acx_set_ht_information(wl,
bss_conf->ht_operation_mode); bss_conf->ht_operation_mode);
if (ret < 0) { if (ret < 0) {
wl1271_warning("Set ht information failed %d", ret); wl1271_warning("Set ht information failed %d", ret);
goto out_sleep; goto out;
} }
} }
/* /*
...@@ -2127,7 +2220,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -2127,7 +2220,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false); ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
if (ret < 0) { if (ret < 0) {
wl1271_warning("Set ht cap false failed %d", ret); wl1271_warning("Set ht cap false failed %d", ret);
goto out_sleep; goto out;
} }
} }
...@@ -2146,7 +2239,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -2146,7 +2239,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
ret = wl1271_cmd_build_arp_rsp(wl, addr); ret = wl1271_cmd_build_arp_rsp(wl, addr);
if (ret < 0) { if (ret < 0) {
wl1271_warning("build arp rsp failed: %d", ret); wl1271_warning("build arp rsp failed: %d", ret);
goto out_sleep; goto out;
} }
ret = wl1271_acx_arp_ip_filter(wl, ret = wl1271_acx_arp_ip_filter(wl,
...@@ -2157,18 +2250,47 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -2157,18 +2250,47 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
ret = wl1271_acx_arp_ip_filter(wl, 0, addr); ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
if (ret < 0) if (ret < 0)
goto out_sleep; goto out;
} }
if (do_join) { if (do_join) {
ret = wl1271_join(wl, set_assoc); ret = wl1271_join(wl, set_assoc);
if (ret < 0) { if (ret < 0) {
wl1271_warning("cmd join failed %d", ret); wl1271_warning("cmd join failed %d", ret);
goto out_sleep; goto out;
} }
} }
out_sleep: out:
return;
}
static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changed)
{
struct wl1271 *wl = hw->priv;
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
(int)changed);
mutex_lock(&wl->mutex);
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
goto out;
if (is_ap)
wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
else
wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
out: out:
......
...@@ -57,6 +57,8 @@ enum { ...@@ -57,6 +57,8 @@ enum {
DEBUG_SDIO = BIT(14), DEBUG_SDIO = BIT(14),
DEBUG_FILTERS = BIT(15), DEBUG_FILTERS = BIT(15),
DEBUG_ADHOC = BIT(16), DEBUG_ADHOC = BIT(16),
DEBUG_AP = BIT(17),
DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP),
DEBUG_ALL = ~0, DEBUG_ALL = ~0,
}; };
...@@ -284,6 +286,7 @@ struct wl1271 { ...@@ -284,6 +286,7 @@ struct wl1271 {
#define WL1271_FLAG_PSPOLL_FAILURE (12) #define WL1271_FLAG_PSPOLL_FAILURE (12)
#define WL1271_FLAG_STA_STATE_SENT (13) #define WL1271_FLAG_STA_STATE_SENT (13)
#define WL1271_FLAG_FW_TX_BUSY (14) #define WL1271_FLAG_FW_TX_BUSY (14)
#define WL1271_FLAG_AP_STARTED (15)
unsigned long flags; unsigned long flags;
struct wl1271_partition_set part; struct wl1271_partition_set part;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment