aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/libertas/cfg.c148
-rw-r--r--drivers/net/wireless/libertas/dev.h5
-rw-r--r--drivers/net/wireless/libertas/main.c1
3 files changed, 121 insertions, 33 deletions
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 6b35d057426d..8e9fbfd804b6 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -699,8 +699,13 @@ static void lbs_scan_worker(struct work_struct *work)
699 699
700 if (priv->scan_channel >= priv->scan_req->n_channels) { 700 if (priv->scan_channel >= priv->scan_req->n_channels) {
701 /* Mark scan done */ 701 /* Mark scan done */
702 cfg80211_scan_done(priv->scan_req, false); 702 if (priv->internal_scan)
703 kfree(priv->scan_req);
704 else
705 cfg80211_scan_done(priv->scan_req, false);
706
703 priv->scan_req = NULL; 707 priv->scan_req = NULL;
708 priv->last_scan = jiffies;
704 } 709 }
705 710
706 /* Restart network */ 711 /* Restart network */
@@ -711,10 +716,33 @@ static void lbs_scan_worker(struct work_struct *work)
711 716
712 kfree(scan_cmd); 717 kfree(scan_cmd);
713 718
719 /* Wake up anything waiting on scan completion */
720 if (priv->scan_req == NULL) {
721 lbs_deb_scan("scan: waking up waiters\n");
722 wake_up_all(&priv->scan_q);
723 }
724
714 out_no_scan_cmd: 725 out_no_scan_cmd:
715 lbs_deb_leave(LBS_DEB_SCAN); 726 lbs_deb_leave(LBS_DEB_SCAN);
716} 727}
717 728
729static void _internal_start_scan(struct lbs_private *priv, bool internal,
730 struct cfg80211_scan_request *request)
731{
732 lbs_deb_enter(LBS_DEB_CFG80211);
733
734 lbs_deb_scan("scan: ssids %d, channels %d, ie_len %zd\n",
735 request->n_ssids, request->n_channels, request->ie_len);
736
737 priv->scan_channel = 0;
738 queue_delayed_work(priv->work_thread, &priv->scan_work,
739 msecs_to_jiffies(50));
740
741 priv->scan_req = request;
742 priv->internal_scan = internal;
743
744 lbs_deb_leave(LBS_DEB_CFG80211);
745}
718 746
719static int lbs_cfg_scan(struct wiphy *wiphy, 747static int lbs_cfg_scan(struct wiphy *wiphy,
720 struct net_device *dev, 748 struct net_device *dev,
@@ -731,18 +759,11 @@ static int lbs_cfg_scan(struct wiphy *wiphy,
731 goto out; 759 goto out;
732 } 760 }
733 761
734 lbs_deb_scan("scan: ssids %d, channels %d, ie_len %zd\n", 762 _internal_start_scan(priv, false, request);
735 request->n_ssids, request->n_channels, request->ie_len);
736
737 priv->scan_channel = 0;
738 queue_delayed_work(priv->work_thread, &priv->scan_work,
739 msecs_to_jiffies(50));
740 763
741 if (priv->surpriseremoved) 764 if (priv->surpriseremoved)
742 ret = -EIO; 765 ret = -EIO;
743 766
744 priv->scan_req = request;
745
746 out: 767 out:
747 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); 768 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
748 return ret; 769 return ret;
@@ -1156,7 +1177,62 @@ done:
1156 return ret; 1177 return ret;
1157} 1178}
1158 1179
1180static struct cfg80211_scan_request *
1181_new_connect_scan_req(struct wiphy *wiphy, struct cfg80211_connect_params *sme)
1182{
1183 struct cfg80211_scan_request *creq = NULL;
1184 int i, n_channels = 0;
1185 enum ieee80211_band band;
1186
1187 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
1188 if (wiphy->bands[band])
1189 n_channels += wiphy->bands[band]->n_channels;
1190 }
1191
1192 creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
1193 n_channels * sizeof(void *),
1194 GFP_ATOMIC);
1195 if (!creq)
1196 return NULL;
1197
1198 /* SSIDs come after channels */
1199 creq->ssids = (void *)&creq->channels[n_channels];
1200 creq->n_channels = n_channels;
1201 creq->n_ssids = 1;
1202
1203 /* Scan all available channels */
1204 i = 0;
1205 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
1206 int j;
1207
1208 if (!wiphy->bands[band])
1209 continue;
1210
1211 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
1212 /* ignore disabled channels */
1213 if (wiphy->bands[band]->channels[j].flags &
1214 IEEE80211_CHAN_DISABLED)
1215 continue;
1216
1217 creq->channels[i] = &wiphy->bands[band]->channels[j];
1218 i++;
1219 }
1220 }
1221 if (i) {
1222 /* Set real number of channels specified in creq->channels[] */
1223 creq->n_channels = i;
1224
1225 /* Scan for the SSID we're going to connect to */
1226 memcpy(creq->ssids[0].ssid, sme->ssid, sme->ssid_len);
1227 creq->ssids[0].ssid_len = sme->ssid_len;
1228 } else {
1229 /* No channels found... */
1230 kfree(creq);
1231 creq = NULL;
1232 }
1159 1233
1234 return creq;
1235}
1160 1236
1161static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, 1237static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
1162 struct cfg80211_connect_params *sme) 1238 struct cfg80211_connect_params *sme)
@@ -1168,37 +1244,43 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
1168 1244
1169 lbs_deb_enter(LBS_DEB_CFG80211); 1245 lbs_deb_enter(LBS_DEB_CFG80211);
1170 1246
1171 if (sme->bssid) { 1247 if (!sme->bssid) {
1172 bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, 1248 /* Run a scan if one isn't in-progress already and if the last
1173 sme->ssid, sme->ssid_len, 1249 * scan was done more than 2 seconds ago.
1174 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
1175 } else {
1176 /*
1177 * Here we have an impedance mismatch. The firmware command
1178 * CMD_802_11_ASSOCIATE always needs a BSSID, it cannot
1179 * connect otherwise. However, for the connect-API of
1180 * cfg80211 the bssid is purely optional. We don't get one,
1181 * except the user specifies one on the "iw" command line.
1182 *
1183 * If we don't got one, we could initiate a scan and look
1184 * for the best matching cfg80211_bss entry.
1185 *
1186 * Or, better yet, net/wireless/sme.c get's rewritten into
1187 * something more generally useful.
1188 */ 1250 */
1189 lbs_pr_err("TODO: no BSS specified\n"); 1251 if (priv->scan_req == NULL &&
1190 ret = -ENOTSUPP; 1252 time_after(jiffies, priv->last_scan + (2 * HZ))) {
1191 goto done; 1253 struct cfg80211_scan_request *creq;
1192 }
1193 1254
1255 creq = _new_connect_scan_req(wiphy, sme);
1256 if (!creq) {
1257 ret = -EINVAL;
1258 goto done;
1259 }
1260
1261 lbs_deb_assoc("assoc: scanning for compatible AP\n");
1262 _internal_start_scan(priv, true, creq);
1263 }
1264
1265 /* Wait for any in-progress scan to complete */
1266 lbs_deb_assoc("assoc: waiting for scan to complete\n");
1267 wait_event_interruptible_timeout(priv->scan_q,
1268 (priv->scan_req == NULL),
1269 (15 * HZ));
1270 lbs_deb_assoc("assoc: scanning competed\n");
1271 }
1194 1272
1273 /* Find the BSS we want using available scan results */
1274 bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
1275 sme->ssid, sme->ssid_len,
1276 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
1195 if (!bss) { 1277 if (!bss) {
1196 lbs_pr_err("assicate: bss %pM not in scan results\n", 1278 lbs_pr_err("assoc: bss %pM not in scan results\n",
1197 sme->bssid); 1279 sme->bssid);
1198 ret = -ENOENT; 1280 ret = -ENOENT;
1199 goto done; 1281 goto done;
1200 } 1282 }
1201 lbs_deb_assoc("trying %pM", sme->bssid); 1283 lbs_deb_assoc("trying %pM\n", bss->bssid);
1202 lbs_deb_assoc("cipher 0x%x, key index %d, key len %d\n", 1284 lbs_deb_assoc("cipher 0x%x, key index %d, key len %d\n",
1203 sme->crypto.cipher_group, 1285 sme->crypto.cipher_group,
1204 sme->key_idx, sme->key_len); 1286 sme->key_idx, sme->key_len);
@@ -1261,7 +1343,7 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
1261 lbs_set_radio(priv, preamble, 1); 1343 lbs_set_radio(priv, preamble, 1);
1262 1344
1263 /* Do the actual association */ 1345 /* Do the actual association */
1264 lbs_associate(priv, bss, sme); 1346 ret = lbs_associate(priv, bss, sme);
1265 1347
1266 done: 1348 done:
1267 if (bss) 1349 if (bss)
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 3c7e255e18c7..f062ed583901 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -161,6 +161,11 @@ struct lbs_private {
161 /** Scanning */ 161 /** Scanning */
162 struct delayed_work scan_work; 162 struct delayed_work scan_work;
163 int scan_channel; 163 int scan_channel;
164 /* Queue of things waiting for scan completion */
165 wait_queue_head_t scan_q;
166 /* Whether the scan was initiated internally and not by cfg80211 */
167 bool internal_scan;
168 unsigned long last_scan;
164}; 169};
165 170
166extern struct cmd_confirm_sleep confirm_sleep; 171extern struct cmd_confirm_sleep confirm_sleep;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 258967144b96..24958a86747b 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -719,6 +719,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
719 priv->deep_sleep_required = 0; 719 priv->deep_sleep_required = 0;
720 priv->wakeup_dev_required = 0; 720 priv->wakeup_dev_required = 0;
721 init_waitqueue_head(&priv->ds_awake_q); 721 init_waitqueue_head(&priv->ds_awake_q);
722 init_waitqueue_head(&priv->scan_q);
722 priv->authtype_auto = 1; 723 priv->authtype_auto = 1;
723 priv->is_host_sleep_configured = 0; 724 priv->is_host_sleep_configured = 0;
724 priv->is_host_sleep_activated = 0; 725 priv->is_host_sleep_activated = 0;