Commit 40822a90 authored by Vladimir Kondratiev's avatar Vladimir Kondratiev Committed by Kalle Valo

wil6210: implement cfg80211 probe_client() op

Access point require this API to check peer alive status.
Assume peer is alive when it is connected, because
firmware implements keep alive checks and will disconnect
peer if it is not alive.
Signed-off-by: default avatarVladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 713c8a29
...@@ -808,6 +808,96 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy, ...@@ -808,6 +808,96 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy,
return 0; return 0;
} }
/* probe_client handling */
static void wil_probe_client_handle(struct wil6210_priv *wil,
struct wil_probe_client_req *req)
{
struct net_device *ndev = wil_to_ndev(wil);
struct wil_sta_info *sta = &wil->sta[req->cid];
/* assume STA is alive if it is still connected,
* else FW will disconnect it
*/
bool alive = (sta->status == wil_sta_connected);
cfg80211_probe_status(ndev, sta->addr, req->cookie, alive, GFP_KERNEL);
}
static struct list_head *next_probe_client(struct wil6210_priv *wil)
{
struct list_head *ret = NULL;
mutex_lock(&wil->probe_client_mutex);
if (!list_empty(&wil->probe_client_pending)) {
ret = wil->probe_client_pending.next;
list_del(ret);
}
mutex_unlock(&wil->probe_client_mutex);
return ret;
}
void wil_probe_client_worker(struct work_struct *work)
{
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
probe_client_worker);
struct wil_probe_client_req *req;
struct list_head *lh;
while ((lh = next_probe_client(wil)) != NULL) {
req = list_entry(lh, struct wil_probe_client_req, list);
wil_probe_client_handle(wil, req);
kfree(req);
}
}
void wil_probe_client_flush(struct wil6210_priv *wil)
{
struct wil_probe_client_req *req, *t;
wil_dbg_misc(wil, "%s()\n", __func__);
mutex_lock(&wil->probe_client_mutex);
list_for_each_entry_safe(req, t, &wil->probe_client_pending, list) {
list_del(&req->list);
kfree(req);
}
mutex_unlock(&wil->probe_client_mutex);
}
static int wil_cfg80211_probe_client(struct wiphy *wiphy,
struct net_device *dev,
const u8 *peer, u64 *cookie)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
struct wil_probe_client_req *req;
int cid = wil_find_cid(wil, peer);
wil_dbg_misc(wil, "%s(%pM => CID %d)\n", __func__, peer, cid);
if (cid < 0)
return -ENOLINK;
req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req)
return -ENOMEM;
req->cid = cid;
req->cookie = cid;
mutex_lock(&wil->probe_client_mutex);
list_add_tail(&req->list, &wil->probe_client_pending);
mutex_unlock(&wil->probe_client_mutex);
*cookie = req->cookie;
queue_work(wil->wq_service, &wil->probe_client_worker);
return 0;
}
static struct cfg80211_ops wil_cfg80211_ops = { static struct cfg80211_ops wil_cfg80211_ops = {
.scan = wil_cfg80211_scan, .scan = wil_cfg80211_scan,
.connect = wil_cfg80211_connect, .connect = wil_cfg80211_connect,
...@@ -827,6 +917,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { ...@@ -827,6 +917,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {
.start_ap = wil_cfg80211_start_ap, .start_ap = wil_cfg80211_start_ap,
.stop_ap = wil_cfg80211_stop_ap, .stop_ap = wil_cfg80211_stop_ap,
.del_station = wil_cfg80211_del_station, .del_station = wil_cfg80211_del_station,
.probe_client = wil_cfg80211_probe_client,
}; };
static void wil_wiphy_init(struct wiphy *wiphy) static void wil_wiphy_init(struct wiphy *wiphy)
......
...@@ -405,6 +405,7 @@ int wil_priv_init(struct wil6210_priv *wil) ...@@ -405,6 +405,7 @@ int wil_priv_init(struct wil6210_priv *wil)
mutex_init(&wil->wmi_mutex); mutex_init(&wil->wmi_mutex);
mutex_init(&wil->back_rx_mutex); mutex_init(&wil->back_rx_mutex);
mutex_init(&wil->back_tx_mutex); mutex_init(&wil->back_tx_mutex);
mutex_init(&wil->probe_client_mutex);
init_completion(&wil->wmi_ready); init_completion(&wil->wmi_ready);
init_completion(&wil->wmi_call); init_completion(&wil->wmi_call);
...@@ -419,10 +420,12 @@ int wil_priv_init(struct wil6210_priv *wil) ...@@ -419,10 +420,12 @@ int wil_priv_init(struct wil6210_priv *wil)
INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker); INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker);
INIT_WORK(&wil->back_tx_worker, wil_back_tx_worker); INIT_WORK(&wil->back_tx_worker, wil_back_tx_worker);
INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker);
INIT_LIST_HEAD(&wil->pending_wmi_ev); INIT_LIST_HEAD(&wil->pending_wmi_ev);
INIT_LIST_HEAD(&wil->back_rx_pending); INIT_LIST_HEAD(&wil->back_rx_pending);
INIT_LIST_HEAD(&wil->back_tx_pending); INIT_LIST_HEAD(&wil->back_tx_pending);
INIT_LIST_HEAD(&wil->probe_client_pending);
spin_lock_init(&wil->wmi_ev_lock); spin_lock_init(&wil->wmi_ev_lock);
init_waitqueue_head(&wil->wq); init_waitqueue_head(&wil->wq);
...@@ -485,6 +488,8 @@ void wil_priv_deinit(struct wil6210_priv *wil) ...@@ -485,6 +488,8 @@ void wil_priv_deinit(struct wil6210_priv *wil)
cancel_work_sync(&wil->back_rx_worker); cancel_work_sync(&wil->back_rx_worker);
wil_back_tx_flush(wil); wil_back_tx_flush(wil);
cancel_work_sync(&wil->back_tx_worker); cancel_work_sync(&wil->back_tx_worker);
wil_probe_client_flush(wil);
cancel_work_sync(&wil->probe_client_worker);
destroy_workqueue(wil->wq_service); destroy_workqueue(wil->wq_service);
destroy_workqueue(wil->wmi_wq); destroy_workqueue(wil->wmi_wq);
} }
......
...@@ -504,6 +504,12 @@ struct wil_back_tx { ...@@ -504,6 +504,12 @@ struct wil_back_tx {
u16 agg_timeout; u16 agg_timeout;
}; };
struct wil_probe_client_req {
struct list_head list;
u64 cookie;
u8 cid;
};
struct wil6210_priv { struct wil6210_priv {
struct pci_dev *pdev; struct pci_dev *pdev;
int n_msi; int n_msi;
...@@ -564,6 +570,10 @@ struct wil6210_priv { ...@@ -564,6 +570,10 @@ struct wil6210_priv {
struct list_head back_tx_pending; struct list_head back_tx_pending;
struct mutex back_tx_mutex; /* protect @back_tx_pending */ struct mutex back_tx_mutex; /* protect @back_tx_pending */
struct work_struct back_tx_worker; struct work_struct back_tx_worker;
/* keep alive */
struct list_head probe_client_pending;
struct mutex probe_client_mutex; /* protect @probe_client_pending */
struct work_struct probe_client_worker;
/* DMA related */ /* DMA related */
struct vring vring_rx; struct vring vring_rx;
struct vring vring_tx[WIL6210_MAX_TX_RINGS]; struct vring vring_tx[WIL6210_MAX_TX_RINGS];
...@@ -722,6 +732,8 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan); ...@@ -722,6 +732,8 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan);
int wmi_pcp_stop(struct wil6210_priv *wil); int wmi_pcp_stop(struct wil6210_priv *wil);
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
u16 reason_code, bool from_event); u16 reason_code, bool from_event);
void wil_probe_client_flush(struct wil6210_priv *wil);
void wil_probe_client_worker(struct work_struct *work);
int wil_rx_init(struct wil6210_priv *wil, u16 size); int wil_rx_init(struct wil6210_priv *wil, u16 size);
void wil_rx_fini(struct wil6210_priv *wil); void wil_rx_fini(struct wil6210_priv *wil);
......
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