brintos

brintos / linux-shallow public Read only

0
0
Text · 8.7 KiB · f26bf04 Raw
380 lines · c
1// SPDX-License-Identifier: ISC2/*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 212#define P2P_SEARCH_DURATION_MS 50013#define P2P_DEFAULT_BI 10014 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 IEs98	 */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}380