mirror of
https://github.com/torvalds/linux.git
synced 2024-12-05 10:32:35 +00:00
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next
John W. Linville says: ==================== One last batch of stragglers intended for 3.9... For the iwlwifi pull, Johannes says: "I hadn't expected to ask you to pull iwlwifi-next again, but I have a number of fixes most of which I'd also send in after rc1, so here it is. The first commit is a merge error between mac80211-next and iwlwifi-next; in addition I have fixes for P2P scanning and MVM driver MAC (virtual interface) management from Ilan, a CT-kill (critical temperature) fix from Eytan, and myself fixed three different little but annoying bugs in the MVM driver. The only ones I might not send for -rc1 are Emmanuel's debug patch, but OTOH it should help greatly if there are any issues, and my own time event debugging patch that I used to find the race condition but we decided to keep it for the future." For the mac80211 pull, Johannes says: "Like iwlwifi-next, this would almost be suitable for rc1. I have a fix for station management on non-TDLS drivers, a CAB queue crash fix for mesh, a fix for an annoying (but harmless) warning, a tracing fix and a documentation fix. Other than that, only a few mesh cleanups." Along with that is a fix for memory corruption in rtlwifi, an orinoco_usb fix to avoid allocating a DMA buffer on the stack, an a hostap fix to return -ENOMEM instead of -1 after a memory allocation failure. The remaining bits implement 802.11ac support for the mwifiex driver -- I think that is still worth getting into 3.9. Please let me know if there are problems! ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
c6b5380797
@ -107,8 +107,8 @@
|
||||
!Finclude/net/cfg80211.h key_params
|
||||
!Finclude/net/cfg80211.h survey_info_flags
|
||||
!Finclude/net/cfg80211.h survey_info
|
||||
!Finclude/net/cfg80211.h beacon_parameters
|
||||
!Finclude/net/cfg80211.h plink_actions
|
||||
!Finclude/net/cfg80211.h cfg80211_beacon_data
|
||||
!Finclude/net/cfg80211.h cfg80211_ap_settings
|
||||
!Finclude/net/cfg80211.h station_parameters
|
||||
!Finclude/net/cfg80211.h station_info_flags
|
||||
!Finclude/net/cfg80211.h rate_info_flags
|
||||
|
@ -376,7 +376,7 @@ int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac)
|
||||
|
||||
entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL);
|
||||
if (entry == NULL)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(entry->addr, mac, ETH_ALEN);
|
||||
|
||||
|
@ -1403,6 +1403,7 @@ enum {
|
||||
|
||||
#define AGG_TX_STATUS_MSK 0x00000fff /* bits 0:11 */
|
||||
#define AGG_TX_TRY_MSK 0x0000f000 /* bits 12:15 */
|
||||
#define AGG_TX_TRY_POS 12
|
||||
|
||||
#define AGG_TX_STATE_LAST_SENT_MSK (AGG_TX_STATE_LAST_SENT_TTL_MSK | \
|
||||
AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
|
||||
|
@ -471,8 +471,8 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
|
||||
set_bit(STATUS_CT_KILL, &priv->status);
|
||||
iwl_perform_ct_kill_task(priv, true);
|
||||
} else {
|
||||
iwl_prepare_ct_kill_task(priv);
|
||||
tt->state = old_state;
|
||||
iwl_prepare_ct_kill_task(priv);
|
||||
}
|
||||
} else if (old_state == IWL_TI_CT_KILL &&
|
||||
tt->state != IWL_TI_CT_KILL) {
|
||||
|
@ -908,6 +908,12 @@ static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
|
||||
{
|
||||
return le32_to_cpup((__le32 *)&tx_resp->status +
|
||||
tx_resp->frame_count) & MAX_SN;
|
||||
}
|
||||
|
||||
static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
|
||||
struct iwlagn_tx_resp *tx_resp)
|
||||
{
|
||||
@ -942,9 +948,15 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
|
||||
if (tx_resp->frame_count == 1)
|
||||
return;
|
||||
|
||||
IWL_DEBUG_TX_REPLY(priv, "TXQ %d initial_rate 0x%x ssn %d frm_cnt %d\n",
|
||||
agg->txq_id,
|
||||
le32_to_cpu(tx_resp->rate_n_flags),
|
||||
iwlagn_get_scd_ssn(tx_resp), tx_resp->frame_count);
|
||||
|
||||
/* Construct bit-map of pending frames within Tx window */
|
||||
for (i = 0; i < tx_resp->frame_count; i++) {
|
||||
u16 fstatus = le16_to_cpu(frame_status[i].status);
|
||||
u8 retry_cnt = (fstatus & AGG_TX_TRY_MSK) >> AGG_TX_TRY_POS;
|
||||
|
||||
if (status & AGG_TX_STATUS_MSK)
|
||||
iwlagn_count_agg_tx_err_status(priv, fstatus);
|
||||
@ -952,6 +964,14 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
|
||||
if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
|
||||
AGG_TX_STATE_ABORT_MSK))
|
||||
continue;
|
||||
|
||||
if (status & AGG_TX_STATUS_MSK || retry_cnt > 1)
|
||||
IWL_DEBUG_TX_REPLY(priv,
|
||||
"%d: status %s (0x%04x), try-count (0x%01x)\n",
|
||||
i,
|
||||
iwl_get_agg_tx_fail_reason(fstatus),
|
||||
fstatus & AGG_TX_STATUS_MSK,
|
||||
retry_cnt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -982,12 +1002,6 @@ const char *iwl_get_agg_tx_fail_reason(u16 status)
|
||||
}
|
||||
#endif /* CONFIG_IWLWIFI_DEBUG */
|
||||
|
||||
static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
|
||||
{
|
||||
return le32_to_cpup((__le32 *)&tx_resp->status +
|
||||
tx_resp->frame_count) & MAX_SN;
|
||||
}
|
||||
|
||||
static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status)
|
||||
{
|
||||
status &= TX_STATUS_MSK;
|
||||
@ -1119,8 +1133,14 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
|
||||
|
||||
spin_lock_bh(&priv->sta_lock);
|
||||
|
||||
if (is_agg)
|
||||
if (is_agg) {
|
||||
WARN_ON_ONCE(sta_id >= IWLAGN_STATION_COUNT ||
|
||||
tid >= IWL_MAX_TID_COUNT);
|
||||
if (txq_id != priv->tid_data[sta_id][tid].agg.txq_id)
|
||||
IWL_ERR(priv, "txq_id mismatch: %d %d\n", txq_id,
|
||||
priv->tid_data[sta_id][tid].agg.txq_id);
|
||||
iwl_rx_reply_tx_agg(priv, tx_resp);
|
||||
}
|
||||
|
||||
__skb_queue_head_init(&skbs);
|
||||
|
||||
@ -1224,17 +1244,18 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
|
||||
*/
|
||||
if (is_offchannel_skb && freed != 1)
|
||||
IWL_ERR(priv, "OFFCHANNEL SKB freed %d\n", freed);
|
||||
|
||||
IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x)\n", txq_id,
|
||||
iwl_get_tx_fail_reason(status), status);
|
||||
|
||||
IWL_DEBUG_TX_REPLY(priv,
|
||||
"\t\t\t\tinitial_rate 0x%x retries %d, idx=%d ssn=%d seq_ctl=0x%x\n",
|
||||
le32_to_cpu(tx_resp->rate_n_flags),
|
||||
tx_resp->failure_frame,
|
||||
SEQ_TO_INDEX(sequence), ssn,
|
||||
le16_to_cpu(tx_resp->seq_ctl));
|
||||
}
|
||||
|
||||
IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x)\n", txq_id,
|
||||
iwl_get_tx_fail_reason(status), status);
|
||||
|
||||
IWL_DEBUG_TX_REPLY(priv,
|
||||
"\t\t\t\tinitial_rate 0x%x retries %d, idx=%d ssn=%d seq_ctl=0x%x\n",
|
||||
le32_to_cpu(tx_resp->rate_n_flags),
|
||||
tx_resp->failure_frame, SEQ_TO_INDEX(sequence), ssn,
|
||||
le16_to_cpu(tx_resp->seq_ctl));
|
||||
|
||||
iwl_check_abort_status(priv, tx_resp->frame_count, status);
|
||||
spin_unlock_bh(&priv->sta_lock);
|
||||
|
||||
|
@ -245,6 +245,10 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
|
||||
* that we should share it with another interface.
|
||||
*/
|
||||
|
||||
/* Currently, MAC ID 0 should be used only for the managed vif */
|
||||
if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
|
||||
__clear_bit(0, data.available_mac_ids);
|
||||
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
iwl_mvm_mac_iface_iterator, &data);
|
||||
@ -286,6 +290,9 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
|
||||
|
||||
mvmvif->color = 0;
|
||||
|
||||
INIT_LIST_HEAD(&mvmvif->time_event_data.list);
|
||||
mvmvif->time_event_data.id = TE_MAX;
|
||||
|
||||
/* No need to allocate data queues to P2P Device MAC.*/
|
||||
if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
|
||||
@ -328,9 +335,6 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
|
||||
mvmvif->bcast_sta.sta_id = IWL_MVM_STATION_COUNT;
|
||||
mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
|
||||
|
||||
INIT_LIST_HEAD(&mvmvif->time_event_data.list);
|
||||
mvmvif->time_event_data.id = TE_MAX;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_fail:
|
||||
@ -585,10 +589,43 @@ static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm,
|
||||
struct iwl_mac_data_sta *ctxt_sta)
|
||||
{
|
||||
/* We need the dtim_period to set the MAC as associated */
|
||||
if (vif->bss_conf.assoc && vif->bss_conf.dtim_period)
|
||||
if (vif->bss_conf.assoc && vif->bss_conf.dtim_period) {
|
||||
u32 dtim_offs;
|
||||
|
||||
/*
|
||||
* The DTIM count counts down, so when it is N that means N
|
||||
* more beacon intervals happen until the DTIM TBTT. Therefore
|
||||
* add this to the current time. If that ends up being in the
|
||||
* future, the firmware will handle it.
|
||||
*
|
||||
* Also note that the system_timestamp (which we get here as
|
||||
* "sync_device_ts") and TSF timestamp aren't at exactly the
|
||||
* same offset in the frame -- the TSF is at the first symbol
|
||||
* of the TSF, the system timestamp is at signal acquisition
|
||||
* time. This means there's an offset between them of at most
|
||||
* a few hundred microseconds (24 * 8 bits + PLCP time gives
|
||||
* 384us in the longest case), this is currently not relevant
|
||||
* as the firmware wakes up around 2ms before the TBTT.
|
||||
*/
|
||||
dtim_offs = vif->bss_conf.sync_dtim_count *
|
||||
vif->bss_conf.beacon_int;
|
||||
/* convert TU to usecs */
|
||||
dtim_offs *= 1024;
|
||||
|
||||
ctxt_sta->dtim_tsf =
|
||||
cpu_to_le64(vif->bss_conf.sync_tsf + dtim_offs);
|
||||
ctxt_sta->dtim_time =
|
||||
cpu_to_le32(vif->bss_conf.sync_device_ts + dtim_offs);
|
||||
|
||||
IWL_DEBUG_INFO(mvm, "DTIM TBTT is 0x%llx/0x%x, offset %d\n",
|
||||
le64_to_cpu(ctxt_sta->dtim_tsf),
|
||||
le32_to_cpu(ctxt_sta->dtim_time),
|
||||
dtim_offs);
|
||||
|
||||
ctxt_sta->is_assoc = cpu_to_le32(1);
|
||||
else
|
||||
} else {
|
||||
ctxt_sta->is_assoc = cpu_to_le32(0);
|
||||
}
|
||||
|
||||
ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int);
|
||||
ctxt_sta->bi_reciprocal =
|
||||
|
@ -113,10 +113,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
||||
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
|
||||
IEEE80211_HW_QUEUE_CONTROL |
|
||||
IEEE80211_HW_WANT_MONITOR_VIF |
|
||||
IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
|
||||
IEEE80211_HW_SUPPORTS_PS |
|
||||
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
|
||||
IEEE80211_HW_AMPDU_AGGREGATION;
|
||||
IEEE80211_HW_AMPDU_AGGREGATION |
|
||||
IEEE80211_HW_TIMING_BEACON_ONLY;
|
||||
|
||||
hw->queues = IWL_FIRST_AMPDU_QUEUE;
|
||||
hw->offchannel_tx_hw_queue = IWL_OFFCHANNEL_QUEUE;
|
||||
@ -857,7 +857,6 @@ iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw,
|
||||
bool more_data)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
|
||||
|
||||
/* TODO: how do we tell the fw to send frames for a specific TID */
|
||||
|
||||
@ -865,8 +864,7 @@ iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw,
|
||||
* The fw will send EOSP notification when the last frame will be
|
||||
* transmitted.
|
||||
*/
|
||||
iwl_mvm_sta_modify_sleep_tx_count(mvm, mvmsta->sta_id, reason,
|
||||
num_frames);
|
||||
iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames);
|
||||
}
|
||||
|
||||
static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
|
||||
@ -890,7 +888,7 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
|
||||
case STA_NOTIFY_AWAKE:
|
||||
if (WARN_ON(mvmsta->sta_id == IWL_INVALID_STATION))
|
||||
break;
|
||||
iwl_mvm_sta_modify_ps_wake(mvm, mvmsta->sta_id);
|
||||
iwl_mvm_sta_modify_ps_wake(mvm, sta);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -267,6 +267,7 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
|
||||
|
||||
/* rx_status carries information about the packet to mac80211 */
|
||||
rx_status.mactime = le64_to_cpu(phy_info->timestamp);
|
||||
rx_status.device_timestamp = le32_to_cpu(phy_info->system_timestamp);
|
||||
rx_status.band =
|
||||
(phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ?
|
||||
IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
|
||||
|
@ -292,7 +292,12 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
|
||||
cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req);
|
||||
cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
|
||||
MAC_FILTER_IN_BEACON);
|
||||
cmd->type = SCAN_TYPE_FORCED;
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
|
||||
cmd->type = cpu_to_le32(SCAN_TYPE_DISCOVERY_FORCED);
|
||||
else
|
||||
cmd->type = cpu_to_le32(SCAN_TYPE_FORCED);
|
||||
|
||||
cmd->repeats = cpu_to_le32(1);
|
||||
|
||||
/*
|
||||
|
@ -1188,13 +1188,16 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, int sta_id)
|
||||
void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
|
||||
struct iwl_mvm_add_sta_cmd cmd = {
|
||||
.add_modify = STA_MODE_MODIFY,
|
||||
.sta_id = sta_id,
|
||||
.sta_id = mvmsta->sta_id,
|
||||
.modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT,
|
||||
.sleep_state_flags = cpu_to_le16(STA_SLEEP_STATE_AWAKE),
|
||||
.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color),
|
||||
};
|
||||
int ret;
|
||||
|
||||
@ -1208,18 +1211,21 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, int sta_id)
|
||||
IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
|
||||
}
|
||||
|
||||
void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, int sta_id,
|
||||
void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta,
|
||||
enum ieee80211_frame_release_type reason,
|
||||
u16 cnt)
|
||||
{
|
||||
u16 sleep_state_flags =
|
||||
(reason == IEEE80211_FRAME_RELEASE_UAPSD) ?
|
||||
STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL;
|
||||
struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
|
||||
struct iwl_mvm_add_sta_cmd cmd = {
|
||||
.add_modify = STA_MODE_MODIFY,
|
||||
.sta_id = sta_id,
|
||||
.sta_id = mvmsta->sta_id,
|
||||
.modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT,
|
||||
.sleep_tx_count = cpu_to_le16(cnt),
|
||||
.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color),
|
||||
/*
|
||||
* Same modify mask for sleep_tx_count and sleep_state_flags so
|
||||
* we must set the sleep_state_flags too.
|
||||
|
@ -362,8 +362,10 @@ int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
struct iwl_mvm_int_sta *bsta);
|
||||
int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta);
|
||||
void iwl_mvm_sta_drained_wk(struct work_struct *wk);
|
||||
void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, int sta_id);
|
||||
void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, int sta_id,
|
||||
void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta);
|
||||
void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta,
|
||||
enum ieee80211_frame_release_type reason,
|
||||
u16 cnt);
|
||||
int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
|
||||
|
@ -248,6 +248,11 @@ static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait,
|
||||
}
|
||||
|
||||
resp = (void *)pkt->data;
|
||||
|
||||
/* we should never get a response to another TIME_EVENT_CMD here */
|
||||
if (WARN_ON_ONCE(le32_to_cpu(resp->id) != te_data->id))
|
||||
return false;
|
||||
|
||||
te_data->uid = le32_to_cpu(resp->unique_id);
|
||||
IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n",
|
||||
te_data->uid);
|
||||
@ -265,6 +270,9 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
IWL_DEBUG_TE(mvm, "Add new TE, duration %d TU\n",
|
||||
le32_to_cpu(te_cmd->duration));
|
||||
|
||||
spin_lock_bh(&mvm->time_event_lock);
|
||||
if (WARN_ON(te_data->id != TE_MAX)) {
|
||||
spin_unlock_bh(&mvm->time_event_lock);
|
||||
@ -413,7 +421,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
|
||||
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
|
||||
|
||||
IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id));
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_ASYNC,
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
|
||||
sizeof(time_cmd), &time_cmd);
|
||||
if (WARN_ON(ret))
|
||||
return;
|
||||
|
261
drivers/net/wireless/mwifiex/11ac.c
Normal file
261
drivers/net/wireless/mwifiex/11ac.c
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Marvell Wireless LAN device driver: 802.11ac
|
||||
*
|
||||
* Copyright (C) 2013, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
* (the "License"). You may use, redistribute and/or modify this File in
|
||||
* accordance with the terms and conditions of the License, a copy of which
|
||||
* is available by writing to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
|
||||
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
||||
*
|
||||
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
||||
* this warranty disclaimer.
|
||||
*/
|
||||
|
||||
#include "decl.h"
|
||||
#include "ioctl.h"
|
||||
#include "fw.h"
|
||||
#include "main.h"
|
||||
#include "11ac.h"
|
||||
|
||||
/* This function converts the 2-bit MCS map to the highest long GI
|
||||
* VHT data rate.
|
||||
*/
|
||||
static u16
|
||||
mwifiex_convert_mcsmap_to_maxrate(struct mwifiex_private *priv,
|
||||
u8 bands, u16 mcs_map)
|
||||
{
|
||||
u8 i, nss, max_mcs;
|
||||
u16 max_rate = 0;
|
||||
u32 usr_vht_cap_info = 0;
|
||||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
/* tables of the MCS map to the highest data rate (in Mbps)
|
||||
* supported for long GI
|
||||
*/
|
||||
u16 max_rate_lgi_80MHZ[8][3] = {
|
||||
{0x124, 0x15F, 0x186}, /* NSS = 1 */
|
||||
{0x249, 0x2BE, 0x30C}, /* NSS = 2 */
|
||||
{0x36D, 0x41D, 0x492}, /* NSS = 3 */
|
||||
{0x492, 0x57C, 0x618}, /* NSS = 4 */
|
||||
{0x5B6, 0x6DB, 0x79E}, /* NSS = 5 */
|
||||
{0x6DB, 0x83A, 0x0}, /* NSS = 6 */
|
||||
{0x7FF, 0x999, 0xAAA}, /* NSS = 7 */
|
||||
{0x924, 0xAF8, 0xC30} /* NSS = 8 */
|
||||
};
|
||||
u16 max_rate_lgi_160MHZ[8][3] = {
|
||||
{0x249, 0x2BE, 0x30C}, /* NSS = 1 */
|
||||
{0x492, 0x57C, 0x618}, /* NSS = 2 */
|
||||
{0x6DB, 0x83A, 0x0}, /* NSS = 3 */
|
||||
{0x924, 0xAF8, 0xC30}, /* NSS = 4 */
|
||||
{0xB6D, 0xDB6, 0xF3C}, /* NSS = 5 */
|
||||
{0xDB6, 0x1074, 0x1248}, /* NSS = 6 */
|
||||
{0xFFF, 0x1332, 0x1554}, /* NSS = 7 */
|
||||
{0x1248, 0x15F0, 0x1860} /* NSS = 8 */
|
||||
};
|
||||
|
||||
if (bands & BAND_AAC)
|
||||
usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
|
||||
else
|
||||
usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
|
||||
|
||||
/* find the max NSS supported */
|
||||
nss = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
max_mcs = (mcs_map >> (2 * i)) & 0x3;
|
||||
if (max_mcs < 3)
|
||||
nss = i;
|
||||
}
|
||||
max_mcs = (mcs_map >> (2 * nss)) & 0x3;
|
||||
|
||||
/* if max_mcs is 3, nss must be 0 (SS = 1). Thus, max mcs is MCS 9 */
|
||||
if (max_mcs >= 3)
|
||||
max_mcs = 2;
|
||||
|
||||
if (GET_VHTCAP_CHWDSET(usr_vht_cap_info)) {
|
||||
/* support 160 MHz */
|
||||
max_rate = max_rate_lgi_160MHZ[nss][max_mcs];
|
||||
if (!max_rate)
|
||||
/* MCS9 is not supported in NSS6 */
|
||||
max_rate = max_rate_lgi_160MHZ[nss][max_mcs - 1];
|
||||
} else {
|
||||
max_rate = max_rate_lgi_80MHZ[nss][max_mcs];
|
||||
if (!max_rate)
|
||||
/* MCS9 is not supported in NSS3 */
|
||||
max_rate = max_rate_lgi_80MHZ[nss][max_mcs - 1];
|
||||
}
|
||||
|
||||
return max_rate;
|
||||
}
|
||||
|
||||
static void
|
||||
mwifiex_fill_vht_cap_info(struct mwifiex_private *priv,
|
||||
struct mwifiex_ie_types_vhtcap *vht_cap, u8 bands)
|
||||
{
|
||||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
|
||||
if (bands & BAND_A)
|
||||
vht_cap->vht_cap.vht_cap_info =
|
||||
cpu_to_le32(adapter->usr_dot_11ac_dev_cap_a);
|
||||
else
|
||||
vht_cap->vht_cap.vht_cap_info =
|
||||
cpu_to_le32(adapter->usr_dot_11ac_dev_cap_bg);
|
||||
}
|
||||
|
||||
static void
|
||||
mwifiex_fill_vht_cap_tlv(struct mwifiex_private *priv,
|
||||
struct mwifiex_ie_types_vhtcap *vht_cap, u8 bands)
|
||||
{
|
||||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
u16 mcs_map_user, mcs_map_resp, mcs_map_result;
|
||||
u16 mcs_user, mcs_resp, nss, tmp;
|
||||
|
||||
/* Fill VHT cap info */
|
||||
mwifiex_fill_vht_cap_info(priv, vht_cap, bands);
|
||||
|
||||
/* rx MCS Set: find the minimum of the user rx mcs and ap rx mcs */
|
||||
mcs_map_user = GET_DEVRXMCSMAP(adapter->usr_dot_11ac_mcs_support);
|
||||
mcs_map_resp = le16_to_cpu(vht_cap->vht_cap.supp_mcs.rx_mcs_map);
|
||||
mcs_map_result = 0;
|
||||
|
||||
for (nss = 1; nss <= 8; nss++) {
|
||||
mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
|
||||
mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
|
||||
|
||||
if ((mcs_user == NO_NSS_SUPPORT) ||
|
||||
(mcs_resp == NO_NSS_SUPPORT))
|
||||
SET_VHTNSSMCS(mcs_map_result, nss, NO_NSS_SUPPORT);
|
||||
else
|
||||
SET_VHTNSSMCS(mcs_map_result, nss,
|
||||
min(mcs_user, mcs_resp));
|
||||
}
|
||||
|
||||
vht_cap->vht_cap.supp_mcs.rx_mcs_map = cpu_to_le16(mcs_map_result);
|
||||
|
||||
tmp = mwifiex_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result);
|
||||
vht_cap->vht_cap.supp_mcs.rx_highest = cpu_to_le16(tmp);
|
||||
|
||||
/* tx MCS Set: find the minimum of the user tx mcs and ap tx mcs */
|
||||
mcs_map_user = GET_DEVTXMCSMAP(adapter->usr_dot_11ac_mcs_support);
|
||||
mcs_map_resp = le16_to_cpu(vht_cap->vht_cap.supp_mcs.tx_mcs_map);
|
||||
mcs_map_result = 0;
|
||||
|
||||
for (nss = 1; nss <= 8; nss++) {
|
||||
mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
|
||||
mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
|
||||
if ((mcs_user == NO_NSS_SUPPORT) ||
|
||||
(mcs_resp == NO_NSS_SUPPORT))
|
||||
SET_VHTNSSMCS(mcs_map_result, nss, NO_NSS_SUPPORT);
|
||||
else
|
||||
SET_VHTNSSMCS(mcs_map_result, nss,
|
||||
min(mcs_user, mcs_resp));
|
||||
}
|
||||
|
||||
vht_cap->vht_cap.supp_mcs.tx_mcs_map = cpu_to_le16(mcs_map_result);
|
||||
|
||||
tmp = mwifiex_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result);
|
||||
vht_cap->vht_cap.supp_mcs.tx_highest = cpu_to_le16(tmp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
|
||||
struct mwifiex_bssdescriptor *bss_desc,
|
||||
u8 **buffer)
|
||||
{
|
||||
struct mwifiex_ie_types_vhtcap *vht_cap;
|
||||
struct mwifiex_ie_types_oper_mode_ntf *oper_ntf;
|
||||
struct ieee_types_oper_mode_ntf *ieee_oper_ntf;
|
||||
struct mwifiex_ie_types_vht_oper *vht_op;
|
||||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
u8 supp_chwd_set;
|
||||
u32 usr_vht_cap_info;
|
||||
int ret_len = 0;
|
||||
|
||||
if (bss_desc->bss_band & BAND_A)
|
||||
usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
|
||||
else
|
||||
usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
|
||||
|
||||
/* VHT Capabilities IE */
|
||||
if (bss_desc->bcn_vht_cap) {
|
||||
vht_cap = (struct mwifiex_ie_types_vhtcap *)*buffer;
|
||||
memset(vht_cap, 0, sizeof(*vht_cap));
|
||||
vht_cap->header.type = cpu_to_le16(WLAN_EID_VHT_CAPABILITY);
|
||||
vht_cap->header.len =
|
||||
cpu_to_le16(sizeof(struct ieee80211_vht_cap));
|
||||
memcpy((u8 *)vht_cap + sizeof(struct mwifiex_ie_types_header),
|
||||
(u8 *)bss_desc->bcn_vht_cap +
|
||||
sizeof(struct ieee_types_header),
|
||||
le16_to_cpu(vht_cap->header.len));
|
||||
|
||||
mwifiex_fill_vht_cap_tlv(priv, vht_cap, bss_desc->bss_band);
|
||||
*buffer += sizeof(*vht_cap);
|
||||
ret_len += sizeof(*vht_cap);
|
||||
}
|
||||
|
||||
/* VHT Operation IE */
|
||||
if (bss_desc->bcn_vht_oper) {
|
||||
if (priv->bss_mode == HostCmd_BSS_MODE_IBSS) {
|
||||
vht_op = (struct mwifiex_ie_types_vht_oper *)*buffer;
|
||||
memset(vht_op, 0, sizeof(*vht_op));
|
||||
vht_op->header.type =
|
||||
cpu_to_le16(WLAN_EID_VHT_OPERATION);
|
||||
vht_op->header.len = cpu_to_le16(sizeof(*vht_op) -
|
||||
sizeof(struct mwifiex_ie_types_header));
|
||||
memcpy((u8 *)vht_op +
|
||||
sizeof(struct mwifiex_ie_types_header),
|
||||
(u8 *)bss_desc->bcn_vht_oper +
|
||||
sizeof(struct ieee_types_header),
|
||||
le16_to_cpu(vht_op->header.len));
|
||||
|
||||
/* negotiate the channel width and central freq
|
||||
* and keep the central freq as the peer suggests
|
||||
*/
|
||||
supp_chwd_set = GET_VHTCAP_CHWDSET(usr_vht_cap_info);
|
||||
|
||||
switch (supp_chwd_set) {
|
||||
case 0:
|
||||
vht_op->chan_width =
|
||||
min_t(u8, IEEE80211_VHT_CHANWIDTH_80MHZ,
|
||||
bss_desc->bcn_vht_oper->chan_width);
|
||||
break;
|
||||
case 1:
|
||||
vht_op->chan_width =
|
||||
min_t(u8, IEEE80211_VHT_CHANWIDTH_160MHZ,
|
||||
bss_desc->bcn_vht_oper->chan_width);
|
||||
break;
|
||||
case 2:
|
||||
vht_op->chan_width =
|
||||
min_t(u8, IEEE80211_VHT_CHANWIDTH_80P80MHZ,
|
||||
bss_desc->bcn_vht_oper->chan_width);
|
||||
break;
|
||||
default:
|
||||
vht_op->chan_width =
|
||||
IEEE80211_VHT_CHANWIDTH_USE_HT;
|
||||
break;
|
||||
}
|
||||
|
||||
*buffer += sizeof(*vht_op);
|
||||
ret_len += sizeof(*vht_op);
|
||||
}
|
||||
}
|
||||
|
||||
/* Operating Mode Notification IE */
|
||||
if (bss_desc->oper_mode) {
|
||||
ieee_oper_ntf = bss_desc->oper_mode;
|
||||
oper_ntf = (void *)*buffer;
|
||||
memset(oper_ntf, 0, sizeof(*oper_ntf));
|
||||
oper_ntf->header.type = cpu_to_le16(WLAN_EID_OPMODE_NOTIF);
|
||||
oper_ntf->header.len = cpu_to_le16(sizeof(u8));
|
||||
oper_ntf->oper_mode = ieee_oper_ntf->oper_mode;
|
||||
*buffer += sizeof(*oper_ntf);
|
||||
ret_len += sizeof(*oper_ntf);
|
||||
}
|
||||
|
||||
return ret_len;
|
||||
}
|
26
drivers/net/wireless/mwifiex/11ac.h
Normal file
26
drivers/net/wireless/mwifiex/11ac.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Marvell Wireless LAN device driver: 802.11ac
|
||||
*
|
||||
* Copyright (C) 2013, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
* (the "License"). You may use, redistribute and/or modify this File in
|
||||
* accordance with the terms and conditions of the License, a copy of which
|
||||
* is available by writing to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
|
||||
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
||||
*
|
||||
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
||||
* this warranty disclaimer.
|
||||
*/
|
||||
|
||||
#ifndef _MWIFIEX_11AC_H_
|
||||
#define _MWIFIEX_11AC_H_
|
||||
|
||||
int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
|
||||
struct mwifiex_bssdescriptor *bss_desc,
|
||||
u8 **buffer);
|
||||
#endif /* _MWIFIEX_11AC_H_ */
|
@ -250,7 +250,8 @@ int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd,
|
||||
* - Setting HT Tx capability and HT Tx information fields
|
||||
* - Ensuring correct endian-ness
|
||||
*/
|
||||
int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action,
|
||||
int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
|
||||
struct host_cmd_ds_command *cmd, u16 cmd_action,
|
||||
struct mwifiex_ds_11n_tx_cfg *txcfg)
|
||||
{
|
||||
struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg;
|
||||
@ -260,6 +261,10 @@ int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action,
|
||||
htcfg->action = cpu_to_le16(cmd_action);
|
||||
htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap);
|
||||
htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo);
|
||||
|
||||
if (priv->adapter->is_hw_11ac_capable)
|
||||
htcfg->misc_config = cpu_to_le16(txcfg->misc_config);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -28,9 +28,9 @@ int mwifiex_ret_11n_delba(struct mwifiex_private *priv,
|
||||
struct host_cmd_ds_command *resp);
|
||||
int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
|
||||
struct host_cmd_ds_command *resp);
|
||||
int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action,
|
||||
int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
|
||||
struct host_cmd_ds_command *cmd, u16 cmd_action,
|
||||
struct mwifiex_ds_11n_tx_cfg *txcfg);
|
||||
|
||||
int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
|
||||
struct mwifiex_bssdescriptor *bss_desc,
|
||||
u8 **buffer);
|
||||
|
@ -23,6 +23,7 @@ mwifiex-y += util.o
|
||||
mwifiex-y += txrx.o
|
||||
mwifiex-y += wmm.o
|
||||
mwifiex-y += 11n.o
|
||||
mwifiex-y += 11ac.o
|
||||
mwifiex-y += 11n_aggr.o
|
||||
mwifiex-y += 11n_rxreorder.o
|
||||
mwifiex-y += scan.o
|
||||
|
@ -834,6 +834,66 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo,
|
||||
struct rate_info *rate)
|
||||
{
|
||||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
|
||||
if (adapter->is_hw_11ac_capable) {
|
||||
/* bit[1-0]: 00=LG 01=HT 10=VHT */
|
||||
if (tx_htinfo & BIT(0)) {
|
||||
/* HT */
|
||||
rate->mcs = priv->tx_rate;
|
||||
rate->flags |= RATE_INFO_FLAGS_MCS;
|
||||
}
|
||||
if (tx_htinfo & BIT(1)) {
|
||||
/* VHT */
|
||||
rate->mcs = priv->tx_rate & 0x0F;
|
||||
rate->flags |= RATE_INFO_FLAGS_VHT_MCS;
|
||||
}
|
||||
|
||||
if (tx_htinfo & (BIT(1) | BIT(0))) {
|
||||
/* HT or VHT */
|
||||
switch (tx_htinfo & (BIT(3) | BIT(2))) {
|
||||
case 0:
|
||||
/* This will be 20MHz */
|
||||
break;
|
||||
case (BIT(2)):
|
||||
rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
|
||||
break;
|
||||
case (BIT(3)):
|
||||
rate->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
|
||||
break;
|
||||
case (BIT(3) | BIT(2)):
|
||||
rate->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tx_htinfo & BIT(4))
|
||||
rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
|
||||
if ((priv->tx_rate >> 4) == 1)
|
||||
rate->nss = 2;
|
||||
else
|
||||
rate->nss = 1;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Bit 0 in tx_htinfo indicates that current Tx rate
|
||||
* is 11n rate. Valid MCS index values for us are 0 to 15.
|
||||
*/
|
||||
if ((tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) {
|
||||
rate->mcs = priv->tx_rate;
|
||||
rate->flags |= RATE_INFO_FLAGS_MCS;
|
||||
if (tx_htinfo & BIT(1))
|
||||
rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
|
||||
if (tx_htinfo & BIT(2))
|
||||
rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function dumps the station information on a buffer.
|
||||
*
|
||||
@ -873,20 +933,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
|
||||
HostCmd_ACT_GEN_GET, DTIM_PERIOD_I,
|
||||
&priv->dtim_period);
|
||||
|
||||
/*
|
||||
* Bit 0 in tx_htinfo indicates that current Tx rate is 11n rate. Valid
|
||||
* MCS index values for us are 0 to 15.
|
||||
*/
|
||||
if ((priv->tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) {
|
||||
sinfo->txrate.mcs = priv->tx_rate;
|
||||
sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
|
||||
/* 40MHz rate */
|
||||
if (priv->tx_htinfo & BIT(1))
|
||||
sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
|
||||
/* SGI enabled */
|
||||
if (priv->tx_htinfo & BIT(2))
|
||||
sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
}
|
||||
mwifiex_parse_htinfo(priv, priv->tx_htinfo, &sinfo->txrate);
|
||||
|
||||
sinfo->signal_avg = priv->bcn_rssi_avg;
|
||||
sinfo->rx_bytes = priv->stats.rx_bytes;
|
||||
@ -1295,20 +1342,22 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
/* Set appropriate bands */
|
||||
if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) {
|
||||
bss_cfg->band_cfg = BAND_CONFIG_BG;
|
||||
config_bands = BAND_B | BAND_G;
|
||||
|
||||
if (cfg80211_get_chandef_type(¶ms->chandef) ==
|
||||
NL80211_CHAN_NO_HT)
|
||||
config_bands = BAND_B | BAND_G;
|
||||
else
|
||||
config_bands = BAND_B | BAND_G | BAND_GN;
|
||||
if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
|
||||
config_bands |= BAND_GN;
|
||||
|
||||
if (params->chandef.width > NL80211_CHAN_WIDTH_40)
|
||||
config_bands |= BAND_GAC;
|
||||
} else {
|
||||
bss_cfg->band_cfg = BAND_CONFIG_A;
|
||||
config_bands = BAND_A;
|
||||
|
||||
if (cfg80211_get_chandef_type(¶ms->chandef) ==
|
||||
NL80211_CHAN_NO_HT)
|
||||
config_bands = BAND_A;
|
||||
else
|
||||
config_bands = BAND_AN | BAND_A;
|
||||
if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
|
||||
config_bands |= BAND_AN;
|
||||
|
||||
if (params->chandef.width > NL80211_CHAN_WIDTH_40)
|
||||
config_bands |= BAND_AAC;
|
||||
}
|
||||
|
||||
if (!((config_bands | priv->adapter->fw_bands) &
|
||||
@ -1879,6 +1928,79 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mwifiex_setup_vht_caps(struct ieee80211_sta_vht_cap *vht_info,
|
||||
struct mwifiex_private *priv)
|
||||
{
|
||||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
u32 vht_cap = 0, cap = adapter->hw_dot_11ac_dev_cap;
|
||||
|
||||
vht_info->vht_supported = true;
|
||||
|
||||
switch (GET_VHTCAP_MAXMPDULEN(cap)) {
|
||||
case 0x00:
|
||||
vht_cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
|
||||
break;
|
||||
case 0x01:
|
||||
vht_cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
|
||||
break;
|
||||
case 0x10:
|
||||
vht_cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
|
||||
break;
|
||||
default:
|
||||
dev_err(adapter->dev, "unsupported MAX MPDU len\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (ISSUPP_11ACVHTHTCVHT(cap))
|
||||
vht_cap |= IEEE80211_VHT_CAP_HTC_VHT;
|
||||
|
||||
if (ISSUPP_11ACVHTTXOPPS(cap))
|
||||
vht_cap |= IEEE80211_VHT_CAP_VHT_TXOP_PS;
|
||||
|
||||
if (ISSUPP_11ACMURXBEAMFORMEE(cap))
|
||||
vht_cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
|
||||
|
||||
if (ISSUPP_11ACMUTXBEAMFORMEE(cap))
|
||||
vht_cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
|
||||
|
||||
if (ISSUPP_11ACSUBEAMFORMER(cap))
|
||||
vht_cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
|
||||
|
||||
if (ISSUPP_11ACSUBEAMFORMEE(cap))
|
||||
vht_cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
|
||||
|
||||
if (ISSUPP_11ACRXSTBC(cap))
|
||||
vht_cap |= IEEE80211_VHT_CAP_RXSTBC_1;
|
||||
|
||||
if (ISSUPP_11ACTXSTBC(cap))
|
||||
vht_cap |= IEEE80211_VHT_CAP_TXSTBC;
|
||||
|
||||
if (ISSUPP_11ACSGI160(cap))
|
||||
vht_cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
|
||||
|
||||
if (ISSUPP_11ACSGI80(cap))
|
||||
vht_cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
|
||||
|
||||
if (ISSUPP_11ACLDPC(cap))
|
||||
vht_cap |= IEEE80211_VHT_CAP_RXLDPC;
|
||||
|
||||
if (ISSUPP_11ACBW8080(cap))
|
||||
vht_cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
|
||||
|
||||
if (ISSUPP_11ACBW160(cap))
|
||||
vht_cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
|
||||
|
||||
vht_info->cap = vht_cap;
|
||||
|
||||
/* Update MCS support for VHT */
|
||||
vht_info->vht_mcs.rx_mcs_map = cpu_to_le16(
|
||||
adapter->hw_dot_11ac_mcs_support & 0xFFFF);
|
||||
vht_info->vht_mcs.rx_highest = 0;
|
||||
vht_info->vht_mcs.tx_mcs_map = cpu_to_le16(
|
||||
adapter->hw_dot_11ac_mcs_support >> 16);
|
||||
vht_info->vht_mcs.tx_highest = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function sets up the CFG802.11 specific HT capability fields
|
||||
* with default values.
|
||||
@ -2092,11 +2214,18 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
||||
priv->netdev = dev;
|
||||
|
||||
mwifiex_setup_ht_caps(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv);
|
||||
if (adapter->is_hw_11ac_capable)
|
||||
mwifiex_setup_vht_caps(
|
||||
&wiphy->bands[IEEE80211_BAND_2GHZ]->vht_cap, priv);
|
||||
|
||||
if (adapter->config_bands & BAND_A)
|
||||
mwifiex_setup_ht_caps(
|
||||
&wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv);
|
||||
|
||||
if ((adapter->config_bands & BAND_A) && adapter->is_hw_11ac_capable)
|
||||
mwifiex_setup_vht_caps(
|
||||
&wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap, priv);
|
||||
|
||||
dev_net_set(dev, wiphy_net(wiphy));
|
||||
dev->ieee80211_ptr = priv->wdev;
|
||||
dev->ieee80211_ptr->iftype = priv->bss_mode;
|
||||
|
@ -106,8 +106,8 @@ u8 *mwifiex_11d_code_2_region(u8 code)
|
||||
* This function maps an index in supported rates table into
|
||||
* the corresponding data rate.
|
||||
*/
|
||||
u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv, u8 index,
|
||||
u8 ht_info)
|
||||
u32 mwifiex_index_to_acs_data_rate(struct mwifiex_private *priv,
|
||||
u8 index, u8 ht_info)
|
||||
{
|
||||
/*
|
||||
* For every mcs_rate line, the first 8 bytes are for stream 1x1,
|
||||
@ -130,10 +130,155 @@ u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv, u8 index,
|
||||
{ 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90,
|
||||
0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 }
|
||||
};
|
||||
/* AC rates */
|
||||
u16 ac_mcs_rate_nss1[8][10] = {
|
||||
/* LG 160M */
|
||||
{ 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
|
||||
0x492, 0x57C, 0x618 },
|
||||
|
||||
/* SG 160M */
|
||||
{ 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
|
||||
0x514, 0x618, 0x6C6 },
|
||||
|
||||
/* LG 80M */
|
||||
{ 0x3B, 0x75, 0xB0, 0xEA, 0x15F, 0x1D4, 0x20F,
|
||||
0x249, 0x2BE, 0x30C },
|
||||
|
||||
/* SG 80M */
|
||||
{ 0x41, 0x82, 0xC3, 0x104, 0x186, 0x208, 0x249,
|
||||
0x28A, 0x30C, 0x363 },
|
||||
|
||||
/* LG 40M */
|
||||
{ 0x1B, 0x36, 0x51, 0x6C, 0xA2, 0xD8, 0xF3,
|
||||
0x10E, 0x144, 0x168 },
|
||||
|
||||
/* SG 40M */
|
||||
{ 0x1E, 0x3C, 0x5A, 0x78, 0xB4, 0xF0, 0x10E,
|
||||
0x12C, 0x168, 0x190 },
|
||||
|
||||
/* LG 20M */
|
||||
{ 0xD, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75, 0x82, 0x9C, 0x00 },
|
||||
|
||||
/* SG 20M */
|
||||
{ 0xF, 0x1D, 0x2C, 0x3A, 0x57, 0x74, 0x82, 0x91, 0xAE, 0x00 },
|
||||
};
|
||||
/* NSS2 note: the value in the table is 2 multiplier of the actual
|
||||
* rate
|
||||
*/
|
||||
u16 ac_mcs_rate_nss2[8][10] = {
|
||||
/* LG 160M */
|
||||
{ 0xEA, 0x1D4, 0x2BE, 0x3A8, 0x57C, 0x750, 0x83A,
|
||||
0x924, 0xAF8, 0xC30 },
|
||||
|
||||
/* SG 160M */
|
||||
{ 0x104, 0x208, 0x30C, 0x410, 0x618, 0x820, 0x924,
|
||||
0xA28, 0xC30, 0xD8B },
|
||||
|
||||
/* LG 80M */
|
||||
{ 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
|
||||
0x492, 0x57C, 0x618 },
|
||||
|
||||
/* SG 80M */
|
||||
{ 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
|
||||
0x514, 0x618, 0x6C6 },
|
||||
|
||||
/* LG 40M */
|
||||
{ 0x36, 0x6C, 0xA2, 0xD8, 0x144, 0x1B0, 0x1E6,
|
||||
0x21C, 0x288, 0x2D0 },
|
||||
|
||||
/* SG 40M */
|
||||
{ 0x3C, 0x78, 0xB4, 0xF0, 0x168, 0x1E0, 0x21C,
|
||||
0x258, 0x2D0, 0x320 },
|
||||
|
||||
/* LG 20M */
|
||||
{ 0x1A, 0x34, 0x4A, 0x68, 0x9C, 0xD0, 0xEA, 0x104,
|
||||
0x138, 0x00 },
|
||||
|
||||
/* SG 20M */
|
||||
{ 0x1D, 0x3A, 0x57, 0x74, 0xAE, 0xE6, 0x104, 0x121,
|
||||
0x15B, 0x00 },
|
||||
};
|
||||
u32 rate = 0;
|
||||
u8 mcs_index = 0;
|
||||
u8 bw = 0;
|
||||
u8 gi = 0;
|
||||
|
||||
if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_VHT) {
|
||||
mcs_index = min(index & 0xF, 9);
|
||||
|
||||
/* 20M: bw=0, 40M: bw=1, 80M: bw=2, 160M: bw=3 */
|
||||
bw = (ht_info & 0xC) >> 2;
|
||||
|
||||
/* LGI: gi =0, SGI: gi = 1 */
|
||||
gi = (ht_info & 0x10) >> 4;
|
||||
|
||||
if ((index >> 4) == 1) /* NSS = 2 */
|
||||
rate = ac_mcs_rate_nss2[2 * (3 - bw) + gi][mcs_index];
|
||||
else /* NSS = 1 */
|
||||
rate = ac_mcs_rate_nss1[2 * (3 - bw) + gi][mcs_index];
|
||||
} else if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_HT) {
|
||||
/* 20M: bw=0, 40M: bw=1 */
|
||||
bw = (ht_info & 0xC) >> 2;
|
||||
|
||||
/* LGI: gi =0, SGI: gi = 1 */
|
||||
gi = (ht_info & 0x10) >> 4;
|
||||
|
||||
if (index == MWIFIEX_RATE_BITMAP_MCS0) {
|
||||
if (gi == 1)
|
||||
rate = 0x0D; /* MCS 32 SGI rate */
|
||||
else
|
||||
rate = 0x0C; /* MCS 32 LGI rate */
|
||||
} else if (index < 16) {
|
||||
if ((bw == 1) || (bw == 0))
|
||||
rate = mcs_rate[2 * (1 - bw) + gi][index];
|
||||
else
|
||||
rate = mwifiex_data_rates[0];
|
||||
} else {
|
||||
rate = mwifiex_data_rates[0];
|
||||
}
|
||||
} else {
|
||||
/* 11n non-HT rates */
|
||||
if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
|
||||
index = 0;
|
||||
rate = mwifiex_data_rates[index];
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
/* This function maps an index in supported rates table into
|
||||
* the corresponding data rate.
|
||||
*/
|
||||
u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv,
|
||||
u8 index, u8 ht_info)
|
||||
{
|
||||
/* For every mcs_rate line, the first 8 bytes are for stream 1x1,
|
||||
* and all 16 bytes are for stream 2x2.
|
||||
*/
|
||||
u16 mcs_rate[4][16] = {
|
||||
/* LGI 40M */
|
||||
{ 0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e,
|
||||
0x36, 0x6c, 0xa2, 0xd8, 0x144, 0x1b0, 0x1e6, 0x21c },
|
||||
|
||||
/* SGI 40M */
|
||||
{ 0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c,
|
||||
0x3c, 0x78, 0xb4, 0xf0, 0x168, 0x1e0, 0x21c, 0x258 },
|
||||
|
||||
/* LGI 20M */
|
||||
{ 0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82,
|
||||
0x1a, 0x34, 0x4e, 0x68, 0x9c, 0xd0, 0xea, 0x104 },
|
||||
|
||||
/* SGI 20M */
|
||||
{ 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90,
|
||||
0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 }
|
||||
};
|
||||
u32 mcs_num_supp =
|
||||
(priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) ? 16 : 8;
|
||||
u32 rate;
|
||||
|
||||
if (priv->adapter->is_hw_11ac_capable)
|
||||
return mwifiex_index_to_acs_data_rate(priv, index, ht_info);
|
||||
|
||||
if (ht_info & BIT(0)) {
|
||||
if (index == MWIFIEX_RATE_BITMAP_MCS0) {
|
||||
if (ht_info & BIT(2))
|
||||
@ -269,6 +414,7 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
|
||||
{
|
||||
u32 k = 0;
|
||||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
|
||||
if (priv->bss_mode == NL80211_IFTYPE_STATION) {
|
||||
switch (adapter->config_bands) {
|
||||
case BAND_B:
|
||||
@ -279,6 +425,7 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
|
||||
break;
|
||||
case BAND_G:
|
||||
case BAND_G | BAND_GN:
|
||||
case BAND_G | BAND_GN | BAND_GAC:
|
||||
dev_dbg(adapter->dev, "info: infra band=%d "
|
||||
"supported_rates_g\n", adapter->config_bands);
|
||||
k = mwifiex_copy_rates(rates, k, supported_rates_g,
|
||||
@ -288,7 +435,11 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
|
||||
case BAND_A | BAND_B | BAND_G:
|
||||
case BAND_A | BAND_B:
|
||||
case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
|
||||
case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN | BAND_AAC:
|
||||
case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN |
|
||||
BAND_AAC | BAND_GAC:
|
||||
case BAND_B | BAND_G | BAND_GN:
|
||||
case BAND_B | BAND_G | BAND_GN | BAND_GAC:
|
||||
dev_dbg(adapter->dev, "info: infra band=%d "
|
||||
"supported_rates_bg\n", adapter->config_bands);
|
||||
k = mwifiex_copy_rates(rates, k, supported_rates_bg,
|
||||
@ -301,14 +452,18 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
|
||||
k = mwifiex_copy_rates(rates, k, supported_rates_a,
|
||||
sizeof(supported_rates_a));
|
||||
break;
|
||||
case BAND_AN:
|
||||
case BAND_A | BAND_AN:
|
||||
case BAND_A | BAND_AN | BAND_AAC:
|
||||
case BAND_A | BAND_G | BAND_AN | BAND_GN:
|
||||
case BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC:
|
||||
dev_dbg(adapter->dev, "info: infra band=%d "
|
||||
"supported_rates_a\n", adapter->config_bands);
|
||||
k = mwifiex_copy_rates(rates, k, supported_rates_a,
|
||||
sizeof(supported_rates_a));
|
||||
break;
|
||||
case BAND_GN:
|
||||
case BAND_GN | BAND_GAC:
|
||||
dev_dbg(adapter->dev, "info: infra band=%d "
|
||||
"supported_rates_n\n", adapter->config_bands);
|
||||
k = mwifiex_copy_rates(rates, k, supported_rates_n,
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "main.h"
|
||||
#include "wmm.h"
|
||||
#include "11n.h"
|
||||
#include "11ac.h"
|
||||
|
||||
/*
|
||||
* This function initializes a command node.
|
||||
@ -1465,6 +1466,24 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
|
||||
adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number);
|
||||
adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna);
|
||||
|
||||
if (le32_to_cpu(hw_spec->dot_11ac_dev_cap)) {
|
||||
adapter->is_hw_11ac_capable = true;
|
||||
|
||||
/* Copy 11AC cap */
|
||||
adapter->hw_dot_11ac_dev_cap =
|
||||
le32_to_cpu(hw_spec->dot_11ac_dev_cap);
|
||||
adapter->usr_dot_11ac_dev_cap_bg = adapter->hw_dot_11ac_dev_cap;
|
||||
adapter->usr_dot_11ac_dev_cap_a = adapter->hw_dot_11ac_dev_cap;
|
||||
|
||||
/* Copy 11AC mcs */
|
||||
adapter->hw_dot_11ac_mcs_support =
|
||||
le32_to_cpu(hw_spec->dot_11ac_mcs_support);
|
||||
adapter->usr_dot_11ac_mcs_support =
|
||||
adapter->hw_dot_11ac_mcs_support;
|
||||
} else {
|
||||
adapter->is_hw_11ac_capable = false;
|
||||
}
|
||||
|
||||
dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n",
|
||||
adapter->fw_release_number);
|
||||
dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n",
|
||||
|
@ -49,13 +49,23 @@ struct tx_packet_hdr {
|
||||
#define A_SUPPORTED_RATES 9
|
||||
#define HOSTCMD_SUPPORTED_RATES 14
|
||||
#define N_SUPPORTED_RATES 3
|
||||
#define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN)
|
||||
#define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN | \
|
||||
BAND_AN | BAND_GAC | BAND_AAC)
|
||||
|
||||
#define FW_MULTI_BANDS_SUPPORT (BIT(8) | BIT(9) | BIT(10) | BIT(11))
|
||||
#define FW_MULTI_BANDS_SUPPORT (BIT(8) | BIT(9) | BIT(10) | BIT(11) | \
|
||||
BIT(12) | BIT(13))
|
||||
#define IS_SUPPORT_MULTI_BANDS(adapter) \
|
||||
(adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT)
|
||||
|
||||
/* shift bit 12 and bit 13 in fw_cap_info from the firmware to bit 13 and 14
|
||||
* for 11ac so that bit 11 is for GN, bit 12 for AN, bit 13 for GAC, and bit
|
||||
* bit 14 for AAC, in order to be compatible with the band capability
|
||||
* defined in the driver after right shift of 8 bits.
|
||||
*/
|
||||
#define GET_FW_DEFAULT_BANDS(adapter) \
|
||||
((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS)
|
||||
(((((adapter->fw_cap_info & 0x3000) << 1) | \
|
||||
(adapter->fw_cap_info & ~0xF000)) >> 8) & \
|
||||
ALL_802_11_BANDS)
|
||||
|
||||
#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff
|
||||
|
||||
@ -216,6 +226,47 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
|
||||
|
||||
#define LLC_SNAP_LEN 8
|
||||
|
||||
/* HW_SPEC fw_cap_info */
|
||||
|
||||
#define ISSUPP_11ACENABLED(fw_cap_info) (fw_cap_info & (BIT(13)|BIT(14)))
|
||||
|
||||
#define GET_VHTCAP_MAXMPDULEN(vht_cap_info) (vht_cap_info & 0x3)
|
||||
#define GET_VHTCAP_CHWDSET(vht_cap_info) ((vht_cap_info >> 2) & 0x3)
|
||||
#define GET_VHTNSSMCS(mcs_mapset, nss) ((mcs_mapset >> (2 * (nss - 1))) & 0x3)
|
||||
#define SET_VHTNSSMCS(mcs_mapset, nss, value) (mcs_mapset |= (value & 0x3) << \
|
||||
(2 * (nss - 1)))
|
||||
#define NO_NSS_SUPPORT 0x3
|
||||
|
||||
/* HW_SPEC: HTC-VHT supported */
|
||||
#define ISSUPP_11ACVHTHTCVHT(Dot11acDevCap) (Dot11acDevCap & BIT(22))
|
||||
/* HW_SPEC: VHT TXOP PS support */
|
||||
#define ISSUPP_11ACVHTTXOPPS(Dot11acDevCap) (Dot11acDevCap & BIT(21))
|
||||
/* HW_SPEC: MU RX beamformee support */
|
||||
#define ISSUPP_11ACMURXBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & BIT(20))
|
||||
/* HW_SPEC: MU TX beamformee support */
|
||||
#define ISSUPP_11ACMUTXBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & BIT(19))
|
||||
/* HW_SPEC: SU Beamformee support */
|
||||
#define ISSUPP_11ACSUBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & BIT(10))
|
||||
/* HW_SPEC: SU Beamformer support */
|
||||
#define ISSUPP_11ACSUBEAMFORMER(Dot11acDevCap) (Dot11acDevCap & BIT(9))
|
||||
/* HW_SPEC: Rx STBC support */
|
||||
#define ISSUPP_11ACRXSTBC(Dot11acDevCap) (Dot11acDevCap & BIT(8))
|
||||
/* HW_SPEC: Tx STBC support */
|
||||
#define ISSUPP_11ACTXSTBC(Dot11acDevCap) (Dot11acDevCap & BIT(7))
|
||||
/* HW_SPEC: Short GI support for 160MHz BW */
|
||||
#define ISSUPP_11ACSGI160(Dot11acDevCap) (Dot11acDevCap & BIT(6))
|
||||
/* HW_SPEC: Short GI support for 80MHz BW */
|
||||
#define ISSUPP_11ACSGI80(Dot11acDevCap) (Dot11acDevCap & BIT(5))
|
||||
/* HW_SPEC: LDPC coding support */
|
||||
#define ISSUPP_11ACLDPC(Dot11acDevCap) (Dot11acDevCap & BIT(4))
|
||||
/* HW_SPEC: Channel BW 20/40/80/160/80+80 MHz support */
|
||||
#define ISSUPP_11ACBW8080(Dot11acDevCap) (Dot11acDevCap & BIT(3))
|
||||
/* HW_SPEC: Channel BW 20/40/80/160 MHz support */
|
||||
#define ISSUPP_11ACBW160(Dot11acDevCap) (Dot11acDevCap & BIT(2))
|
||||
|
||||
#define GET_DEVTXMCSMAP(dev_mcs_map) (dev_mcs_map >> 16)
|
||||
#define GET_DEVRXMCSMAP(dev_mcs_map) (dev_mcs_map & 0xFFFF)
|
||||
|
||||
#define MOD_CLASS_HR_DSSS 0x03
|
||||
#define MOD_CLASS_OFDM 0x07
|
||||
#define MOD_CLASS_HT 0x08
|
||||
@ -455,9 +506,22 @@ struct rxpd {
|
||||
u8 rx_rate;
|
||||
s8 snr;
|
||||
s8 nf;
|
||||
/* Ht Info [Bit 0] RxRate format: LG=0, HT=1
|
||||
|
||||
/* For: Non-802.11 AC cards
|
||||
*
|
||||
* Ht Info [Bit 0] RxRate format: LG=0, HT=1
|
||||
* [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1
|
||||
* [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */
|
||||
* [Bit 2] HT Guard Interval: LGI = 0, SGI = 1
|
||||
*
|
||||
* For: 802.11 AC cards
|
||||
* [Bit 1] [Bit 0] RxRate format: legacy rate = 00 HT = 01 VHT = 10
|
||||
* [Bit 3] [Bit 2] HT/VHT Bandwidth BW20 = 00 BW40 = 01
|
||||
* BW80 = 10 BW160 = 11
|
||||
* [Bit 4] HT/VHT Guard interval LGI = 0 SGI = 1
|
||||
* [Bit 5] STBC support Enabled = 1
|
||||
* [Bit 6] LDPC support Enabled = 1
|
||||
* [Bit 7] Reserved
|
||||
*/
|
||||
u8 ht_info;
|
||||
u8 reserved;
|
||||
} __packed;
|
||||
@ -680,7 +744,11 @@ struct host_cmd_ds_get_hw_spec {
|
||||
__le32 dot_11n_dev_cap;
|
||||
u8 dev_mcs_support;
|
||||
__le16 mp_end_port; /* SDIO only, reserved for other interfacces */
|
||||
__le16 reserved_4;
|
||||
__le16 mgmt_buf_count; /* mgmt IE buffer count */
|
||||
__le32 reserved_5;
|
||||
__le32 reserved_6;
|
||||
__le32 dot_11ac_dev_cap;
|
||||
__le32 dot_11ac_mcs_support;
|
||||
} __packed;
|
||||
|
||||
struct host_cmd_ds_802_11_rssi_info {
|
||||
@ -786,6 +854,12 @@ union ieee_types_phy_param_set {
|
||||
struct ieee_types_ds_param_set ds_param_set;
|
||||
} __packed;
|
||||
|
||||
struct ieee_types_oper_mode_ntf {
|
||||
u8 element_id;
|
||||
u8 len;
|
||||
u8 oper_mode;
|
||||
} __packed;
|
||||
|
||||
struct host_cmd_ds_802_11_ad_hoc_start {
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
u8 bss_mode;
|
||||
@ -846,11 +920,27 @@ struct host_cmd_ds_802_11_get_log {
|
||||
__le32 wep_icv_err_cnt[4];
|
||||
};
|
||||
|
||||
/* Enumeration for rate format */
|
||||
enum _mwifiex_rate_format {
|
||||
MWIFIEX_RATE_FORMAT_LG = 0,
|
||||
MWIFIEX_RATE_FORMAT_HT,
|
||||
MWIFIEX_RATE_FORMAT_VHT,
|
||||
MWIFIEX_RATE_FORMAT_AUTO = 0xFF,
|
||||
};
|
||||
|
||||
struct host_cmd_ds_tx_rate_query {
|
||||
u8 tx_rate;
|
||||
/* Ht Info [Bit 0] RxRate format: LG=0, HT=1
|
||||
/* Tx Rate Info: For 802.11 AC cards
|
||||
*
|
||||
* [Bit 0-1] tx rate formate: LG = 0, HT = 1, VHT = 2
|
||||
* [Bit 2-3] HT/VHT Bandwidth: BW20 = 0, BW40 = 1, BW80 = 2, BW160 = 3
|
||||
* [Bit 4] HT/VHT Guard Interval: LGI = 0, SGI = 1
|
||||
*
|
||||
* For non-802.11 AC cards
|
||||
* Ht Info [Bit 0] RxRate format: LG=0, HT=1
|
||||
* [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1
|
||||
* [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */
|
||||
* [Bit 2] HT Guard Interval: LGI = 0, SGI = 1
|
||||
*/
|
||||
u8 ht_info;
|
||||
} __packed;
|
||||
|
||||
@ -1096,6 +1186,7 @@ struct host_cmd_ds_11n_cfg {
|
||||
__le16 action;
|
||||
__le16 ht_tx_cap;
|
||||
__le16 ht_tx_info;
|
||||
__le16 misc_config; /* Needed for 802.11AC cards only */
|
||||
} __packed;
|
||||
|
||||
struct host_cmd_ds_txbuf_cfg {
|
||||
@ -1183,6 +1274,26 @@ struct mwifiex_ie_types_htcap {
|
||||
struct ieee80211_ht_cap ht_cap;
|
||||
} __packed;
|
||||
|
||||
struct mwifiex_ie_types_vhtcap {
|
||||
struct mwifiex_ie_types_header header;
|
||||
struct ieee80211_vht_cap vht_cap;
|
||||
} __packed;
|
||||
|
||||
struct mwifiex_ie_types_oper_mode_ntf {
|
||||
struct mwifiex_ie_types_header header;
|
||||
u8 oper_mode;
|
||||
} __packed;
|
||||
|
||||
/* VHT Operations IE */
|
||||
struct mwifiex_ie_types_vht_oper {
|
||||
struct mwifiex_ie_types_header header;
|
||||
u8 chan_width;
|
||||
u8 chan_center_freq_1;
|
||||
u8 chan_center_freq_2;
|
||||
/* Basic MCS set map, each 2 bits stands for a NSS */
|
||||
u16 basic_mcs_map;
|
||||
} __packed;
|
||||
|
||||
struct mwifiex_ie_types_wmmcap {
|
||||
struct mwifiex_ie_types_header header;
|
||||
struct mwifiex_types_wmm_info wmm_info;
|
||||
|
@ -60,6 +60,8 @@ enum {
|
||||
BAND_A = 4,
|
||||
BAND_GN = 8,
|
||||
BAND_AN = 16,
|
||||
BAND_GAC = 32,
|
||||
BAND_AAC = 64,
|
||||
};
|
||||
|
||||
#define MWIFIEX_WPA_PASSHPHRASE_LEN 64
|
||||
@ -103,6 +105,7 @@ struct mwifiex_uap_bss_param {
|
||||
struct wpa_param wpa_cfg;
|
||||
struct wep_key wep_cfg[NUM_WEP_KEYS];
|
||||
struct ieee80211_ht_cap ht_cap;
|
||||
struct ieee80211_vht_cap vht_cap;
|
||||
u8 rates[MWIFIEX_SUPPORTED_RATES];
|
||||
u32 sta_ao_timer;
|
||||
u32 ps_sta_ao_timer;
|
||||
@ -272,6 +275,7 @@ struct mwifiex_ds_pm_cfg {
|
||||
struct mwifiex_ds_11n_tx_cfg {
|
||||
u16 tx_htcap;
|
||||
u16 tx_htinfo;
|
||||
u16 misc_config; /* Needed for 802.11AC cards only */
|
||||
};
|
||||
|
||||
struct mwifiex_ds_11n_amsdu_aggr_ctrl {
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "main.h"
|
||||
#include "wmm.h"
|
||||
#include "11n.h"
|
||||
#include "11ac.h"
|
||||
|
||||
#define CAPINFO_MASK (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9)))
|
||||
|
||||
@ -512,6 +513,12 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
|
||||
priv->adapter->config_bands & BAND_AN))
|
||||
mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos);
|
||||
|
||||
if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
|
||||
!bss_desc->disable_11n && !bss_desc->disable_11ac &&
|
||||
(priv->adapter->config_bands & BAND_GAC ||
|
||||
priv->adapter->config_bands & BAND_AAC))
|
||||
mwifiex_cmd_append_11ac_tlv(priv, bss_desc, &pos);
|
||||
|
||||
/* Append vendor specific IE TLV */
|
||||
mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos);
|
||||
|
||||
@ -1421,6 +1428,7 @@ mwifiex_band_to_radio_type(u8 band)
|
||||
case BAND_A:
|
||||
case BAND_AN:
|
||||
case BAND_A | BAND_AN:
|
||||
case BAND_A | BAND_AN | BAND_AAC:
|
||||
return HostCmd_SCAN_RADIO_TYPE_A;
|
||||
case BAND_B:
|
||||
case BAND_G:
|
||||
|
@ -295,6 +295,13 @@ struct mwifiex_bssdescriptor {
|
||||
u16 bss_co_2040_offset;
|
||||
u8 *bcn_ext_cap;
|
||||
u16 ext_cap_offset;
|
||||
struct ieee80211_vht_cap *bcn_vht_cap;
|
||||
u16 vht_cap_offset;
|
||||
struct ieee80211_vht_operation *bcn_vht_oper;
|
||||
u16 vht_info_offset;
|
||||
struct ieee_types_oper_mode_ntf *oper_mode;
|
||||
u16 oper_mode_offset;
|
||||
u8 disable_11ac;
|
||||
struct ieee_types_vendor_specific *bcn_wpa_ie;
|
||||
u16 wpa_offset;
|
||||
struct ieee_types_generic *bcn_rsn_ie;
|
||||
@ -499,6 +506,7 @@ struct mwifiex_private {
|
||||
u16 rsn_idx;
|
||||
struct timer_list scan_delay_timer;
|
||||
u8 ap_11n_enabled;
|
||||
u8 ap_11ac_enabled;
|
||||
u32 mgmt_frame_mask;
|
||||
struct mwifiex_roc_cfg roc_cfg;
|
||||
};
|
||||
@ -722,6 +730,15 @@ struct mwifiex_adapter {
|
||||
u16 max_mgmt_ie_index;
|
||||
u8 scan_delay_cnt;
|
||||
u8 empty_tx_q_cnt;
|
||||
|
||||
/* 11AC */
|
||||
u32 is_hw_11ac_capable;
|
||||
u32 hw_dot_11ac_dev_cap;
|
||||
u32 hw_dot_11ac_mcs_support;
|
||||
u32 usr_dot_11ac_dev_cap_bg;
|
||||
u32 usr_dot_11ac_dev_cap_a;
|
||||
u32 usr_dot_11ac_mcs_support;
|
||||
|
||||
atomic_t is_tx_received;
|
||||
atomic_t pending_bridged_pkts;
|
||||
};
|
||||
@ -864,8 +881,10 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
|
||||
int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd);
|
||||
struct mwifiex_chan_freq_power *mwifiex_get_cfp(struct mwifiex_private *priv,
|
||||
u8 band, u16 channel, u32 freq);
|
||||
u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv, u8 index,
|
||||
u8 ht_info);
|
||||
u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv,
|
||||
u8 index, u8 ht_info);
|
||||
u32 mwifiex_index_to_acs_data_rate(struct mwifiex_private *priv,
|
||||
u8 index, u8 ht_info);
|
||||
u32 mwifiex_find_freq_from_band_chan(u8, u8);
|
||||
int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask,
|
||||
u8 **buffer);
|
||||
|
@ -1023,10 +1023,7 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
|
||||
adapter->data_sent = false;
|
||||
|
||||
if (card->txbd_flush) {
|
||||
if (((card->txbd_wrptr & reg->tx_mask) ==
|
||||
(card->txbd_rdptr & reg->tx_mask)) &&
|
||||
((card->txbd_wrptr & reg->tx_rollover_ind) !=
|
||||
(card->txbd_rdptr & reg->tx_rollover_ind)))
|
||||
if (mwifiex_pcie_txbd_empty(card, card->txbd_rdptr))
|
||||
card->txbd_flush = 0;
|
||||
else
|
||||
mwifiex_clean_pcie_ring_buf(adapter);
|
||||
|
@ -1250,6 +1250,23 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
|
||||
sizeof(struct ieee_types_header) -
|
||||
bss_entry->beacon_buf);
|
||||
break;
|
||||
case WLAN_EID_VHT_CAPABILITY:
|
||||
bss_entry->disable_11ac = false;
|
||||
bss_entry->bcn_vht_cap =
|
||||
(void *)(current_ptr +
|
||||
sizeof(struct ieee_types_header));
|
||||
bss_entry->vht_cap_offset =
|
||||
(u16)((u8 *)bss_entry->bcn_vht_cap -
|
||||
bss_entry->beacon_buf);
|
||||
break;
|
||||
case WLAN_EID_VHT_OPERATION:
|
||||
bss_entry->bcn_vht_oper =
|
||||
(void *)(current_ptr +
|
||||
sizeof(struct ieee_types_header));
|
||||
bss_entry->vht_info_offset =
|
||||
(u16)((u8 *)bss_entry->bcn_vht_oper -
|
||||
bss_entry->beacon_buf);
|
||||
break;
|
||||
case WLAN_EID_BSS_COEX_2040:
|
||||
bss_entry->bcn_bss_co_2040 = current_ptr +
|
||||
sizeof(struct ieee_types_header);
|
||||
@ -1264,6 +1281,14 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
|
||||
sizeof(struct ieee_types_header) -
|
||||
bss_entry->beacon_buf);
|
||||
break;
|
||||
case WLAN_EID_OPMODE_NOTIF:
|
||||
bss_entry->oper_mode =
|
||||
(void *)(current_ptr +
|
||||
sizeof(struct ieee_types_header));
|
||||
bss_entry->oper_mode_offset =
|
||||
(u16)((u8 *)bss_entry->oper_mode -
|
||||
bss_entry->beacon_buf);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1479,20 +1504,26 @@ static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
|
||||
priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL;
|
||||
priv->curr_bss_params.bss_descriptor.wapi_offset = 0;
|
||||
priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL;
|
||||
priv->curr_bss_params.bss_descriptor.ht_cap_offset =
|
||||
0;
|
||||
priv->curr_bss_params.bss_descriptor.ht_cap_offset = 0;
|
||||
priv->curr_bss_params.bss_descriptor.bcn_ht_oper = NULL;
|
||||
priv->curr_bss_params.bss_descriptor.ht_info_offset =
|
||||
0;
|
||||
priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 =
|
||||
NULL;
|
||||
priv->curr_bss_params.bss_descriptor.
|
||||
bss_co_2040_offset = 0;
|
||||
priv->curr_bss_params.bss_descriptor.ht_info_offset = 0;
|
||||
priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = NULL;
|
||||
priv->curr_bss_params.bss_descriptor.bss_co_2040_offset = 0;
|
||||
priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL;
|
||||
priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0;
|
||||
priv->curr_bss_params.bss_descriptor.beacon_buf = NULL;
|
||||
priv->curr_bss_params.bss_descriptor.beacon_buf_size =
|
||||
0;
|
||||
priv->curr_bss_params.bss_descriptor.beacon_buf_size = 0;
|
||||
priv->curr_bss_params.bss_descriptor.bcn_vht_cap = NULL;
|
||||
priv->curr_bss_params.bss_descriptor.vht_cap_offset = 0;
|
||||
priv->curr_bss_params.bss_descriptor.bcn_vht_oper = NULL;
|
||||
priv->curr_bss_params.bss_descriptor.vht_info_offset = 0;
|
||||
priv->curr_bss_params.bss_descriptor.oper_mode = NULL;
|
||||
priv->curr_bss_params.bss_descriptor.oper_mode_offset = 0;
|
||||
|
||||
/* Disable 11ac by default. Enable it only where there
|
||||
* exist VHT_CAP IE in AP beacon
|
||||
*/
|
||||
priv->curr_bss_params.bss_descriptor.disable_11ac = true;
|
||||
|
||||
/* Make a copy of current BSSID descriptor */
|
||||
memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc,
|
||||
@ -2022,6 +2053,14 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
|
||||
(curr_bss->beacon_buf +
|
||||
curr_bss->ht_info_offset);
|
||||
|
||||
if (curr_bss->bcn_vht_cap)
|
||||
curr_bss->bcn_ht_cap = (void *)(curr_bss->beacon_buf +
|
||||
curr_bss->vht_cap_offset);
|
||||
|
||||
if (curr_bss->bcn_vht_oper)
|
||||
curr_bss->bcn_ht_oper = (void *)(curr_bss->beacon_buf +
|
||||
curr_bss->vht_info_offset);
|
||||
|
||||
if (curr_bss->bcn_bss_co_2040)
|
||||
curr_bss->bcn_bss_co_2040 =
|
||||
(curr_bss->beacon_buf + curr_bss->bss_co_2040_offset);
|
||||
@ -2029,6 +2068,10 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
|
||||
if (curr_bss->bcn_ext_cap)
|
||||
curr_bss->bcn_ext_cap = curr_bss->beacon_buf +
|
||||
curr_bss->ext_cap_offset;
|
||||
|
||||
if (curr_bss->oper_mode)
|
||||
curr_bss->oper_mode = (void *)(curr_bss->beacon_buf +
|
||||
curr_bss->oper_mode_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1230,7 +1230,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
|
||||
data_buf);
|
||||
break;
|
||||
case HostCmd_CMD_11N_CFG:
|
||||
ret = mwifiex_cmd_11n_cfg(cmd_ptr, cmd_action, data_buf);
|
||||
ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action, data_buf);
|
||||
break;
|
||||
case HostCmd_CMD_WMM_GET_STATUS:
|
||||
dev_dbg(priv->adapter->dev,
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "main.h"
|
||||
#include "wmm.h"
|
||||
#include "11n.h"
|
||||
#include "11ac.h"
|
||||
|
||||
|
||||
/*
|
||||
|
@ -281,9 +281,10 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
|
||||
|
||||
if (mwifiex_band_to_radio_type((u8) bss_desc->bss_band)
|
||||
== HostCmd_SCAN_RADIO_TYPE_BG)
|
||||
config_bands = BAND_B | BAND_G | BAND_GN;
|
||||
config_bands = BAND_B | BAND_G | BAND_GN |
|
||||
BAND_GAC;
|
||||
else
|
||||
config_bands = BAND_A | BAND_AN;
|
||||
config_bands = BAND_A | BAND_AN | BAND_AAC;
|
||||
|
||||
if (!((config_bands | adapter->fw_bands) &
|
||||
~adapter->fw_bands))
|
||||
|
@ -804,10 +804,15 @@ static inline int ezusb_8051_cpucs(struct ezusb_priv *upriv, int reset)
|
||||
static int ezusb_firmware_download(struct ezusb_priv *upriv,
|
||||
struct ez_usb_fw *fw)
|
||||
{
|
||||
u8 fw_buffer[FW_BUF_SIZE];
|
||||
u8 *fw_buffer;
|
||||
int retval, addr;
|
||||
int variant_offset;
|
||||
|
||||
fw_buffer = kmalloc(FW_BUF_SIZE, GFP_KERNEL);
|
||||
if (!fw_buffer) {
|
||||
printk(KERN_ERR PFX "Out of memory for firmware buffer.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
/*
|
||||
* This byte is 1 and should be replaced with 0. The offset is
|
||||
* 0x10AD in version 0.0.6. The byte in question should follow
|
||||
@ -859,6 +864,7 @@ static int ezusb_firmware_download(struct ezusb_priv *upriv,
|
||||
printk(KERN_ERR PFX "Firmware download failed, error %d\n",
|
||||
retval);
|
||||
exit:
|
||||
kfree(fw_buffer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1681,7 +1687,8 @@ static int ezusb_probe(struct usb_interface *interface,
|
||||
firmware.code = fw_entry->data;
|
||||
}
|
||||
if (firmware.size && firmware.code) {
|
||||
ezusb_firmware_download(upriv, &firmware);
|
||||
if (ezusb_firmware_download(upriv, &firmware))
|
||||
goto error;
|
||||
} else {
|
||||
err("No firmware to download");
|
||||
goto error;
|
||||
|
@ -42,8 +42,12 @@
|
||||
|
||||
static void usbctrl_async_callback(struct urb *urb)
|
||||
{
|
||||
if (urb)
|
||||
kfree(urb->context);
|
||||
if (urb) {
|
||||
/* free dr */
|
||||
kfree(urb->setup_packet);
|
||||
/* free databuf */
|
||||
kfree(urb->transfer_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
|
||||
@ -55,25 +59,31 @@ static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
|
||||
u8 reqtype;
|
||||
struct usb_ctrlrequest *dr;
|
||||
struct urb *urb;
|
||||
struct rtl819x_async_write_data {
|
||||
u8 data[REALTEK_USB_VENQT_MAX_BUF_SIZE];
|
||||
struct usb_ctrlrequest dr;
|
||||
} *buf;
|
||||
const u16 databuf_maxlen = REALTEK_USB_VENQT_MAX_BUF_SIZE;
|
||||
u8 *databuf;
|
||||
|
||||
if (WARN_ON_ONCE(len > databuf_maxlen))
|
||||
len = databuf_maxlen;
|
||||
|
||||
pipe = usb_sndctrlpipe(udev, 0); /* write_out */
|
||||
reqtype = REALTEK_USB_VENQT_WRITE;
|
||||
|
||||
buf = kmalloc(sizeof(*buf), GFP_ATOMIC);
|
||||
if (!buf)
|
||||
dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
|
||||
if (!dr)
|
||||
return -ENOMEM;
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!urb) {
|
||||
kfree(buf);
|
||||
databuf = kmalloc(databuf_maxlen, GFP_ATOMIC);
|
||||
if (!databuf) {
|
||||
kfree(dr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dr = &buf->dr;
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!urb) {
|
||||
kfree(databuf);
|
||||
kfree(dr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dr->bRequestType = reqtype;
|
||||
dr->bRequest = request;
|
||||
@ -81,13 +91,15 @@ static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
|
||||
dr->wIndex = cpu_to_le16(index);
|
||||
dr->wLength = cpu_to_le16(len);
|
||||
/* data are already in little-endian order */
|
||||
memcpy(buf, pdata, len);
|
||||
memcpy(databuf, pdata, len);
|
||||
usb_fill_control_urb(urb, udev, pipe,
|
||||
(unsigned char *)dr, buf, len,
|
||||
usbctrl_async_callback, buf);
|
||||
(unsigned char *)dr, databuf, len,
|
||||
usbctrl_async_callback, NULL);
|
||||
rc = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (rc < 0)
|
||||
kfree(buf);
|
||||
if (rc < 0) {
|
||||
kfree(databuf);
|
||||
kfree(dr);
|
||||
}
|
||||
usb_free_urb(urb);
|
||||
return rc;
|
||||
}
|
||||
|
@ -1500,13 +1500,13 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
err = mesh_path_add(dst, sdata);
|
||||
err = mesh_path_add(sdata, dst);
|
||||
if (err) {
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
mpath = mesh_path_lookup(dst, sdata);
|
||||
mpath = mesh_path_lookup(sdata, dst);
|
||||
if (!mpath) {
|
||||
rcu_read_unlock();
|
||||
return -ENXIO;
|
||||
@ -1518,12 +1518,12 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
|
||||
}
|
||||
|
||||
static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 *dst)
|
||||
u8 *dst)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (dst)
|
||||
return mesh_path_del(dst, sdata);
|
||||
return mesh_path_del(sdata, dst);
|
||||
|
||||
mesh_path_flush_by_iface(sdata);
|
||||
return 0;
|
||||
@ -1547,7 +1547,7 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
mpath = mesh_path_lookup(dst, sdata);
|
||||
mpath = mesh_path_lookup(sdata, dst);
|
||||
if (!mpath) {
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
@ -1611,7 +1611,7 @@ static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
rcu_read_lock();
|
||||
mpath = mesh_path_lookup(dst, sdata);
|
||||
mpath = mesh_path_lookup(sdata, dst);
|
||||
if (!mpath) {
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
@ -1632,7 +1632,7 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
rcu_read_lock();
|
||||
mpath = mesh_path_lookup_by_idx(idx, sdata);
|
||||
mpath = mesh_path_lookup_by_idx(sdata, idx);
|
||||
if (!mpath) {
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
|
@ -294,7 +294,8 @@ static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata)
|
||||
}
|
||||
}
|
||||
|
||||
if ((sdata->vif.type != NL80211_IFTYPE_AP) ||
|
||||
if ((sdata->vif.type != NL80211_IFTYPE_AP &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MESH_POINT) ||
|
||||
!(sdata->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) {
|
||||
sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
|
||||
return 0;
|
||||
@ -695,6 +696,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ieee80211_roc_purge(sdata);
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
ieee80211_mgd_stop(sdata);
|
||||
|
||||
/*
|
||||
* Remove all stations associated with this interface.
|
||||
*
|
||||
@ -782,8 +786,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&ps->bc_buf.lock, flags);
|
||||
} else if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
ieee80211_mgd_stop(sdata);
|
||||
}
|
||||
|
||||
if (going_down)
|
||||
|
@ -1173,8 +1173,7 @@ static void __exit ieee80211_exit(void)
|
||||
rc80211_minstrel_ht_exit();
|
||||
rc80211_minstrel_exit();
|
||||
|
||||
if (mesh_allocated)
|
||||
ieee80211s_stop();
|
||||
ieee80211s_stop();
|
||||
|
||||
ieee80211_iface_exit();
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
#define TMR_RUNNING_MP 1
|
||||
#define TMR_RUNNING_MPR 2
|
||||
|
||||
int mesh_allocated;
|
||||
static int mesh_allocated;
|
||||
static struct kmem_cache *rm_cache;
|
||||
|
||||
bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
|
||||
@ -36,6 +36,8 @@ void ieee80211s_init(void)
|
||||
|
||||
void ieee80211s_stop(void)
|
||||
{
|
||||
if (!mesh_allocated)
|
||||
return;
|
||||
mesh_pathtbl_unregister();
|
||||
kmem_cache_destroy(rm_cache);
|
||||
}
|
||||
@ -90,24 +92,22 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
|
||||
(ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) &&
|
||||
(ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) &&
|
||||
(ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)))
|
||||
goto mismatch;
|
||||
return false;
|
||||
|
||||
ieee80211_sta_get_rates(local, ie, ieee80211_get_sdata_band(sdata),
|
||||
&basic_rates);
|
||||
|
||||
if (sdata->vif.bss_conf.basic_rates != basic_rates)
|
||||
goto mismatch;
|
||||
return false;
|
||||
|
||||
ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
|
||||
ie->ht_operation, &sta_chan_def);
|
||||
|
||||
if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
|
||||
&sta_chan_def))
|
||||
goto mismatch;
|
||||
return false;
|
||||
|
||||
return true;
|
||||
mismatch:
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,7 +118,7 @@ mismatch:
|
||||
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
|
||||
{
|
||||
return (ie->mesh_config->meshconf_cap &
|
||||
IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS) != 0;
|
||||
IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -196,11 +196,12 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
|
||||
if (!sdata->u.mesh.rmc)
|
||||
return;
|
||||
|
||||
for (i = 0; i < RMC_BUCKETS; i++)
|
||||
for (i = 0; i < RMC_BUCKETS; i++) {
|
||||
list_for_each_entry_safe(p, n, &rmc->bucket[i], list) {
|
||||
list_del(&p->list);
|
||||
kmem_cache_free(rm_cache, p);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(rmc);
|
||||
sdata->u.mesh.rmc = NULL;
|
||||
@ -209,6 +210,7 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
|
||||
/**
|
||||
* mesh_rmc_check - Check frame in recent multicast cache and add if absent.
|
||||
*
|
||||
* @sdata: interface
|
||||
* @sa: source address
|
||||
* @mesh_hdr: mesh_header
|
||||
*
|
||||
@ -218,8 +220,8 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
|
||||
* received this frame lately. If the frame is not in the cache, it is added to
|
||||
* it.
|
||||
*/
|
||||
int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *sa, struct ieee80211s_hdr *mesh_hdr)
|
||||
{
|
||||
struct mesh_rmc *rmc = sdata->u.mesh.rmc;
|
||||
u32 seqnum = 0;
|
||||
@ -233,12 +235,11 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
|
||||
list_for_each_entry_safe(p, n, &rmc->bucket[idx], list) {
|
||||
++entries;
|
||||
if (time_after(jiffies, p->exp_time) ||
|
||||
(entries == RMC_QUEUE_MAX_LEN)) {
|
||||
entries == RMC_QUEUE_MAX_LEN) {
|
||||
list_del(&p->list);
|
||||
kmem_cache_free(rm_cache, p);
|
||||
--entries;
|
||||
} else if ((seqnum == p->seqnum) &&
|
||||
(ether_addr_equal(sa, p->sa)))
|
||||
} else if ((seqnum == p->seqnum) && ether_addr_equal(sa, p->sa))
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -253,8 +254,8 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
|
||||
int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
u8 *pos, neighbors;
|
||||
@ -285,19 +286,18 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
|
||||
/* Mesh capability */
|
||||
*pos = IEEE80211_MESHCONF_CAPAB_FORWARDING;
|
||||
*pos |= ifmsh->accepting_plinks ?
|
||||
IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
|
||||
IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
|
||||
/* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */
|
||||
*pos |= ifmsh->ps_peers_deep_sleep ?
|
||||
IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00;
|
||||
IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00;
|
||||
*pos++ |= ifmsh->adjusting_tbtt ?
|
||||
IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00;
|
||||
IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00;
|
||||
*pos++ = 0x00;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mesh_add_meshid_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
|
||||
int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
u8 *pos;
|
||||
@ -314,8 +314,8 @@ mesh_add_meshid_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mesh_add_awake_window_ie(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
static int mesh_add_awake_window_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
u8 *pos;
|
||||
@ -337,8 +337,8 @@ int mesh_add_awake_window_ie(struct sk_buff *skb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
|
||||
int mesh_add_vendor_ies(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
u8 offset, len;
|
||||
@ -361,8 +361,7 @@ mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
|
||||
int mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
u8 len = 0;
|
||||
@ -390,8 +389,8 @@ mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mesh_add_ds_params_ie(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
static int mesh_add_ds_params_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_channel *chan;
|
||||
@ -417,8 +416,8 @@ int mesh_add_ds_params_ie(struct sk_buff *skb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mesh_add_ht_cap_ie(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
|
||||
@ -439,8 +438,8 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mesh_add_ht_oper_ie(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
@ -475,6 +474,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ieee80211_mesh_path_timer(unsigned long data)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
@ -520,7 +520,7 @@ void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
|
||||
|
||||
/**
|
||||
* ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
|
||||
* @hdr: 802.11 frame header
|
||||
* @hdr: 802.11 frame header
|
||||
* @fc: frame control field
|
||||
* @meshda: destination address in the mesh
|
||||
* @meshsa: source address address in the mesh. Same as TA, as frame is
|
||||
@ -551,8 +551,8 @@ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
|
||||
|
||||
/**
|
||||
* ieee80211_new_mesh_header - create a new mesh header
|
||||
* @meshhdr: uninitialized mesh header
|
||||
* @sdata: mesh interface to be used
|
||||
* @meshhdr: uninitialized mesh header
|
||||
* @addr4or5: 1st address in the ae header, which may correspond to address 4
|
||||
* (if addr6 is NULL) or address 5 (if addr6 is present). It may
|
||||
* be NULL.
|
||||
@ -561,32 +561,38 @@ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
|
||||
*
|
||||
* Return the header length.
|
||||
*/
|
||||
int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
|
||||
struct ieee80211_sub_if_data *sdata, char *addr4or5,
|
||||
char *addr6)
|
||||
int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211s_hdr *meshhdr,
|
||||
const char *addr4or5, const char *addr6)
|
||||
{
|
||||
int aelen = 0;
|
||||
BUG_ON(!addr4or5 && addr6);
|
||||
if (WARN_ON(!addr4or5 && addr6))
|
||||
return 0;
|
||||
|
||||
memset(meshhdr, 0, sizeof(*meshhdr));
|
||||
|
||||
meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
|
||||
|
||||
/* FIXME: racy -- TX on multiple queues can be concurrent */
|
||||
put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum);
|
||||
sdata->u.mesh.mesh_seqnum++;
|
||||
|
||||
if (addr4or5 && !addr6) {
|
||||
meshhdr->flags |= MESH_FLAGS_AE_A4;
|
||||
aelen += ETH_ALEN;
|
||||
memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
|
||||
return 2 * ETH_ALEN;
|
||||
} else if (addr4or5 && addr6) {
|
||||
meshhdr->flags |= MESH_FLAGS_AE_A5_A6;
|
||||
aelen += 2 * ETH_ALEN;
|
||||
memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
|
||||
memcpy(meshhdr->eaddr2, addr6, ETH_ALEN);
|
||||
return 3 * ETH_ALEN;
|
||||
}
|
||||
return 6 + aelen;
|
||||
|
||||
return ETH_ALEN;
|
||||
}
|
||||
|
||||
static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_if_mesh *ifmsh)
|
||||
static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
u32 changed;
|
||||
|
||||
ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
|
||||
@ -596,7 +602,8 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_mbss_info_change_notify(sdata, changed);
|
||||
|
||||
mod_timer(&ifmsh->housekeeping_timer,
|
||||
round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
|
||||
round_jiffies(jiffies +
|
||||
IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
|
||||
}
|
||||
|
||||
static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
|
||||
@ -708,7 +715,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
|
||||
*pos++ = 0x0;
|
||||
|
||||
if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
|
||||
mesh_add_ds_params_ie(skb, sdata))
|
||||
mesh_add_ds_params_ie(sdata, skb))
|
||||
goto out_free;
|
||||
|
||||
bcn->head_len = skb->len;
|
||||
@ -719,13 +726,13 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
|
||||
bcn->tail = bcn->head + bcn->head_len;
|
||||
|
||||
if (ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
|
||||
mesh_add_rsn_ie(skb, sdata) ||
|
||||
mesh_add_ht_cap_ie(skb, sdata) ||
|
||||
mesh_add_ht_oper_ie(skb, sdata) ||
|
||||
mesh_add_meshid_ie(skb, sdata) ||
|
||||
mesh_add_meshconf_ie(skb, sdata) ||
|
||||
mesh_add_awake_window_ie(skb, sdata) ||
|
||||
mesh_add_vendor_ies(skb, sdata))
|
||||
mesh_add_rsn_ie(sdata, skb) ||
|
||||
mesh_add_ht_cap_ie(sdata, skb) ||
|
||||
mesh_add_ht_oper_ie(sdata, skb) ||
|
||||
mesh_add_meshid_ie(sdata, skb) ||
|
||||
mesh_add_meshconf_ie(sdata, skb) ||
|
||||
mesh_add_awake_window_ie(sdata, skb) ||
|
||||
mesh_add_vendor_ies(sdata, skb))
|
||||
goto out_free;
|
||||
|
||||
bcn->tail_len = skb->len;
|
||||
@ -918,7 +925,6 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_PROBE_RESP);
|
||||
memcpy(hdr->da, mgmt->sa, ETH_ALEN);
|
||||
mpl_dbg(sdata, "sending probe resp. to %pM\n", hdr->da);
|
||||
IEEE80211_SKB_CB(presp)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
ieee80211_tx_skb(sdata, presp);
|
||||
out:
|
||||
@ -1039,7 +1045,7 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
|
||||
mesh_mpp_table_grow();
|
||||
|
||||
if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags))
|
||||
ieee80211_mesh_housekeeping(sdata, ifmsh);
|
||||
ieee80211_mesh_housekeeping(sdata);
|
||||
|
||||
if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags))
|
||||
ieee80211_mesh_rootpath(sdata);
|
||||
|
@ -26,12 +26,12 @@
|
||||
* @MESH_PATH_ACTIVE: the mesh path can be used for forwarding
|
||||
* @MESH_PATH_RESOLVING: the discovery process is running for this mesh path
|
||||
* @MESH_PATH_SN_VALID: the mesh path contains a valid destination sequence
|
||||
* number
|
||||
* number
|
||||
* @MESH_PATH_FIXED: the mesh path has been manually set and should not be
|
||||
* modified
|
||||
* modified
|
||||
* @MESH_PATH_RESOLVED: the mesh path can has been resolved
|
||||
* @MESH_PATH_REQ_QUEUED: there is an unsent path request for this destination
|
||||
* already queued up, waiting for the discovery process to start.
|
||||
* already queued up, waiting for the discovery process to start.
|
||||
*
|
||||
* MESH_PATH_RESOLVED is used by the mesh path timer to
|
||||
* decide when to stop or cancel the mesh path discovery.
|
||||
@ -73,16 +73,16 @@ enum mesh_deferred_task_flags {
|
||||
* @dst: mesh path destination mac address
|
||||
* @sdata: mesh subif
|
||||
* @next_hop: mesh neighbor to which frames for this destination will be
|
||||
* forwarded
|
||||
* forwarded
|
||||
* @timer: mesh path discovery timer
|
||||
* @frame_queue: pending queue for frames sent to this destination while the
|
||||
* path is unresolved
|
||||
* path is unresolved
|
||||
* @sn: target sequence number
|
||||
* @metric: current metric to this destination
|
||||
* @hop_count: hops to destination
|
||||
* @exp_time: in jiffies, when the path will expire or when it expired
|
||||
* @discovery_timeout: timeout (lapse in jiffies) used for the last discovery
|
||||
* retry
|
||||
* retry
|
||||
* @discovery_retries: number of discovery retries
|
||||
* @flags: mesh path flags, as specified on &enum mesh_path_flags
|
||||
* @state_lock: mesh path state lock used to protect changes to the
|
||||
@ -206,38 +206,33 @@ struct mesh_rmc {
|
||||
/* Various */
|
||||
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
|
||||
const u8 *da, const u8 *sa);
|
||||
int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
|
||||
struct ieee80211_sub_if_data *sdata, char *addr4or5,
|
||||
char *addr6);
|
||||
int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211s_hdr *meshhdr,
|
||||
const char *addr4or5, const char *addr6);
|
||||
int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *addr, struct ieee80211s_hdr *mesh_hdr);
|
||||
bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee802_11_elems *ie);
|
||||
void mesh_ids_set_default(struct ieee80211_if_mesh *mesh);
|
||||
void mesh_mgmt_ies_add(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
int mesh_add_meshconf_ie(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
int mesh_add_meshid_ie(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
int mesh_add_rsn_ie(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
int mesh_add_awake_window_ie(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
int mesh_add_vendor_ies(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
int mesh_add_ds_params_ie(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
int mesh_add_ht_cap_ie(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
int mesh_add_ht_oper_ie(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_mgmt_ies_add(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
int mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
int mesh_add_vendor_ies(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
|
||||
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211s_init(void);
|
||||
void ieee80211s_update_metric(struct ieee80211_local *local,
|
||||
struct sta_info *sta, struct sk_buff *skb);
|
||||
void ieee80211s_stop(void);
|
||||
struct sta_info *sta, struct sk_buff *skb);
|
||||
void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
|
||||
int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
|
||||
@ -263,31 +258,32 @@ void ieee80211_mps_frame_release(struct sta_info *sta,
|
||||
struct ieee802_11_elems *elems);
|
||||
|
||||
/* Mesh paths */
|
||||
int mesh_nexthop_lookup(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
int mesh_nexthop_resolve(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata);
|
||||
struct mesh_path *mesh_path_lookup(const u8 *dst,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
struct mesh_path *mpp_path_lookup(u8 *dst,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata);
|
||||
struct mesh_path *mesh_path_lookup_by_idx(int idx,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
struct mesh_path *mesh_path_lookup(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *dst);
|
||||
struct mesh_path *mpp_path_lookup(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *dst);
|
||||
int mpp_path_add(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *dst, const u8 *mpp);
|
||||
struct mesh_path *
|
||||
mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx);
|
||||
void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
|
||||
void mesh_path_expire(struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len);
|
||||
int mesh_path_add(const u8 *dst, struct ieee80211_sub_if_data *sdata);
|
||||
struct ieee80211_mgmt *mgmt, size_t len);
|
||||
int mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst);
|
||||
|
||||
int mesh_path_add_gate(struct mesh_path *mpath);
|
||||
int mesh_path_send_to_gates(struct mesh_path *mpath);
|
||||
int mesh_gate_num(struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
/* Mesh plinks */
|
||||
void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
|
||||
u8 *hw_addr,
|
||||
struct ieee802_11_elems *ie);
|
||||
u8 *hw_addr, struct ieee802_11_elems *ie);
|
||||
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie);
|
||||
u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_plink_broken(struct sta_info *sta);
|
||||
@ -304,19 +300,19 @@ void mesh_sta_cleanup(struct sta_info *sta);
|
||||
void mesh_mpath_table_grow(void);
|
||||
void mesh_mpp_table_grow(void);
|
||||
/* Mesh paths */
|
||||
int mesh_path_error_tx(u8 ttl, const u8 *target, __le32 target_sn,
|
||||
__le16 target_rcode, const u8 *ra,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
|
||||
u8 ttl, const u8 *target, __le32 target_sn,
|
||||
__le16 target_rcode, const u8 *ra);
|
||||
void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
|
||||
void mesh_path_flush_pending(struct mesh_path *mpath);
|
||||
void mesh_path_tx_pending(struct mesh_path *mpath);
|
||||
int mesh_pathtbl_init(void);
|
||||
void mesh_pathtbl_unregister(void);
|
||||
int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata);
|
||||
int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr);
|
||||
void mesh_path_timer(unsigned long data);
|
||||
void mesh_path_flush_by_nexthop(struct sta_info *sta);
|
||||
void mesh_path_discard_frame(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_path_restart(struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);
|
||||
@ -325,8 +321,6 @@ bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
|
||||
extern int mesh_paths_generation;
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
extern int mesh_allocated;
|
||||
|
||||
static inline
|
||||
u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
@ -371,8 +365,8 @@ void mesh_plink_quiesce(struct sta_info *sta);
|
||||
void mesh_plink_restart(struct sta_info *sta);
|
||||
void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211s_stop(void);
|
||||
#else
|
||||
#define mesh_allocated 0
|
||||
static inline void
|
||||
ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {}
|
||||
static inline void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
|
||||
@ -385,6 +379,7 @@ static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
|
||||
{ return false; }
|
||||
static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
|
||||
{}
|
||||
static inline void ieee80211s_stop(void) {}
|
||||
#endif
|
||||
|
||||
#endif /* IEEE80211S_H */
|
||||
|
@ -238,9 +238,9 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata,
|
||||
* also acquires in the TX path. To avoid a deadlock we don't transmit the
|
||||
* frame directly but add it to the pending queue instead.
|
||||
*/
|
||||
int mesh_path_error_tx(u8 ttl, const u8 *target, __le32 target_sn,
|
||||
__le16 target_rcode, const u8 *ra,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
|
||||
u8 ttl, const u8 *target, __le32 target_sn,
|
||||
__le16 target_rcode, const u8 *ra)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb;
|
||||
@ -430,7 +430,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
|
||||
process = false;
|
||||
fresh_info = false;
|
||||
} else {
|
||||
mpath = mesh_path_lookup(orig_addr, sdata);
|
||||
mpath = mesh_path_lookup(sdata, orig_addr);
|
||||
if (mpath) {
|
||||
spin_lock_bh(&mpath->state_lock);
|
||||
if (mpath->flags & MESH_PATH_FIXED)
|
||||
@ -445,8 +445,8 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mesh_path_add(orig_addr, sdata);
|
||||
mpath = mesh_path_lookup(orig_addr, sdata);
|
||||
mesh_path_add(sdata, orig_addr);
|
||||
mpath = mesh_path_lookup(sdata, orig_addr);
|
||||
if (!mpath) {
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
@ -478,7 +478,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
|
||||
else {
|
||||
fresh_info = true;
|
||||
|
||||
mpath = mesh_path_lookup(ta, sdata);
|
||||
mpath = mesh_path_lookup(sdata, ta);
|
||||
if (mpath) {
|
||||
spin_lock_bh(&mpath->state_lock);
|
||||
if ((mpath->flags & MESH_PATH_FIXED) ||
|
||||
@ -486,8 +486,8 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
|
||||
(last_hop_metric > mpath->metric)))
|
||||
fresh_info = false;
|
||||
} else {
|
||||
mesh_path_add(ta, sdata);
|
||||
mpath = mesh_path_lookup(ta, sdata);
|
||||
mesh_path_add(sdata, ta);
|
||||
mpath = mesh_path_lookup(sdata, ta);
|
||||
if (!mpath) {
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
@ -553,7 +553,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
|
||||
} else if (is_broadcast_ether_addr(target_addr) &&
|
||||
(target_flags & IEEE80211_PREQ_TO_FLAG)) {
|
||||
rcu_read_lock();
|
||||
mpath = mesh_path_lookup(orig_addr, sdata);
|
||||
mpath = mesh_path_lookup(sdata, orig_addr);
|
||||
if (mpath) {
|
||||
if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) {
|
||||
reply = true;
|
||||
@ -568,7 +568,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
|
||||
rcu_read_unlock();
|
||||
} else {
|
||||
rcu_read_lock();
|
||||
mpath = mesh_path_lookup(target_addr, sdata);
|
||||
mpath = mesh_path_lookup(sdata, target_addr);
|
||||
if (mpath) {
|
||||
if ((!(mpath->flags & MESH_PATH_SN_VALID)) ||
|
||||
SN_LT(mpath->sn, target_sn)) {
|
||||
@ -678,7 +678,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
mpath = mesh_path_lookup(orig_addr, sdata);
|
||||
mpath = mesh_path_lookup(sdata, orig_addr);
|
||||
if (mpath)
|
||||
spin_lock_bh(&mpath->state_lock);
|
||||
else
|
||||
@ -736,7 +736,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
|
||||
target_rcode = PERR_IE_TARGET_RCODE(perr_elem);
|
||||
|
||||
rcu_read_lock();
|
||||
mpath = mesh_path_lookup(target_addr, sdata);
|
||||
mpath = mesh_path_lookup(sdata, target_addr);
|
||||
if (mpath) {
|
||||
struct sta_info *sta;
|
||||
|
||||
@ -751,9 +751,10 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
|
||||
spin_unlock_bh(&mpath->state_lock);
|
||||
if (!ifmsh->mshcfg.dot11MeshForwarding)
|
||||
goto endperr;
|
||||
mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn),
|
||||
mesh_path_error_tx(sdata, ttl, target_addr,
|
||||
cpu_to_le32(target_sn),
|
||||
cpu_to_le16(target_rcode),
|
||||
broadcast_addr, sdata);
|
||||
broadcast_addr);
|
||||
} else
|
||||
spin_unlock_bh(&mpath->state_lock);
|
||||
}
|
||||
@ -801,10 +802,10 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
metric_txsta = airtime_link_metric_get(local, sta);
|
||||
|
||||
mpath = mesh_path_lookup(orig_addr, sdata);
|
||||
mpath = mesh_path_lookup(sdata, orig_addr);
|
||||
if (!mpath) {
|
||||
mesh_path_add(orig_addr, sdata);
|
||||
mpath = mesh_path_lookup(orig_addr, sdata);
|
||||
mesh_path_add(sdata, orig_addr);
|
||||
mpath = mesh_path_lookup(sdata, orig_addr);
|
||||
if (!mpath) {
|
||||
rcu_read_unlock();
|
||||
sdata->u.mesh.mshstats.dropped_frames_no_route++;
|
||||
@ -861,8 +862,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
|
||||
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
size_t len)
|
||||
struct ieee80211_mgmt *mgmt, size_t len)
|
||||
{
|
||||
struct ieee802_11_elems elems;
|
||||
size_t baselen;
|
||||
@ -1006,7 +1006,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
|
||||
spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
|
||||
|
||||
rcu_read_lock();
|
||||
mpath = mesh_path_lookup(preq_node->dst, sdata);
|
||||
mpath = mesh_path_lookup(sdata, preq_node->dst);
|
||||
if (!mpath)
|
||||
goto enddiscovery;
|
||||
|
||||
@ -1076,8 +1076,8 @@ enddiscovery:
|
||||
* Returns: 0 if the next hop was found and -ENOENT if the frame was queued.
|
||||
* skb is freeed here if no mpath could be allocated.
|
||||
*/
|
||||
int mesh_nexthop_resolve(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
@ -1091,17 +1091,17 @@ int mesh_nexthop_resolve(struct sk_buff *skb,
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
err = mesh_nexthop_lookup(skb, sdata);
|
||||
err = mesh_nexthop_lookup(sdata, skb);
|
||||
if (!err)
|
||||
goto endlookup;
|
||||
|
||||
/* no nexthop found, start resolving */
|
||||
mpath = mesh_path_lookup(target_addr, sdata);
|
||||
mpath = mesh_path_lookup(sdata, target_addr);
|
||||
if (!mpath) {
|
||||
mesh_path_add(target_addr, sdata);
|
||||
mpath = mesh_path_lookup(target_addr, sdata);
|
||||
mesh_path_add(sdata, target_addr);
|
||||
mpath = mesh_path_lookup(sdata, target_addr);
|
||||
if (!mpath) {
|
||||
mesh_path_discard_frame(skb, sdata);
|
||||
mesh_path_discard_frame(sdata, skb);
|
||||
err = -ENOSPC;
|
||||
goto endlookup;
|
||||
}
|
||||
@ -1118,12 +1118,13 @@ int mesh_nexthop_resolve(struct sk_buff *skb,
|
||||
skb_queue_tail(&mpath->frame_queue, skb);
|
||||
err = -ENOENT;
|
||||
if (skb_to_free)
|
||||
mesh_path_discard_frame(skb_to_free, sdata);
|
||||
mesh_path_discard_frame(sdata, skb_to_free);
|
||||
|
||||
endlookup:
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* mesh_nexthop_lookup - put the appropriate next hop on a mesh frame. Calling
|
||||
* this function is considered "using" the associated mpath, so preempt a path
|
||||
@ -1134,8 +1135,8 @@ endlookup:
|
||||
*
|
||||
* Returns: 0 if the next hop was found. Nonzero otherwise.
|
||||
*/
|
||||
int mesh_nexthop_lookup(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct mesh_path *mpath;
|
||||
struct sta_info *next_hop;
|
||||
@ -1144,7 +1145,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
|
||||
int err = -ENOENT;
|
||||
|
||||
rcu_read_lock();
|
||||
mpath = mesh_path_lookup(target_addr, sdata);
|
||||
mpath = mesh_path_lookup(sdata, target_addr);
|
||||
|
||||
if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE))
|
||||
goto endlookup;
|
||||
@ -1203,8 +1204,7 @@ void mesh_path_timer(unsigned long data)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
|
||||
void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
|
||||
|
@ -24,9 +24,12 @@
|
||||
/* Keep the mean chain length below this constant */
|
||||
#define MEAN_CHAIN_LEN 2
|
||||
|
||||
#define MPATH_EXPIRED(mpath) ((mpath->flags & MESH_PATH_ACTIVE) && \
|
||||
time_after(jiffies, mpath->exp_time) && \
|
||||
!(mpath->flags & MESH_PATH_FIXED))
|
||||
static inline bool mpath_expired(struct mesh_path *mpath)
|
||||
{
|
||||
return (mpath->flags & MESH_PATH_ACTIVE) &&
|
||||
time_after(jiffies, mpath->exp_time) &&
|
||||
!(mpath->flags & MESH_PATH_FIXED);
|
||||
}
|
||||
|
||||
struct mpath_node {
|
||||
struct hlist_node list;
|
||||
@ -185,8 +188,8 @@ static u32 mesh_table_hash(const u8 *addr, struct ieee80211_sub_if_data *sdata,
|
||||
struct mesh_table *tbl)
|
||||
{
|
||||
/* Use last four bytes of hw addr and interface index as hash index */
|
||||
return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex, tbl->hash_rnd)
|
||||
& tbl->hash_mask;
|
||||
return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex,
|
||||
tbl->hash_rnd) & tbl->hash_mask;
|
||||
}
|
||||
|
||||
|
||||
@ -339,7 +342,7 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
|
||||
mpath = node->mpath;
|
||||
if (mpath->sdata == sdata &&
|
||||
ether_addr_equal(dst, mpath->dst)) {
|
||||
if (MPATH_EXPIRED(mpath)) {
|
||||
if (mpath_expired(mpath)) {
|
||||
spin_lock_bh(&mpath->state_lock);
|
||||
mpath->flags &= ~MESH_PATH_ACTIVE;
|
||||
spin_unlock_bh(&mpath->state_lock);
|
||||
@ -352,20 +355,21 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
|
||||
|
||||
/**
|
||||
* mesh_path_lookup - look up a path in the mesh path table
|
||||
* @dst: hardware address (ETH_ALEN length) of destination
|
||||
* @sdata: local subif
|
||||
* @dst: hardware address (ETH_ALEN length) of destination
|
||||
*
|
||||
* Returns: pointer to the mesh path structure, or NULL if not found
|
||||
*
|
||||
* Locking: must be called within a read rcu section.
|
||||
*/
|
||||
struct mesh_path *mesh_path_lookup(const u8 *dst,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
struct mesh_path *
|
||||
mesh_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
|
||||
{
|
||||
return mpath_lookup(rcu_dereference(mesh_paths), dst, sdata);
|
||||
}
|
||||
|
||||
struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
|
||||
struct mesh_path *
|
||||
mpp_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
|
||||
{
|
||||
return mpath_lookup(rcu_dereference(mpp_paths), dst, sdata);
|
||||
}
|
||||
@ -380,7 +384,8 @@ struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
|
||||
*
|
||||
* Locking: must be called within a read rcu section.
|
||||
*/
|
||||
struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data *sdata)
|
||||
struct mesh_path *
|
||||
mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
|
||||
{
|
||||
struct mesh_table *tbl = rcu_dereference(mesh_paths);
|
||||
struct mpath_node *node;
|
||||
@ -392,7 +397,7 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data
|
||||
if (sdata && node->mpath->sdata != sdata)
|
||||
continue;
|
||||
if (j++ == idx) {
|
||||
if (MPATH_EXPIRED(node->mpath)) {
|
||||
if (mpath_expired(node->mpath)) {
|
||||
spin_lock_bh(&node->mpath->state_lock);
|
||||
node->mpath->flags &= ~MESH_PATH_ACTIVE;
|
||||
spin_unlock_bh(&node->mpath->state_lock);
|
||||
@ -436,11 +441,10 @@ int mesh_path_add_gate(struct mesh_path *mpath)
|
||||
spin_lock_bh(&tbl->gates_lock);
|
||||
hlist_add_head_rcu(&new_gate->list, tbl->known_gates);
|
||||
spin_unlock_bh(&tbl->gates_lock);
|
||||
rcu_read_unlock();
|
||||
mpath_dbg(mpath->sdata,
|
||||
"Mesh path: Recorded new gate: %pM. %d known gates\n",
|
||||
mpath->dst, mpath->sdata->u.mesh.num_gates);
|
||||
return 0;
|
||||
err = 0;
|
||||
err_rcu:
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
@ -451,30 +455,27 @@ err_rcu:
|
||||
* @tbl: table which holds our list of known gates
|
||||
* @mpath: gate mpath
|
||||
*
|
||||
* Returns: 0 on success
|
||||
*
|
||||
* Locking: must be called inside rcu_read_lock() section
|
||||
*/
|
||||
static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)
|
||||
static void mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)
|
||||
{
|
||||
struct mpath_node *gate;
|
||||
struct hlist_node *p, *q;
|
||||
|
||||
hlist_for_each_entry_safe(gate, p, q, tbl->known_gates, list)
|
||||
if (gate->mpath == mpath) {
|
||||
spin_lock_bh(&tbl->gates_lock);
|
||||
hlist_del_rcu(&gate->list);
|
||||
kfree_rcu(gate, rcu);
|
||||
spin_unlock_bh(&tbl->gates_lock);
|
||||
mpath->sdata->u.mesh.num_gates--;
|
||||
mpath->is_gate = false;
|
||||
mpath_dbg(mpath->sdata,
|
||||
"Mesh path: Deleted gate: %pM. %d known gates\n",
|
||||
mpath->dst, mpath->sdata->u.mesh.num_gates);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
hlist_for_each_entry_safe(gate, p, q, tbl->known_gates, list) {
|
||||
if (gate->mpath != mpath)
|
||||
continue;
|
||||
spin_lock_bh(&tbl->gates_lock);
|
||||
hlist_del_rcu(&gate->list);
|
||||
kfree_rcu(gate, rcu);
|
||||
spin_unlock_bh(&tbl->gates_lock);
|
||||
mpath->sdata->u.mesh.num_gates--;
|
||||
mpath->is_gate = false;
|
||||
mpath_dbg(mpath->sdata,
|
||||
"Mesh path: Deleted gate: %pM. %d known gates\n",
|
||||
mpath->dst, mpath->sdata->u.mesh.num_gates);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -488,14 +489,14 @@ int mesh_gate_num(struct ieee80211_sub_if_data *sdata)
|
||||
|
||||
/**
|
||||
* mesh_path_add - allocate and add a new path to the mesh path table
|
||||
* @addr: destination address of the path (ETH_ALEN length)
|
||||
* @dst: destination address of the path (ETH_ALEN length)
|
||||
* @sdata: local subif
|
||||
*
|
||||
* Returns: 0 on success
|
||||
*
|
||||
* State: the initial state of the new path is set to 0
|
||||
*/
|
||||
int mesh_path_add(const u8 *dst, struct ieee80211_sub_if_data *sdata)
|
||||
int mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
@ -630,7 +631,8 @@ void mesh_mpp_table_grow(void)
|
||||
write_unlock_bh(&pathtbl_resize_lock);
|
||||
}
|
||||
|
||||
int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
|
||||
int mpp_path_add(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *dst, const u8 *mpp)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
@ -739,9 +741,10 @@ void mesh_plink_broken(struct sta_info *sta)
|
||||
mpath->flags &= ~MESH_PATH_ACTIVE;
|
||||
++mpath->sn;
|
||||
spin_unlock_bh(&mpath->state_lock);
|
||||
mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl,
|
||||
mpath->dst, cpu_to_le32(mpath->sn),
|
||||
reason, bcast, sdata);
|
||||
mesh_path_error_tx(sdata,
|
||||
sdata->u.mesh.mshcfg.element_ttl,
|
||||
mpath->dst, cpu_to_le32(mpath->sn),
|
||||
reason, bcast);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
@ -856,7 +859,7 @@ void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
|
||||
*
|
||||
* Returns: 0 if successful
|
||||
*/
|
||||
int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
|
||||
int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
|
||||
{
|
||||
struct mesh_table *tbl;
|
||||
struct mesh_path *mpath;
|
||||
@ -965,8 +968,8 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
|
||||
*
|
||||
* Locking: the function must me called within a rcu_read_lock region
|
||||
*/
|
||||
void mesh_path_discard_frame(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
kfree_skb(skb);
|
||||
sdata->u.mesh.mshstats.dropped_frames_no_route++;
|
||||
@ -984,7 +987,7 @@ void mesh_path_flush_pending(struct mesh_path *mpath)
|
||||
struct sk_buff *skb;
|
||||
|
||||
while ((skb = skb_dequeue(&mpath->frame_queue)) != NULL)
|
||||
mesh_path_discard_frame(skb, mpath->sdata);
|
||||
mesh_path_discard_frame(mpath->sdata, skb);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1105,7 +1108,7 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
|
||||
if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
|
||||
(!(mpath->flags & MESH_PATH_FIXED)) &&
|
||||
time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
|
||||
mesh_path_del(mpath->dst, mpath->sdata);
|
||||
mesh_path_del(mpath->sdata, mpath->dst);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
@ -37,9 +37,31 @@ enum plink_event {
|
||||
CLS_IGNR
|
||||
};
|
||||
|
||||
static const char * const mplstates[] = {
|
||||
[NL80211_PLINK_LISTEN] = "LISTEN",
|
||||
[NL80211_PLINK_OPN_SNT] = "OPN-SNT",
|
||||
[NL80211_PLINK_OPN_RCVD] = "OPN-RCVD",
|
||||
[NL80211_PLINK_CNF_RCVD] = "CNF_RCVD",
|
||||
[NL80211_PLINK_ESTAB] = "ESTAB",
|
||||
[NL80211_PLINK_HOLDING] = "HOLDING",
|
||||
[NL80211_PLINK_BLOCKED] = "BLOCKED"
|
||||
};
|
||||
|
||||
static const char * const mplevents[] = {
|
||||
[PLINK_UNDEFINED] = "NONE",
|
||||
[OPN_ACPT] = "OPN_ACPT",
|
||||
[OPN_RJCT] = "OPN_RJCT",
|
||||
[OPN_IGNR] = "OPN_IGNR",
|
||||
[CNF_ACPT] = "CNF_ACPT",
|
||||
[CNF_RJCT] = "CNF_RJCT",
|
||||
[CNF_IGNR] = "CNF_IGNR",
|
||||
[CLS_ACPT] = "CLS_ACPT",
|
||||
[CLS_IGNR] = "CLS_IGNR"
|
||||
};
|
||||
|
||||
static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_self_protected_actioncode action,
|
||||
u8 *da, __le16 llid, __le16 plid, __le16 reason);
|
||||
enum ieee80211_self_protected_actioncode action,
|
||||
u8 *da, __le16 llid, __le16 plid, __le16 reason);
|
||||
|
||||
/**
|
||||
* mesh_plink_fsm_restart - restart a mesh peer link finite state machine
|
||||
@ -129,7 +151,6 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
u32 changed = 0;
|
||||
u16 ht_opmode;
|
||||
bool non_ht_sta = false, ht20_sta = false;
|
||||
|
||||
@ -142,23 +163,19 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
|
||||
sta->plink_state != NL80211_PLINK_ESTAB)
|
||||
continue;
|
||||
|
||||
switch (sta->ch_width) {
|
||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||
mpl_dbg(sdata,
|
||||
"mesh_plink %pM: nonHT sta (%pM) is present\n",
|
||||
sdata->vif.addr, sta->sta.addr);
|
||||
if (sta->sta.bandwidth > IEEE80211_STA_RX_BW_20)
|
||||
continue;
|
||||
|
||||
if (!sta->sta.ht_cap.ht_supported) {
|
||||
mpl_dbg(sdata, "nonHT sta (%pM) is present\n",
|
||||
sta->sta.addr);
|
||||
non_ht_sta = true;
|
||||
goto out;
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
mpl_dbg(sdata,
|
||||
"mesh_plink %pM: HT20 sta (%pM) is present\n",
|
||||
sdata->vif.addr, sta->sta.addr);
|
||||
ht20_sta = true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
mpl_dbg(sdata, "HT20 sta (%pM) is present\n", sta->sta.addr);
|
||||
ht20_sta = true;
|
||||
}
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
|
||||
if (non_ht_sta)
|
||||
@ -169,16 +186,13 @@ out:
|
||||
else
|
||||
ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
|
||||
|
||||
if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
|
||||
sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
|
||||
sdata->u.mesh.mshcfg.ht_opmode = ht_opmode;
|
||||
changed = BSS_CHANGED_HT;
|
||||
mpl_dbg(sdata,
|
||||
"mesh_plink %pM: protection mode changed to %d\n",
|
||||
sdata->vif.addr, ht_opmode);
|
||||
}
|
||||
if (sdata->vif.bss_conf.ht_operation_mode == ht_opmode)
|
||||
return 0;
|
||||
|
||||
return changed;
|
||||
sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
|
||||
sdata->u.mesh.mshcfg.ht_opmode = ht_opmode;
|
||||
mpl_dbg(sdata, "selected new HT protection mode %d\n", ht_opmode);
|
||||
return BSS_CHANGED_HT;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -231,8 +245,9 @@ u32 mesh_plink_deactivate(struct sta_info *sta)
|
||||
}
|
||||
|
||||
static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_self_protected_actioncode action,
|
||||
u8 *da, __le16 llid, __le16 plid, __le16 reason) {
|
||||
enum ieee80211_self_protected_actioncode action,
|
||||
u8 *da, __le16 llid, __le16 plid, __le16 reason)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_tx_info *info;
|
||||
@ -283,13 +298,13 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
|
||||
ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
|
||||
mesh_add_rsn_ie(skb, sdata) ||
|
||||
mesh_add_meshid_ie(skb, sdata) ||
|
||||
mesh_add_meshconf_ie(skb, sdata))
|
||||
mesh_add_rsn_ie(sdata, skb) ||
|
||||
mesh_add_meshid_ie(sdata, skb) ||
|
||||
mesh_add_meshconf_ie(sdata, skb))
|
||||
goto free;
|
||||
} else { /* WLAN_SP_MESH_PEERING_CLOSE */
|
||||
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
||||
if (mesh_add_meshid_ie(skb, sdata))
|
||||
if (mesh_add_meshid_ie(sdata, skb))
|
||||
goto free;
|
||||
}
|
||||
|
||||
@ -333,12 +348,12 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
if (action != WLAN_SP_MESH_PEERING_CLOSE) {
|
||||
if (mesh_add_ht_cap_ie(skb, sdata) ||
|
||||
mesh_add_ht_oper_ie(skb, sdata))
|
||||
if (mesh_add_ht_cap_ie(sdata, skb) ||
|
||||
mesh_add_ht_oper_ie(sdata, skb))
|
||||
goto free;
|
||||
}
|
||||
|
||||
if (mesh_add_vendor_ies(skb, sdata))
|
||||
if (mesh_add_vendor_ies(sdata, skb))
|
||||
goto free;
|
||||
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
@ -370,24 +385,18 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
|
||||
if (sta->sta.supp_rates[band] != rates)
|
||||
changed |= IEEE80211_RC_SUPP_RATES_CHANGED;
|
||||
sta->sta.supp_rates[band] = rates;
|
||||
if (elems->ht_cap_elem &&
|
||||
sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
|
||||
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
||||
elems->ht_cap_elem, sta);
|
||||
else
|
||||
memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap));
|
||||
|
||||
if (elems->ht_operation) {
|
||||
struct cfg80211_chan_def chandef;
|
||||
if (ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
||||
elems->ht_cap_elem, sta))
|
||||
changed |= IEEE80211_RC_BW_CHANGED;
|
||||
|
||||
if (!(elems->ht_operation->ht_param &
|
||||
IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
|
||||
sta->sta.bandwidth = IEEE80211_STA_RX_BW_20;
|
||||
ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
|
||||
elems->ht_operation, &chandef);
|
||||
if (sta->ch_width != chandef.width)
|
||||
/* HT peer is operating 20MHz-only */
|
||||
if (elems->ht_operation &&
|
||||
!(elems->ht_operation->ht_param &
|
||||
IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
|
||||
if (sta->sta.bandwidth != IEEE80211_STA_RX_BW_20)
|
||||
changed |= IEEE80211_RC_BW_CHANGED;
|
||||
sta->ch_width = chandef.width;
|
||||
sta->sta.bandwidth = IEEE80211_STA_RX_BW_20;
|
||||
}
|
||||
|
||||
if (insert)
|
||||
@ -666,8 +675,9 @@ u32 mesh_plink_block(struct sta_info *sta)
|
||||
}
|
||||
|
||||
|
||||
void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt,
|
||||
size_t len, struct ieee80211_rx_status *rx_status)
|
||||
void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
|
||||
struct ieee802_11_elems elems;
|
||||
@ -680,15 +690,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
|
||||
u8 *baseaddr;
|
||||
u32 changed = 0;
|
||||
__le16 plid, llid, reason;
|
||||
static const char *mplstates[] = {
|
||||
[NL80211_PLINK_LISTEN] = "LISTEN",
|
||||
[NL80211_PLINK_OPN_SNT] = "OPN-SNT",
|
||||
[NL80211_PLINK_OPN_RCVD] = "OPN-RCVD",
|
||||
[NL80211_PLINK_CNF_RCVD] = "CNF_RCVD",
|
||||
[NL80211_PLINK_ESTAB] = "ESTAB",
|
||||
[NL80211_PLINK_HOLDING] = "HOLDING",
|
||||
[NL80211_PLINK_BLOCKED] = "BLOCKED"
|
||||
};
|
||||
|
||||
/* need action_code, aux */
|
||||
if (len < IEEE80211_MIN_ACTION_SIZE + 3)
|
||||
@ -708,13 +709,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
|
||||
baselen += 4;
|
||||
}
|
||||
ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
|
||||
|
||||
if (!elems.peering) {
|
||||
mpl_dbg(sdata,
|
||||
"Mesh plink: missing necessary peer link ie\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (elems.rsn_len &&
|
||||
sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
|
||||
sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
|
||||
mpl_dbg(sdata,
|
||||
"Mesh plink: can't establish link with secure peer\n");
|
||||
return;
|
||||
@ -733,7 +736,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
|
||||
}
|
||||
|
||||
if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
|
||||
(!elems.mesh_id || !elems.mesh_config)) {
|
||||
(!elems.mesh_id || !elems.mesh_config)) {
|
||||
mpl_dbg(sdata, "Mesh plink: missing necessary ie\n");
|
||||
return;
|
||||
}
|
||||
@ -859,11 +862,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
|
||||
}
|
||||
}
|
||||
|
||||
mpl_dbg(sdata,
|
||||
"Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n",
|
||||
mgmt->sa, mplstates[sta->plink_state],
|
||||
le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
|
||||
event);
|
||||
mpl_dbg(sdata, "peer %pM in state %s got event %s\n", mgmt->sa,
|
||||
mplstates[sta->plink_state], mplevents[event]);
|
||||
reason = 0;
|
||||
spin_lock_bh(&sta->lock);
|
||||
switch (sta->plink_state) {
|
||||
|
@ -43,7 +43,7 @@ struct sync_method {
|
||||
static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie)
|
||||
{
|
||||
return (ie->mesh_config->meshconf_cap &
|
||||
IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING) != 0;
|
||||
IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING) != 0;
|
||||
}
|
||||
|
||||
void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
|
||||
@ -112,7 +112,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) {
|
||||
clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
|
||||
msync_dbg(sdata, "STA %pM : is adjusting TBTT\n", sta->sta.addr);
|
||||
msync_dbg(sdata, "STA %pM : is adjusting TBTT\n",
|
||||
sta->sta.addr);
|
||||
goto no_sync;
|
||||
}
|
||||
|
||||
@ -129,18 +130,15 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
||||
sta->t_offset = t_t - t_r;
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
|
||||
s64 t_clockdrift = sta->t_offset_setpoint
|
||||
- sta->t_offset;
|
||||
s64 t_clockdrift = sta->t_offset_setpoint - sta->t_offset;
|
||||
msync_dbg(sdata,
|
||||
"STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld\n",
|
||||
sta->sta.addr,
|
||||
(long long) sta->t_offset,
|
||||
(long long)
|
||||
sta->t_offset_setpoint,
|
||||
sta->sta.addr, (long long) sta->t_offset,
|
||||
(long long) sta->t_offset_setpoint,
|
||||
(long long) t_clockdrift);
|
||||
|
||||
if (t_clockdrift > TOFFSET_MAXIMUM_ADJUSTMENT ||
|
||||
t_clockdrift < -TOFFSET_MAXIMUM_ADJUSTMENT) {
|
||||
t_clockdrift < -TOFFSET_MAXIMUM_ADJUSTMENT) {
|
||||
msync_dbg(sdata,
|
||||
"STA %pM : t_clockdrift=%lld too large, setpoint reset\n",
|
||||
sta->sta.addr,
|
||||
@ -149,15 +147,10 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
||||
goto no_sync;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
spin_lock_bh(&ifmsh->sync_offset_lock);
|
||||
if (t_clockdrift >
|
||||
ifmsh->sync_offset_clockdrift_max)
|
||||
ifmsh->sync_offset_clockdrift_max
|
||||
= t_clockdrift;
|
||||
if (t_clockdrift > ifmsh->sync_offset_clockdrift_max)
|
||||
ifmsh->sync_offset_clockdrift_max = t_clockdrift;
|
||||
spin_unlock_bh(&ifmsh->sync_offset_lock);
|
||||
|
||||
} else {
|
||||
sta->t_offset_setpoint = sta->t_offset - TOFFSET_SET_MARGIN;
|
||||
set_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
|
||||
@ -165,9 +158,7 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
||||
"STA %pM : offset was invalid, sta->t_offset=%lld\n",
|
||||
sta->sta.addr,
|
||||
(long long) sta->t_offset);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
return;
|
||||
|
||||
no_sync:
|
||||
rcu_read_unlock();
|
||||
@ -177,14 +168,12 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
|
||||
WARN_ON(ifmsh->mesh_sp_id
|
||||
!= IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET);
|
||||
WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET);
|
||||
BUG_ON(!rcu_read_lock_held());
|
||||
|
||||
spin_lock_bh(&ifmsh->sync_offset_lock);
|
||||
|
||||
if (ifmsh->sync_offset_clockdrift_max >
|
||||
TOFFSET_MINIMUM_ADJUSTMENT) {
|
||||
if (ifmsh->sync_offset_clockdrift_max > TOFFSET_MINIMUM_ADJUSTMENT) {
|
||||
/* Since ajusting the tsf here would
|
||||
* require a possibly blocking call
|
||||
* to the driver tsf setter, we punt
|
||||
@ -193,8 +182,7 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
|
||||
msync_dbg(sdata,
|
||||
"TBTT : kicking off TBTT adjustment with clockdrift_max=%lld\n",
|
||||
ifmsh->sync_offset_clockdrift_max);
|
||||
set_bit(MESH_WORK_DRIFT_ADJUST,
|
||||
&ifmsh->wrkq_flags);
|
||||
set_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags);
|
||||
|
||||
ifmsh->adjusting_tbtt = true;
|
||||
} else {
|
||||
@ -220,14 +208,11 @@ static const struct sync_method sync_methods[] = {
|
||||
|
||||
const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method)
|
||||
{
|
||||
const struct ieee80211_mesh_sync_ops *ops = NULL;
|
||||
u8 i;
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(sync_methods); ++i) {
|
||||
if (sync_methods[i].method == method) {
|
||||
ops = &sync_methods[i].ops;
|
||||
break;
|
||||
}
|
||||
if (sync_methods[i].method == method)
|
||||
return &sync_methods[i].ops;
|
||||
}
|
||||
return ops;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2027,7 +2027,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||||
/* frame is in RMC, don't forward */
|
||||
if (ieee80211_is_data(hdr->frame_control) &&
|
||||
is_multicast_ether_addr(hdr->addr1) &&
|
||||
mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata))
|
||||
mesh_rmc_check(rx->sdata, hdr->addr3, mesh_hdr))
|
||||
return RX_DROP_MONITOR;
|
||||
|
||||
if (!ieee80211_is_data(hdr->frame_control) ||
|
||||
@ -2054,9 +2054,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
mppath = mpp_path_lookup(proxied_addr, sdata);
|
||||
mppath = mpp_path_lookup(sdata, proxied_addr);
|
||||
if (!mppath) {
|
||||
mpp_path_add(proxied_addr, mpp_addr, sdata);
|
||||
mpp_path_add(sdata, proxied_addr, mpp_addr);
|
||||
} else {
|
||||
spin_lock_bh(&mppath->state_lock);
|
||||
if (!ether_addr_equal(mppath->mpp, mpp_addr))
|
||||
@ -2104,13 +2104,13 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||||
memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
|
||||
/* update power mode indication when forwarding */
|
||||
ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
|
||||
} else if (!mesh_nexthop_lookup(fwd_skb, sdata)) {
|
||||
} else if (!mesh_nexthop_lookup(sdata, fwd_skb)) {
|
||||
/* mesh power mode flags updated in mesh_nexthop_lookup */
|
||||
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
|
||||
} else {
|
||||
/* unable to resolve next hop */
|
||||
mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3,
|
||||
0, reason, fwd_hdr->addr2, sdata);
|
||||
mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
|
||||
fwd_hdr->addr3, 0, reason, fwd_hdr->addr2);
|
||||
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
|
||||
kfree_skb(fwd_skb);
|
||||
return RX_DROP_MONITOR;
|
||||
|
@ -285,7 +285,6 @@ struct sta_ampdu_mlme {
|
||||
* @t_offset: timing offset relative to this host
|
||||
* @t_offset_setpoint: reference timing offset of this sta to be used when
|
||||
* calculating clockdrift
|
||||
* @ch_width: peer's channel width
|
||||
* @local_pm: local link-specific power save mode
|
||||
* @peer_pm: peer-specific power save mode towards local STA
|
||||
* @nonpeer_pm: STA power save mode towards non-peer neighbors
|
||||
@ -386,7 +385,6 @@ struct sta_info {
|
||||
struct timer_list plink_timer;
|
||||
s64 t_offset;
|
||||
s64 t_offset_setpoint;
|
||||
enum nl80211_chan_width ch_width;
|
||||
/* mesh power save */
|
||||
enum nl80211_mesh_power_mode local_pm;
|
||||
enum nl80211_mesh_power_mode peer_pm;
|
||||
|
@ -479,7 +479,7 @@ TRACE_EVENT(drv_set_tim,
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT STA_PR_FMT " set:%d",
|
||||
LOCAL_PR_ARG, STA_PR_FMT, __entry->set
|
||||
LOCAL_PR_ARG, STA_PR_ARG, __entry->set
|
||||
)
|
||||
);
|
||||
|
||||
@ -1684,7 +1684,7 @@ TRACE_EVENT(api_sta_block_awake,
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT STA_PR_FMT " block:%d",
|
||||
LOCAL_PR_ARG, STA_PR_FMT, __entry->block
|
||||
LOCAL_PR_ARG, STA_PR_ARG, __entry->block
|
||||
)
|
||||
);
|
||||
|
||||
@ -1782,7 +1782,7 @@ TRACE_EVENT(api_eosp,
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT STA_PR_FMT,
|
||||
LOCAL_PR_ARG, STA_PR_FMT
|
||||
LOCAL_PR_ARG, STA_PR_ARG
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -1495,7 +1495,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
if (ieee80211_is_data(hdr->frame_control) &&
|
||||
is_unicast_ether_addr(hdr->addr1)) {
|
||||
if (mesh_nexthop_resolve(skb, sdata))
|
||||
if (mesh_nexthop_resolve(sdata, skb))
|
||||
return; /* skb queued: don't free */
|
||||
} else {
|
||||
ieee80211_mps_set_frame_flags(sdata, NULL, hdr);
|
||||
@ -1844,9 +1844,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
if (!is_multicast_ether_addr(skb->data)) {
|
||||
mpath = mesh_path_lookup(skb->data, sdata);
|
||||
mpath = mesh_path_lookup(sdata, skb->data);
|
||||
if (!mpath)
|
||||
mppath = mpp_path_lookup(skb->data, sdata);
|
||||
mppath = mpp_path_lookup(sdata, skb->data);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1859,8 +1859,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
!(mppath && !ether_addr_equal(mppath->mpp, skb->data))) {
|
||||
hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
|
||||
skb->data, skb->data + ETH_ALEN);
|
||||
meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
|
||||
sdata, NULL, NULL);
|
||||
meshhdrlen = ieee80211_new_mesh_header(sdata, &mesh_hdr,
|
||||
NULL, NULL);
|
||||
} else {
|
||||
/* DS -> MBSS (802.11-2012 13.11.3.3).
|
||||
* For unicast with unknown forwarding information,
|
||||
@ -1879,18 +1879,14 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
mesh_da, sdata->vif.addr);
|
||||
if (is_multicast_ether_addr(mesh_da))
|
||||
/* DA TA mSA AE:SA */
|
||||
meshhdrlen =
|
||||
ieee80211_new_mesh_header(&mesh_hdr,
|
||||
sdata,
|
||||
skb->data + ETH_ALEN,
|
||||
NULL);
|
||||
meshhdrlen = ieee80211_new_mesh_header(
|
||||
sdata, &mesh_hdr,
|
||||
skb->data + ETH_ALEN, NULL);
|
||||
else
|
||||
/* RA TA mDA mSA AE:DA SA */
|
||||
meshhdrlen =
|
||||
ieee80211_new_mesh_header(&mesh_hdr,
|
||||
sdata,
|
||||
skb->data,
|
||||
skb->data + ETH_ALEN);
|
||||
meshhdrlen = ieee80211_new_mesh_header(
|
||||
sdata, &mesh_hdr, skb->data,
|
||||
skb->data + ETH_ALEN);
|
||||
|
||||
}
|
||||
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
|
||||
|
@ -3418,19 +3418,10 @@ nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = {
|
||||
static int nl80211_set_station_tdls(struct genl_info *info,
|
||||
struct station_parameters *params)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct nlattr *tb[NL80211_STA_WME_MAX + 1];
|
||||
struct nlattr *nla;
|
||||
int err;
|
||||
|
||||
/* Can only set if TDLS ... */
|
||||
if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* ... with external setup is supported */
|
||||
if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Dummy STA entry gets updated once the peer capabilities are known */
|
||||
if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
|
||||
params->ht_capa =
|
||||
|
Loading…
Reference in New Issue
Block a user