|
@@ -1753,6 +1753,8 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
|
|
|
|
|
|
if (priv->workqueue) {
|
|
|
cancel_delayed_work(&priv->request_scan);
|
|
|
+ cancel_delayed_work(&priv->request_direct_scan);
|
|
|
+ cancel_delayed_work(&priv->request_passive_scan);
|
|
|
cancel_delayed_work(&priv->scan_event);
|
|
|
}
|
|
|
queue_work(priv->workqueue, &priv->down);
|
|
@@ -2005,6 +2007,8 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
|
|
|
wake_up_interruptible(&priv->wait_command_queue);
|
|
|
priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
|
|
|
cancel_delayed_work(&priv->request_scan);
|
|
|
+ cancel_delayed_work(&priv->request_direct_scan);
|
|
|
+ cancel_delayed_work(&priv->request_passive_scan);
|
|
|
cancel_delayed_work(&priv->scan_event);
|
|
|
schedule_work(&priv->link_down);
|
|
|
queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ);
|
|
@@ -4712,6 +4716,12 @@ static void ipw_rx_notification(struct ipw_priv *priv,
|
|
|
priv->status &= ~STATUS_SCAN_FORCED;
|
|
|
#endif /* CONFIG_IPW2200_MONITOR */
|
|
|
|
|
|
+ /* Do queued direct scans first */
|
|
|
+ if (priv->status & STATUS_DIRECT_SCAN_PENDING) {
|
|
|
+ queue_delayed_work(priv->workqueue,
|
|
|
+ &priv->request_direct_scan, 0);
|
|
|
+ }
|
|
|
+
|
|
|
if (!(priv->status & (STATUS_ASSOCIATED |
|
|
|
STATUS_ASSOCIATING |
|
|
|
STATUS_ROAMING |
|
|
@@ -6267,7 +6277,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int ipw_request_scan_helper(struct ipw_priv *priv, int type)
|
|
|
+static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct)
|
|
|
{
|
|
|
struct ipw_scan_request_ext scan;
|
|
|
int err = 0, scan_type;
|
|
@@ -6278,22 +6288,31 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type)
|
|
|
|
|
|
mutex_lock(&priv->mutex);
|
|
|
|
|
|
+ if (direct && (priv->direct_scan_ssid_len == 0)) {
|
|
|
+ IPW_DEBUG_HC("Direct scan requested but no SSID to scan for\n");
|
|
|
+ priv->status &= ~STATUS_DIRECT_SCAN_PENDING;
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
if (priv->status & STATUS_SCANNING) {
|
|
|
- IPW_DEBUG_HC("Concurrent scan requested. Ignoring.\n");
|
|
|
- priv->status |= STATUS_SCAN_PENDING;
|
|
|
+ IPW_DEBUG_HC("Concurrent scan requested. Queuing.\n");
|
|
|
+ priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING :
|
|
|
+ STATUS_SCAN_PENDING;
|
|
|
goto done;
|
|
|
}
|
|
|
|
|
|
if (!(priv->status & STATUS_SCAN_FORCED) &&
|
|
|
priv->status & STATUS_SCAN_ABORTING) {
|
|
|
IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n");
|
|
|
- priv->status |= STATUS_SCAN_PENDING;
|
|
|
+ priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING :
|
|
|
+ STATUS_SCAN_PENDING;
|
|
|
goto done;
|
|
|
}
|
|
|
|
|
|
if (priv->status & STATUS_RF_KILL_MASK) {
|
|
|
- IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n");
|
|
|
- priv->status |= STATUS_SCAN_PENDING;
|
|
|
+ IPW_DEBUG_HC("Queuing scan due to RF Kill activation\n");
|
|
|
+ priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING :
|
|
|
+ STATUS_SCAN_PENDING;
|
|
|
goto done;
|
|
|
}
|
|
|
|
|
@@ -6321,6 +6340,7 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type)
|
|
|
cpu_to_le16(20);
|
|
|
|
|
|
scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120);
|
|
|
+ scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20);
|
|
|
|
|
|
#ifdef CONFIG_IPW2200_MONITOR
|
|
|
if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
|
|
@@ -6360,13 +6380,23 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type)
|
|
|
cpu_to_le16(2000);
|
|
|
} else {
|
|
|
#endif /* CONFIG_IPW2200_MONITOR */
|
|
|
- /* If we are roaming, then make this a directed scan for the
|
|
|
- * current network. Otherwise, ensure that every other scan
|
|
|
- * is a fast channel hop scan */
|
|
|
- if ((priv->status & STATUS_ROAMING)
|
|
|
- || (!(priv->status & STATUS_ASSOCIATED)
|
|
|
- && (priv->config & CFG_STATIC_ESSID)
|
|
|
- && (le32_to_cpu(scan.full_scan_index) % 2))) {
|
|
|
+ /* Honor direct scans first, otherwise if we are roaming make
|
|
|
+ * this a direct scan for the current network. Finally,
|
|
|
+ * ensure that every other scan is a fast channel hop scan */
|
|
|
+ if (direct) {
|
|
|
+ err = ipw_send_ssid(priv, priv->direct_scan_ssid,
|
|
|
+ priv->direct_scan_ssid_len);
|
|
|
+ if (err) {
|
|
|
+ IPW_DEBUG_HC("Attempt to send SSID command "
|
|
|
+ "failed\n");
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
+ scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
|
|
|
+ } else if ((priv->status & STATUS_ROAMING)
|
|
|
+ || (!(priv->status & STATUS_ASSOCIATED)
|
|
|
+ && (priv->config & CFG_STATIC_ESSID)
|
|
|
+ && (le32_to_cpu(scan.full_scan_index) % 2))) {
|
|
|
err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
|
|
|
if (err) {
|
|
|
IPW_DEBUG_HC("Attempt to send SSID command "
|
|
@@ -6391,7 +6421,12 @@ send_request:
|
|
|
}
|
|
|
|
|
|
priv->status |= STATUS_SCANNING;
|
|
|
- priv->status &= ~STATUS_SCAN_PENDING;
|
|
|
+ if (direct) {
|
|
|
+ priv->status &= ~STATUS_DIRECT_SCAN_PENDING;
|
|
|
+ priv->direct_scan_ssid_len = 0;
|
|
|
+ } else
|
|
|
+ priv->status &= ~STATUS_SCAN_PENDING;
|
|
|
+
|
|
|
queue_delayed_work(priv->workqueue, &priv->scan_check,
|
|
|
IPW_SCAN_CHECK_WATCHDOG);
|
|
|
done:
|
|
@@ -6402,15 +6437,22 @@ done:
|
|
|
static void ipw_request_passive_scan(struct work_struct *work)
|
|
|
{
|
|
|
struct ipw_priv *priv =
|
|
|
- container_of(work, struct ipw_priv, request_passive_scan);
|
|
|
- ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE);
|
|
|
+ container_of(work, struct ipw_priv, request_passive_scan.work);
|
|
|
+ ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE, 0);
|
|
|
}
|
|
|
|
|
|
static void ipw_request_scan(struct work_struct *work)
|
|
|
{
|
|
|
struct ipw_priv *priv =
|
|
|
container_of(work, struct ipw_priv, request_scan.work);
|
|
|
- ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE);
|
|
|
+ ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 0);
|
|
|
+}
|
|
|
+
|
|
|
+static void ipw_request_direct_scan(struct work_struct *work)
|
|
|
+{
|
|
|
+ struct ipw_priv *priv =
|
|
|
+ container_of(work, struct ipw_priv, request_direct_scan.work);
|
|
|
+ ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 1);
|
|
|
}
|
|
|
|
|
|
static void ipw_bg_abort_scan(struct work_struct *work)
|
|
@@ -9477,99 +9519,38 @@ static int ipw_wx_get_retry(struct net_device *dev,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid,
|
|
|
- int essid_len)
|
|
|
-{
|
|
|
- struct ipw_scan_request_ext scan;
|
|
|
- int err = 0, scan_type;
|
|
|
-
|
|
|
- if (!(priv->status & STATUS_INIT) ||
|
|
|
- (priv->status & STATUS_EXIT_PENDING))
|
|
|
- return 0;
|
|
|
-
|
|
|
- mutex_lock(&priv->mutex);
|
|
|
-
|
|
|
- if (priv->status & STATUS_RF_KILL_MASK) {
|
|
|
- IPW_DEBUG_HC("Aborting scan due to RF kill activation\n");
|
|
|
- priv->status |= STATUS_SCAN_PENDING;
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
- IPW_DEBUG_HC("starting request direct scan!\n");
|
|
|
-
|
|
|
- if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) {
|
|
|
- /* We should not sleep here; otherwise we will block most
|
|
|
- * of the system (for instance, we hold rtnl_lock when we
|
|
|
- * get here).
|
|
|
- */
|
|
|
- err = -EAGAIN;
|
|
|
- goto done;
|
|
|
- }
|
|
|
- memset(&scan, 0, sizeof(scan));
|
|
|
-
|
|
|
- if (priv->config & CFG_SPEED_SCAN)
|
|
|
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
|
|
|
- cpu_to_le16(30);
|
|
|
- else
|
|
|
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
|
|
|
- cpu_to_le16(20);
|
|
|
-
|
|
|
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] =
|
|
|
- cpu_to_le16(20);
|
|
|
- scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120);
|
|
|
- scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20);
|
|
|
-
|
|
|
- scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
|
|
|
-
|
|
|
- err = ipw_send_ssid(priv, essid, essid_len);
|
|
|
- if (err) {
|
|
|
- IPW_DEBUG_HC("Attempt to send SSID command failed\n");
|
|
|
- goto done;
|
|
|
- }
|
|
|
- scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
|
|
|
-
|
|
|
- ipw_add_scan_channels(priv, &scan, scan_type);
|
|
|
-
|
|
|
- err = ipw_send_scan_request_ext(priv, &scan);
|
|
|
- if (err) {
|
|
|
- IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
- priv->status |= STATUS_SCANNING;
|
|
|
-
|
|
|
- done:
|
|
|
- mutex_unlock(&priv->mutex);
|
|
|
- return err;
|
|
|
-}
|
|
|
-
|
|
|
static int ipw_wx_set_scan(struct net_device *dev,
|
|
|
struct iw_request_info *info,
|
|
|
union iwreq_data *wrqu, char *extra)
|
|
|
{
|
|
|
struct ipw_priv *priv = ieee80211_priv(dev);
|
|
|
struct iw_scan_req *req = (struct iw_scan_req *)extra;
|
|
|
+ struct delayed_work *work = NULL;
|
|
|
|
|
|
mutex_lock(&priv->mutex);
|
|
|
+
|
|
|
priv->user_requested_scan = 1;
|
|
|
- mutex_unlock(&priv->mutex);
|
|
|
|
|
|
if (wrqu->data.length == sizeof(struct iw_scan_req)) {
|
|
|
if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
|
|
|
- ipw_request_direct_scan(priv, req->essid,
|
|
|
- req->essid_len);
|
|
|
- return 0;
|
|
|
- }
|
|
|
- if (req->scan_type == IW_SCAN_TYPE_PASSIVE) {
|
|
|
- queue_work(priv->workqueue,
|
|
|
- &priv->request_passive_scan);
|
|
|
- return 0;
|
|
|
+ int len = min((int)req->essid_len,
|
|
|
+ (int)sizeof(priv->direct_scan_ssid));
|
|
|
+ memcpy(priv->direct_scan_ssid, req->essid, len);
|
|
|
+ priv->direct_scan_ssid_len = len;
|
|
|
+ work = &priv->request_direct_scan;
|
|
|
+ } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) {
|
|
|
+ work = &priv->request_passive_scan;
|
|
|
}
|
|
|
+ } else {
|
|
|
+ /* Normal active broadcast scan */
|
|
|
+ work = &priv->request_scan;
|
|
|
}
|
|
|
|
|
|
+ mutex_unlock(&priv->mutex);
|
|
|
+
|
|
|
IPW_DEBUG_WX("Start scan\n");
|
|
|
|
|
|
- queue_delayed_work(priv->workqueue, &priv->request_scan, 0);
|
|
|
+ queue_delayed_work(priv->workqueue, work, 0);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -10731,6 +10712,8 @@ static void ipw_link_up(struct ipw_priv *priv)
|
|
|
}
|
|
|
|
|
|
cancel_delayed_work(&priv->request_scan);
|
|
|
+ cancel_delayed_work(&priv->request_direct_scan);
|
|
|
+ cancel_delayed_work(&priv->request_passive_scan);
|
|
|
cancel_delayed_work(&priv->scan_event);
|
|
|
ipw_reset_stats(priv);
|
|
|
/* Ensure the rate is updated immediately */
|
|
@@ -10761,6 +10744,8 @@ static void ipw_link_down(struct ipw_priv *priv)
|
|
|
|
|
|
/* Cancel any queued work ... */
|
|
|
cancel_delayed_work(&priv->request_scan);
|
|
|
+ cancel_delayed_work(&priv->request_direct_scan);
|
|
|
+ cancel_delayed_work(&priv->request_passive_scan);
|
|
|
cancel_delayed_work(&priv->adhoc_check);
|
|
|
cancel_delayed_work(&priv->gather_stats);
|
|
|
|
|
@@ -10800,8 +10785,9 @@ static int __devinit ipw_setup_deferred_work(struct ipw_priv *priv)
|
|
|
INIT_WORK(&priv->up, ipw_bg_up);
|
|
|
INIT_WORK(&priv->down, ipw_bg_down);
|
|
|
INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan);
|
|
|
+ INIT_DELAYED_WORK(&priv->request_direct_scan, ipw_request_direct_scan);
|
|
|
+ INIT_DELAYED_WORK(&priv->request_passive_scan, ipw_request_passive_scan);
|
|
|
INIT_DELAYED_WORK(&priv->scan_event, ipw_scan_event);
|
|
|
- INIT_WORK(&priv->request_passive_scan, ipw_request_passive_scan);
|
|
|
INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats);
|
|
|
INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan);
|
|
|
INIT_WORK(&priv->roam, ipw_bg_roam);
|
|
@@ -11835,6 +11821,8 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev)
|
|
|
cancel_delayed_work(&priv->adhoc_check);
|
|
|
cancel_delayed_work(&priv->gather_stats);
|
|
|
cancel_delayed_work(&priv->request_scan);
|
|
|
+ cancel_delayed_work(&priv->request_direct_scan);
|
|
|
+ cancel_delayed_work(&priv->request_passive_scan);
|
|
|
cancel_delayed_work(&priv->scan_event);
|
|
|
cancel_delayed_work(&priv->rf_kill);
|
|
|
cancel_delayed_work(&priv->scan_check);
|