summaryrefslogtreecommitdiff
path: root/mwl_mac80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'mwl_mac80211.c')
-rw-r--r--mwl_mac80211.c304
1 files changed, 166 insertions, 138 deletions
diff --git a/mwl_mac80211.c b/mwl_mac80211.c
index 5f14bdc..17a9438 100644
--- a/mwl_mac80211.c
+++ b/mwl_mac80211.c
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2006-2014 Marvell International Ltd.
+* Copyright (c) 2006-2015 Marvell International Ltd.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -39,7 +39,7 @@
static void mwl_mac80211_tx(struct ieee80211_hw *hw,
struct ieee80211_tx_control *control,
- struct sk_buff *skb);
+ struct sk_buff *skb);
static int mwl_mac80211_start(struct ieee80211_hw *hw);
static void mwl_mac80211_stop(struct ieee80211_hw *hw);
static int mwl_mac80211_add_interface(struct ieee80211_hw *hw,
@@ -50,42 +50,49 @@ static int mwl_mac80211_config(struct ieee80211_hw *hw,
u32 changed);
static void mwl_mac80211_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info,
- u32 changed);
+ struct ieee80211_bss_conf *info,
+ u32 changed);
static void mwl_mac80211_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
- unsigned int *total_flags,
- u64 multicast);
+ unsigned int *total_flags,
+ u64 multicast);
static int mwl_mac80211_set_key(struct ieee80211_hw *hw,
enum set_key_cmd cmd_param,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key);
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key);
static int mwl_mac80211_set_rts_threshold(struct ieee80211_hw *hw,
u32 value);
static int mwl_mac80211_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
+ struct ieee80211_sta *sta);
static int mwl_mac80211_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
+ struct ieee80211_sta *sta);
static int mwl_mac80211_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- u16 queue,
- const struct ieee80211_tx_queue_params *params);
+ u16 queue,
+ const struct ieee80211_tx_queue_params *params);
static int mwl_mac80211_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats);
static int mwl_mac80211_get_survey(struct ieee80211_hw *hw,
int idx,
- struct survey_info *survey);
+ struct survey_info *survey);
static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- enum ieee80211_ampdu_mlme_action action,
- struct ieee80211_sta *sta,
- u16 tid, u16 *ssn, u8 buf_size);
-
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta,
+ u16 tid, u16 *ssn, u8 buf_size);
static void mwl_mac80211_remove_vif(struct mwl_priv *priv,
struct mwl_vif *vif);
+static void mwl_mac80211_bss_info_changed_sta(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed);
+static void mwl_mac80211_bss_info_changed_ap(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed);
/* PRIVATE VARIABLES
*/
@@ -174,7 +181,6 @@ static void mwl_mac80211_tx(struct ieee80211_hw *hw,
BUG_ON(!skb);
if (!priv->radio_on) {
-
WLDBG_EXIT_INFO(DBG_LEVEL_5,
"dropped TX frame since radio disabled");
dev_kfree_skb_any(skb);
@@ -232,17 +238,13 @@ static int mwl_mac80211_start(struct ieee80211_hw *hw)
rc = mwl_fwcmd_set_fw_flush_timer(hw, 0);
if (rc) {
-
mwl_fwcmd_int_disable(hw);
free_irq(priv->pdev->irq, hw);
priv->irq = -1;
tasklet_disable(&priv->tx_task);
tasklet_disable(&priv->rx_task);
-
} else {
-
ieee80211_wake_queues(hw);
-
}
WLDBG_EXIT(DBG_LEVEL_5);
@@ -297,12 +299,20 @@ static int mwl_mac80211_add_interface(struct ieee80211_hw *hw,
WLDBG_ENTER(DBG_LEVEL_5);
- macids_supported = priv->ap_macids_supported;
+ switch (vif->type) {
+ case NL80211_IFTYPE_AP:
+ macids_supported = priv->ap_macids_supported;
+ break;
+ case NL80211_IFTYPE_STATION:
+ macids_supported = priv->sta_macids_supported;
+ break;
+ default:
+ return -EINVAL;
+ }
macid = ffs(macids_supported & ~priv->macids_used);
if (!macid--) {
-
WLDBG_EXIT_INFO(DBG_LEVEL_5, "no macid can be allocated");
return -EBUSY;
}
@@ -314,13 +324,25 @@ static int mwl_mac80211_add_interface(struct ieee80211_hw *hw,
mwl_vif->vif = vif;
mwl_vif->macid = macid;
mwl_vif->seqno = 0;
- memcpy(mwl_vif->bssid, vif->addr, ETH_ALEN);
mwl_vif->is_hw_crypto_enabled = false;
+ mwl_vif->is_sta = false;
mwl_vif->beacon_info.valid = false;
mwl_vif->iv16 = 1;
mwl_vif->iv32 = 0;
+ mwl_vif->keyidx = 0;
+
+ if (vif->type == NL80211_IFTYPE_STATION) {
+ memcpy(mwl_vif->sta_mac, vif->addr, ETH_ALEN);
+ mwl_vif->is_sta = true;
+ mwl_fwcmd_bss_start(hw, vif, true);
+ mwl_fwcmd_set_infra_mode(hw, vif);
+ mwl_fwcmd_set_mac_addr_client(hw, vif, vif->addr);
+ }
- mwl_fwcmd_set_new_stn_add_self(hw, vif);
+ if (vif->type == NL80211_IFTYPE_AP) {
+ memcpy(mwl_vif->bssid, vif->addr, ETH_ALEN);
+ mwl_fwcmd_set_new_stn_add_self(hw, vif);
+ }
priv->macids_used |= 1 << mwl_vif->macid;
list_add_tail(&mwl_vif->list, &priv->vif_list);
@@ -338,7 +360,11 @@ static void mwl_mac80211_remove_interface(struct ieee80211_hw *hw,
WLDBG_ENTER(DBG_LEVEL_5);
- mwl_fwcmd_set_new_stn_del(hw, vif, vif->addr);
+ if (vif->type == NL80211_IFTYPE_STATION)
+ mwl_fwcmd_remove_mac_addr(hw, vif, vif->addr);
+
+ if (vif->type == NL80211_IFTYPE_AP)
+ mwl_fwcmd_set_new_stn_del(hw, vif, vif->addr);
mwl_mac80211_remove_vif(priv, mwl_vif);
@@ -364,17 +390,26 @@ static int mwl_mac80211_config(struct ieee80211_hw *hw,
goto out;
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-
- if (conf->chandef.chan->band == IEEE80211_BAND_2GHZ)
+ int rate = 0;
+
+ if (conf->chandef.chan->band == IEEE80211_BAND_2GHZ) {
mwl_fwcmd_set_apmode(hw, AP_MODE_2_4GHZ_11AC_MIXED);
- else if (conf->chandef.chan->band == IEEE80211_BAND_5GHZ)
+ rate = mwl_rates_24[0].hw_value;
+ } else if (conf->chandef.chan->band == IEEE80211_BAND_5GHZ) {
mwl_fwcmd_set_apmode(hw, AP_MODE_11AC);
+ rate = mwl_rates_50[0].hw_value;
+ }
rc = mwl_fwcmd_set_rf_channel(hw, conf);
if (rc)
goto out;
+ rc = mwl_fwcmd_use_fixed_rate(hw, rate, rate);
+
+ if (rc)
+ goto out;
+
rc = mwl_fwcmd_max_tx_power(hw, conf, 0);
if (rc)
@@ -397,71 +432,26 @@ out:
static void mwl_mac80211_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info,
- u32 changed)
+ struct ieee80211_bss_conf *info,
+ u32 changed)
{
WLDBG_ENTER(DBG_LEVEL_5);
- WLDBG_INFO(DBG_LEVEL_5, "change: 0x%x", changed);
-
- if (changed & BSS_CHANGED_ERP_PREAMBLE) {
-
- mwl_fwcmd_set_radio_preamble(hw,
- vif->bss_conf.use_short_preamble);
- }
-
- if (changed & BSS_CHANGED_BASIC_RATES) {
-
- int idx;
- int rate;
-
- /*
- * Use lowest supported basic rate for multicasts
- * and management frames (such as probe responses --
- * beacons will always go out at 1 Mb/s).
- */
- idx = ffs(vif->bss_conf.basic_rates);
- if (idx)
- idx--;
-
- if (hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ)
- rate = mwl_rates_24[idx].hw_value;
- else
- rate = mwl_rates_50[idx].hw_value;
-
- mwl_fwcmd_use_fixed_rate(hw, rate, rate);
- }
-
- if (changed & (BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON)) {
-
- struct sk_buff *skb;
+ WLDBG_INFO(DBG_LEVEL_5, "interface: %d, change: 0x%x", vif->type, changed);
- skb = ieee80211_beacon_get(hw, vif);
+ if (vif->type == NL80211_IFTYPE_STATION)
+ mwl_mac80211_bss_info_changed_sta(hw, vif, info, changed);
- if (skb != NULL) {
-
- mwl_fwcmd_set_beacon(hw, vif, skb->data, skb->len);
- dev_kfree_skb_any(skb);
- }
-
- if ((info->ssid[0] != '\0') && (info->ssid_len != 0))
- mwl_fwcmd_broadcast_ssid_enable(hw, vif, true);
- else
- mwl_fwcmd_broadcast_ssid_enable(hw, vif, false);
- }
-
- if (changed & BSS_CHANGED_BEACON_ENABLED) {
-
- mwl_fwcmd_bss_start(hw, vif, info->enable_beacon);
- }
+ if (vif->type == NL80211_IFTYPE_AP)
+ mwl_mac80211_bss_info_changed_ap(hw, vif, info, changed);
WLDBG_EXIT(DBG_LEVEL_5);
}
static void mwl_mac80211_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
- unsigned int *total_flags,
- u64 multicast)
+ unsigned int *total_flags,
+ u64 multicast)
{
WLDBG_ENTER(DBG_LEVEL_5);
@@ -476,9 +466,9 @@ static void mwl_mac80211_configure_filter(struct ieee80211_hw *hw,
static int mwl_mac80211_set_key(struct ieee80211_hw *hw,
enum set_key_cmd cmd_param,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
{
int rc = 0;
u8 encr_type;
@@ -491,19 +481,15 @@ static int mwl_mac80211_set_key(struct ieee80211_hw *hw,
BUG_ON(!mwl_vif);
BUG_ON(!sta_info);
- if (vif->type == NL80211_IFTYPE_STATION) {
-
- WLDBG_EXIT_INFO(DBG_LEVEL_5, "station mode is not supported");
- return -EOPNOTSUPP;
- }
-
- if (sta == NULL)
+ if (sta == NULL) {
addr = vif->addr;
- else
+ } else {
addr = sta->addr;
+ if (mwl_vif->is_sta == true)
+ memcpy(mwl_vif->bssid, addr, ETH_ALEN);
+ }
if (cmd_param == SET_KEY) {
-
rc = mwl_fwcmd_encryption_set_key(hw, vif, addr, key);
if (rc)
@@ -511,24 +497,17 @@ static int mwl_mac80211_set_key(struct ieee80211_hw *hw,
if ((key->cipher == WLAN_CIPHER_SUITE_WEP40)
|| (key->cipher == WLAN_CIPHER_SUITE_WEP104)) {
-
encr_type = ENCR_TYPE_WEP;
-
} else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) {
-
encr_type = ENCR_TYPE_AES;
-
- if ((key->flags & IEEE80211_KEY_FLAG_PAIRWISE) == 0)
- mwl_vif->keyidx = key->keyidx;
-
+ if ((key->flags & IEEE80211_KEY_FLAG_PAIRWISE) == 0) {
+ if (mwl_vif->is_sta == false)
+ mwl_vif->keyidx = key->keyidx;
+ }
} else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
-
encr_type = ENCR_TYPE_TKIP;
-
} else {
-
encr_type = ENCR_TYPE_DISABLE;
-
}
rc = mwl_fwcmd_update_encryption_enable(hw, vif, addr,
@@ -538,14 +517,11 @@ static int mwl_mac80211_set_key(struct ieee80211_hw *hw,
goto out;
mwl_vif->is_hw_crypto_enabled = true;
-
} else {
-
rc = mwl_fwcmd_encryption_remove_key(hw, vif, addr, key);
if (rc)
goto out;
-
}
out:
@@ -571,7 +547,7 @@ static int mwl_mac80211_set_rts_threshold(struct ieee80211_hw *hw,
static int mwl_mac80211_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+ struct ieee80211_sta *sta)
{
struct mwl_vif *mwl_vif = MWL_VIF(vif);
struct mwl_sta *sta_info = MWL_STA(sta);
@@ -590,10 +566,12 @@ static int mwl_mac80211_sta_add(struct ieee80211_hw *hw,
if (sta->ht_cap.ht_supported)
sta_info->is_ampdu_allowed = true;
+ if (mwl_vif->is_sta == true)
+ mwl_fwcmd_set_new_stn_del(hw, vif, sta->addr);
+
rc = mwl_fwcmd_set_new_stn_add(hw, vif, sta);
for (i = 0; i < NUM_WEP_KEYS; i++) {
-
key = IEEE80211_KEY_CONF(mwl_vif->wep_key_conf[i].key);
if (mwl_vif->wep_key_conf[i].enabled)
@@ -607,7 +585,7 @@ static int mwl_mac80211_sta_add(struct ieee80211_hw *hw,
static int mwl_mac80211_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+ struct ieee80211_sta *sta)
{
int rc;
@@ -622,8 +600,8 @@ static int mwl_mac80211_sta_remove(struct ieee80211_hw *hw,
static int mwl_mac80211_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- u16 queue,
- const struct ieee80211_tx_queue_params *params)
+ u16 queue,
+ const struct ieee80211_tx_queue_params *params)
{
struct mwl_priv *priv = hw->priv;
int rc = 0;
@@ -635,13 +613,11 @@ static int mwl_mac80211_conf_tx(struct ieee80211_hw *hw,
memcpy(&priv->wmm_params[queue], params, sizeof(*params));
if (!priv->wmm_enabled) {
-
rc = mwl_fwcmd_set_wmm_mode(hw, true);
priv->wmm_enabled = true;
}
if (!rc) {
-
int q = SYSADPT_TX_WMM_QUEUES - 1 - queue;
rc = mwl_fwcmd_set_edca_params(hw, q,
@@ -691,9 +667,9 @@ static int mwl_mac80211_get_survey(struct ieee80211_hw *hw,
static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- enum ieee80211_ampdu_mlme_action action,
- struct ieee80211_sta *sta,
- u16 tid, u16 *ssn, u8 buf_size)
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta,
+ u16 tid, u16 *ssn, u8 buf_size)
{
int i, rc = 0;
struct mwl_priv *priv = hw->priv;
@@ -704,7 +680,6 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
WLDBG_ENTER(DBG_LEVEL_5);
if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) {
-
WLDBG_EXIT_INFO(DBG_LEVEL_5, "no HW AMPDU");
return -ENOTSUPP;
}
@@ -714,11 +689,9 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
stream = mwl_fwcmd_lookup_stream(hw, addr, tid);
switch (action) {
-
case IEEE80211_AMPDU_RX_START:
case IEEE80211_AMPDU_RX_STOP:
break;
-
case IEEE80211_AMPDU_TX_START:
/* By the time we get here the hw queues may contain outgoing
* packets for this RA/TID that are not part of this BA
@@ -732,7 +705,6 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
*ssn = 0;
if (stream == NULL) {
-
/* This means that somebody outside this driver called
* ieee80211_start_tx_ba_session. This is unexpected
* because we do our own rate control. Just warn and
@@ -742,7 +714,6 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
}
if (stream == NULL) {
-
WLDBG_EXIT_INFO(DBG_LEVEL_5, "no stream found");
rc = -EBUSY;
break;
@@ -755,11 +726,9 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
SPIN_UNLOCK(&priv->locks.stream_lock);
for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) {
-
/* Check if link is still valid
*/
if (!sta_info->is_ampdu_allowed) {
-
SPIN_LOCK(&priv->locks.stream_lock);
mwl_fwcmd_remove_stream(hw, stream);
SPIN_UNLOCK(&priv->locks.stream_lock);
@@ -778,7 +747,6 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
SPIN_LOCK(&priv->locks.stream_lock);
if (rc) {
-
mwl_fwcmd_remove_stream(hw, stream);
WLDBG_EXIT_INFO(DBG_LEVEL_5, "error code: %d", rc);
rc = -EBUSY;
@@ -787,15 +755,11 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
break;
-
case IEEE80211_AMPDU_TX_STOP_CONT:
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
-
if (stream) {
-
if (stream->state == AMPDU_STREAM_ACTIVE) {
-
idx = stream->idx;
SPIN_UNLOCK(&priv->locks.stream_lock);
mwl_fwcmd_destroy_ba(hw, idx);
@@ -807,9 +771,7 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
break;
-
case IEEE80211_AMPDU_TX_OPERATIONAL:
-
BUG_ON(stream == NULL);
BUG_ON(stream->state != AMPDU_STREAM_IN_PROGRESS);
SPIN_UNLOCK(&priv->locks.stream_lock);
@@ -819,7 +781,6 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
if (!rc)
stream->state = AMPDU_STREAM_ACTIVE;
else {
-
idx = stream->idx;
SPIN_UNLOCK(&priv->locks.stream_lock);
mwl_fwcmd_destroy_ba(hw, idx);
@@ -827,10 +788,8 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
mwl_fwcmd_remove_stream(hw, stream);
}
break;
-
default:
rc = -ENOTSUPP;
-
}
SPIN_UNLOCK(&priv->locks.stream_lock);
@@ -848,3 +807,72 @@ static void mwl_mac80211_remove_vif(struct mwl_priv *priv, struct mwl_vif *vif)
priv->macids_used &= ~(1 << vif->macid);
list_del(&vif->list);
}
+
+static void mwl_mac80211_bss_info_changed_sta(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed)
+{
+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+ mwl_fwcmd_set_radio_preamble(hw,
+ vif->bss_conf.use_short_preamble);
+ }
+
+ if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) {
+
+ mwl_fwcmd_set_aid(hw, vif, (u8 *) vif->bss_conf.bssid,
+ vif->bss_conf.aid);
+ }
+}
+
+static void mwl_mac80211_bss_info_changed_ap(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed)
+{
+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+ mwl_fwcmd_set_radio_preamble(hw,
+ vif->bss_conf.use_short_preamble);
+ }
+
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ int idx;
+ int rate;
+
+ /*
+ * Use lowest supported basic rate for multicasts
+ * and management frames (such as probe responses --
+ * beacons will always go out at 1 Mb/s).
+ */
+ idx = ffs(vif->bss_conf.basic_rates);
+ if (idx)
+ idx--;
+
+ if (hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ)
+ rate = mwl_rates_24[idx].hw_value;
+ else
+ rate = mwl_rates_50[idx].hw_value;
+
+ mwl_fwcmd_use_fixed_rate(hw, rate, rate);
+ }
+
+ if (changed & (BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON)) {
+ struct sk_buff *skb;
+
+ skb = ieee80211_beacon_get(hw, vif);
+
+ if (skb != NULL) {
+
+ mwl_fwcmd_set_beacon(hw, vif, skb->data, skb->len);
+ dev_kfree_skb_any(skb);
+ }
+
+ if ((info->ssid[0] != '\0') && (info->ssid_len != 0))
+ mwl_fwcmd_broadcast_ssid_enable(hw, vif, true);
+ else
+ mwl_fwcmd_broadcast_ssid_enable(hw, vif, false);
+ }
+
+ if (changed & BSS_CHANGED_BEACON_ENABLED)
+ mwl_fwcmd_bss_start(hw, vif, info->enable_beacon);
+}