* [PATCH 1/2] Revert "rndis_wlan: wait association to complete"
@ 2009-08-11 14:52 Jussi Kivilinna
2009-08-11 14:52 ` [PATCH 2/2] usbnet: add rx queue pausing Jussi Kivilinna
0 siblings, 1 reply; 5+ messages in thread
From: Jussi Kivilinna @ 2009-08-11 14:52 UTC (permalink / raw)
To: linux-wireless; +Cc: linville, Jussi Kivilinna
"rndis_wlan: wait association to complete" would block SIOCSIWESSID
to fix broken WPA associations. This is wrong way of fixing the
problem, so revert this one.
This reverts commit 1f717679fe4e2c804bab964b60bb01c69ef015c7.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
---
drivers/net/wireless/rndis_wlan.c | 47 ++++---------------------------------
1 files changed, 5 insertions(+), 42 deletions(-)
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index f2e7505..828dc18 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -378,7 +378,6 @@ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
#define WORK_LINK_UP (1<<0)
#define WORK_LINK_DOWN (1<<1)
#define WORK_SET_MULTICAST_LIST (1<<2)
-#define WORK_ASSOC_WAIT (1<<3)
#define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set))
@@ -437,7 +436,6 @@ struct rndis_wlan_private {
struct work_struct work;
struct mutex command_lock;
spinlock_t stats_lock;
- struct completion assoc_wait;
unsigned long work_pending;
struct ieee80211_supported_band band;
@@ -938,9 +936,7 @@ static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
}
-#define ASSOC_TIMEOUT_JIFFIES (HZ*10)
-static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid,
- bool wait)
+static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
int ret;
@@ -952,21 +948,6 @@ static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid,
devdbg(usbdev, "set_essid: radio_on = 1");
}
- if (!wait)
- return ret;
-
- /* If we return now, userspace would get association events too late
- * (after receiving first packets from access point). This causes
- * WPA authentication to fail.
- */
- set_bit(WORK_ASSOC_WAIT, &priv->work_pending);
- queue_work(priv->workqueue, &priv->work);
-
- wait_for_completion_interruptible_timeout(&priv->assoc_wait,
- ASSOC_TIMEOUT_JIFFIES);
-
- clear_bit(WORK_ASSOC_WAIT, &priv->work_pending);
-
return ret;
}
@@ -1028,7 +1009,7 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid)
ssid.essid[1] = 0xff;
for (i = 2; i < sizeof(ssid.essid); i++)
ssid.essid[i] = 0x1 + (ssid.essid[i] * 0xfe / 0xff);
- ret = set_essid(usbdev, &ssid, false);
+ ret = set_essid(usbdev, &ssid);
}
return ret;
}
@@ -1784,7 +1765,7 @@ static int rndis_iw_set_essid(struct net_device *dev,
if (!wrqu->essid.flags || length == 0)
return disassociate(usbdev, 1);
else
- return set_essid(usbdev, &ssid, true);
+ return set_essid(usbdev, &ssid);
}
@@ -2025,7 +2006,7 @@ static int rndis_iw_set_encode(struct net_device *dev,
if (index == priv->encr_tx_key_index)
/* ndis drivers want essid to be set after setting encr */
- set_essid(usbdev, &priv->essid, false);
+ set_essid(usbdev, &priv->essid);
return 0;
}
@@ -2307,20 +2288,7 @@ static void rndis_wlan_worker(struct work_struct *work)
unsigned char bssid[ETH_ALEN];
struct ndis_80211_assoc_info *info;
int assoc_size = sizeof(*info) + IW_CUSTOM_MAX + 32;
- int ret, offset, len;
- __le32 tmp = 0;
-
- if (test_bit(WORK_ASSOC_WAIT, &priv->work_pending)) {
- /* dummy OID to poll device */
- len = sizeof(tmp);
- rndis_query_oid(usbdev, OID_GEN_XMIT_ERROR, &tmp, &len);
-
- /* requeue work if no link up response from device */
- if (!test_bit(WORK_LINK_UP, &priv->work_pending)) {
- msleep(10);
- queue_work(priv->workqueue, &priv->work);
- }
- }
+ int ret, offset;
if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending)) {
netif_carrier_on(usbdev->net);
@@ -2360,8 +2328,6 @@ get_bssid:
memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN);
wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL);
}
-
- complete_all(&priv->assoc_wait);
}
if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) {
@@ -2864,7 +2830,6 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
mutex_init(&priv->command_lock);
spin_lock_init(&priv->stats_lock);
- init_completion(&priv->assoc_wait);
/* because rndis_command() sleeps we need to use workqueue */
priv->workqueue = create_singlethread_workqueue("rndis_wlan");
@@ -2967,7 +2932,6 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf)
/* turn radio off */
disassociate(usbdev, 0);
- complete_all(&priv->assoc_wait);
cancel_delayed_work_sync(&priv->stats_work);
cancel_delayed_work_sync(&priv->scan_work);
cancel_work_sync(&priv->work);
@@ -3017,7 +2981,6 @@ static int rndis_wlan_stop(struct usbnet *usbdev)
retval = disassociate(usbdev, 0);
priv->work_pending = 0;
- complete_all(&priv->assoc_wait);
cancel_delayed_work_sync(&priv->stats_work);
cancel_delayed_work_sync(&priv->scan_work);
cancel_work_sync(&priv->work);
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] usbnet: add rx queue pausing
2009-08-11 14:52 [PATCH 1/2] Revert "rndis_wlan: wait association to complete" Jussi Kivilinna
@ 2009-08-11 14:52 ` Jussi Kivilinna
2009-08-11 14:57 ` Johannes Berg
2009-08-11 14:58 ` Johannes Berg
0 siblings, 2 replies; 5+ messages in thread
From: Jussi Kivilinna @ 2009-08-11 14:52 UTC (permalink / raw)
To: linux-wireless; +Cc: linville, David Brownell, Jussi Kivilinna
Add rx queue pausing to usbnet. This is needed by rndis_wlan so that it can
control rx queue and prevent received packets from being send forward before
rndis_wlan receives and handles 'media connect'-indication. Without this
establishing WPA connections is hard and fail often.
Cc: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
---
drivers/net/usb/usbnet.c | 52 ++++++++++++++++++++++++++++++++++++-
drivers/net/wireless/rndis_wlan.c | 13 +++++++++
include/linux/usb/usbnet.h | 6 ++++
3 files changed, 69 insertions(+), 2 deletions(-)
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index af1fe46..06cf18a 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -233,6 +233,19 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
{
int status;
+ if (test_bit(EVENT_RX_PAUSED, &dev->flags)) {
+ struct sk_buff *skb2;
+
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (unlikely(!skb2))
+ return;
+
+ skb_queue_tail(&dev->rxq_pause, skb2);
+ kfree_skb(skb);
+
+ return;
+ }
+
skb->protocol = eth_type_trans (skb, dev->net);
dev->net->stats.rx_packets++;
dev->net->stats.rx_bytes += skb->len;
@@ -526,6 +539,41 @@ static void intr_complete (struct urb *urb)
}
/*-------------------------------------------------------------------------*/
+void usbnet_pause_rx(struct usbnet *dev)
+{
+ set_bit(EVENT_RX_PAUSED, &dev->flags);
+
+ if (netif_msg_rx_status(dev))
+ devdbg(dev, "paused rx queue enabled");
+}
+EXPORT_SYMBOL_GPL(usbnet_pause_rx);
+
+void usbnet_resume_rx(struct usbnet *dev)
+{
+ struct sk_buff *skb;
+ int num = 0;
+
+ clear_bit(EVENT_RX_PAUSED, &dev->flags);
+
+ while ((skb = skb_dequeue(&dev->rxq_pause)) != NULL) {
+ usbnet_skb_return(dev, skb);
+ num++;
+ }
+
+ tasklet_schedule(&dev->bh);
+
+ if (netif_msg_rx_status(dev))
+ devdbg(dev, "paused rx queue disabled, %d skbs requeued", num);
+}
+EXPORT_SYMBOL_GPL(usbnet_resume_rx);
+
+void usbnet_purge_paused_rxq(struct usbnet *dev)
+{
+ skb_queue_purge(&dev->rxq_pause);
+}
+EXPORT_SYMBOL_GPL(usbnet_purge_paused_rxq);
+
+/*-------------------------------------------------------------------------*/
// unlink pending rx/tx; completion handlers do all other cleanup
@@ -623,6 +671,8 @@ int usbnet_stop (struct net_device *net)
usb_kill_urb(dev->interrupt);
+ usbnet_purge_paused_rxq(dev);
+
/* deferred work (task, timer, softirq) must also stop.
* can't flush_scheduled_work() until we drop rtnl (later),
* else workers could deadlock; so make workers a NOP.
@@ -1113,7 +1163,6 @@ static void usbnet_bh (unsigned long param)
}
-\f
/*-------------------------------------------------------------------------
*
* USB Device Driver support
@@ -1210,6 +1259,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
skb_queue_head_init (&dev->rxq);
skb_queue_head_init (&dev->txq);
skb_queue_head_init (&dev->done);
+ skb_queue_head_init(&dev->rxq_pause);
dev->bh.func = usbnet_bh;
dev->bh.data = (unsigned long) dev;
INIT_WORK (&dev->kevent, kevent);
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 828dc18..d42692d 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -1764,8 +1764,15 @@ static int rndis_iw_set_essid(struct net_device *dev,
if (!wrqu->essid.flags || length == 0)
return disassociate(usbdev, 1);
- else
+ else {
+ /* Pause and purge rx queue, so we don't pass packets before
+ * 'media connect'-indication.
+ */
+ usbnet_pause_rx(usbdev);
+ usbnet_purge_paused_rxq(usbdev);
+
return set_essid(usbdev, &ssid);
+ }
}
@@ -2328,6 +2335,8 @@ get_bssid:
memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN);
wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL);
}
+
+ usbnet_resume_rx(usbdev);
}
if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) {
@@ -2541,6 +2550,8 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen)
switch (msg->status) {
case RNDIS_STATUS_MEDIA_CONNECT:
+ usbnet_pause_rx(usbdev);
+
devinfo(usbdev, "media connect");
/* queue work to avoid recursive calls into rndis_command */
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index de8b4b1..0951425 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -53,6 +53,7 @@ struct usbnet {
struct sk_buff_head rxq;
struct sk_buff_head txq;
struct sk_buff_head done;
+ struct sk_buff_head rxq_pause;
struct urb *interrupt;
struct tasklet_struct bh;
@@ -63,6 +64,7 @@ struct usbnet {
# define EVENT_RX_MEMORY 2
# define EVENT_STS_SPLIT 3
# define EVENT_LINK_RESET 4
+# define EVENT_RX_PAUSED 5
};
static inline struct usb_driver *driver_of(struct usb_interface *intf)
@@ -190,6 +192,10 @@ extern void usbnet_defer_kevent (struct usbnet *, int);
extern void usbnet_skb_return (struct usbnet *, struct sk_buff *);
extern void usbnet_unlink_rx_urbs(struct usbnet *);
+extern void usbnet_pause_rx(struct usbnet *);
+extern void usbnet_resume_rx(struct usbnet *);
+extern void usbnet_purge_paused_rxq(struct usbnet *);
+
extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd);
extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd);
extern u32 usbnet_get_link (struct net_device *net);
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] usbnet: add rx queue pausing
2009-08-11 14:52 ` [PATCH 2/2] usbnet: add rx queue pausing Jussi Kivilinna
@ 2009-08-11 14:57 ` Johannes Berg
2009-08-11 16:50 ` Jussi Kivilinna
2009-08-11 14:58 ` Johannes Berg
1 sibling, 1 reply; 5+ messages in thread
From: Johannes Berg @ 2009-08-11 14:57 UTC (permalink / raw)
To: Jussi Kivilinna; +Cc: linux-wireless, linville, David Brownell
[-- Attachment #1: Type: text/plain, Size: 353 bytes --]
On Tue, 2009-08-11 at 17:52 +0300, Jussi Kivilinna wrote:
> + if (test_bit(EVENT_RX_PAUSED, &dev->flags)) {
> + struct sk_buff *skb2;
> +
> + skb2 = skb_clone(skb, GFP_ATOMIC);
> + if (unlikely(!skb2))
> + return;
> +
> + skb_queue_tail(&dev->rxq_pause, skb2);
> + kfree_skb(skb);
Why clone and then free the original?
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] usbnet: add rx queue pausing
2009-08-11 14:52 ` [PATCH 2/2] usbnet: add rx queue pausing Jussi Kivilinna
2009-08-11 14:57 ` Johannes Berg
@ 2009-08-11 14:58 ` Johannes Berg
1 sibling, 0 replies; 5+ messages in thread
From: Johannes Berg @ 2009-08-11 14:58 UTC (permalink / raw)
To: Jussi Kivilinna; +Cc: linux-wireless, linville, David Brownell
[-- Attachment #1: Type: text/plain, Size: 275 bytes --]
On Tue, 2009-08-11 at 17:52 +0300, Jussi Kivilinna wrote:
> + if (test_bit(EVENT_RX_PAUSED, &dev->flags)) {
> + struct sk_buff *skb2;
> +
> + skb2 = skb_clone(skb, GFP_ATOMIC);
> + if (unlikely(!skb2))
> + return;
that leaks the original afaict.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] usbnet: add rx queue pausing
2009-08-11 14:57 ` Johannes Berg
@ 2009-08-11 16:50 ` Jussi Kivilinna
0 siblings, 0 replies; 5+ messages in thread
From: Jussi Kivilinna @ 2009-08-11 16:50 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, linville, David Brownell
Quoting "Johannes Berg" <johannes@sipsolutions.net>:
> On Tue, 2009-08-11 at 17:52 +0300, Jussi Kivilinna wrote:
>
>> + if (test_bit(EVENT_RX_PAUSED, &dev->flags)) {
>> + struct sk_buff *skb2;
>> +
>> + skb2 = skb_clone(skb, GFP_ATOMIC);
>> + if (unlikely(!skb2))
>> + return;
>> +
>> + skb_queue_tail(&dev->rxq_pause, skb2);
>> + kfree_skb(skb);
>
> Why clone and then free the original?
>
Ah, I had some problems and let this in. No reason, works fine without
cloning. I'll post v2 soon.
-Jussi
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2009-08-11 16:50 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-08-11 14:52 [PATCH 1/2] Revert "rndis_wlan: wait association to complete" Jussi Kivilinna
2009-08-11 14:52 ` [PATCH 2/2] usbnet: add rx queue pausing Jussi Kivilinna
2009-08-11 14:57 ` Johannes Berg
2009-08-11 16:50 ` Jussi Kivilinna
2009-08-11 14:58 ` Johannes Berg
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).