cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

p2p.c (8912B)


      1// SPDX-License-Identifier: ISC
      2/*
      3 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
      4 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
      5 */
      6
      7#include "wil6210.h"
      8#include "wmi.h"
      9
     10#define P2P_WILDCARD_SSID "DIRECT-"
     11#define P2P_DMG_SOCIAL_CHANNEL 2
     12#define P2P_SEARCH_DURATION_MS 500
     13#define P2P_DEFAULT_BI 100
     14
     15static int wil_p2p_start_listen(struct wil6210_vif *vif)
     16{
     17	struct wil6210_priv *wil = vif_to_wil(vif);
     18	struct wil_p2p_info *p2p = &vif->p2p;
     19	u8 channel = p2p->listen_chan.hw_value;
     20	int rc;
     21
     22	lockdep_assert_held(&wil->mutex);
     23
     24	rc = wmi_p2p_cfg(vif, channel, P2P_DEFAULT_BI);
     25	if (rc) {
     26		wil_err(wil, "wmi_p2p_cfg failed\n");
     27		goto out;
     28	}
     29
     30	rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
     31	if (rc) {
     32		wil_err(wil, "wmi_set_ssid failed\n");
     33		goto out_stop;
     34	}
     35
     36	rc = wmi_start_listen(vif);
     37	if (rc) {
     38		wil_err(wil, "wmi_start_listen failed\n");
     39		goto out_stop;
     40	}
     41
     42	INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired);
     43	mod_timer(&p2p->discovery_timer,
     44		  jiffies + msecs_to_jiffies(p2p->listen_duration));
     45out_stop:
     46	if (rc)
     47		wmi_stop_discovery(vif);
     48
     49out:
     50	return rc;
     51}
     52
     53bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
     54{
     55	return (request->n_channels == 1) &&
     56	       (request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL);
     57}
     58
     59int wil_p2p_search(struct wil6210_vif *vif,
     60		   struct cfg80211_scan_request *request)
     61{
     62	struct wil6210_priv *wil = vif_to_wil(vif);
     63	int rc;
     64	struct wil_p2p_info *p2p = &vif->p2p;
     65
     66	wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL);
     67
     68	lockdep_assert_held(&wil->mutex);
     69
     70	if (p2p->discovery_started) {
     71		wil_err(wil, "search failed. discovery already ongoing\n");
     72		rc = -EBUSY;
     73		goto out;
     74	}
     75
     76	rc = wmi_p2p_cfg(vif, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
     77	if (rc) {
     78		wil_err(wil, "wmi_p2p_cfg failed\n");
     79		goto out;
     80	}
     81
     82	rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
     83	if (rc) {
     84		wil_err(wil, "wmi_set_ssid failed\n");
     85		goto out_stop;
     86	}
     87
     88	/* Set application IE to probe request and probe response */
     89	rc = wmi_set_ie(vif, WMI_FRAME_PROBE_REQ,
     90			request->ie_len, request->ie);
     91	if (rc) {
     92		wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n");
     93		goto out_stop;
     94	}
     95
     96	/* supplicant doesn't provide Probe Response IEs. As a workaround -
     97	 * re-use Probe Request IEs
     98	 */
     99	rc = wmi_set_ie(vif, WMI_FRAME_PROBE_RESP,
    100			request->ie_len, request->ie);
    101	if (rc) {
    102		wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n");
    103		goto out_stop;
    104	}
    105
    106	rc = wmi_start_search(vif);
    107	if (rc) {
    108		wil_err(wil, "wmi_start_search failed\n");
    109		goto out_stop;
    110	}
    111
    112	p2p->discovery_started = 1;
    113	INIT_WORK(&p2p->discovery_expired_work, wil_p2p_search_expired);
    114	mod_timer(&p2p->discovery_timer,
    115		  jiffies + msecs_to_jiffies(P2P_SEARCH_DURATION_MS));
    116
    117out_stop:
    118	if (rc)
    119		wmi_stop_discovery(vif);
    120
    121out:
    122	return rc;
    123}
    124
    125int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
    126		   unsigned int duration, struct ieee80211_channel *chan,
    127		   u64 *cookie)
    128{
    129	struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
    130	struct wil_p2p_info *p2p = &vif->p2p;
    131	int rc;
    132
    133	if (!chan)
    134		return -EINVAL;
    135
    136	wil_dbg_misc(wil, "p2p_listen: duration %d\n", duration);
    137
    138	mutex_lock(&wil->mutex);
    139
    140	if (p2p->discovery_started) {
    141		wil_err(wil, "discovery already ongoing\n");
    142		rc = -EBUSY;
    143		goto out;
    144	}
    145
    146	memcpy(&p2p->listen_chan, chan, sizeof(*chan));
    147	*cookie = ++p2p->cookie;
    148	p2p->listen_duration = duration;
    149
    150	mutex_lock(&wil->vif_mutex);
    151	if (vif->scan_request) {
    152		wil_dbg_misc(wil, "Delaying p2p listen until scan done\n");
    153		p2p->pending_listen_wdev = wdev;
    154		p2p->discovery_started = 1;
    155		rc = 0;
    156		mutex_unlock(&wil->vif_mutex);
    157		goto out;
    158	}
    159	mutex_unlock(&wil->vif_mutex);
    160
    161	rc = wil_p2p_start_listen(vif);
    162	if (rc)
    163		goto out;
    164
    165	p2p->discovery_started = 1;
    166	if (vif->mid == 0)
    167		wil->radio_wdev = wdev;
    168
    169	cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
    170				  GFP_KERNEL);
    171
    172out:
    173	mutex_unlock(&wil->mutex);
    174	return rc;
    175}
    176
    177u8 wil_p2p_stop_discovery(struct wil6210_vif *vif)
    178{
    179	struct wil_p2p_info *p2p = &vif->p2p;
    180	u8 started = p2p->discovery_started;
    181
    182	if (p2p->discovery_started) {
    183		if (p2p->pending_listen_wdev) {
    184			/* discovery not really started, only pending */
    185			p2p->pending_listen_wdev = NULL;
    186		} else {
    187			del_timer_sync(&p2p->discovery_timer);
    188			wmi_stop_discovery(vif);
    189		}
    190		p2p->discovery_started = 0;
    191	}
    192
    193	return started;
    194}
    195
    196int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie)
    197{
    198	struct wil6210_priv *wil = vif_to_wil(vif);
    199	struct wil_p2p_info *p2p = &vif->p2p;
    200	u8 started;
    201
    202	mutex_lock(&wil->mutex);
    203
    204	if (cookie != p2p->cookie) {
    205		wil_info(wil, "Cookie mismatch: 0x%016llx vs. 0x%016llx\n",
    206			 p2p->cookie, cookie);
    207		mutex_unlock(&wil->mutex);
    208		return -ENOENT;
    209	}
    210
    211	started = wil_p2p_stop_discovery(vif);
    212
    213	mutex_unlock(&wil->mutex);
    214
    215	if (!started) {
    216		wil_err(wil, "listen not started\n");
    217		return -ENOENT;
    218	}
    219
    220	mutex_lock(&wil->vif_mutex);
    221	cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
    222					   p2p->cookie,
    223					   &p2p->listen_chan,
    224					   GFP_KERNEL);
    225	if (vif->mid == 0)
    226		wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
    227	mutex_unlock(&wil->vif_mutex);
    228	return 0;
    229}
    230
    231void wil_p2p_listen_expired(struct work_struct *work)
    232{
    233	struct wil_p2p_info *p2p = container_of(work,
    234			struct wil_p2p_info, discovery_expired_work);
    235	struct wil6210_vif *vif = container_of(p2p,
    236			struct wil6210_vif, p2p);
    237	struct wil6210_priv *wil = vif_to_wil(vif);
    238	u8 started;
    239
    240	wil_dbg_misc(wil, "p2p_listen_expired\n");
    241
    242	mutex_lock(&wil->mutex);
    243	started = wil_p2p_stop_discovery(vif);
    244	mutex_unlock(&wil->mutex);
    245
    246	if (!started)
    247		return;
    248
    249	mutex_lock(&wil->vif_mutex);
    250	cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
    251					   p2p->cookie,
    252					   &p2p->listen_chan,
    253					   GFP_KERNEL);
    254	if (vif->mid == 0)
    255		wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
    256	mutex_unlock(&wil->vif_mutex);
    257}
    258
    259void wil_p2p_search_expired(struct work_struct *work)
    260{
    261	struct wil_p2p_info *p2p = container_of(work,
    262			struct wil_p2p_info, discovery_expired_work);
    263	struct wil6210_vif *vif = container_of(p2p,
    264			struct wil6210_vif, p2p);
    265	struct wil6210_priv *wil = vif_to_wil(vif);
    266	u8 started;
    267
    268	wil_dbg_misc(wil, "p2p_search_expired\n");
    269
    270	mutex_lock(&wil->mutex);
    271	started = wil_p2p_stop_discovery(vif);
    272	mutex_unlock(&wil->mutex);
    273
    274	if (started) {
    275		struct cfg80211_scan_info info = {
    276			.aborted = false,
    277		};
    278
    279		mutex_lock(&wil->vif_mutex);
    280		if (vif->scan_request) {
    281			cfg80211_scan_done(vif->scan_request, &info);
    282			vif->scan_request = NULL;
    283			if (vif->mid == 0)
    284				wil->radio_wdev =
    285					wil->main_ndev->ieee80211_ptr;
    286		}
    287		mutex_unlock(&wil->vif_mutex);
    288	}
    289}
    290
    291void wil_p2p_delayed_listen_work(struct work_struct *work)
    292{
    293	struct wil_p2p_info *p2p = container_of(work,
    294			struct wil_p2p_info, delayed_listen_work);
    295	struct wil6210_vif *vif = container_of(p2p,
    296			struct wil6210_vif, p2p);
    297	struct wil6210_priv *wil = vif_to_wil(vif);
    298	int rc;
    299
    300	mutex_lock(&wil->mutex);
    301
    302	wil_dbg_misc(wil, "Checking delayed p2p listen\n");
    303	if (!p2p->discovery_started || !p2p->pending_listen_wdev)
    304		goto out;
    305
    306	mutex_lock(&wil->vif_mutex);
    307	if (vif->scan_request) {
    308		/* another scan started, wait again... */
    309		mutex_unlock(&wil->vif_mutex);
    310		goto out;
    311	}
    312	mutex_unlock(&wil->vif_mutex);
    313
    314	rc = wil_p2p_start_listen(vif);
    315
    316	mutex_lock(&wil->vif_mutex);
    317	if (rc) {
    318		cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev,
    319						   p2p->cookie,
    320						   &p2p->listen_chan,
    321						   GFP_KERNEL);
    322		if (vif->mid == 0)
    323			wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
    324	} else {
    325		cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
    326					  &p2p->listen_chan,
    327					  p2p->listen_duration, GFP_KERNEL);
    328		if (vif->mid == 0)
    329			wil->radio_wdev = p2p->pending_listen_wdev;
    330	}
    331	p2p->pending_listen_wdev = NULL;
    332	mutex_unlock(&wil->vif_mutex);
    333
    334out:
    335	mutex_unlock(&wil->mutex);
    336}
    337
    338void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
    339{
    340	struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
    341	struct wil_p2p_info *p2p = &vif->p2p;
    342	struct cfg80211_scan_info info = {
    343		.aborted = true,
    344	};
    345
    346	lockdep_assert_held(&wil->mutex);
    347	lockdep_assert_held(&wil->vif_mutex);
    348
    349	if (wil->radio_wdev != wil->p2p_wdev)
    350		goto out;
    351
    352	if (!p2p->discovery_started) {
    353		/* Regular scan on the p2p device */
    354		if (vif->scan_request &&
    355		    vif->scan_request->wdev == wil->p2p_wdev)
    356			wil_abort_scan(vif, true);
    357		goto out;
    358	}
    359
    360	/* Search or listen on p2p device */
    361	mutex_unlock(&wil->vif_mutex);
    362	wil_p2p_stop_discovery(vif);
    363	mutex_lock(&wil->vif_mutex);
    364
    365	if (vif->scan_request) {
    366		/* search */
    367		cfg80211_scan_done(vif->scan_request, &info);
    368		vif->scan_request = NULL;
    369	} else {
    370		/* listen */
    371		cfg80211_remain_on_channel_expired(wil->radio_wdev,
    372						   p2p->cookie,
    373						   &p2p->listen_chan,
    374						   GFP_KERNEL);
    375	}
    376
    377out:
    378	wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
    379}