staging: wfx: implement the rest of mac80211 API
Finish to fill struct ieee80211_ops with necessary callbacks. Driver is now ready to be registered to mac80211. Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com> Link: https://lore.kernel.org/r/20190919142527.31797-21-Jerome.Pouiller@silabs.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
fb2490f693
commit
40115bbc40
|
@ -21,6 +21,8 @@ static int wfx_handle_pspoll(struct wfx_vif *wvif, struct sk_buff *skb)
|
|||
u32 pspoll_mask = 0;
|
||||
int i;
|
||||
|
||||
if (wvif->state != WFX_STATE_AP)
|
||||
return 1;
|
||||
if (!ether_addr_equal(wvif->vif->addr, pspoll->bssid))
|
||||
return 1;
|
||||
|
||||
|
@ -162,6 +164,30 @@ void wfx_rx_cb(struct wfx_vif *wvif, struct hif_ind_rx *arg, struct sk_buff *skb
|
|||
&& arg->rx_flags.match_uc_addr
|
||||
&& mgmt->u.action.category == WLAN_CATEGORY_BACK)
|
||||
goto drop;
|
||||
if (ieee80211_is_beacon(frame->frame_control)
|
||||
&& !arg->status && wvif->vif
|
||||
&& ether_addr_equal(ieee80211_get_SA(frame), wvif->vif->bss_conf.bssid)) {
|
||||
const u8 *tim_ie;
|
||||
u8 *ies = mgmt->u.beacon.variable;
|
||||
size_t ies_len = skb->len - (ies - skb->data);
|
||||
|
||||
tim_ie = cfg80211_find_ie(WLAN_EID_TIM, ies, ies_len);
|
||||
if (tim_ie) {
|
||||
struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie *) &tim_ie[2];
|
||||
|
||||
if (wvif->dtim_period != tim->dtim_period) {
|
||||
wvif->dtim_period = tim->dtim_period;
|
||||
schedule_work(&wvif->set_beacon_wakeup_period_work);
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable beacon filter once we're associated... */
|
||||
if (wvif->disable_beacon_filter &&
|
||||
(wvif->vif->bss_conf.assoc || wvif->vif->bss_conf.ibss_joined)) {
|
||||
wvif->disable_beacon_filter = false;
|
||||
schedule_work(&wvif->update_filtering_work);
|
||||
}
|
||||
}
|
||||
|
||||
if (early_data) {
|
||||
spin_lock_bh(&wvif->ps_state_lock);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "data_tx.h"
|
||||
#include "wfx.h"
|
||||
#include "bh.h"
|
||||
#include "sta.h"
|
||||
#include "queue.h"
|
||||
#include "debug.h"
|
||||
#include "traces.h"
|
||||
|
@ -359,6 +360,9 @@ void wfx_link_id_gc_work(struct work_struct *work)
|
|||
u32 mask;
|
||||
int i;
|
||||
|
||||
if (wvif->state != WFX_STATE_AP)
|
||||
return;
|
||||
|
||||
wfx_tx_lock_flush(wvif->wdev);
|
||||
spin_lock_bh(&wvif->ps_state_lock);
|
||||
for (i = 0; i < WFX_MAX_STA_IN_AP_MODE; ++i) {
|
||||
|
@ -729,14 +733,26 @@ void wfx_tx_confirm_cb(struct wfx_vif *wvif, struct hif_cnf_tx *arg)
|
|||
memset(tx_info->pad, 0, sizeof(tx_info->pad));
|
||||
|
||||
if (!arg->status) {
|
||||
if (wvif->bss_loss_state && arg->packet_id == wvif->bss_loss_confirm_id)
|
||||
wfx_cqm_bssloss_sm(wvif, 0, 1, 0);
|
||||
tx_info->status.tx_time = arg->media_delay - arg->tx_queue_delay;
|
||||
if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
|
||||
tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
|
||||
else
|
||||
tx_info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
} else if (arg->status == HIF_REQUEUE) {
|
||||
/* "REQUEUE" means "implicit suspend" */
|
||||
struct hif_ind_suspend_resume_tx suspend = {
|
||||
.suspend_resume_flags.resume = 0,
|
||||
.suspend_resume_flags.bc_mc_only = 1,
|
||||
};
|
||||
|
||||
WARN(!arg->tx_result_flags.requeue, "incoherent status and result_flags");
|
||||
wfx_suspend_resume(wvif, &suspend);
|
||||
tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
|
||||
} else {
|
||||
if (wvif->bss_loss_state && arg->packet_id == wvif->bss_loss_confirm_id)
|
||||
wfx_cqm_bssloss_sm(wvif, 0, 0, 1);
|
||||
}
|
||||
wfx_pending_remove(wvif->wdev, skb);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
|
||||
#include "debug.h"
|
||||
#include "wfx.h"
|
||||
#include "sta.h"
|
||||
#include "main.h"
|
||||
#include "hif_tx.h"
|
||||
#include "hif_tx_mib.h"
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "hif_rx.h"
|
||||
#include "wfx.h"
|
||||
#include "scan.h"
|
||||
#include "bh.h"
|
||||
#include "sta.h"
|
||||
#include "data_rx.h"
|
||||
#include "secure_link.h"
|
||||
#include "hif_api_cmd.h"
|
||||
|
@ -144,6 +146,43 @@ static int hif_receive_indication(struct wfx_dev *wdev, struct hif_msg *hif, voi
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int hif_event_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf)
|
||||
{
|
||||
struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
|
||||
struct hif_ind_event *body = buf;
|
||||
struct wfx_hif_event *event;
|
||||
int first;
|
||||
|
||||
WARN_ON(!wvif);
|
||||
if (!wvif)
|
||||
return 0;
|
||||
|
||||
event = kzalloc(sizeof(*event), GFP_KERNEL);
|
||||
if (!event)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(&event->evt, body, sizeof(struct hif_ind_event));
|
||||
spin_lock(&wvif->event_queue_lock);
|
||||
first = list_empty(&wvif->event_queue);
|
||||
list_add_tail(&event->link, &wvif->event_queue);
|
||||
spin_unlock(&wvif->event_queue_lock);
|
||||
|
||||
if (first)
|
||||
schedule_work(&wvif->event_handler_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hif_pm_mode_complete_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf)
|
||||
{
|
||||
struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
|
||||
|
||||
WARN_ON(!wvif);
|
||||
complete(&wvif->set_pm_mode_complete);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hif_scan_complete_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf)
|
||||
{
|
||||
struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
|
||||
|
@ -165,6 +204,17 @@ static int hif_join_complete_indication(struct wfx_dev *wdev, struct hif_msg *hi
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int hif_suspend_resume_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf)
|
||||
{
|
||||
struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
|
||||
struct hif_ind_suspend_resume_tx *body = buf;
|
||||
|
||||
WARN_ON(!wvif);
|
||||
wfx_suspend_resume(wvif, body);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hif_error_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf)
|
||||
{
|
||||
struct hif_ind_error *body = buf;
|
||||
|
@ -242,8 +292,11 @@ static const struct {
|
|||
{ HIF_IND_ID_STARTUP, hif_startup_indication },
|
||||
{ HIF_IND_ID_WAKEUP, hif_wakeup_indication },
|
||||
{ HIF_IND_ID_JOIN_COMPLETE, hif_join_complete_indication },
|
||||
{ HIF_IND_ID_SET_PM_MODE_CMPL, hif_pm_mode_complete_indication },
|
||||
{ HIF_IND_ID_SCAN_CMPL, hif_scan_complete_indication },
|
||||
{ HIF_IND_ID_SUSPEND_RESUME_TX, hif_suspend_resume_indication },
|
||||
{ HIF_IND_ID_SL_EXCHANGE_PUB_KEYS, hif_keys_indication },
|
||||
{ HIF_IND_ID_EVENT, hif_event_indication },
|
||||
{ HIF_IND_ID_GENERIC, hif_generic_indication },
|
||||
{ HIF_IND_ID_ERROR, hif_error_indication },
|
||||
{ HIF_IND_ID_EXCEPTION, hif_exception_indication },
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "bh.h"
|
||||
#include "hwio.h"
|
||||
#include "debug.h"
|
||||
#include "sta.h"
|
||||
|
||||
void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd)
|
||||
{
|
||||
|
|
|
@ -50,14 +50,112 @@ static char *slk_key;
|
|||
module_param(slk_key, charp, 0600);
|
||||
MODULE_PARM_DESC(slk_key, "secret key for secure link (expect 64 hexdecimal digits).");
|
||||
|
||||
#define RATETAB_ENT(_rate, _rateid, _flags) { \
|
||||
.bitrate = (_rate), \
|
||||
.hw_value = (_rateid), \
|
||||
.flags = (_flags), \
|
||||
}
|
||||
|
||||
static struct ieee80211_rate wfx_rates[] = {
|
||||
RATETAB_ENT(10, 0, 0),
|
||||
RATETAB_ENT(20, 1, IEEE80211_RATE_SHORT_PREAMBLE),
|
||||
RATETAB_ENT(55, 2, IEEE80211_RATE_SHORT_PREAMBLE),
|
||||
RATETAB_ENT(110, 3, IEEE80211_RATE_SHORT_PREAMBLE),
|
||||
RATETAB_ENT(60, 6, 0),
|
||||
RATETAB_ENT(90, 7, 0),
|
||||
RATETAB_ENT(120, 8, 0),
|
||||
RATETAB_ENT(180, 9, 0),
|
||||
RATETAB_ENT(240, 10, 0),
|
||||
RATETAB_ENT(360, 11, 0),
|
||||
RATETAB_ENT(480, 12, 0),
|
||||
RATETAB_ENT(540, 13, 0),
|
||||
};
|
||||
|
||||
#define CHAN2G(_channel, _freq, _flags) { \
|
||||
.band = NL80211_BAND_2GHZ, \
|
||||
.center_freq = (_freq), \
|
||||
.hw_value = (_channel), \
|
||||
.flags = (_flags), \
|
||||
.max_antenna_gain = 0, \
|
||||
.max_power = 30, \
|
||||
}
|
||||
|
||||
static struct ieee80211_channel wfx_2ghz_chantable[] = {
|
||||
CHAN2G(1, 2412, 0),
|
||||
CHAN2G(2, 2417, 0),
|
||||
CHAN2G(3, 2422, 0),
|
||||
CHAN2G(4, 2427, 0),
|
||||
CHAN2G(5, 2432, 0),
|
||||
CHAN2G(6, 2437, 0),
|
||||
CHAN2G(7, 2442, 0),
|
||||
CHAN2G(8, 2447, 0),
|
||||
CHAN2G(9, 2452, 0),
|
||||
CHAN2G(10, 2457, 0),
|
||||
CHAN2G(11, 2462, 0),
|
||||
CHAN2G(12, 2467, 0),
|
||||
CHAN2G(13, 2472, 0),
|
||||
CHAN2G(14, 2484, 0),
|
||||
};
|
||||
|
||||
static const struct ieee80211_supported_band wfx_band_2ghz = {
|
||||
.channels = wfx_2ghz_chantable,
|
||||
.n_channels = ARRAY_SIZE(wfx_2ghz_chantable),
|
||||
.bitrates = wfx_rates,
|
||||
.n_bitrates = ARRAY_SIZE(wfx_rates),
|
||||
.ht_cap = {
|
||||
// Receive caps
|
||||
.cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 |
|
||||
IEEE80211_HT_CAP_MAX_AMSDU | (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT),
|
||||
.ht_supported = 1,
|
||||
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
|
||||
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE,
|
||||
.mcs = {
|
||||
.rx_mask = { 0xFF }, // MCS0 to MCS7
|
||||
.rx_highest = 65,
|
||||
.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_limit wdev_iface_limits[] = {
|
||||
{ .max = 1, .types = BIT(NL80211_IFTYPE_STATION) },
|
||||
{ .max = 1, .types = BIT(NL80211_IFTYPE_AP) },
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_combination wfx_iface_combinations[] = {
|
||||
{
|
||||
.num_different_channels = 2,
|
||||
.max_interfaces = 2,
|
||||
.limits = wdev_iface_limits,
|
||||
.n_limits = ARRAY_SIZE(wdev_iface_limits),
|
||||
}
|
||||
};
|
||||
|
||||
static const struct ieee80211_ops wfx_ops = {
|
||||
.start = wfx_start,
|
||||
.stop = wfx_stop,
|
||||
.add_interface = wfx_add_interface,
|
||||
.remove_interface = wfx_remove_interface,
|
||||
.config = wfx_config,
|
||||
.tx = wfx_tx,
|
||||
.conf_tx = wfx_conf_tx,
|
||||
.hw_scan = wfx_hw_scan,
|
||||
.sta_add = wfx_sta_add,
|
||||
.sta_remove = wfx_sta_remove,
|
||||
.sta_notify = wfx_sta_notify,
|
||||
.set_tim = wfx_set_tim,
|
||||
.set_key = wfx_set_key,
|
||||
.set_rts_threshold = wfx_set_rts_threshold,
|
||||
.bss_info_changed = wfx_bss_info_changed,
|
||||
.prepare_multicast = wfx_prepare_multicast,
|
||||
.configure_filter = wfx_configure_filter,
|
||||
.ampdu_action = wfx_ampdu_action,
|
||||
.flush = wfx_flush,
|
||||
.add_chanctx = wfx_add_chanctx,
|
||||
.remove_chanctx = wfx_remove_chanctx,
|
||||
.change_chanctx = wfx_change_chanctx,
|
||||
.assign_vif_chanctx = wfx_assign_vif_chanctx,
|
||||
.unassign_vif_chanctx = wfx_unassign_vif_chanctx,
|
||||
};
|
||||
|
||||
bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor)
|
||||
|
@ -198,6 +296,16 @@ struct wfx_dev *wfx_init_common(struct device *dev,
|
|||
|
||||
SET_IEEE80211_DEV(hw, dev);
|
||||
|
||||
ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC);
|
||||
ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);
|
||||
ieee80211_hw_set(hw, AMPDU_AGGREGATION);
|
||||
ieee80211_hw_set(hw, CONNECTION_MONITOR);
|
||||
ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
|
||||
ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
|
||||
ieee80211_hw_set(hw, SIGNAL_DBM);
|
||||
ieee80211_hw_set(hw, SUPPORTS_PS);
|
||||
ieee80211_hw_set(hw, MFP_CAPABLE);
|
||||
|
||||
hw->vif_data_size = sizeof(struct wfx_vif);
|
||||
hw->sta_data_size = sizeof(struct wfx_sta_priv);
|
||||
hw->queues = 4;
|
||||
|
@ -206,8 +314,19 @@ struct wfx_dev *wfx_init_common(struct device *dev,
|
|||
hw->extra_tx_headroom = sizeof(struct hif_sl_msg_hdr) + sizeof(struct hif_msg)
|
||||
+ sizeof(struct hif_req_tx)
|
||||
+ 4 /* alignment */ + 8 /* TKIP IV */;
|
||||
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_AP);
|
||||
hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
|
||||
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
||||
hw->wiphy->max_ap_assoc_sta = WFX_MAX_STA_IN_AP_MODE;
|
||||
hw->wiphy->max_scan_ssids = 2;
|
||||
hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
|
||||
hw->wiphy->n_iface_combinations = ARRAY_SIZE(wfx_iface_combinations);
|
||||
hw->wiphy->iface_combinations = wfx_iface_combinations;
|
||||
hw->wiphy->bands[NL80211_BAND_2GHZ] = devm_kmalloc(dev, sizeof(wfx_band_2ghz), GFP_KERNEL);
|
||||
// FIXME: also copy wfx_rates and wfx_2ghz_chantable
|
||||
memcpy(hw->wiphy->bands[NL80211_BAND_2GHZ], &wfx_band_2ghz, sizeof(wfx_band_2ghz));
|
||||
|
||||
wdev = hw->priv;
|
||||
wdev->hw = hw;
|
||||
|
@ -290,6 +409,12 @@ int wfx_probe(struct wfx_dev *wdev)
|
|||
goto err1;
|
||||
}
|
||||
|
||||
if (wdev->hw_caps.regul_sel_mode_info.region_sel_mode) {
|
||||
wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[11].flags |= IEEE80211_CHAN_NO_IR;
|
||||
wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[12].flags |= IEEE80211_CHAN_NO_IR;
|
||||
wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[13].flags |= IEEE80211_CHAN_DISABLED;
|
||||
}
|
||||
|
||||
dev_dbg(wdev->dev, "sending configuration file %s\n", wdev->pdata.file_pds);
|
||||
err = wfx_send_pdata_pds(wdev);
|
||||
if (err < 0)
|
||||
|
@ -322,6 +447,12 @@ int wfx_probe(struct wfx_dev *wdev)
|
|||
}
|
||||
dev_info(wdev->dev, "MAC address %d: %pM\n", i, wdev->addresses[i].addr);
|
||||
}
|
||||
wdev->hw->wiphy->n_addresses = ARRAY_SIZE(wdev->addresses);
|
||||
wdev->hw->wiphy->addresses = wdev->addresses;
|
||||
|
||||
err = ieee80211_register_hw(wdev->hw);
|
||||
if (err)
|
||||
goto err1;
|
||||
|
||||
err = wfx_debug_init(wdev);
|
||||
if (err)
|
||||
|
@ -330,6 +461,7 @@ int wfx_probe(struct wfx_dev *wdev)
|
|||
return 0;
|
||||
|
||||
err2:
|
||||
ieee80211_unregister_hw(wdev->hw);
|
||||
ieee80211_free_hw(wdev->hw);
|
||||
err1:
|
||||
wfx_bh_unregister(wdev);
|
||||
|
@ -338,6 +470,7 @@ err1:
|
|||
|
||||
void wfx_release(struct wfx_dev *wdev)
|
||||
{
|
||||
ieee80211_unregister_hw(wdev->hw);
|
||||
hif_shutdown(wdev);
|
||||
wfx_bh_unregister(wdev);
|
||||
wfx_sl_deinit(wdev);
|
||||
|
|
|
@ -351,6 +351,83 @@ bool wfx_tx_queues_is_empty(struct wfx_dev *wdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool hif_handle_tx_data(struct wfx_vif *wvif, struct sk_buff *skb,
|
||||
struct wfx_queue *queue)
|
||||
{
|
||||
bool handled = false;
|
||||
struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb);
|
||||
struct hif_req_tx *req = wfx_skb_txreq(skb);
|
||||
struct ieee80211_hdr *frame = (struct ieee80211_hdr *) (req->frame + req->data_flags.fc_offset);
|
||||
|
||||
enum {
|
||||
do_probe,
|
||||
do_drop,
|
||||
do_wep,
|
||||
do_tx,
|
||||
} action = do_tx;
|
||||
|
||||
switch (wvif->vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (wvif->state < WFX_STATE_PRE_STA)
|
||||
action = do_drop;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
if (!wvif->state) {
|
||||
action = do_drop;
|
||||
} else if (!(BIT(tx_priv->raw_link_id) & (BIT(0) | wvif->link_id_map))) {
|
||||
dev_warn(wvif->wdev->dev, "a frame with expired link-id is dropped\n");
|
||||
action = do_drop;
|
||||
}
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
if (wvif->state != WFX_STATE_IBSS)
|
||||
action = do_drop;
|
||||
break;
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
default:
|
||||
action = do_drop;
|
||||
break;
|
||||
}
|
||||
|
||||
if (action == do_tx) {
|
||||
if (ieee80211_is_nullfunc(frame->frame_control)) {
|
||||
mutex_lock(&wvif->bss_loss_lock);
|
||||
if (wvif->bss_loss_state) {
|
||||
wvif->bss_loss_confirm_id = req->packet_id;
|
||||
req->queue_id.queue_id = HIF_QUEUE_ID_VOICE;
|
||||
}
|
||||
mutex_unlock(&wvif->bss_loss_lock);
|
||||
} else if (ieee80211_has_protected(frame->frame_control) &&
|
||||
tx_priv->hw_key &&
|
||||
tx_priv->hw_key->keyidx != wvif->wep_default_key_id &&
|
||||
(tx_priv->hw_key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
|
||||
tx_priv->hw_key->cipher == WLAN_CIPHER_SUITE_WEP104)) {
|
||||
action = do_wep;
|
||||
}
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case do_drop:
|
||||
BUG_ON(wfx_pending_remove(wvif->wdev, skb));
|
||||
handled = true;
|
||||
break;
|
||||
case do_wep:
|
||||
wfx_tx_lock(wvif->wdev);
|
||||
wvif->wep_default_key_id = tx_priv->hw_key->keyidx;
|
||||
wvif->wep_pending_skb = skb;
|
||||
if (!schedule_work(&wvif->wep_key_work))
|
||||
wfx_tx_unlock(wvif->wdev);
|
||||
handled = true;
|
||||
break;
|
||||
case do_tx:
|
||||
break;
|
||||
default:
|
||||
/* Do nothing */
|
||||
break;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
static int wfx_get_prio_queue(struct wfx_vif *wvif,
|
||||
u32 tx_allowed_mask, int *total)
|
||||
{
|
||||
|
@ -498,6 +575,9 @@ struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev)
|
|||
wvif = wdev_to_wvif(wdev, hif->interface);
|
||||
WARN_ON(!wvif);
|
||||
|
||||
if (hif_handle_tx_data(wvif, skb, queue))
|
||||
continue; /* Handled by WSM */
|
||||
|
||||
wvif->pspoll_mask &= ~BIT(tx_priv->raw_link_id);
|
||||
|
||||
/* allow bursting if txop is set */
|
||||
|
|
|
@ -21,11 +21,26 @@ static void __ieee80211_scan_completed_compat(struct ieee80211_hw *hw, bool abor
|
|||
ieee80211_scan_completed(hw, &info);
|
||||
}
|
||||
|
||||
static void wfx_scan_restart_delayed(struct wfx_vif *wvif)
|
||||
{
|
||||
if (wvif->delayed_unjoin) {
|
||||
wvif->delayed_unjoin = false;
|
||||
if (!schedule_work(&wvif->unjoin_work))
|
||||
wfx_tx_unlock(wvif->wdev);
|
||||
} else if (wvif->delayed_link_loss) {
|
||||
wvif->delayed_link_loss = 0;
|
||||
wfx_cqm_bssloss_sm(wvif, 1, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int wfx_scan_start(struct wfx_vif *wvif, struct wfx_scan_params *scan)
|
||||
{
|
||||
int ret;
|
||||
int tmo = 500;
|
||||
|
||||
if (wvif->state == WFX_STATE_PRE_STA)
|
||||
return -EBUSY;
|
||||
|
||||
tmo += scan->scan_req.num_of_channels *
|
||||
((20 * (scan->scan_req.max_channel_time)) + 10);
|
||||
atomic_set(&wvif->scan.in_progress, 1);
|
||||
|
@ -38,6 +53,7 @@ static int wfx_scan_start(struct wfx_vif *wvif, struct wfx_scan_params *scan)
|
|||
atomic_set(&wvif->scan.in_progress, 0);
|
||||
atomic_set(&wvif->wdev->scan_in_progress, 0);
|
||||
cancel_delayed_work_sync(&wvif->scan.timeout);
|
||||
wfx_scan_restart_delayed(wvif);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -56,6 +72,9 @@ int wfx_hw_scan(struct ieee80211_hw *hw,
|
|||
if (!wvif)
|
||||
return -EINVAL;
|
||||
|
||||
if (wvif->state == WFX_STATE_AP)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (req->n_ssids == 1 && !req->ssids[0].ssid_len)
|
||||
req->n_ssids = 0;
|
||||
|
||||
|
@ -121,11 +140,23 @@ void wfx_scan_work(struct work_struct *work)
|
|||
.scan_req.scan_type.type = 0, /* Foreground */
|
||||
};
|
||||
struct ieee80211_channel *first;
|
||||
bool first_run = (wvif->scan.begin == wvif->scan.curr &&
|
||||
wvif->scan.begin != wvif->scan.end);
|
||||
int i;
|
||||
|
||||
down(&wvif->scan.lock);
|
||||
mutex_lock(&wvif->wdev->conf_mutex);
|
||||
|
||||
if (first_run) {
|
||||
if (wvif->state == WFX_STATE_STA &&
|
||||
!(wvif->powersave_mode.pm_mode.enter_psm)) {
|
||||
struct hif_req_set_pm_mode pm = wvif->powersave_mode;
|
||||
|
||||
pm.pm_mode.enter_psm = 1;
|
||||
wfx_set_pm(wvif, &pm);
|
||||
}
|
||||
}
|
||||
|
||||
if (!wvif->scan.req || wvif->scan.curr == wvif->scan.end) {
|
||||
if (wvif->scan.output_power != wvif->wdev->output_power)
|
||||
hif_set_output_power(wvif, wvif->wdev->output_power * 10);
|
||||
|
@ -138,10 +169,14 @@ void wfx_scan_work(struct work_struct *work)
|
|||
dev_dbg(wvif->wdev->dev, "scan canceled\n");
|
||||
|
||||
wvif->scan.req = NULL;
|
||||
wfx_scan_restart_delayed(wvif);
|
||||
wfx_tx_unlock(wvif->wdev);
|
||||
mutex_unlock(&wvif->wdev->conf_mutex);
|
||||
__ieee80211_scan_completed_compat(wvif->wdev->hw, wvif->scan.status ? 1 : 0);
|
||||
up(&wvif->scan.lock);
|
||||
if (wvif->state == WFX_STATE_STA &&
|
||||
!(wvif->powersave_mode.pm_mode.enter_psm))
|
||||
wfx_set_pm(wvif, &wvif->powersave_mode);
|
||||
return;
|
||||
}
|
||||
first = *wvif->scan.curr;
|
||||
|
@ -170,6 +205,11 @@ void wfx_scan_work(struct work_struct *work)
|
|||
scan.ssids = &wvif->scan.ssids[0];
|
||||
scan.scan_req.num_of_channels = it - wvif->scan.curr;
|
||||
scan.scan_req.probe_delay = 100;
|
||||
// FIXME: Check if FW can do active scan while joined.
|
||||
if (wvif->state == WFX_STATE_STA) {
|
||||
scan.scan_req.scan_type.type = 1;
|
||||
scan.scan_req.scan_flags.fbg = 1;
|
||||
}
|
||||
|
||||
scan.ch = kcalloc(scan.scan_req.num_of_channels, sizeof(u8), GFP_KERNEL);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -12,14 +12,40 @@
|
|||
|
||||
#include "hif_api_cmd.h"
|
||||
|
||||
struct wfx_dev;
|
||||
struct wfx_vif;
|
||||
|
||||
enum wfx_state {
|
||||
WFX_STATE_PASSIVE = 0,
|
||||
WFX_STATE_PRE_STA,
|
||||
WFX_STATE_STA,
|
||||
WFX_STATE_IBSS,
|
||||
WFX_STATE_AP,
|
||||
};
|
||||
|
||||
struct wfx_ht_info {
|
||||
struct ieee80211_sta_ht_cap ht_cap;
|
||||
enum nl80211_channel_type channel_type;
|
||||
uint16_t operation_mode;
|
||||
};
|
||||
|
||||
struct wfx_hif_event {
|
||||
struct list_head link;
|
||||
struct hif_ind_event evt;
|
||||
};
|
||||
|
||||
struct wfx_edca_params {
|
||||
/* NOTE: index is a linux queue id. */
|
||||
struct hif_req_edca_queue_params params[IEEE80211_NUM_ACS];
|
||||
bool uapsd_enable[IEEE80211_NUM_ACS];
|
||||
};
|
||||
|
||||
struct wfx_grp_addr_table {
|
||||
bool enable;
|
||||
int num_addresses;
|
||||
u8 address_list[8][ETH_ALEN];
|
||||
};
|
||||
|
||||
struct wfx_sta_priv {
|
||||
int link_id;
|
||||
int vif_id;
|
||||
|
@ -28,9 +54,48 @@ struct wfx_sta_priv {
|
|||
// mac80211 interface
|
||||
int wfx_start(struct ieee80211_hw *hw);
|
||||
void wfx_stop(struct ieee80211_hw *hw);
|
||||
int wfx_config(struct ieee80211_hw *hw, u32 changed);
|
||||
int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
|
||||
u64 wfx_prepare_multicast(struct ieee80211_hw *hw,
|
||||
struct netdev_hw_addr_list *mc_list);
|
||||
void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
|
||||
unsigned int *total_flags, u64 unused);
|
||||
|
||||
int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
|
||||
void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
|
||||
void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
u32 queues, bool drop);
|
||||
int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
u16 queue, const struct ieee80211_tx_queue_params *params);
|
||||
void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *info, u32 changed);
|
||||
int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta);
|
||||
int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta);
|
||||
void wfx_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum sta_notify_cmd cmd, struct ieee80211_sta *sta);
|
||||
int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set);
|
||||
int wfx_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_ampdu_params *params);
|
||||
int wfx_add_chanctx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_chanctx_conf *conf);
|
||||
void wfx_remove_chanctx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_chanctx_conf *conf);
|
||||
void wfx_change_chanctx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_chanctx_conf *conf, u32 changed);
|
||||
int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_chanctx_conf *conf);
|
||||
void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_chanctx_conf *conf);
|
||||
|
||||
// WSM Callbacks
|
||||
void wfx_suspend_resume(struct wfx_vif *wvif, struct hif_ind_suspend_resume_tx *arg);
|
||||
|
||||
// Other Helpers
|
||||
void wfx_cqm_bssloss_sm(struct wfx_vif *wvif, int init, int good, int bad);
|
||||
void wfx_update_filtering(struct wfx_vif *wvif);
|
||||
int wfx_set_pm(struct wfx_vif *wvif, const struct hif_req_set_pm_mode *arg);
|
||||
int wfx_fwd_probe_req(struct wfx_vif *wvif, bool enable);
|
||||
|
||||
#endif /* WFX_STA_H */
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#define WFX_H
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "bh.h"
|
||||
|
@ -61,8 +63,15 @@ struct wfx_dev {
|
|||
struct wfx_vif {
|
||||
struct wfx_dev *wdev;
|
||||
struct ieee80211_vif *vif;
|
||||
struct ieee80211_channel *channel;
|
||||
int id;
|
||||
enum wfx_state state;
|
||||
|
||||
int delayed_link_loss;
|
||||
int bss_loss_state;
|
||||
u32 bss_loss_confirm_id;
|
||||
struct mutex bss_loss_lock;
|
||||
struct delayed_work bss_loss_work;
|
||||
|
||||
u32 link_id_map;
|
||||
struct wfx_link_entry link_id_db[WFX_MAX_STA_IN_AP_MODE];
|
||||
|
@ -72,6 +81,7 @@ struct wfx_vif {
|
|||
bool aid0_bit_set;
|
||||
bool mcast_tx;
|
||||
bool mcast_buffered;
|
||||
struct wfx_grp_addr_table mcast_filter;
|
||||
struct timer_list mcast_timeout;
|
||||
struct work_struct mcast_start_work;
|
||||
struct work_struct mcast_stop_work;
|
||||
|
@ -86,13 +96,40 @@ struct wfx_vif {
|
|||
u32 sta_asleep_mask;
|
||||
u32 pspoll_mask;
|
||||
spinlock_t ps_state_lock;
|
||||
struct work_struct set_tim_work;
|
||||
|
||||
int dtim_period;
|
||||
int beacon_int;
|
||||
bool enable_beacon;
|
||||
struct work_struct set_beacon_wakeup_period_work;
|
||||
|
||||
bool filter_bssid;
|
||||
bool fwd_probe_req;
|
||||
bool disable_beacon_filter;
|
||||
struct work_struct update_filtering_work;
|
||||
|
||||
u32 erp_info;
|
||||
int cqm_rssi_thold;
|
||||
bool setbssparams_done;
|
||||
struct wfx_ht_info ht_info;
|
||||
struct wfx_edca_params edca;
|
||||
struct hif_mib_set_uapsd_information uapsd_info;
|
||||
struct hif_req_set_bss_params bss_params;
|
||||
struct work_struct bss_params_work;
|
||||
struct work_struct set_cts_work;
|
||||
|
||||
int join_complete_status;
|
||||
bool delayed_unjoin;
|
||||
struct work_struct unjoin_work;
|
||||
|
||||
struct wfx_scan scan;
|
||||
|
||||
struct hif_req_set_pm_mode powersave_mode;
|
||||
struct completion set_pm_mode_complete;
|
||||
|
||||
struct list_head event_queue;
|
||||
spinlock_t event_queue_lock;
|
||||
struct work_struct event_handler_work;
|
||||
};
|
||||
|
||||
static inline struct wfx_vif *wdev_to_wvif(struct wfx_dev *wdev, int vif_id)
|
||||
|
@ -126,6 +163,20 @@ static inline struct wfx_vif *wvif_iterate(struct wfx_dev *wdev, struct wfx_vif
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline int wvif_count(struct wfx_dev *wdev)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
struct wfx_vif *wvif;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) {
|
||||
wvif = wdev_to_wvif(wdev, i);
|
||||
if (wvif)
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void memreverse(uint8_t *src, uint8_t length)
|
||||
{
|
||||
uint8_t *lo = src;
|
||||
|
|
Loading…
Reference in a new issue