diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/libertas/cfg.c | 148 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/dev.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 1 |
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 | ||
729 | static 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 | ||
719 | static int lbs_cfg_scan(struct wiphy *wiphy, | 747 | static 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 | ||
1180 | static 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 | ||
1161 | static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, | 1237 | static 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 | ||
166 | extern struct cmd_confirm_sleep confirm_sleep; | 171 | extern 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; |