aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrea Merello <andrea.merello@gmail.com>2014-06-05 10:10:12 -0400
committerJohn W. Linville <linville@tuxdriver.com>2014-06-05 14:15:08 -0400
commitc678de55361aa5b72b1aaa495380a395b8cc1bd2 (patch)
tree0acdf58bca369ae1fc1a98389329950676891618
parent67be1e4f4b0a512f6af3a7db681ae9b62d31de5e (diff)
at76c50x: fix scan does not work with latest mac80211
since commit 3afc2167f60a327a2c1e1e2600ef209a3c2b75b7 scan in not working anymore, due to mac80211 requires rx frequency status information. This patch makes the driver report this information. While NOT scanning this is straightforward. While scanning the firmware performs RF sweep and we cannot track the actual tuning frequency, so this is guessed by parsing beacons and probe responses. This should be enough for ensuring functionality. Thanks-to: Johannes Berg <johannes@sipsolutions.net> [ for suggestions and reviewing ] Signed-off-by: Andrea Merello <andrea.merello@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/at76c50x-usb.c53
-rw-r--r--drivers/net/wireless/at76c50x-usb.h1
2 files changed, 54 insertions, 0 deletions
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 10fd12ec85be..d48776e4f343 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1429,6 +1429,8 @@ static int at76_startup_device(struct at76_priv *priv)
1429 /* remove BSSID from previous run */ 1429 /* remove BSSID from previous run */
1430 memset(priv->bssid, 0, ETH_ALEN); 1430 memset(priv->bssid, 0, ETH_ALEN);
1431 1431
1432 priv->scanning = false;
1433
1432 if (at76_set_radio(priv, 1) == 1) 1434 if (at76_set_radio(priv, 1) == 1)
1433 at76_wait_completion(priv, CMD_RADIO_ON); 1435 at76_wait_completion(priv, CMD_RADIO_ON);
1434 1436
@@ -1502,6 +1504,52 @@ static void at76_work_submit_rx(struct work_struct *work)
1502 mutex_unlock(&priv->mtx); 1504 mutex_unlock(&priv->mtx);
1503} 1505}
1504 1506
1507/* This is a workaround to make scan working:
1508 * currently mac80211 does not process frames with no frequency
1509 * information.
1510 * However during scan the HW performs a sweep by itself, and we
1511 * are unable to know where the radio is actually tuned.
1512 * This function tries to do its best to guess this information..
1513 * During scan, If the current frame is a beacon or a probe response,
1514 * the channel information is extracted from it.
1515 * When not scanning, for other frames, or if it happens that for
1516 * whatever reason we fail to parse beacons and probe responses, this
1517 * function returns the priv->channel information, that should be correct
1518 * at least when we are not scanning.
1519 */
1520static inline int at76_guess_freq(struct at76_priv *priv)
1521{
1522 size_t el_off;
1523 const u8 *el;
1524 int channel = priv->channel;
1525 int len = priv->rx_skb->len;
1526 struct ieee80211_hdr *hdr = (void *)priv->rx_skb->data;
1527
1528 if (!priv->scanning)
1529 goto exit;
1530
1531 if (len < 24)
1532 goto exit;
1533
1534 if (ieee80211_is_probe_resp(hdr->frame_control)) {
1535 el_off = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
1536 el = ((struct ieee80211_mgmt *)hdr)->u.probe_resp.variable;
1537 } else if (ieee80211_is_beacon(hdr->frame_control)) {
1538 el_off = offsetof(struct ieee80211_mgmt, u.beacon.variable);
1539 el = ((struct ieee80211_mgmt *)hdr)->u.beacon.variable;
1540 } else {
1541 goto exit;
1542 }
1543 len -= el_off;
1544
1545 el = cfg80211_find_ie(WLAN_EID_DS_PARAMS, el, len);
1546 if (el && el[1] > 0)
1547 channel = el[2];
1548
1549exit:
1550 return ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
1551}
1552
1505static void at76_rx_tasklet(unsigned long param) 1553static void at76_rx_tasklet(unsigned long param)
1506{ 1554{
1507 struct urb *urb = (struct urb *)param; 1555 struct urb *urb = (struct urb *)param;
@@ -1542,6 +1590,8 @@ static void at76_rx_tasklet(unsigned long param)
1542 rx_status.signal = buf->rssi; 1590 rx_status.signal = buf->rssi;
1543 rx_status.flag |= RX_FLAG_DECRYPTED; 1591 rx_status.flag |= RX_FLAG_DECRYPTED;
1544 rx_status.flag |= RX_FLAG_IV_STRIPPED; 1592 rx_status.flag |= RX_FLAG_IV_STRIPPED;
1593 rx_status.band = IEEE80211_BAND_2GHZ;
1594 rx_status.freq = at76_guess_freq(priv);
1545 1595
1546 at76_dbg(DBG_MAC80211, "calling ieee80211_rx_irqsafe(): %d/%d", 1596 at76_dbg(DBG_MAC80211, "calling ieee80211_rx_irqsafe(): %d/%d",
1547 priv->rx_skb->len, priv->rx_skb->data_len); 1597 priv->rx_skb->len, priv->rx_skb->data_len);
@@ -1894,6 +1944,8 @@ static void at76_dwork_hw_scan(struct work_struct *work)
1894 if (is_valid_ether_addr(priv->bssid)) 1944 if (is_valid_ether_addr(priv->bssid))
1895 at76_join(priv); 1945 at76_join(priv);
1896 1946
1947 priv->scanning = false;
1948
1897 mutex_unlock(&priv->mtx); 1949 mutex_unlock(&priv->mtx);
1898 1950
1899 ieee80211_scan_completed(priv->hw, false); 1951 ieee80211_scan_completed(priv->hw, false);
@@ -1948,6 +2000,7 @@ static int at76_hw_scan(struct ieee80211_hw *hw,
1948 goto exit; 2000 goto exit;
1949 } 2001 }
1950 2002
2003 priv->scanning = true;
1951 ieee80211_queue_delayed_work(priv->hw, &priv->dwork_hw_scan, 2004 ieee80211_queue_delayed_work(priv->hw, &priv->dwork_hw_scan,
1952 SCAN_POLL_INTERVAL); 2005 SCAN_POLL_INTERVAL);
1953 2006
diff --git a/drivers/net/wireless/at76c50x-usb.h b/drivers/net/wireless/at76c50x-usb.h
index 4718aa59f051..55090a38ac95 100644
--- a/drivers/net/wireless/at76c50x-usb.h
+++ b/drivers/net/wireless/at76c50x-usb.h
@@ -418,6 +418,7 @@ struct at76_priv {
418 int scan_max_time; /* scan max channel time */ 418 int scan_max_time; /* scan max channel time */
419 int scan_mode; /* SCAN_TYPE_ACTIVE, SCAN_TYPE_PASSIVE */ 419 int scan_mode; /* SCAN_TYPE_ACTIVE, SCAN_TYPE_PASSIVE */
420 int scan_need_any; /* if set, need to scan for any ESSID */ 420 int scan_need_any; /* if set, need to scan for any ESSID */
421 bool scanning; /* if set, the scan is running */
421 422
422 u16 assoc_id; /* current association ID, if associated */ 423 u16 assoc_id; /* current association ID, if associated */
423 424