diff options
Diffstat (limited to 'mwl_mac80211.c')
-rw-r--r-- | mwl_mac80211.c | 304 |
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); +} |