Commit 40115bbc authored by Jérôme Pouiller's avatar Jérôme Pouiller Committed by Greg Kroah-Hartman

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: default avatarJérôme Pouiller <jerome.pouiller@silabs.com>
Link: https://lore.kernel.org/r/20190919142527.31797-21-Jerome.Pouiller@silabs.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent fb2490f6
...@@ -21,6 +21,8 @@ static int wfx_handle_pspoll(struct wfx_vif *wvif, struct sk_buff *skb) ...@@ -21,6 +21,8 @@ static int wfx_handle_pspoll(struct wfx_vif *wvif, struct sk_buff *skb)
u32 pspoll_mask = 0; u32 pspoll_mask = 0;
int i; int i;
if (wvif->state != WFX_STATE_AP)
return 1;
if (!ether_addr_equal(wvif->vif->addr, pspoll->bssid)) if (!ether_addr_equal(wvif->vif->addr, pspoll->bssid))
return 1; return 1;
...@@ -162,6 +164,30 @@ void wfx_rx_cb(struct wfx_vif *wvif, struct hif_ind_rx *arg, struct sk_buff *skb ...@@ -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 && arg->rx_flags.match_uc_addr
&& mgmt->u.action.category == WLAN_CATEGORY_BACK) && mgmt->u.action.category == WLAN_CATEGORY_BACK)
goto drop; 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) { if (early_data) {
spin_lock_bh(&wvif->ps_state_lock); spin_lock_bh(&wvif->ps_state_lock);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "data_tx.h" #include "data_tx.h"
#include "wfx.h" #include "wfx.h"
#include "bh.h" #include "bh.h"
#include "sta.h"
#include "queue.h" #include "queue.h"
#include "debug.h" #include "debug.h"
#include "traces.h" #include "traces.h"
...@@ -359,6 +360,9 @@ void wfx_link_id_gc_work(struct work_struct *work) ...@@ -359,6 +360,9 @@ void wfx_link_id_gc_work(struct work_struct *work)
u32 mask; u32 mask;
int i; int i;
if (wvif->state != WFX_STATE_AP)
return;
wfx_tx_lock_flush(wvif->wdev); wfx_tx_lock_flush(wvif->wdev);
spin_lock_bh(&wvif->ps_state_lock); spin_lock_bh(&wvif->ps_state_lock);
for (i = 0; i < WFX_MAX_STA_IN_AP_MODE; ++i) { 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) ...@@ -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)); memset(tx_info->pad, 0, sizeof(tx_info->pad));
if (!arg->status) { 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; tx_info->status.tx_time = arg->media_delay - arg->tx_queue_delay;
if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
else else
tx_info->flags |= IEEE80211_TX_STAT_ACK; tx_info->flags |= IEEE80211_TX_STAT_ACK;
} else if (arg->status == HIF_REQUEUE) { } 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"); WARN(!arg->tx_result_flags.requeue, "incoherent status and result_flags");
wfx_suspend_resume(wvif, &suspend);
tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; 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); wfx_pending_remove(wvif->wdev, skb);
} }
......
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
#include "debug.h" #include "debug.h"
#include "wfx.h" #include "wfx.h"
#include "sta.h"
#include "main.h" #include "main.h"
#include "hif_tx.h"
#include "hif_tx_mib.h" #include "hif_tx_mib.h"
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include "hif_rx.h" #include "hif_rx.h"
#include "wfx.h" #include "wfx.h"
#include "scan.h" #include "scan.h"
#include "bh.h"
#include "sta.h"
#include "data_rx.h" #include "data_rx.h"
#include "secure_link.h" #include "secure_link.h"
#include "hif_api_cmd.h" #include "hif_api_cmd.h"
...@@ -144,6 +146,43 @@ static int hif_receive_indication(struct wfx_dev *wdev, struct hif_msg *hif, voi ...@@ -144,6 +146,43 @@ static int hif_receive_indication(struct wfx_dev *wdev, struct hif_msg *hif, voi
return 0; 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) 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); 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 ...@@ -165,6 +204,17 @@ static int hif_join_complete_indication(struct wfx_dev *wdev, struct hif_msg *hi
return 0; 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) static int hif_error_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf)
{ {
struct hif_ind_error *body = buf; struct hif_ind_error *body = buf;
...@@ -242,8 +292,11 @@ static const struct { ...@@ -242,8 +292,11 @@ static const struct {
{ HIF_IND_ID_STARTUP, hif_startup_indication }, { HIF_IND_ID_STARTUP, hif_startup_indication },
{ HIF_IND_ID_WAKEUP, hif_wakeup_indication }, { HIF_IND_ID_WAKEUP, hif_wakeup_indication },
{ HIF_IND_ID_JOIN_COMPLETE, hif_join_complete_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_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_SL_EXCHANGE_PUB_KEYS, hif_keys_indication },
{ HIF_IND_ID_EVENT, hif_event_indication },
{ HIF_IND_ID_GENERIC, hif_generic_indication }, { HIF_IND_ID_GENERIC, hif_generic_indication },
{ HIF_IND_ID_ERROR, hif_error_indication }, { HIF_IND_ID_ERROR, hif_error_indication },
{ HIF_IND_ID_EXCEPTION, hif_exception_indication }, { HIF_IND_ID_EXCEPTION, hif_exception_indication },
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "bh.h" #include "bh.h"
#include "hwio.h" #include "hwio.h"
#include "debug.h" #include "debug.h"
#include "sta.h"
void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd) void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd)
{ {
......
...@@ -50,14 +50,112 @@ static char *slk_key; ...@@ -50,14 +50,112 @@ static char *slk_key;
module_param(slk_key, charp, 0600); module_param(slk_key, charp, 0600);
MODULE_PARM_DESC(slk_key, "secret key for secure link (expect 64 hexdecimal digits)."); 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 = { static const struct ieee80211_ops wfx_ops = {
.start = wfx_start, .start = wfx_start,
.stop = wfx_stop, .stop = wfx_stop,
.add_interface = wfx_add_interface, .add_interface = wfx_add_interface,
.remove_interface = wfx_remove_interface, .remove_interface = wfx_remove_interface,
.config = wfx_config,
.tx = wfx_tx, .tx = wfx_tx,
.conf_tx = wfx_conf_tx,
.hw_scan = wfx_hw_scan, .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_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) 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, ...@@ -198,6 +296,16 @@ struct wfx_dev *wfx_init_common(struct device *dev,
SET_IEEE80211_DEV(hw, 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->vif_data_size = sizeof(struct wfx_vif);
hw->sta_data_size = sizeof(struct wfx_sta_priv); hw->sta_data_size = sizeof(struct wfx_sta_priv);
hw->queues = 4; hw->queues = 4;
...@@ -206,8 +314,19 @@ struct wfx_dev *wfx_init_common(struct device *dev, ...@@ -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) hw->extra_tx_headroom = sizeof(struct hif_sl_msg_hdr) + sizeof(struct hif_msg)
+ sizeof(struct hif_req_tx) + sizeof(struct hif_req_tx)
+ 4 /* alignment */ + 8 /* TKIP IV */; + 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_ssids = 2;
hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; 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->priv;
wdev->hw = hw; wdev->hw = hw;
...@@ -290,6 +409,12 @@ int wfx_probe(struct wfx_dev *wdev) ...@@ -290,6 +409,12 @@ int wfx_probe(struct wfx_dev *wdev)
goto err1; 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); dev_dbg(wdev->dev, "sending configuration file %s\n", wdev->pdata.file_pds);
err = wfx_send_pdata_pds(wdev); err = wfx_send_pdata_pds(wdev);
if (err < 0) if (err < 0)
...@@ -322,6 +447,12 @@ int wfx_probe(struct wfx_dev *wdev) ...@@ -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); 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); err = wfx_debug_init(wdev);
if (err) if (err)
...@@ -330,6 +461,7 @@ int wfx_probe(struct wfx_dev *wdev) ...@@ -330,6 +461,7 @@ int wfx_probe(struct wfx_dev *wdev)
return 0; return 0;
err2: err2:
ieee80211_unregister_hw(wdev->hw);
ieee80211_free_hw(wdev->hw); ieee80211_free_hw(wdev->hw);
err1: err1:
wfx_bh_unregister(wdev); wfx_bh_unregister(wdev);
...@@ -338,6 +470,7 @@ int wfx_probe(struct wfx_dev *wdev) ...@@ -338,6 +470,7 @@ int wfx_probe(struct wfx_dev *wdev)
void wfx_release(struct wfx_dev *wdev) void wfx_release(struct wfx_dev *wdev)
{ {
ieee80211_unregister_hw(wdev->hw);
hif_shutdown(wdev); hif_shutdown(wdev);
wfx_bh_unregister(wdev); wfx_bh_unregister(wdev);
wfx_sl_deinit(wdev); wfx_sl_deinit(wdev);
......
...@@ -351,6 +351,83 @@ bool wfx_tx_queues_is_empty(struct wfx_dev *wdev) ...@@ -351,6 +351,83 @@ bool wfx_tx_queues_is_empty(struct wfx_dev *wdev)
return ret; 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, static int wfx_get_prio_queue(struct wfx_vif *wvif,
u32 tx_allowed_mask, int *total) u32 tx_allowed_mask, int *total)
{ {
...@@ -498,6 +575,9 @@ struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev) ...@@ -498,6 +575,9 @@ struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev)
wvif = wdev_to_wvif(wdev, hif->interface); wvif = wdev_to_wvif(wdev, hif->interface);
WARN_ON(!wvif); WARN_ON(!wvif);
if (hif_handle_tx_data(wvif, skb, queue))
continue; /* Handled by WSM */
wvif->pspoll_mask &= ~BIT(tx_priv->raw_link_id); wvif->pspoll_mask &= ~BIT(tx_priv->raw_link_id);
/* allow bursting if txop is set */ /* allow bursting if txop is set */
......
...@@ -21,11 +21,26 @@ static void __ieee80211_scan_completed_compat(struct ieee80211_hw *hw, bool abor ...@@ -21,11 +21,26 @@ static void __ieee80211_scan_completed_compat(struct ieee80211_hw *hw, bool abor
ieee80211_scan_completed(hw, &info); 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) static int wfx_scan_start(struct wfx_vif *wvif, struct wfx_scan_params *scan)
{ {
int ret; int ret;
int tmo = 500; int tmo = 500;
if (wvif->state == WFX_STATE_PRE_STA)
return -EBUSY;
tmo += scan->scan_req.num_of_channels * tmo += scan->scan_req.num_of_channels *
((20 * (scan->scan_req.max_channel_time)) + 10); ((20 * (scan->scan_req.max_channel_time)) + 10);
atomic_set(&wvif->scan.in_progress, 1); 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) ...@@ -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->scan.in_progress, 0);
atomic_set(&wvif->wdev->scan_in_progress, 0); atomic_set(&wvif->wdev->scan_in_progress, 0);
cancel_delayed_work_sync(&wvif->scan.timeout); cancel_delayed_work_sync(&wvif->scan.timeout);
wfx_scan_restart_delayed(wvif);
} }
return ret; return ret;
} }
...@@ -56,6 +72,9 @@ int wfx_hw_scan(struct ieee80211_hw *hw, ...@@ -56,6 +72,9 @@ int wfx_hw_scan(struct ieee80211_hw *hw,
if (!wvif) if (!wvif)
return -EINVAL; return -EINVAL;
if (wvif->state == WFX_STATE_AP)
return -EOPNOTSUPP;
if (req->n_ssids == 1 && !req->ssids[0].ssid_len) if (req->n_ssids == 1 && !req->ssids[0].ssid_len)
req->n_ssids = 0; req->n_ssids = 0;
...@@ -121,11 +140,23 @@ void wfx_scan_work(struct work_struct *work) ...@@ -121,11 +140,23 @@ void wfx_scan_work(struct work_struct *work)
.scan_req.scan_type.type = 0, /* Foreground */ .scan_req.scan_type.type = 0, /* Foreground */
}; };
struct ieee80211_channel *first; struct ieee80211_channel *first;
bool first_run = (wvif->scan.begin == wvif->scan.curr &&
wvif->scan.begin != wvif->scan.end);
int i; int i;
down(&wvif->scan.lock); down(&wvif->scan.lock);
mutex_lock(&wvif->wdev->conf_mutex); 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.req || wvif->scan.curr == wvif->scan.end) {
if (wvif->scan.output_power != wvif->wdev->output_power) if (wvif->scan.output_power != wvif->wdev->output_power)
hif_set_output_power(wvif, wvif->wdev->output_power * 10); hif_set_output_power(wvif, wvif->wdev->output_power * 10);
...@@ -138,10 +169,14 @@ void wfx_scan_work(struct work_struct *work) ...@@ -138,10 +169,14 @@ void wfx_scan_work(struct work_struct *work)
dev_dbg(wvif->wdev->dev, "scan canceled\n"); dev_dbg(wvif->wdev->dev, "scan canceled\n");
wvif->scan.req = NULL; wvif->scan.req = NULL;
wfx_scan_restart_delayed(wvif);
wfx_tx_unlock(wvif->wdev); wfx_tx_unlock(wvif->wdev);
mutex_unlock(&wvif->wdev->conf_mutex); mutex_unlock(&wvif->wdev->conf_mutex);
__ieee80211_scan_completed_compat(wvif->wdev->hw, wvif->scan.status ? 1 : 0); __ieee80211_scan_completed_compat(wvif->wdev->hw, wvif->scan.status ? 1 : 0);
up(&wvif->scan.lock); 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; return;
} }
first = *wvif->scan.curr; first = *wvif->scan.curr;
...@@ -170,6 +205,11 @@ void wfx_scan_work(struct work_struct *work) ...@@ -170,6 +205,11 @@ void wfx_scan_work(struct work_struct *work)
scan.ssids = &wvif->scan.ssids[0]; scan.ssids = &wvif->scan.ssids[0];
scan.scan_req.num_of_channels = it - wvif->scan.curr; scan.scan_req.num_of_channels = it - wvif->scan.curr;
scan.scan_req.probe_delay = 100; 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); scan.ch = kcalloc(scan.scan_req.num_of_channels, sizeof(u8), GFP_KERNEL);
......
This diff is collapsed.
...@@ -12,14 +12,40 @@ ...@@ -12,14 +12,40 @@
#include "hif_api_cmd.h" #include "hif_api_cmd.h"
struct wfx_dev;
struct wfx_vif; 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 { struct wfx_edca_params {
/* NOTE: index is a linux queue id. */ /* NOTE: index is a linux queue id. */
struct hif_req_edca_queue_params params[IEEE80211_NUM_ACS]; struct hif_req_edca_queue_params params[IEEE80211_NUM_ACS];
bool uapsd_enable[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 { struct wfx_sta_priv {
int link_id; int link_id;
int vif_id; int vif_id;
...@@ -28,9 +54,48 @@ struct wfx_sta_priv { ...@@ -28,9 +54,48 @@ struct wfx_sta_priv {
// mac80211 interface // mac80211 interface
int wfx_start(struct ieee80211_hw *hw); int wfx_start(struct ieee80211_hw *hw);
void wfx_stop(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); 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_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); int wfx_fwd_probe_req(struct wfx_vif *wvif, bool enable);
#endif /* WFX_STA_H */ #endif /* WFX_STA_H */
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#define WFX_H #define WFX_H
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <net/mac80211.h> #include <net/mac80211.h>
#include "bh.h" #include "bh.h"
...@@ -61,8 +63,15 @@ struct wfx_dev { ...@@ -61,8 +63,15 @@ struct wfx_dev {
struct wfx_vif { struct wfx_vif {
struct wfx_dev *wdev; struct wfx_dev *wdev;
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
struct ieee80211_channel *channel;
int id; 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; u32 link_id_map;
struct wfx_link_entry link_id_db[WFX_MAX_STA_IN_AP_MODE]; struct wfx_link_entry link_id_db[WFX_MAX_STA_IN_AP_MODE];
...@@ -72,6 +81,7 @@ struct wfx_vif { ...@@ -72,6 +81,7 @@ struct wfx_vif {
bool aid0_bit_set; bool aid0_bit_set;
bool mcast_tx; bool mcast_tx;
bool mcast_buffered; bool mcast_buffered;
struct wfx_grp_addr_table mcast_filter;
struct timer_list mcast_timeout; struct timer_list mcast_timeout;
struct work_struct mcast_start_work; struct work_struct mcast_start_work;
struct work_struct mcast_stop_work; struct work_struct mcast_stop_work;
...@@ -86,13 +96,40 @@ struct wfx_vif { ...@@ -86,13 +96,40 @@ struct wfx_vif {
u32 sta_asleep_mask; u32 sta_asleep_mask;
u32 pspoll_mask; u32 pspoll_mask;
spinlock_t ps_state_lock; 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 filter_bssid;
bool fwd_probe_req; 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 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 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) 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 ...@@ -126,6 +163,20 @@ static inline struct wfx_vif *wvif_iterate(struct wfx_dev *wdev, struct wfx_vif
return NULL; 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) static inline void memreverse(uint8_t *src, uint8_t length)
{ {
uint8_t *lo = src; uint8_t *lo = src;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment