* [PATCH v2 0/3] wireless: fix 11d lockdep and move 11d hint to cfg80211
From: Luis R. Rodriguez @ 2009-07-30 17:22 UTC (permalink / raw)
To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez
This cures the lockdep warning, now with a mutex instead of a spin_lock
to allow sleeping during the driver reg notifier, and we finish the
move of the regulatory_hint_11d() to cfg80211. We also add some missing
lock calls and remove the cfg80211 mutex usage from the driver custom
regulatory settings wiphy_apply_custom_regulatory(). This caller is now
used internally within cfg80211 automatically for all cfg80211 drivers.
Luis R. Rodriguez (3):
cfg80211: use goto out on 11d reg hint failure
cfg80211: decouple regulatory variables from cfg80211_mutex
cfg80211: enable country IE support to all cfg80211 drivers
Sorry -- forgot to address John...
include/net/cfg80211.h | 14 ------------
net/mac80211/mlme.c | 6 +----
net/wireless/core.c | 4 +--
net/wireless/reg.c | 53 +++++++++++++++++++++++++++++++++++------------
net/wireless/reg.h | 15 +++++++++++++
net/wireless/sme.c | 16 ++++++++++++++
6 files changed, 72 insertions(+), 36 deletions(-)
^ permalink raw reply
* [PATCH v2 3/3] cfg80211: enable country IE support to all cfg80211 drivers
From: Luis R. Rodriguez @ 2009-07-30 17:19 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Luis R. Rodriguez
In-Reply-To: <1248974386-8168-1-git-send-email-lrodriguez@atheros.com>
Since the bss is always set now once we are connected, if the
bss has its own information element we refer to it and pass that
instead of relying on mac80211's parsing.
Now all cfg80211 drivers get country IE support, automatically.
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
include/net/cfg80211.h | 14 --------------
net/mac80211/mlme.c | 6 +-----
net/wireless/reg.c | 1 -
net/wireless/reg.h | 15 +++++++++++++++
net/wireless/sme.c | 16 ++++++++++++++++
5 files changed, 32 insertions(+), 20 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e1b9235..fa72997 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1514,20 +1514,6 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb);
extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
/**
- * regulatory_hint_11d - hints a country IE as a regulatory domain
- * @wiphy: the wireless device giving the hint (used only for reporting
- * conflicts)
- * @country_ie: pointer to the country IE
- * @country_ie_len: length of the country IE
- *
- * We will intersect the rd with the what CRDA tells us should apply
- * for the alpha2 this country IE belongs to, this prevents APs from
- * sending us incorrect or outdated information against a country.
- */
-extern void regulatory_hint_11d(struct wiphy *wiphy,
- u8 *country_ie,
- u8 country_ie_len);
-/**
* wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
* @wiphy: the wireless device we want to process the regulatory domain on
* @regd: the custom regulatory domain to use for this wiphy
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0779ba1..5ff1496 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1846,12 +1846,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
bssid, ap_ht_cap_flags);
}
+ /* Note: country IE parsing is done for us by cfg80211 */
if (elems.country_elem) {
- /* Note we are only reviewing this on beacons
- * for the BSSID we are associated to */
- regulatory_hint_11d(local->hw.wiphy,
- elems.country_elem, elems.country_elem_len);
-
/* TODO: IBSS also needs this */
if (elems.pwr_constr_elem)
ieee80211_handle_pwr_constr(sdata,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 14e0c87..06abd7a 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1911,7 +1911,6 @@ free_rd_out:
out:
mutex_unlock(®_mutex);
}
-EXPORT_SYMBOL(regulatory_hint_11d);
static bool freq_is_chan_12_13_14(u16 freq)
{
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index e37829a..662a9da 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -36,4 +36,19 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
struct ieee80211_channel *beacon_chan,
gfp_t gfp);
+/**
+ * regulatory_hint_11d - hints a country IE as a regulatory domain
+ * @wiphy: the wireless device giving the hint (used only for reporting
+ * conflicts)
+ * @country_ie: pointer to the country IE
+ * @country_ie_len: length of the country IE
+ *
+ * We will intersect the rd with the what CRDA tells us should apply
+ * for the alpha2 this country IE belongs to, this prevents APs from
+ * sending us incorrect or outdated information against a country.
+ */
+void regulatory_hint_11d(struct wiphy *wiphy,
+ u8 *country_ie,
+ u8 country_ie_len);
+
#endif /* __NET_WIRELESS_REG_H */
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 3728d2b..bc0fb7d 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -13,6 +13,7 @@
#include <net/cfg80211.h>
#include <net/rtnetlink.h>
#include "nl80211.h"
+#include "reg.h"
struct cfg80211_conn {
struct cfg80211_connect_params params;
@@ -320,6 +321,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
struct cfg80211_bss *bss)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
+ u8 *country_ie;
#ifdef CONFIG_WIRELESS_EXT
union iwreq_data wrqu;
#endif
@@ -401,6 +403,20 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
wdev->sme_state = CFG80211_SME_CONNECTED;
cfg80211_upload_connect_keys(wdev);
+
+ country_ie = (u8 *) ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
+
+ if (!country_ie)
+ return;
+
+ /*
+ * ieee80211_bss_get()_ie ensures we can access:
+ * - country_ie + 2, the start of the country ie data, and
+ * - and country_ie[1] which is the IE length
+ */
+ regulatory_hint_11d(wdev->wiphy,
+ country_ie + 2,
+ country_ie[1]);
}
void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
--
1.6.0.4
^ permalink raw reply related
* [PATCH v2 2/3] cfg80211: decouple regulatory variables from cfg80211_mutex
From: Luis R. Rodriguez @ 2009-07-30 17:19 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Luis R. Rodriguez
In-Reply-To: <1248974386-8168-1-git-send-email-lrodriguez@atheros.com>
We change regulatory code to be protected by its own regulatory
mutex and alleviate cfg80211_mutex to only be used to protect
cfg80211_rdev_list, the registered device list.
By doing this we will be able to work on regulatory core components
without having to have hog up the cfg80211_mutex. An example here is
we no longer need to use the cfg80211_mutex during driver specific
wiphy_apply_custom_regulatory(). We also no longer need it for the
the country IE regulatory hint; by doing so we end up curing this
new lockdep warning:
=======================================================
[ INFO: possible circular locking dependency detected ]
2.6.31-rc4-wl #12
-------------------------------------------------------
phy1/1709 is trying to acquire lock:
(cfg80211_mutex){+.+.+.}, at: [<ffffffffa00af852>] regulatory_hint_11d+0x32/0x3f0 [cfg80211]
but task is already holding lock:
(&ifmgd->mtx){+.+.+.}, at: [<ffffffffa0144228>] ieee80211_sta_work+0x108/0x10f0 [mac80211]
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #3 (&ifmgd->mtx){+.+.+.}:
[<ffffffff810857b6>] __lock_acquire+0xd76/0x12b0
[<ffffffff81085dd3>] lock_acquire+0xe3/0x120
[<ffffffff814eeae4>] mutex_lock_nested+0x44/0x350
[<ffffffffa0141bb8>] ieee80211_mgd_auth+0x108/0x1f0 [mac80211]
[<ffffffffa0148563>] ieee80211_auth+0x13/0x20 [mac80211]
[<ffffffffa00bc3a1>] __cfg80211_mlme_auth+0x1b1/0x2a0 [cfg80211]
[<ffffffffa00bc516>] cfg80211_mlme_auth+0x86/0xc0 [cfg80211]
[<ffffffffa00b368d>] nl80211_authenticate+0x21d/0x230 [cfg80211]
[<ffffffff81416ba6>] genl_rcv_msg+0x1b6/0x1f0
[<ffffffff81415c39>] netlink_rcv_skb+0x89/0xb0
[<ffffffff814169d9>] genl_rcv+0x29/0x40
[<ffffffff8141591d>] netlink_unicast+0x29d/0x2b0
[<ffffffff81416514>] netlink_sendmsg+0x214/0x300
[<ffffffff813e4407>] sock_sendmsg+0x107/0x130
[<ffffffff813e45b9>] sys_sendmsg+0x189/0x320
[<ffffffff81011f82>] system_call_fastpath+0x16/0x1b
[<ffffffffffffffff>] 0xffffffffffffffff
-> #2 (&wdev->mtx){+.+.+.}:
[<ffffffff810857b6>] __lock_acquire+0xd76/0x12b0
[<ffffffff81085dd3>] lock_acquire+0xe3/0x120
[<ffffffff814eeae4>] mutex_lock_nested+0x44/0x350
[<ffffffffa00ab304>] cfg80211_netdev_notifier_call+0x1a4/0x390 [cfg80211]
[<ffffffff814f3dff>] notifier_call_chain+0x3f/0x80
[<ffffffff81075a91>] raw_notifier_call_chain+0x11/0x20
[<ffffffff813f665a>] dev_open+0x10a/0x120
[<ffffffff813f59bd>] dev_change_flags+0x9d/0x1e0
[<ffffffff8144eb6e>] devinet_ioctl+0x6fe/0x760
[<ffffffff81450204>] inet_ioctl+0x94/0xc0
[<ffffffff813e25fa>] sock_ioctl+0x6a/0x290
[<ffffffff8111e911>] vfs_ioctl+0x31/0xa0
[<ffffffff8111ea9a>] do_vfs_ioctl+0x8a/0x5c0
[<ffffffff8111f069>] sys_ioctl+0x99/0xa0
[<ffffffff81011f82>] system_call_fastpath+0x16/0x1b
[<ffffffffffffffff>] 0xffffffffffffffff
-> #1 (&rdev->mtx){+.+.+.}:
[<ffffffff810857b6>] __lock_acquire+0xd76/0x12b0
[<ffffffff81085dd3>] lock_acquire+0xe3/0x120
[<ffffffff814eeae4>] mutex_lock_nested+0x44/0x350
[<ffffffffa00ac4d0>] cfg80211_get_dev_from_ifindex+0x60/0x90 [cfg80211]
[<ffffffffa00b21ff>] get_rdev_dev_by_info_ifindex+0x6f/0xa0 [cfg80211]
[<ffffffffa00b51eb>] nl80211_set_interface+0x3b/0x260 [cfg80211]
[<ffffffff81416ba6>] genl_rcv_msg+0x1b6/0x1f0
[<ffffffff81415c39>] netlink_rcv_skb+0x89/0xb0
[<ffffffff814169d9>] genl_rcv+0x29/0x40
[<ffffffff8141591d>] netlink_unicast+0x29d/0x2b0
[<ffffffff81416514>] netlink_sendmsg+0x214/0x300
[<ffffffff813e4407>] sock_sendmsg+0x107/0x130
[<ffffffff813e45b9>] sys_sendmsg+0x189/0x320
[<ffffffff81011f82>] system_call_fastpath+0x16/0x1b
[<ffffffffffffffff>] 0xffffffffffffffff
other info that might help us debug this:
3 locks held by phy1/1709:
#0: ((wiphy_name(local->hw.wiphy))){+.+.+.}, at: [<ffffffff8106b45d>] worker_thread+0x19d/0x340
#1: (&ifmgd->work){+.+.+.}, at: [<ffffffff8106b45d>] worker_thread+0x19d/0x340
#2: (&ifmgd->mtx){+.+.+.}, at: [<ffffffffa0144228>] ieee80211_sta_work+0x108/0x10f0 [mac80211]
Reported-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
net/wireless/core.c | 4 +---
net/wireless/reg.c | 46 +++++++++++++++++++++++++++++++++++++---------
2 files changed, 38 insertions(+), 12 deletions(-)
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 755cdf1..d8dbd7f 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -34,9 +34,7 @@ MODULE_DESCRIPTION("wireless configuration support");
LIST_HEAD(cfg80211_rdev_list);
/*
- * This is used to protect the cfg80211_rdev_list, cfg80211_regdomain,
- * country_ie_regdomain, the reg_beacon_list and the the last regulatory
- * request receipt (last_request).
+ * This is used to protect the cfg80211_rdev_list
*/
DEFINE_MUTEX(cfg80211_mutex);
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 2d1d183..14e0c87 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -62,6 +62,16 @@ const struct ieee80211_regdomain *cfg80211_regdomain;
*/
static const struct ieee80211_regdomain *country_ie_regdomain;
+/*
+ * Protects static reg.c components:
+ * - cfg80211_world_regdom
+ * - cfg80211_regdom
+ * - country_ie_regdomain
+ * - last_request
+ */
+DEFINE_MUTEX(reg_mutex);
+#define assert_reg_lock() WARN_ON(!mutex_is_locked(®_mutex))
+
/* Used to queue up regulatory hints */
static LIST_HEAD(reg_requests_list);
static spinlock_t reg_requests_lock;
@@ -1293,7 +1303,7 @@ static void handle_channel_custom(struct wiphy *wiphy,
struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan;
- assert_cfg80211_lock();
+ assert_reg_lock();
sband = wiphy->bands[band];
BUG_ON(chan_idx >= sband->n_channels);
@@ -1342,14 +1352,14 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
enum ieee80211_band band;
unsigned int bands_set = 0;
- mutex_lock(&cfg80211_mutex);
+ mutex_lock(®_mutex);
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (!wiphy->bands[band])
continue;
handle_band_custom(wiphy, band, regd);
bands_set++;
}
- mutex_unlock(&cfg80211_mutex);
+ mutex_unlock(®_mutex);
/*
* no point in calling this if it won't have any effect
@@ -1495,7 +1505,7 @@ static int ignore_request(struct wiphy *wiphy,
* Returns zero if all went fine, %-EALREADY if a regulatory domain had
* already been set or other standard error codes.
*
- * Caller must hold &cfg80211_mutex
+ * Caller must hold &cfg80211_mutex and ®_mutex
*/
static int __regulatory_hint(struct wiphy *wiphy,
struct regulatory_request *pending_request)
@@ -1570,6 +1580,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
BUG_ON(!reg_request->alpha2);
mutex_lock(&cfg80211_mutex);
+ mutex_lock(®_mutex);
if (wiphy_idx_valid(reg_request->wiphy_idx))
wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
@@ -1585,6 +1596,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
if (r == -EALREADY && wiphy && wiphy->strict_regulatory)
wiphy_update_regulatory(wiphy, reg_request->initiator);
out:
+ mutex_unlock(®_mutex);
mutex_unlock(&cfg80211_mutex);
}
@@ -1613,6 +1625,10 @@ static void reg_process_pending_beacon_hints(void)
struct cfg80211_registered_device *rdev;
struct reg_beacon *pending_beacon, *tmp;
+ /*
+ * No need to hold the reg_mutex here as we just touch wiphys
+ * and do not read or access regulatory variables.
+ */
mutex_lock(&cfg80211_mutex);
/* This goes through the _pending_ beacon list */
@@ -1734,12 +1750,13 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
}
EXPORT_SYMBOL(regulatory_hint);
+/* Caller must hold reg_mutex */
static bool reg_same_country_ie_hint(struct wiphy *wiphy,
u32 country_ie_checksum)
{
struct wiphy *request_wiphy;
- assert_cfg80211_lock();
+ assert_reg_lock();
if (unlikely(last_request->initiator !=
NL80211_REGDOM_SET_BY_COUNTRY_IE))
@@ -1772,7 +1789,7 @@ void regulatory_hint_11d(struct wiphy *wiphy,
enum environment_cap env = ENVIRON_ANY;
struct regulatory_request *request;
- mutex_lock(&cfg80211_mutex);
+ mutex_lock(®_mutex);
if (unlikely(!last_request))
goto out;
@@ -1883,7 +1900,7 @@ void regulatory_hint_11d(struct wiphy *wiphy,
request->country_ie_checksum = checksum;
request->country_ie_env = env;
- mutex_unlock(&cfg80211_mutex);
+ mutex_unlock(®_mutex);
queue_regulatory_request(request);
@@ -1892,7 +1909,7 @@ void regulatory_hint_11d(struct wiphy *wiphy,
free_rd_out:
kfree(rd);
out:
- mutex_unlock(&cfg80211_mutex);
+ mutex_unlock(®_mutex);
}
EXPORT_SYMBOL(regulatory_hint_11d);
@@ -2225,10 +2242,13 @@ int set_regdom(const struct ieee80211_regdomain *rd)
assert_cfg80211_lock();
+ mutex_lock(®_mutex);
+
/* Note that this doesn't update the wiphys, this is done below */
r = __set_regdom(rd);
if (r) {
kfree(rd);
+ mutex_unlock(®_mutex);
return r;
}
@@ -2243,6 +2263,8 @@ int set_regdom(const struct ieee80211_regdomain *rd)
nl80211_send_reg_change_event(last_request);
+ mutex_unlock(®_mutex);
+
return r;
}
@@ -2253,16 +2275,20 @@ void reg_device_remove(struct wiphy *wiphy)
assert_cfg80211_lock();
+ mutex_lock(®_mutex);
+
kfree(wiphy->regd);
if (last_request)
request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
if (!request_wiphy || request_wiphy != wiphy)
- return;
+ goto out;
last_request->wiphy_idx = WIPHY_IDX_STALE;
last_request->country_ie_env = ENVIRON_ANY;
+out:
+ mutex_unlock(®_mutex);
}
int regulatory_init(void)
@@ -2323,6 +2349,7 @@ void regulatory_exit(void)
cancel_work_sync(®_work);
mutex_lock(&cfg80211_mutex);
+ mutex_lock(®_mutex);
reset_regdomains();
@@ -2361,5 +2388,6 @@ void regulatory_exit(void)
}
spin_unlock(®_requests_lock);
+ mutex_unlock(®_mutex);
mutex_unlock(&cfg80211_mutex);
}
--
1.6.0.4
^ permalink raw reply related
* [PATCH v2 1/3] cfg80211: use goto out on 11d reg hint failure
From: Luis R. Rodriguez @ 2009-07-30 17:19 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Luis R. Rodriguez
In-Reply-To: <1248974386-8168-1-git-send-email-lrodriguez@atheros.com>
This does not change functionality.
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
net/wireless/reg.c | 6 ++----
1 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index fb40428..2d1d183 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1774,10 +1774,8 @@ void regulatory_hint_11d(struct wiphy *wiphy,
mutex_lock(&cfg80211_mutex);
- if (unlikely(!last_request)) {
- mutex_unlock(&cfg80211_mutex);
- return;
- }
+ if (unlikely(!last_request))
+ goto out;
/* IE len must be evenly divisible by 2 */
if (country_ie_len & 0x01)
--
1.6.0.4
^ permalink raw reply related
* [PATCH v2 0/3] wireless: fix 11d lockdep and move 11d hint to cfg80211
From: Luis R. Rodriguez @ 2009-07-30 17:19 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Luis R. Rodriguez
This cures the lockdep warning, now with a mutex instead of a spin_lock
to allow sleeping during the driver reg notifier, and we finish the
move of the regulatory_hint_11d() to cfg80211. We also add some missing
lock calls and remove the cfg80211 mutex usage from the driver custom
regulatory settings wiphy_apply_custom_regulatory(). This caller is now
used internally within cfg80211 automatically for all cfg80211 drivers.
Luis R. Rodriguez (3):
cfg80211: use goto out on 11d reg hint failure
cfg80211: decouple regulatory variables from cfg80211_mutex
cfg80211: enable country IE support to all cfg80211 drivers
include/net/cfg80211.h | 14 ------------
net/mac80211/mlme.c | 6 +----
net/wireless/core.c | 4 +--
net/wireless/reg.c | 53 +++++++++++++++++++++++++++++++++++------------
net/wireless/reg.h | 15 +++++++++++++
net/wireless/sme.c | 16 ++++++++++++++
6 files changed, 72 insertions(+), 36 deletions(-)
^ permalink raw reply
* Re: [wireless] rt2870sta BUGs on shutdown, 2.6.30.2->git.today+git.wireless.today
From: Johannes Berg @ 2009-07-30 17:11 UTC (permalink / raw)
To: Ivo van Doorn
Cc: Bartlomiej Zolnierkiewicz, Luis Correia, Mike Galbraith,
linux-wireless, LKML, John W. Linville
In-Reply-To: <200907301852.28172.IvDoorn@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 2435 bytes --]
On Thu, 2009-07-30 at 18:52 +0200, Ivo van Doorn wrote:
> [some text expressing his frustration]
This is exactly why I was against staging all the time. Now suddenly
"The Crap" seems like a viable alternative. WAKE UP PEOPLE. The code is
not useful. Just look at the code that Mike pasted into his email. That
alone should be enough to send cold shivers down your spine!
What staging has achieved here is giving the crap vendor code a
blessing, receiving it welcomingly and forgivingly instead of saying
"well screw you, go ahead and ship this to your users but don't ever say
you support Linux well" ... now even some hackers and just just "dumb
users" think that the crap in staging could possibly at some point
become useful code!
It won't. EVER. No matter _how_ much you clean it up, it will NEVER fit
into the code scheme that everything else wireless has adopted.
And, Bartlomiej, don't give me the straw-man argument of user support,
if all you cared about were users you could well have _distros_ ship the
crap. They don't want to, of course, support this, for good reason! As
long as the vendors don't wake up, and some people see The Crap as a
viable alternative, good hardware support will never become a reality.
Look what you've done, really! You've frustrated the only person (Ivo)
who cares about giving these devices _proper_ support to a point where
he's no longer really interested in it because he's always measured
against The Crap right away. And that's perfectly understandable!
Effectively, you're saying that while he may have done good work, you
don't care about it because it's not perfect. Mike at least was willing
to try rt2x00 and work with it.
And now you're coming out of the woods and claiming that The Crap
works?! When the thread started with how it crashed? Get real.
In the end, while the letters you typed into your email claim to say the
opposite, the message of your email is that nobody should care about
rt2x00 and that the vendor driver should remain the status quo. Well, in
that case, get lost, crawl into the staging list and at least don't
bother us with The Crap.
Such attitude is part of the problem, the other big part is that vendors
can now claim their hardware "has mainline Linux support (in the staging
area)" and nobody will be the wiser.
So how about you help work on it, or think about a solution instead?
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [wireless] rt2870sta BUGs on shutdown, 2.6.30.2->git.today+git.wireless.today
From: Mike Galbraith @ 2009-07-30 17:09 UTC (permalink / raw)
To: Ivo van Doorn
Cc: Bartlomiej Zolnierkiewicz, Luis Correia, linux-wireless, LKML,
John W. Linville, Johannes Berg
In-Reply-To: <200907301852.28172.IvDoorn@gmail.com>
On Thu, 2009-07-30 at 18:52 +0200, Ivo van Doorn wrote:
> I planned, and actually did write, a lengthy reply for this thread, when I completed the reply
> I reconsidred and opted for this shorter reply. Every 2 or 3 months this discussion is started
> again and I am f***ing tired of it, so excuse me but I am not going to throw myself into
> this completely pointless discussion
>
> What you are suggesting in your mail is something the rt2x00 project did for 5 years, we stopped
> with that 4 months ago because it wasn't working out. Apparently you have more experience in this
> matter so I hope you will find a way to make that solution work out.
>
> If you want to maintain the legacy drivers then do it, start a new project and start maintaining
> the code. I can forward you all the users with complains about the "good enough" drivers. It is
> good to know that you apparently have the resources to maintain the old drivers.
> Most people who are helping with the rt2800pci/usb drivers lack the required time to boost the driver
> into such a state it can be widely adopted. But every time it amazes me that the people who want
> to develop and have the time to do it, all want to jump on the old Ralink code... Apparently there
> is some appeal to maintaining crap rather then helping to ship out proper drivers to the users.
>
> But I'll shut up now, as I said this discussion is held every few months, so perhaps that when
> the discussion is started again in a couple of months I am more interested in a lengthy reply.
Hohum. Please remove me from CC for any further discussion.
-Mike
^ permalink raw reply
* Re: [Linux Wireless] Update of "en/users/Download" by ReinetteChatre
From: Luis R. Rodriguez @ 2009-07-30 17:06 UTC (permalink / raw)
To: Roman Macko; +Cc: reinette chatre, linux-wireless
In-Reply-To: <4A71D172.1000306@gmail.com>
On Thu, Jul 30, 2009 at 9:59 AM, Roman Macko<rmacko72@gmail.com> wrote:
> Yes, I tested it. When you place that config file containing "search updates
> built-in" in /etc/depmod.d
> directory, it doesn't work.
OK you probably have an old version of depmod. depmod is provided by
module-init-tools, what version of module-init-tools do you have?
I have 3.10 (as on Ubuntu Karmic)
> You have to place it in global config file
> /etc/depmod.conf.
If this is an old depmod thing we will have to check the version of
depmod and do this for that case.
> How depmod works with config files in /etc/depmod.d directory is a mystery
> for me.
Its not that tricky, the new version reads /etc/depmod.conf and if
that is not found then moves on to check /etc/depmod.d/* files.
> I wasn't able to learn
> this from manual pages.
That's probably because your version doesn't use depmod.d dir.
> And I tested another thing too. When some of config files (either global
> /etc/depmod.conf or one of those in /etc/depmod.d directory)
> doesn't contain search command ,
> everything works fine, according to manual page for depmod, using builtin
> search string "updates built-in" what is
> what you need.
Right, built-in will use /lib/modules/$(uname -r)/kernel/ for modules,
chances are if no depmod.conf file or depmod.d dir is present default
may be to use built-in.
> As soon as one of them (either global or one of those in
> /etc/depmod.d directory) contains search command,
> then depmod uses this one. It seems seach command in global config file
> (/etc/depmod.conf) has higher priory. But as I say
> I really don't know how depmod works with all config files.
I believe this is built-in by default, then read depmod.conf first, if
that is not present read depmod.d dir.
Luis
^ permalink raw reply
* Re: [Linux Wireless] Update of "en/users/Download" by ReinetteChatre
From: Roman Macko @ 2009-07-30 16:59 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: reinette chatre, linux-wireless
In-Reply-To: <43e72e890907300743nd3a80eck2153d01f4e99ddf9@mail.gmail.com>
Yes, I tested it. When you place that config file containing "search
updates built-in" in /etc/depmod.d
directory, it doesn't work. You have to place it in global config file
/etc/depmod.conf.
How depmod works with config files in /etc/depmod.d directory is a
mystery for me. I wasn't able to learn
this from manual pages.
And I tested another thing too. When some of config files (either global
/etc/depmod.conf or one of those in /etc/depmod.d directory)
doesn't contain search command ,
everything works fine, according to manual page for depmod, using
builtin search string "updates built-in" what is
what you need. As soon as one of them (either global or one of those in
/etc/depmod.d directory) contains search command,
then depmod uses this one. It seems seach command in global config file
(/etc/depmod.conf) has higher priory. But as I say
I really don't know how depmod works with all config files.
roman
Luis R. Rodriguez wrote:
> On Thu, Jul 30, 2009 at 6:12 AM, Roman Macko<rmacko72@gmail.com> wrote:
>
>> Luis,
>>
>> I used stable version 2.6.30.
>> Anyway I downloaded bleeding edge version and ran script check_depmod.
>> But it created new configuration in /etc/depmod.d directory instead of
>> creating
>> global configuration /etc/depmod.conf what I did. It doesn't work in that
>> way.
>>
>
> What do you mean it doesn't work that way?
> Do you mean you tested it and that it didn't work?
>
>
>> I can read in manual pages of depmod.conf that depmod.d directory serves for
>> configuration on per-module basis,
>> so I think you can change the order of proceding directories for particular
>> module only there.
>>
>
> Nope. Even Ubuntu uses their own file in there for the same purpose:
>
> mcgrof@tux ~ $ cat /etc/depmod.d/ubuntu.conf
> search updates ubuntu built-in
>
>
>> But I don't know how to name that file or if my thought is right at all.
>>
>
> The man page needs some updating.
>
> Luis
>
^ permalink raw reply
* Re: [wireless] rt2870sta BUGs on shutdown, 2.6.30.2->git.today+git.wireless.today
From: Ivo van Doorn @ 2009-07-30 16:52 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz
Cc: Luis Correia, Mike Galbraith, linux-wireless, LKML,
John W. Linville, Johannes Berg
In-Reply-To: <200907301517.57811.bzolnier@gmail.com>
I planned, and actually did write, a lengthy reply for this thread, when I completed the reply
I reconsidred and opted for this shorter reply. Every 2 or 3 months this discussion is started
again and I am f***ing tired of it, so excuse me but I am not going to throw myself into
this completely pointless discussion
What you are suggesting in your mail is something the rt2x00 project did for 5 years, we stopped
with that 4 months ago because it wasn't working out. Apparently you have more experience in this
matter so I hope you will find a way to make that solution work out.
If you want to maintain the legacy drivers then do it, start a new project and start maintaining
the code. I can forward you all the users with complains about the "good enough" drivers. It is
good to know that you apparently have the resources to maintain the old drivers.
Most people who are helping with the rt2800pci/usb drivers lack the required time to boost the driver
into such a state it can be widely adopted. But every time it amazes me that the people who want
to develop and have the time to do it, all want to jump on the old Ralink code... Apparently there
is some appeal to maintaining crap rather then helping to ship out proper drivers to the users.
But I'll shut up now, as I said this discussion is held every few months, so perhaps that when
the discussion is started again in a couple of months I am more interested in a lengthy reply.
Ivo
^ permalink raw reply
* [PATCH 10/10] rndis_wlan: rework key handling
From: Jussi Kivilinna @ 2009-07-30 16:42 UTC (permalink / raw)
To: linux-wireless; +Cc: linville, Jussi Kivilinna
In-Reply-To: <20090730164120.28317.53313.stgit@fate.lan>
Organize key data in private structure better and store WPA keys, so
they can be restored as WEP keys.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
---
drivers/net/wireless/rndis_wlan.c | 188 ++++++++++++++++++++++++++++---------
1 files changed, 142 insertions(+), 46 deletions(-)
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 3d92b77..828dc18 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -413,6 +413,15 @@ static const struct ieee80211_rate rndis_rates[] = {
{ .bitrate = 540 }
};
+struct rndis_wlan_encr_key {
+ int len;
+ int cipher;
+ u8 material[32];
+ u8 bssid[ETH_ALEN];
+ bool pairwise;
+ bool tx_key;
+};
+
/* RNDIS device private data */
struct rndis_wlan_private {
struct usbnet *usbdev;
@@ -456,9 +465,7 @@ struct rndis_wlan_private {
/* encryption stuff */
int encr_tx_key_index;
- char encr_keys[4][32];
- int encr_key_len[4];
- char encr_key_wpa[4];
+ struct rndis_wlan_encr_key encr_keys[4];
int wpa_version;
int wpa_keymgmt;
int wpa_authalg;
@@ -525,6 +532,15 @@ static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv)
}
+static bool is_wpa_key(struct rndis_wlan_private *priv, int idx)
+{
+ int cipher = priv->encr_keys[idx].cipher;
+
+ return (cipher == WLAN_CIPHER_SUITE_CCMP ||
+ cipher == WLAN_CIPHER_SUITE_TKIP);
+}
+
+
#ifdef DEBUG
static const char *oid_to_string(__le32 oid)
{
@@ -895,8 +911,7 @@ static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig)
/*
* common functions
*/
-static int
-add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index);
+static void restore_keys(struct usbnet *usbdev);
static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
{
@@ -1115,7 +1130,7 @@ static int set_infra_mode(struct usbnet *usbdev, int mode)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
__le32 tmp;
- int ret, i;
+ int ret;
devdbg(usbdev, "set_infra_mode: infra_mode=0x%x", priv->infra_mode);
@@ -1130,14 +1145,7 @@ static int set_infra_mode(struct usbnet *usbdev, int mode)
/* NDIS drivers clear keys when infrastructure mode is
* changed. But Linux tools assume otherwise. So set the
* keys */
- if (priv->wpa_keymgmt == 0 ||
- priv->wpa_keymgmt == IW_AUTH_KEY_MGMT_802_1X) {
- for (i = 0; i < 4; i++) {
- if (priv->encr_key_len[i] > 0 && !priv->encr_key_wpa[i])
- add_wep_key(usbdev, priv->encr_keys[i],
- priv->encr_key_len[i], i);
- }
- }
+ restore_keys(usbdev);
priv->infra_mode = mode;
return 0;
@@ -1204,11 +1212,16 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
struct ndis_80211_wep_key ndis_key;
- int ret;
+ int cipher, ret;
- if (key_len <= 0 || key_len > 32 || index < 0 || index >= 4)
+ if ((key_len != 5 || key_len != 13) || index < 0 || index > 3)
return -EINVAL;
+ if (key_len == 5)
+ cipher = WLAN_CIPHER_SUITE_WEP40;
+ else
+ cipher = WLAN_CIPHER_SUITE_WEP104;
+
memset(&ndis_key, 0, sizeof(ndis_key));
ndis_key.size = cpu_to_le32(sizeof(ndis_key));
@@ -1233,30 +1246,44 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index)
return ret;
}
- priv->encr_key_len[index] = key_len;
- priv->encr_key_wpa[index] = 0;
- memcpy(&priv->encr_keys[index], key, key_len);
+ priv->encr_keys[index].len = key_len;
+ priv->encr_keys[index].cipher = cipher;
+ memcpy(&priv->encr_keys[index].material, key, key_len);
+ memset(&priv->encr_keys[index].bssid, 0xff, ETH_ALEN);
return 0;
}
static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
- int index, const struct sockaddr *addr,
- const u8 *rx_seq, int alg, int flags)
+ int index, const u8 *addr, const u8 *rx_seq, int cipher,
+ int flags)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
struct ndis_80211_key ndis_key;
+ bool is_addr_ok;
int ret;
- if (index < 0 || index >= 4)
+ if (index < 0 || index >= 4) {
+ devdbg(usbdev, "add_wpa_key: index out of range (%i)", index);
return -EINVAL;
- if (key_len > sizeof(ndis_key.material) || key_len < 0)
+ }
+ if (key_len > sizeof(ndis_key.material) || key_len < 0) {
+ devdbg(usbdev, "add_wpa_key: key length out of range (%i)",
+ key_len);
return -EINVAL;
- if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq)
+ }
+ if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq) {
+ devdbg(usbdev, "add_wpa_key: recv seq flag without buffer");
return -EINVAL;
- if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !addr)
+ }
+ is_addr_ok = addr && memcmp(addr, zero_bssid, ETH_ALEN) != 0 &&
+ memcmp(addr, ffff_bssid, ETH_ALEN) != 0;
+ if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) {
+ devdbg(usbdev, "add_wpa_key: pairwise but bssid invalid (%pM)",
+ addr);
return -EINVAL;
+ }
devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index,
!!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY),
@@ -1270,7 +1297,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
ndis_key.length = cpu_to_le32(key_len);
ndis_key.index = cpu_to_le32(index) | flags;
- if (alg == IW_ENCODE_ALG_TKIP && key_len == 32) {
+ if (cipher == WLAN_CIPHER_SUITE_TKIP && key_len == 32) {
/* wpa_supplicant gives us the Michael MIC RX/TX keys in
* different order than NDIS spec, so swap the order here. */
memcpy(ndis_key.material, key, 16);
@@ -1284,7 +1311,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) {
/* pairwise key */
- memcpy(ndis_key.bssid, addr->sa_data, ETH_ALEN);
+ memcpy(ndis_key.bssid, addr, ETH_ALEN);
} else {
/* group key */
if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
@@ -1299,8 +1326,14 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
if (ret != 0)
return ret;
- priv->encr_key_len[index] = key_len;
- priv->encr_key_wpa[index] = 1;
+ memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index]));
+ priv->encr_keys[index].len = key_len;
+ priv->encr_keys[index].cipher = cipher;
+ memcpy(&priv->encr_keys[index].material, key, key_len);
+ if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY)
+ memcpy(&priv->encr_keys[index].bssid, ndis_key.bssid, ETH_ALEN);
+ else
+ memset(&priv->encr_keys[index].bssid, 0xff, ETH_ALEN);
if (flags & NDIS_80211_ADDKEY_TRANSMIT_KEY)
priv->encr_tx_key_index = index;
@@ -1309,25 +1342,74 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
}
+static int restore_key(struct usbnet *usbdev, int key_idx)
+{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ struct rndis_wlan_encr_key key;
+ int flags;
+
+ key = priv->encr_keys[key_idx];
+
+ devdbg(usbdev, "restore_key: %i:%s:%i", key_idx,
+ is_wpa_key(priv, key_idx) ? "wpa" : "wep",
+ key.len);
+
+ if (key.len == 0)
+ return 0;
+
+ if (is_wpa_key(priv, key_idx)) {
+ flags = 0;
+
+ /*if (priv->encr_tx_key_index == key_idx)
+ flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY;*/
+
+ if (memcmp(key.bssid, zero_bssid, ETH_ALEN) != 0 &&
+ memcmp(key.bssid, ffff_bssid, ETH_ALEN) != 0)
+ flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY;
+
+ return add_wpa_key(usbdev, key.material, key.len, key_idx,
+ key.bssid, NULL, key.cipher, flags);
+ }
+
+ return add_wep_key(usbdev, key.material, key.len, key_idx);
+}
+
+
+static void restore_keys(struct usbnet *usbdev)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ restore_key(usbdev, i);
+}
+
+
+static void clear_key(struct rndis_wlan_private *priv, int idx)
+{
+ memset(&priv->encr_keys[idx], 0, sizeof(priv->encr_keys[idx]));
+}
+
+
/* remove_key is for both wep and wpa */
static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN])
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
struct ndis_80211_remove_key remove_key;
__le32 keyindex;
+ bool is_wpa;
int ret;
- if (priv->encr_key_len[index] == 0)
+ if (priv->encr_keys[index].len == 0)
return 0;
- priv->encr_key_len[index] = 0;
- priv->encr_key_wpa[index] = 0;
- memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index]));
+ is_wpa = is_wpa_key(priv, index);
- if (priv->wpa_cipher_pair == IW_AUTH_CIPHER_TKIP ||
- priv->wpa_cipher_pair == IW_AUTH_CIPHER_CCMP ||
- priv->wpa_cipher_group == IW_AUTH_CIPHER_TKIP ||
- priv->wpa_cipher_group == IW_AUTH_CIPHER_CCMP) {
+ devdbg(usbdev, "remove_key: %i:%s:%i", index, is_wpa ? "wpa" : "wep",
+ priv->encr_keys[index].len);
+
+ clear_key(priv, index);
+
+ if (is_wpa) {
remove_key.size = cpu_to_le32(sizeof(remove_key));
remove_key.index = cpu_to_le32(index);
if (bssid) {
@@ -1871,8 +1953,9 @@ static int rndis_iw_set_encode(struct net_device *dev,
{
struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ struct rndis_wlan_encr_key key;
int ret, index, key_len;
- u8 *key;
+ u8 *keybuf;
index = (wrqu->encoding.flags & IW_ENCODE_INDEX);
@@ -1907,17 +1990,18 @@ static int rndis_iw_set_encode(struct net_device *dev,
if (wrqu->data.length > 0) {
key_len = wrqu->data.length;
- key = extra;
+ keybuf = extra;
} else {
/* must be set as tx key */
- if (priv->encr_key_len[index] == 0)
+ if (priv->encr_keys[index].len == 0)
return -EINVAL;
- key_len = priv->encr_key_len[index];
key = priv->encr_keys[index];
+ key_len = key.len;
+ keybuf = key.material;
priv->encr_tx_key_index = index;
}
- if (add_wep_key(usbdev, key, key_len, index) != 0)
+ if (add_wep_key(usbdev, keybuf, key_len, index) != 0)
return -EINVAL;
if (index == priv->encr_tx_key_index)
@@ -1934,7 +2018,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev,
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- int keyidx, flags;
+ int keyidx, flags, cipher;
keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX;
@@ -1944,8 +2028,10 @@ static int rndis_iw_set_encode_ext(struct net_device *dev,
else
keyidx = priv->encr_tx_key_index;
- if (keyidx < 0 || keyidx >= 4)
+ if (keyidx < 0 || keyidx >= 4) {
+ devwarn(usbdev, "encryption index out of range (%u)", keyidx);
return -EINVAL;
+ }
if (ext->alg == WPA_ALG_WEP) {
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
@@ -1953,10 +2039,19 @@ static int rndis_iw_set_encode_ext(struct net_device *dev,
return add_wep_key(usbdev, ext->key, ext->key_len, keyidx);
}
+ cipher = -1;
+ if (ext->alg == IW_ENCODE_ALG_TKIP)
+ cipher = WLAN_CIPHER_SUITE_TKIP;
+ else if (ext->alg == IW_ENCODE_ALG_CCMP)
+ cipher = WLAN_CIPHER_SUITE_CCMP;
+
if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) ||
ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0)
return remove_key(usbdev, keyidx, NULL);
+ if (cipher == -1)
+ return -EOPNOTSUPP;
+
flags = 0;
if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ;
@@ -1965,8 +2060,9 @@ static int rndis_iw_set_encode_ext(struct net_device *dev,
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY;
- return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, &ext->addr,
- ext->rx_seq, ext->alg, flags);
+ return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx,
+ (u8 *)&ext->addr.sa_data, ext->rx_seq, cipher,
+ flags);
}
^ permalink raw reply related
* [PATCH 05/10] rndis_wlan: set current packet filter to zero on stop
From: Jussi Kivilinna @ 2009-07-30 16:41 UTC (permalink / raw)
To: linux-wireless; +Cc: linville, Jussi Kivilinna
In-Reply-To: <20090730164120.28317.53313.stgit@fate.lan>
Set current packet filter to zero to block receiving data packets from
device.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
---
drivers/net/wireless/rndis_wlan.c | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index bfb9861..974f724 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2530,7 +2530,8 @@ static int rndis_wlan_reset(struct usbnet *usbdev)
if (retval)
devwarn(usbdev, "rndis_reset() failed: %d", retval);
- /* rndis_reset cleared multicast list, so restore here. */
+ /* rndis_reset cleared multicast list, so restore here.
+ (set_multicast_list() also turns on current packet filter) */
set_multicast_list(usbdev);
queue_delayed_work(priv->workqueue, &priv->stats_work,
@@ -2544,6 +2545,7 @@ static int rndis_wlan_stop(struct usbnet *usbdev)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
int retval;
+ __le32 filter;
devdbg(usbdev, "rndis_wlan_stop");
@@ -2560,6 +2562,12 @@ static int rndis_wlan_stop(struct usbnet *usbdev)
priv->scan_request = NULL;
}
+ /* Set current packet filter zero to block receiving data packets from
+ device. */
+ filter = 0;
+ rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter,
+ sizeof(filter));
+
return retval;
}
^ permalink raw reply related
* [PATCH 06/10] rndis_wlan: add rndis_set/query_oid debugging
From: Jussi Kivilinna @ 2009-07-30 16:41 UTC (permalink / raw)
To: linux-wireless; +Cc: linville, Jussi Kivilinna
In-Reply-To: <20090730164120.28317.53313.stgit@fate.lan>
Add better debugging for failed OID queries.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
---
drivers/net/wireless/rndis_wlan.c | 86 ++++++++++++++++++++++++++++++++++++-
1 files changed, 84 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 974f724..f6dcbb1 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -100,7 +100,6 @@ MODULE_PARM_DESC(workaround_interval,
#define OID_GEN_RCV_ERROR cpu_to_le32(0x00020104)
#define OID_GEN_RCV_NO_BUFFER cpu_to_le32(0x00020105)
-#define OID_802_3_PERMANENT_ADDRESS cpu_to_le32(0x01010101)
#define OID_802_3_CURRENT_ADDRESS cpu_to_le32(0x01010102)
#define OID_802_3_MULTICAST_LIST cpu_to_le32(0x01010103)
#define OID_802_3_MAXIMUM_LIST_SIZE cpu_to_le32(0x01010104)
@@ -478,6 +477,68 @@ static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv)
}
+#ifdef DEBUG
+static const char *oid_to_string(__le32 oid)
+{
+ switch (oid) {
+#define OID_STR(oid) case oid: return(#oid)
+ /* from rndis_host.h */
+ OID_STR(OID_802_3_PERMANENT_ADDRESS);
+ OID_STR(OID_GEN_MAXIMUM_FRAME_SIZE);
+ OID_STR(OID_GEN_CURRENT_PACKET_FILTER);
+ OID_STR(OID_GEN_PHYSICAL_MEDIUM);
+
+ /* from rndis_wlan.c */
+ OID_STR(OID_GEN_LINK_SPEED);
+ OID_STR(OID_GEN_RNDIS_CONFIG_PARAMETER);
+
+ OID_STR(OID_GEN_XMIT_OK);
+ OID_STR(OID_GEN_RCV_OK);
+ OID_STR(OID_GEN_XMIT_ERROR);
+ OID_STR(OID_GEN_RCV_ERROR);
+ OID_STR(OID_GEN_RCV_NO_BUFFER);
+
+ OID_STR(OID_802_3_CURRENT_ADDRESS);
+ OID_STR(OID_802_3_MULTICAST_LIST);
+ OID_STR(OID_802_3_MAXIMUM_LIST_SIZE);
+
+ OID_STR(OID_802_11_BSSID);
+ OID_STR(OID_802_11_SSID);
+ OID_STR(OID_802_11_INFRASTRUCTURE_MODE);
+ OID_STR(OID_802_11_ADD_WEP);
+ OID_STR(OID_802_11_REMOVE_WEP);
+ OID_STR(OID_802_11_DISASSOCIATE);
+ OID_STR(OID_802_11_AUTHENTICATION_MODE);
+ OID_STR(OID_802_11_PRIVACY_FILTER);
+ OID_STR(OID_802_11_BSSID_LIST_SCAN);
+ OID_STR(OID_802_11_ENCRYPTION_STATUS);
+ OID_STR(OID_802_11_ADD_KEY);
+ OID_STR(OID_802_11_REMOVE_KEY);
+ OID_STR(OID_802_11_ASSOCIATION_INFORMATION);
+ OID_STR(OID_802_11_PMKID);
+ OID_STR(OID_802_11_NETWORK_TYPES_SUPPORTED);
+ OID_STR(OID_802_11_NETWORK_TYPE_IN_USE);
+ OID_STR(OID_802_11_TX_POWER_LEVEL);
+ OID_STR(OID_802_11_RSSI);
+ OID_STR(OID_802_11_RSSI_TRIGGER);
+ OID_STR(OID_802_11_FRAGMENTATION_THRESHOLD);
+ OID_STR(OID_802_11_RTS_THRESHOLD);
+ OID_STR(OID_802_11_SUPPORTED_RATES);
+ OID_STR(OID_802_11_CONFIGURATION);
+ OID_STR(OID_802_11_BSSID_LIST);
+#undef OID_STR
+ }
+
+ return "?";
+}
+#else
+static const char *oid_to_string(__le32 oid)
+{
+ return "?";
+}
+#endif
+
+
/* translate error code */
static int rndis_error_status(__le32 rndis_status)
{
@@ -533,11 +594,21 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
u.get->oid = oid;
ret = rndis_command(dev, u.header, buflen);
+ if (ret < 0)
+ devdbg(dev, "rndis_query_oid(%s): rndis_command() failed, %d "
+ "(%08x)", oid_to_string(oid), ret,
+ le32_to_cpu(u.get_c->status));
+
if (ret == 0) {
ret = le32_to_cpu(u.get_c->len);
*len = (*len > ret) ? ret : *len;
memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len);
ret = rndis_error_status(u.get_c->status);
+
+ if (ret < 0)
+ devdbg(dev, "rndis_query_oid(%s): device returned "
+ "error, 0x%08x (%d)", oid_to_string(oid),
+ le32_to_cpu(u.get_c->status), ret);
}
mutex_unlock(&priv->command_lock);
@@ -583,9 +654,20 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len)
memcpy(u.buf + sizeof(*u.set), data, len);
ret = rndis_command(dev, u.header, buflen);
- if (ret == 0)
+ if (ret < 0)
+ devdbg(dev, "rndis_set_oid(%s): rndis_command() failed, %d "
+ "(%08x)", oid_to_string(oid), ret,
+ le32_to_cpu(u.set_c->status));
+
+ if (ret == 0) {
ret = rndis_error_status(u.set_c->status);
+ if (ret < 0)
+ devdbg(dev, "rndis_set_oid(%s): device returned error, "
+ "0x%08x (%d)", oid_to_string(oid),
+ le32_to_cpu(u.set_c->status), ret);
+ }
+
mutex_unlock(&priv->command_lock);
if (u.buf != priv->command_buffer)
^ permalink raw reply related
* [PATCH 07/10] rndis_host: allow rndis_wlan to see all indications
From: Jussi Kivilinna @ 2009-07-30 16:41 UTC (permalink / raw)
To: linux-wireless; +Cc: linville, Jussi Kivilinna, David Brownell
In-Reply-To: <20090730164120.28317.53313.stgit@fate.lan>
Allow rndis_wlan to see all indications. Currently rndis_host lets rndis_wlan to
know about link state changes only, but there is whole set of other
802.11-specific indications that rndis_wlan should handle properly. So rename
link_change() to indication() and convert rndis_wlan to use it.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
Cc: David Brownell <dbrownell@users.sourceforge.net>
---
drivers/net/usb/rndis_host.c | 50 +++++++++++++++++++++----------------
drivers/net/wireless/rndis_wlan.c | 31 +++++++++++++++++++----
include/linux/usb/usbnet.h | 5 +---
3 files changed, 56 insertions(+), 30 deletions(-)
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 2232232..d032bba 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -65,6 +65,32 @@ void rndis_status(struct usbnet *dev, struct urb *urb)
EXPORT_SYMBOL_GPL(rndis_status);
/*
+ * RNDIS indicate messages.
+ */
+static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg,
+ int buflen)
+{
+ struct cdc_state *info = (void *)&dev->data;
+ struct device *udev = &info->control->dev;
+
+ if (dev->driver_info->indication) {
+ dev->driver_info->indication(dev, msg, buflen);
+ } else {
+ switch (msg->status) {
+ case RNDIS_STATUS_MEDIA_CONNECT:
+ dev_info(udev, "rndis media connect\n");
+ break;
+ case RNDIS_STATUS_MEDIA_DISCONNECT:
+ dev_info(udev, "rndis media disconnect\n");
+ break;
+ default:
+ dev_info(udev, "rndis indication: 0x%08x\n",
+ le32_to_cpu(msg->status));
+ }
+ }
+}
+
+/*
* RPC done RNDIS-style. Caller guarantees:
* - message is properly byteswapped
* - there's no other request pending
@@ -143,27 +169,9 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen)
request_id, xid);
/* then likely retry */
} else switch (buf->msg_type) {
- case RNDIS_MSG_INDICATE: { /* fault/event */
- struct rndis_indicate *msg = (void *)buf;
- int state = 0;
-
- switch (msg->status) {
- case RNDIS_STATUS_MEDIA_CONNECT:
- state = 1;
- case RNDIS_STATUS_MEDIA_DISCONNECT:
- dev_info(&info->control->dev,
- "rndis media %sconnect\n",
- !state?"dis":"");
- if (dev->driver_info->link_change)
- dev->driver_info->link_change(
- dev, state);
- break;
- default:
- dev_info(&info->control->dev,
- "rndis indication: 0x%08x\n",
- le32_to_cpu(msg->status));
- }
- }
+ case RNDIS_MSG_INDICATE: /* fault/event */
+ rndis_msg_indicate(dev, (void *)buf, buflen);
+
break;
case RNDIS_MSG_KEEPALIVE: { /* ping */
struct rndis_keepalive_c *msg = (void *)buf;
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index f6dcbb1..6b6452b 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2211,13 +2211,32 @@ static void rndis_wlan_set_multicast_list(struct net_device *dev)
queue_work(priv->workqueue, &priv->work);
}
-static void rndis_wlan_link_change(struct usbnet *usbdev, int state)
+static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ struct rndis_indicate *msg = ind;
/* queue work to avoid recursive calls into rndis_command */
- set_bit(state ? WORK_LINK_UP : WORK_LINK_DOWN, &priv->work_pending);
- queue_work(priv->workqueue, &priv->work);
+ switch (msg->status) {
+ case RNDIS_STATUS_MEDIA_CONNECT:
+ devinfo(usbdev, "media connect");
+
+ set_bit(WORK_LINK_UP, &priv->work_pending);
+ queue_work(priv->workqueue, &priv->work);
+ break;
+
+ case RNDIS_STATUS_MEDIA_DISCONNECT:
+ devinfo(usbdev, "media disconnect");
+
+ set_bit(WORK_LINK_DOWN, &priv->work_pending);
+ queue_work(priv->workqueue, &priv->work);
+ break;
+
+ default:
+ devinfo(usbdev, "indication: 0x%08x",
+ le32_to_cpu(msg->status));
+ break;
+ }
}
@@ -2666,7 +2685,7 @@ static const struct driver_info bcm4320b_info = {
.reset = rndis_wlan_reset,
.stop = rndis_wlan_stop,
.early_init = bcm4320b_early_init,
- .link_change = rndis_wlan_link_change,
+ .indication = rndis_wlan_indication,
};
static const struct driver_info bcm4320a_info = {
@@ -2681,7 +2700,7 @@ static const struct driver_info bcm4320a_info = {
.reset = rndis_wlan_reset,
.stop = rndis_wlan_stop,
.early_init = bcm4320a_early_init,
- .link_change = rndis_wlan_link_change,
+ .indication = rndis_wlan_indication,
};
static const struct driver_info rndis_wlan_info = {
@@ -2696,7 +2715,7 @@ static const struct driver_info rndis_wlan_info = {
.reset = rndis_wlan_reset,
.stop = rndis_wlan_stop,
.early_init = bcm4320a_early_init,
- .link_change = rndis_wlan_link_change,
+ .indication = rndis_wlan_indication,
};
/*-------------------------------------------------------------------------*/
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index c642f78..de8b4b1 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -122,9 +122,8 @@ struct driver_info {
* right after minidriver have initialized hardware. */
int (*early_init)(struct usbnet *dev);
- /* called by minidriver when link state changes, state: 0=disconnect,
- * 1=connect */
- void (*link_change)(struct usbnet *dev, int state);
+ /* called by minidriver when receiving indication */
+ void (*indication)(struct usbnet *dev, void *ind, int indlen);
/* for new devices, use the descriptor-reading code instead */
int in; /* rx endpoint */
^ permalink raw reply related
* [PATCH 02/10] rndis_wlan: stop workers on rndis_wlan_stop() and restore on rndis_wlan_reset()
From: Jussi Kivilinna @ 2009-07-30 16:41 UTC (permalink / raw)
To: linux-wireless; +Cc: linville, Jussi Kivilinna
In-Reply-To: <20090730164120.28317.53313.stgit@fate.lan>
Driver doesn't need to poll statistics/link status when stopped.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
---
drivers/net/wireless/rndis_wlan.c | 23 +++++++++++++++++++----
1 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 76c5ec6..3c7c620 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2457,9 +2457,6 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
disassociate(usbdev, 1);
netif_carrier_off(usbdev->net);
- queue_delayed_work(priv->workqueue, &priv->stats_work,
- round_jiffies_relative(STATS_UPDATE_JIFFIES));
-
return 0;
fail:
@@ -2499,15 +2496,33 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf)
static int rndis_wlan_reset(struct usbnet *usbdev)
{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+
devdbg(usbdev, "rndis_wlan_reset");
+
+ queue_delayed_work(priv->workqueue, &priv->stats_work,
+ round_jiffies_relative(STATS_UPDATE_JIFFIES));
+
return deauthenticate(usbdev);
}
static int rndis_wlan_stop(struct usbnet *usbdev)
{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ int retval;
+
devdbg(usbdev, "rndis_wlan_stop");
- return disassociate(usbdev, 0);
+
+ retval = disassociate(usbdev, 0);
+
+ priv->work_pending = 0;
+ cancel_delayed_work_sync(&priv->stats_work);
+ cancel_delayed_work_sync(&priv->scan_work);
+ cancel_work_sync(&priv->work);
+ flush_workqueue(priv->workqueue);
+
+ return retval;
}
^ permalink raw reply related
* [PATCH 04/10] rndis_wlan: reset device and restore multicast list on rndis_wlan_reset()
From: Jussi Kivilinna @ 2009-07-30 16:41 UTC (permalink / raw)
To: linux-wireless; +Cc: linville, Jussi Kivilinna
In-Reply-To: <20090730164120.28317.53313.stgit@fate.lan>
Reset device properly with RNDIS_MSG_RESET in rndis_wlan_reset() and restore
multicast list afterwards.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
---
drivers/net/wireless/rndis_wlan.c | 30 ++++++++++++++++++++++++++++++
1 files changed, 30 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index dee0551..bfb9861 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -594,6 +594,28 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len)
}
+static int rndis_reset(struct usbnet *usbdev)
+{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ struct rndis_reset *reset;
+ int ret;
+
+ mutex_lock(&priv->command_lock);
+
+ reset = (void *)priv->command_buffer;
+ memset(reset, 0, sizeof(*reset));
+ reset->msg_type = RNDIS_MSG_RESET;
+ reset->msg_len = cpu_to_le32(sizeof(*reset));
+ ret = rndis_command(usbdev, (void *)reset, CONTROL_BUFFER_SIZE);
+
+ mutex_unlock(&priv->command_lock);
+
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+
/*
* Specs say that we can only set config parameters only soon after device
* initialization.
@@ -2500,9 +2522,17 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf)
static int rndis_wlan_reset(struct usbnet *usbdev)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ int retval;
devdbg(usbdev, "rndis_wlan_reset");
+ retval = rndis_reset(usbdev);
+ if (retval)
+ devwarn(usbdev, "rndis_reset() failed: %d", retval);
+
+ /* rndis_reset cleared multicast list, so restore here. */
+ set_multicast_list(usbdev);
+
queue_delayed_work(priv->workqueue, &priv->stats_work,
round_jiffies_relative(STATS_UPDATE_JIFFIES));
^ permalink raw reply related
* [PATCH 03/10] rndis_wlan: clear cfg80211 scan on rndis_wlan_stop()
From: Jussi Kivilinna @ 2009-07-30 16:41 UTC (permalink / raw)
To: linux-wireless; +Cc: linville, Jussi Kivilinna
In-Reply-To: <20090730164120.28317.53313.stgit@fate.lan>
Scanning gets stuck if device is stopped when scan is active. Fix by
clearing/aborting cfg80211 scan on rndis_wlan_stop().
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
---
drivers/net/wireless/rndis_wlan.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 3c7c620..dee0551 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -1484,6 +1484,9 @@ static void rndis_get_scan_results(struct work_struct *work)
devdbg(usbdev, "get_scan_results");
+ if (!priv->scan_request)
+ return;
+
ret = rndis_check_bssid_list(usbdev);
cfg80211_scan_done(priv->scan_request, ret < 0);
@@ -2522,6 +2525,11 @@ static int rndis_wlan_stop(struct usbnet *usbdev)
cancel_work_sync(&priv->work);
flush_workqueue(priv->workqueue);
+ if (priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, true);
+ priv->scan_request = NULL;
+ }
+
return retval;
}
^ permalink raw reply related
* [PATCH 01/10] usbnet: allow "minidriver" to prevent urb unlinking on usbnet_stop
From: Jussi Kivilinna @ 2009-07-30 16:41 UTC (permalink / raw)
To: linux-wireless; +Cc: linville, Jussi Kivilinna, David Brownell
rndis_wlan devices freeze after running usbnet_stop several times. It appears
that firmware freezes in state where it does not respond to any RNDIS commands
and device have to be physically unplugged/replugged. This patch lets
minidrivers to disable unlink_urbs on usbnet_stop through new info flag.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
Cc: David Brownell <dbrownell@users.sourceforge.net>
---
drivers/net/usb/usbnet.c | 32 ++++++++++++++++++--------------
drivers/net/wireless/rndis_wlan.c | 9 ++++++---
include/linux/usb/usbnet.h | 1 +
3 files changed, 25 insertions(+), 17 deletions(-)
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 25e435c..af1fe46 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -601,21 +601,25 @@ int usbnet_stop (struct net_device *net)
info->description);
}
- // ensure there are no more active urbs
- add_wait_queue (&unlink_wakeup, &wait);
- dev->wait = &unlink_wakeup;
- temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq);
-
- // maybe wait for deletions to finish.
- while (!skb_queue_empty(&dev->rxq)
- && !skb_queue_empty(&dev->txq)
- && !skb_queue_empty(&dev->done)) {
- msleep(UNLINK_TIMEOUT_MS);
- if (netif_msg_ifdown (dev))
- devdbg (dev, "waited for %d urb completions", temp);
+ if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) {
+ /* ensure there are no more active urbs */
+ add_wait_queue(&unlink_wakeup, &wait);
+ dev->wait = &unlink_wakeup;
+ temp = unlink_urbs(dev, &dev->txq) +
+ unlink_urbs(dev, &dev->rxq);
+
+ /* maybe wait for deletions to finish. */
+ while (!skb_queue_empty(&dev->rxq)
+ && !skb_queue_empty(&dev->txq)
+ && !skb_queue_empty(&dev->done)) {
+ msleep(UNLINK_TIMEOUT_MS);
+ if (netif_msg_ifdown(dev))
+ devdbg(dev, "waited for %d urb completions",
+ temp);
+ }
+ dev->wait = NULL;
+ remove_wait_queue(&unlink_wakeup, &wait);
}
- dev->wait = NULL;
- remove_wait_queue (&unlink_wakeup, &wait);
usb_kill_urb(dev->interrupt);
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 09c0702..76c5ec6 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2513,7 +2513,8 @@ static int rndis_wlan_stop(struct usbnet *usbdev)
static const struct driver_info bcm4320b_info = {
.description = "Wireless RNDIS device, BCM4320b based",
- .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+ .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
+ FLAG_AVOID_UNLINK_URBS,
.bind = rndis_wlan_bind,
.unbind = rndis_wlan_unbind,
.status = rndis_status,
@@ -2527,7 +2528,8 @@ static const struct driver_info bcm4320b_info = {
static const struct driver_info bcm4320a_info = {
.description = "Wireless RNDIS device, BCM4320a based",
- .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+ .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
+ FLAG_AVOID_UNLINK_URBS,
.bind = rndis_wlan_bind,
.unbind = rndis_wlan_unbind,
.status = rndis_status,
@@ -2541,7 +2543,8 @@ static const struct driver_info bcm4320a_info = {
static const struct driver_info rndis_wlan_info = {
.description = "Wireless RNDIS device",
- .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+ .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
+ FLAG_AVOID_UNLINK_URBS,
.bind = rndis_wlan_bind,
.unbind = rndis_wlan_unbind,
.status = rndis_status,
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index 7c17b2e..c642f78 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -86,6 +86,7 @@ struct driver_info {
#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */
#define FLAG_WLAN 0x0080 /* use "wlan%d" names */
+#define FLAG_AVOID_UNLINK_URBS 0x0100 /* don't unlink urbs at usbnet_stop() */
/* init device ... can sleep, or cause probe() failure */
^ permalink raw reply related
* [PATCH 09/10] rndis_wlan: add missing padding to struct rndis_80211_remove_key
From: Jussi Kivilinna @ 2009-07-30 16:42 UTC (permalink / raw)
To: linux-wireless; +Cc: linville, Jussi Kivilinna
In-Reply-To: <20090730164120.28317.53313.stgit@fate.lan>
OID_802_11_REMOVE_KEY failed with invalid length error, add missing padding to
structure fix this.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
---
drivers/net/wireless/rndis_wlan.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 7a50cfa..3d92b77 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -327,6 +327,7 @@ struct ndis_80211_remove_key {
__le32 size;
__le32 index;
u8 bssid[6];
+ u8 padding[2];
} __attribute__((packed));
struct ndis_config_param {
^ permalink raw reply related
* [PATCH 08/10] rndis_wlan: handle 802.11 indications from device
From: Jussi Kivilinna @ 2009-07-30 16:41 UTC (permalink / raw)
To: linux-wireless; +Cc: linville, Jussi Kivilinna
In-Reply-To: <20090730164120.28317.53313.stgit@fate.lan>
Add handling for 802.11 specific rndis indications.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
---
drivers/net/wireless/rndis_wlan.c | 233 +++++++++++++++++++++++++++++++++++++
include/linux/usb/rndis_host.h | 13 +-
2 files changed, 239 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 6b6452b..7a50cfa 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -201,6 +201,24 @@ enum ndis_80211_priv_filter {
NDIS_80211_PRIV_8021X_WEP
};
+enum ndis_80211_status_type {
+ NDIS_80211_STATUSTYPE_AUTHENTICATION,
+ NDIS_80211_STATUSTYPE_MEDIASTREAMMODE,
+ NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST,
+ NDIS_80211_STATUSTYPE_RADIOSTATE,
+};
+
+enum ndis_80211_media_stream_mode {
+ NDIS_80211_MEDIA_STREAM_OFF,
+ NDIS_80211_MEDIA_STREAM_ON
+};
+
+enum ndis_80211_radio_status {
+ NDIS_80211_RADIO_STATUS_ON,
+ NDIS_80211_RADIO_STATUS_HARDWARE_OFF,
+ NDIS_80211_RADIO_STATUS_SOFTWARE_OFF,
+};
+
enum ndis_80211_addkey_bits {
NDIS_80211_ADDKEY_8021X_AUTH = cpu_to_le32(1 << 28),
NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ = cpu_to_le32(1 << 29),
@@ -213,6 +231,35 @@ enum ndis_80211_addwep_bits {
NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31)
};
+struct ndis_80211_auth_request {
+ __le32 length;
+ u8 bssid[6];
+ u8 padding[2];
+ __le32 flags;
+} __attribute__((packed));
+
+struct ndis_80211_pmkid_candidate {
+ u8 bssid[6];
+ u8 padding[2];
+ __le32 flags;
+} __attribute__((packed));
+
+struct ndis_80211_pmkid_cand_list {
+ __le32 version;
+ __le32 num_candidates;
+ struct ndis_80211_pmkid_candidate candidate_list[0];
+} __attribute__((packed));
+
+struct ndis_80211_status_indication {
+ __le32 status_type;
+ union {
+ enum ndis_80211_media_stream_mode media_stream_mode;
+ enum ndis_80211_radio_status radio_status;
+ struct ndis_80211_auth_request auth_request[0];
+ struct ndis_80211_pmkid_cand_list cand_list;
+ } u;
+} __attribute__((packed));
+
struct ndis_80211_ssid {
__le32 length;
u8 essid[NDIS_802_11_LENGTH_SSID];
@@ -2211,16 +2258,195 @@ static void rndis_wlan_set_multicast_list(struct net_device *dev)
queue_work(priv->workqueue, &priv->work);
}
+
+static void rndis_wlan_auth_indication(struct usbnet *usbdev,
+ struct ndis_80211_status_indication *indication,
+ int len)
+{
+ u8 *buf;
+ const char *type;
+ int flags, buflen;
+ bool pairwise_error, group_error;
+ struct ndis_80211_auth_request *auth_req;
+
+ /* must have at least one array entry */
+ if (len < offsetof(struct ndis_80211_status_indication, u) +
+ sizeof(struct ndis_80211_auth_request)) {
+ devinfo(usbdev, "authentication indication: "
+ "too short message (%i)", len);
+ return;
+ }
+
+ buf = (void *)&indication->u.auth_request[0];
+ buflen = len - offsetof(struct ndis_80211_status_indication, u);
+
+ while (buflen >= sizeof(*auth_req)) {
+ auth_req = (void *)buf;
+ type = "unknown";
+ flags = le32_to_cpu(auth_req->flags);
+ pairwise_error = false;
+ group_error = false;
+
+ if (flags & 0x1)
+ type = "reauth request";
+ if (flags & 0x2)
+ type = "key update request";
+ if (flags & 0x6) {
+ pairwise_error = true;
+ type = "pairwise_error";
+ }
+ if (flags & 0xe) {
+ group_error = true;
+ type = "group_error";
+ }
+
+ devinfo(usbdev, "authentication indication: %s (0x%08x)", type,
+ le32_to_cpu(auth_req->flags));
+
+ if (pairwise_error || group_error) {
+ union iwreq_data wrqu;
+ struct iw_michaelmicfailure micfailure;
+
+ memset(&micfailure, 0, sizeof(micfailure));
+ if (pairwise_error)
+ micfailure.flags |= IW_MICFAILURE_PAIRWISE;
+ if (group_error)
+ micfailure.flags |= IW_MICFAILURE_GROUP;
+
+ memcpy(micfailure.src_addr.sa_data, auth_req->bssid,
+ ETH_ALEN);
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = sizeof(micfailure);
+ wireless_send_event(usbdev->net, IWEVMICHAELMICFAILURE,
+ &wrqu, (u8 *)&micfailure);
+ }
+
+ buflen -= le32_to_cpu(auth_req->length);
+ buf += le32_to_cpu(auth_req->length);
+ }
+}
+
+static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev,
+ struct ndis_80211_status_indication *indication,
+ int len)
+{
+ struct ndis_80211_pmkid_cand_list *cand_list;
+ int list_len, expected_len, i;
+
+ if (len < offsetof(struct ndis_80211_status_indication, u) +
+ sizeof(struct ndis_80211_pmkid_cand_list)) {
+ devinfo(usbdev, "pmkid candidate list indication: "
+ "too short message (%i)", len);
+ return;
+ }
+
+ list_len = le32_to_cpu(indication->u.cand_list.num_candidates) *
+ sizeof(struct ndis_80211_pmkid_candidate);
+ expected_len = sizeof(struct ndis_80211_pmkid_cand_list) + list_len +
+ offsetof(struct ndis_80211_status_indication, u);
+
+ if (len < expected_len) {
+ devinfo(usbdev, "pmkid candidate list indication: "
+ "list larger than buffer (%i < %i)",
+ len, expected_len);
+ return;
+ }
+
+ cand_list = &indication->u.cand_list;
+
+ devinfo(usbdev, "pmkid candidate list indication: "
+ "version %i, candidates %i",
+ le32_to_cpu(cand_list->version),
+ le32_to_cpu(cand_list->num_candidates));
+
+ if (le32_to_cpu(cand_list->version) != 1)
+ return;
+
+ for (i = 0; i < le32_to_cpu(cand_list->num_candidates); i++) {
+ struct iw_pmkid_cand pcand;
+ union iwreq_data wrqu;
+ struct ndis_80211_pmkid_candidate *cand =
+ &cand_list->candidate_list[i];
+
+ devdbg(usbdev, "cand[%i]: flags: 0x%08x, bssid: %pM",
+ i, le32_to_cpu(cand->flags), cand->bssid);
+
+ memset(&pcand, 0, sizeof(pcand));
+ if (le32_to_cpu(cand->flags) & 0x01)
+ pcand.flags |= IW_PMKID_CAND_PREAUTH;
+ pcand.index = i;
+ memcpy(pcand.bssid.sa_data, cand->bssid, ETH_ALEN);
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = sizeof(pcand);
+ wireless_send_event(usbdev->net, IWEVPMKIDCAND, &wrqu,
+ (u8 *)&pcand);
+ }
+}
+
+static void rndis_wlan_media_specific_indication(struct usbnet *usbdev,
+ struct rndis_indicate *msg, int buflen)
+{
+ struct ndis_80211_status_indication *indication;
+ int len, offset;
+
+ offset = offsetof(struct rndis_indicate, status) +
+ le32_to_cpu(msg->offset);
+ len = le32_to_cpu(msg->length);
+
+ if (len < 8) {
+ devinfo(usbdev, "media specific indication, "
+ "ignore too short message (%i < 8)", len);
+ return;
+ }
+
+ if (offset + len > buflen) {
+ devinfo(usbdev, "media specific indication, "
+ "too large to fit to buffer (%i > %i)",
+ offset + len, buflen);
+ return;
+ }
+
+ indication = (void *)((u8 *)msg + offset);
+
+ switch (le32_to_cpu(indication->status_type)) {
+ case NDIS_80211_STATUSTYPE_RADIOSTATE:
+ devinfo(usbdev, "radio state indication: %i",
+ le32_to_cpu(indication->u.radio_status));
+ return;
+
+ case NDIS_80211_STATUSTYPE_MEDIASTREAMMODE:
+ devinfo(usbdev, "media stream mode indication: %i",
+ le32_to_cpu(indication->u.media_stream_mode));
+ return;
+
+ case NDIS_80211_STATUSTYPE_AUTHENTICATION:
+ rndis_wlan_auth_indication(usbdev, indication, len);
+ return;
+
+ case NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST:
+ rndis_wlan_pmkid_cand_list_indication(usbdev, indication, len);
+ return;
+
+ default:
+ devinfo(usbdev, "media specific indication: "
+ "unknown status type 0x%08x",
+ le32_to_cpu(indication->status_type));
+ }
+}
+
+
static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
struct rndis_indicate *msg = ind;
- /* queue work to avoid recursive calls into rndis_command */
switch (msg->status) {
case RNDIS_STATUS_MEDIA_CONNECT:
devinfo(usbdev, "media connect");
+ /* queue work to avoid recursive calls into rndis_command */
set_bit(WORK_LINK_UP, &priv->work_pending);
queue_work(priv->workqueue, &priv->work);
break;
@@ -2228,10 +2454,15 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen)
case RNDIS_STATUS_MEDIA_DISCONNECT:
devinfo(usbdev, "media disconnect");
+ /* queue work to avoid recursive calls into rndis_command */
set_bit(WORK_LINK_DOWN, &priv->work_pending);
queue_work(priv->workqueue, &priv->work);
break;
+ case RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION:
+ rndis_wlan_media_specific_indication(usbdev, msg, buflen);
+ break;
+
default:
devinfo(usbdev, "indication: 0x%08x",
le32_to_cpu(msg->status));
diff --git a/include/linux/usb/rndis_host.h b/include/linux/usb/rndis_host.h
index 37836b9..1ef1ebc 100644
--- a/include/linux/usb/rndis_host.h
+++ b/include/linux/usb/rndis_host.h
@@ -70,12 +70,13 @@ struct rndis_msg_hdr {
#define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION)
/* codes for "status" field of completion messages */
-#define RNDIS_STATUS_SUCCESS cpu_to_le32(0x00000000)
-#define RNDIS_STATUS_FAILURE cpu_to_le32(0xc0000001)
-#define RNDIS_STATUS_INVALID_DATA cpu_to_le32(0xc0010015)
-#define RNDIS_STATUS_NOT_SUPPORTED cpu_to_le32(0xc00000bb)
-#define RNDIS_STATUS_MEDIA_CONNECT cpu_to_le32(0x4001000b)
-#define RNDIS_STATUS_MEDIA_DISCONNECT cpu_to_le32(0x4001000c)
+#define RNDIS_STATUS_SUCCESS cpu_to_le32(0x00000000)
+#define RNDIS_STATUS_FAILURE cpu_to_le32(0xc0000001)
+#define RNDIS_STATUS_INVALID_DATA cpu_to_le32(0xc0010015)
+#define RNDIS_STATUS_NOT_SUPPORTED cpu_to_le32(0xc00000bb)
+#define RNDIS_STATUS_MEDIA_CONNECT cpu_to_le32(0x4001000b)
+#define RNDIS_STATUS_MEDIA_DISCONNECT cpu_to_le32(0x4001000c)
+#define RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION cpu_to_le32(0x40010012)
/* codes for OID_GEN_PHYSICAL_MEDIUM */
#define RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED cpu_to_le32(0x00000000)
^ permalink raw reply related
* Re: Ath5k/mac80211 triggers WARN_ON in kernel/softirq.c
From: Bob Copeland @ 2009-07-30 16:08 UTC (permalink / raw)
To: Michael Buesch
Cc: Johannes Berg, jirislaby, mickflemm, lrodriguez, wireless,
John Linville
In-Reply-To: <200907301752.23855.mb@bu3sch.de>
On Thu, Jul 30, 2009 at 11:52 AM, Michael Buesch<mb@bu3sch.de> wrote:
>> John, can you revert the BH patch ("mac80211: do not use irq locks where
>> not necessary") and I'll send a new one with those changes removed?
>
> I didn't look at the code, but can't we simply request the beacon from
> mac80211 before locking? Or isn't the spin_lock_irqsave() done in the driver?
>
We could drop the lock around it, but it'd be nice to keep the option
open here. For example, some people want to move the beacon tasklet
into the hard IRQ - in that case the driver would have to jump through
a lot of hoops to refresh the beacon.
--
Bob Copeland %% www.bobcopeland.com
^ permalink raw reply
* Re: Ath5k/mac80211 triggers WARN_ON in kernel/softirq.c
From: Michael Buesch @ 2009-07-30 15:52 UTC (permalink / raw)
To: Johannes Berg
Cc: Bob Copeland, jirislaby, mickflemm, lrodriguez, wireless,
John Linville
In-Reply-To: <1248968229.16129.9.camel@johannes.local>
On Thursday 30 July 2009 17:37:09 Johannes Berg wrote:
> On Thu, 2009-07-30 at 10:45 -0400, Bob Copeland wrote:
> > On Thu, Jul 30, 2009 at 10:31 AM, Michael Buesch<mb@bu3sch.de> wrote:
> > > Ath5k from today's compat-wireless triggers the following WARNing
> > > on hostapd startup.
> > > [ 1669.799870] ------------[ cut here ]------------
> > > [ 1669.799934] WARNING: at kernel/softirq.c:141 local_bh_enable_ip+0x8b/0xb0()
> >
> > because ath5k calls ieee80211_beacon_get inside a spin_lock_irqsave()
> > and this is WARN_ON_ONCE(in_irq() || irqs_disabled).
>
> > > [ 1669.800493] [<ffffffff807e0fef>] _spin_unlock_bh+0xf/0x20
> > > [ 1669.800564] [<ffffffffa0040b92>] ieee80211_beacon_get+0x2c2/0x2d0 [mac80211]
> >
> > I guess this is the first victim of spin_lock_bh conversion?
>
> Indeed. I think this means we need to convert the local->sta_lock back
> to _irqsave/restore.
>
> John, can you revert the BH patch ("mac80211: do not use irq locks where
> not necessary") and I'll send a new one with those changes removed?
I didn't look at the code, but can't we simply request the beacon from
mac80211 before locking? Or isn't the spin_lock_irqsave() done in the driver?
--
Greetings, Michael.
^ permalink raw reply
* Re: [RFT] cfg80211: enable country IE support to all cfg80211 drivers
From: Luis R. Rodriguez @ 2009-07-30 15:42 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1248940662.8925.6.camel@johannes.local>
On Thu, Jul 30, 2009 at 12:57 AM, Johannes
Berg<johannes@sipsolutions.net> wrote:
> On Wed, 2009-07-29 at 18:01 -0700, Luis R. Rodriguez wrote:
>> Since the bss is always set now once we are connected, if the
>> bss has its own information element we refer to it and pass that
>> instead of relying on mac80211's parsing.
>>
>> Now all cfg80211 drivers get country IE support, automatically.
>>
>> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
>> ---
>>
>> Johill, I think this is what you wanted in the end, I tested it and
>> I get no country IE hint going through :( I could debug further but I'm
>> done for now and gotta work on some other stuff, not sure when I can
>> get back to this.
>
> Well, you've made a critical mistake:
>
> + regulatory_hint_11d(wdev->wiphy,
> + bss->information_elements,
> + bss->len_information_elements);
>
> needs to be
>
> const u8 *country_ie
>
> country_ie = ieee80211_bss_get_ie(&bss->pub, WLAN_EID_COUNTRY);
> if (country_ie)
> regulatory_hint_11d(wdev->wiphy,
> country_ie + 2,
> country_ie[1]);
>
>
> It's rather likely that it doesn't come first, so whatever is in
> information_elements first would end up not looking like a country IE or
> having the right length, so the _11d function would just throw it out.
Hah, thanks, will try it.
Luis
^ permalink raw reply
* Re: The problem of driver of rtl8187 wireless card
From: Hin-Tak Leung @ 2009-07-30 15:40 UTC (permalink / raw)
To: gu gu; +Cc: linux-wireless
In-Reply-To: <939177.72004.qm@web15806.mail.cnb.yahoo.com>
2009/7/30 gu gu <guatsheng@yahoo.com.cn>:
> Hi!
> Thank you for your reply.
> Because I have an ARM board which run linux -v2.6.25.10,so I have to use "compat-wireless-2.6-old.tar.bz2" packet to generate the "rtl8187.ko" .But the real problem is that I can't make it to get "rtl8187.ko"(modules).And you say need other modules, So which modules I needed?And how can I do?
> The directory "compat-wireless-2.6-old/drivers/net/wireless" has no
> driver of rtl8187,So I send the compiled packet for you in Accessory.I think something wrong in it ,I just set the values of KLIB & KLIB_BUILD in Makefile.How do that?
>
> Could you tell me how to resolve it ,thank you!Looking forward
> from you .
Hmm, you only have 18 modules, not the 50+ it should be. You also
make a mistake with your editing of the Makefile. (I think it is
common ettique to check for problems from self-inflicted issues like
that). I think compat-wireless won't build any modules your tree have
them built-in (because if you can't unload the old one, there is no
point building new), so you *must* set your KBUILD/KLIB correctly, if
you choose to edit the makefile by hand. if you read the Makefile (as
you should, since you edited it), it mostly just do
$(MAKE) -C $(KLIB_BUILD) M=$(PWD) modules
recursively down the directory. You could do "make -C <someplace>
M=<here> rtl8187.ko" inside drivers/net/wireless/ and see if a
rtl8187.ko .
but first, correct your editing of the Makefile.
^ permalink raw reply
* Re: Ath5k/mac80211 triggers WARN_ON in kernel/softirq.c
From: Johannes Berg @ 2009-07-30 15:37 UTC (permalink / raw)
To: Bob Copeland
Cc: Michael Buesch, jirislaby, mickflemm, lrodriguez, wireless,
John Linville
In-Reply-To: <b6c5339f0907300745l3e7ec63eu9819503c4e7766bb@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 975 bytes --]
On Thu, 2009-07-30 at 10:45 -0400, Bob Copeland wrote:
> On Thu, Jul 30, 2009 at 10:31 AM, Michael Buesch<mb@bu3sch.de> wrote:
> > Ath5k from today's compat-wireless triggers the following WARNing
> > on hostapd startup.
> > [ 1669.799870] ------------[ cut here ]------------
> > [ 1669.799934] WARNING: at kernel/softirq.c:141 local_bh_enable_ip+0x8b/0xb0()
>
> because ath5k calls ieee80211_beacon_get inside a spin_lock_irqsave()
> and this is WARN_ON_ONCE(in_irq() || irqs_disabled).
> > [ 1669.800493] [<ffffffff807e0fef>] _spin_unlock_bh+0xf/0x20
> > [ 1669.800564] [<ffffffffa0040b92>] ieee80211_beacon_get+0x2c2/0x2d0 [mac80211]
>
> I guess this is the first victim of spin_lock_bh conversion?
Indeed. I think this means we need to convert the local->sta_lock back
to _irqsave/restore.
John, can you revert the BH patch ("mac80211: do not use irq locks where
not necessary") and I'll send a new one with those changes removed?
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox