From patchwork Wed Jun 4 21:02:19 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrea Merello X-Patchwork-Id: 4296991 Return-Path: X-Original-To: patchwork-linux-wireless@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 4247A9F1D6 for ; Wed, 4 Jun 2014 21:03:03 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 4A5EA2012E for ; Wed, 4 Jun 2014 21:03:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3C93920142 for ; Wed, 4 Jun 2014 21:03:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752088AbaFDVCq (ORCPT ); Wed, 4 Jun 2014 17:02:46 -0400 Received: from mail-wg0-f49.google.com ([74.125.82.49]:34022 "EHLO mail-wg0-f49.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752067AbaFDVCn (ORCPT ); Wed, 4 Jun 2014 17:02:43 -0400 Received: by mail-wg0-f49.google.com with SMTP id m15so68305wgh.32 for ; Wed, 04 Jun 2014 14:02:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:reply-to:in-reply-to:references:from:date:message-id :subject:to:cc:content-type; bh=QgEoCjtq7D8vJfHZOZx3yEv5OuvkoWNmyQIS+y+xgxk=; b=cJQrFSiYirUQc+NhHtcF6VDub9SRQh4G12FqapPMOJ1pZ+BbXB/oIkHWrOF9nAN3kD h7+BJVX1uWGjnkKqej+sd1HKfXOw2qqKmq1LTNbB2WzGebemp0cjdwInHayZ55qZHE15 MA5Ujm2Nv7s3dAcmAepzSA+/7PsNigPFV/BZExVkZkfT0vHvly8G/N0nLvaVJSZqdKhv BiBufXX4jgrdhdYPk5bXjmCJVUKgmTmWkgPgUcZC+K48tkLvcWS5Ips6DAcWiP/CgKZa d5R4BHWBcg6iAT2/8m8X8QKb/TPXCaFb8AhHH4FN6VF4x1mw5yER92OQJKFPF2jVa6px fSUA== X-Received: by 10.194.82.170 with SMTP id j10mr75225931wjy.63.1401915762537; Wed, 04 Jun 2014 14:02:42 -0700 (PDT) MIME-Version: 1.0 Received: by 10.216.244.134 with HTTP; Wed, 4 Jun 2014 14:02:19 -0700 (PDT) Reply-To: andrea.merello@gmail.com In-Reply-To: <1401825462.4157.42.camel@jlt4.sipsolutions.net> References: <1400509775.4273.8.camel@jlt4.sipsolutions.net> <1400510950.4273.9.camel@jlt4.sipsolutions.net> <1400515344.4273.19.camel@jlt4.sipsolutions.net> <1401285737.8146.21.camel@jlt4.sipsolutions.net> <1401825462.4157.42.camel@jlt4.sipsolutions.net> From: Andrea Merello Date: Wed, 4 Jun 2014 23:02:19 +0200 Message-ID: Subject: Re: [RFC] mac80211: at76x50x_usb driver broken by commit 3afc216.. and RX path involved in scan To: Johannes Berg Cc: emmanuel.grumbach@intel.com, Linux Wireless List , joerg.albert@gmx.de, Alex Stewart , n0_5p4m_p13453@hotmail.com, Pavel Roskin , agx@sigxcpu.org, Kalle Valo , sesmo@gmx.net, John Linville Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Hi Johannes, > Yeah, and it would do much more than what you want. You could use > cfg80211_find_ie() though to simplify the code. Excellent! I missed it.. > So the loop can be simplified to > > el = cfg80211_find_ie(WLAN_EID_DS_PARAMS, el, el_len); > if (el && el[1] > 0) > channel = el[2]; I guess el_len should be len, but I got it :) > You might also invoke this only when you know you're scanning, to avoid > the overhead otherwise, but with this driver it probably doesn't matter > much. Probably it doesn't, but you are right that is useless to waste time parsing those mgmt frames when not scanning. I modified the function (and I changed also its name) in a way that when scanning it avoid parsing and it does return priv->channel, and I made it also inline. So this is the updated patch. If you agree, we could push it for merge :) Thank you Andrea drivers/net/wireless/at76c50x-usb.c | 53 +++++++++++++++++++++++++++++++++++++ drivers/net/wireless/at76c50x-usb.h | 1 + 2 files changed, 54 insertions(+) diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 10fd12e..6f52633 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) /* remove BSSID from previous run */ memset(priv->bssid, 0, ETH_ALEN); + priv->scanning = false; + if (at76_set_radio(priv, 1) == 1) at76_wait_completion(priv, CMD_RADIO_ON); @@ -1502,6 +1504,52 @@ static void at76_work_submit_rx(struct work_struct *work) mutex_unlock(&priv->mtx); } +/* This is a workaround to make scan working: + * currently mac80211 does not process frames with no frequency + * information. + * However during scan the HW performs a sweep by itself, and we + * are unable to know where the radio is actually tuned. + * This function tries to do its best to guess this information.. + * During scan, If the current frame is a beacon or a probe response, + * the channel information is extracted from it. + * When not scanning, for other frames, or if it happens that for + * whatever reason we fail to parse beacons and probe responses, this + * function returns the priv->channel information, that should be correct + * at least when we are not scanning. + */ +static inline int at76_guess_freq(struct at76_priv *priv) +{ + size_t el_off; + const u8 *el; + int channel = priv->channel; + int len = priv->rx_skb->len; + struct ieee80211_hdr *hdr = (void *)priv->rx_skb->data; + + if (!priv->scanning) + goto exit; + + if (len < 24) + goto exit; + + if (ieee80211_is_probe_resp(hdr->frame_control)) { + el_off = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + el = ((struct ieee80211_mgmt *)hdr)->u.probe_resp.variable; + } else if (ieee80211_is_beacon(hdr->frame_control)) { + el_off = offsetof(struct ieee80211_mgmt, u.beacon.variable); + el = ((struct ieee80211_mgmt *)hdr)->u.beacon.variable; + } else + goto exit; + + len -= el_off; + + el = cfg80211_find_ie(WLAN_EID_DS_PARAMS, el, len); + if (el && el[1] > 0) + channel = el[2]; + +exit: + return ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); +} + static void at76_rx_tasklet(unsigned long param) { struct urb *urb = (struct urb *)param; @@ -1542,6 +1590,8 @@ static void at76_rx_tasklet(unsigned long param) rx_status.signal = buf->rssi; rx_status.flag |= RX_FLAG_DECRYPTED; rx_status.flag |= RX_FLAG_IV_STRIPPED; + rx_status.band = IEEE80211_BAND_2GHZ; + rx_status.freq = at76_guess_freq(priv); at76_dbg(DBG_MAC80211, "calling ieee80211_rx_irqsafe(): %d/%d", priv->rx_skb->len, priv->rx_skb->data_len); @@ -1894,6 +1944,8 @@ static void at76_dwork_hw_scan(struct work_struct *work) if (is_valid_ether_addr(priv->bssid)) at76_join(priv); + priv->scanning = false; + mutex_unlock(&priv->mtx); ieee80211_scan_completed(priv->hw, false); @@ -1948,6 +2000,7 @@ static int at76_hw_scan(struct ieee80211_hw *hw, goto exit; } + priv->scanning = true; ieee80211_queue_delayed_work(priv->hw, &priv->dwork_hw_scan, SCAN_POLL_INTERVAL); diff --git a/drivers/net/wireless/at76c50x-usb.h b/drivers/net/wireless/at76c50x-usb.h index 4718aa5..55090a3 100644 --- a/drivers/net/wireless/at76c50x-usb.h +++ b/drivers/net/wireless/at76c50x-usb.h @@ -418,6 +418,7 @@ struct at76_priv { int scan_max_time; /* scan max channel time */ int scan_mode; /* SCAN_TYPE_ACTIVE, SCAN_TYPE_PASSIVE */ int scan_need_any; /* if set, need to scan for any ESSID */ + bool scanning; /* if set, the scan is running */ u16 assoc_id; /* current association ID, if associated */