--- /dev/null
+From f36d83a8cb7224f45fdfa1129a616dff56479a09 Mon Sep 17 00:00:00 2001
+From: Larry Finger <Larry.Finger@lwfinger.net>
+Date: Sat, 13 Nov 2010 13:01:56 -0600
+Subject: staging: rtl8187se: Change panic to warn when RF switch turned off
+
+From: Larry Finger <Larry.Finger@lwfinger.net>
+
+commit f36d83a8cb7224f45fdfa1129a616dff56479a09 upstream.
+
+This driver issues a kernel panic over conditions that do not
+justify such drastic action. Change these to log entries with
+a stack dump.
+
+This patch fixes the system crash reported in
+https://bugs.launchpad.net/ubuntu/+source/linux/+bug/674285.
+
+Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
+Reported-and-Tested-by: Robie Basik <rb-oss-3@justgohome.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/rtl8187se/r8185b_init.c | 32 +++++++++++++++++++++++---------
+ 1 file changed, 23 insertions(+), 9 deletions(-)
+
+--- a/drivers/staging/rtl8187se/r8185b_init.c
++++ b/drivers/staging/rtl8187se/r8185b_init.c
+@@ -356,8 +356,12 @@ HwHSSIThreeWire(
+ }
+ udelay(10);
+ }
+- if (TryCnt == TC_3W_POLL_MAX_TRY_CNT)
+- panic("HwThreeWire(): CmdReg: %#X RE|WE bits are not clear!!\n", u1bTmp);
++ if (TryCnt == TC_3W_POLL_MAX_TRY_CNT) {
++ printk(KERN_ERR "rtl8187se: HwThreeWire(): CmdReg:"
++ " %#X RE|WE bits are not clear!!\n", u1bTmp);
++ dump_stack();
++ return 0;
++ }
+
+ // RTL8187S HSSI Read/Write Function
+ u1bTmp = read_nic_byte(dev, RF_SW_CONFIG);
+@@ -397,13 +401,23 @@ HwHSSIThreeWire(
+ int idx;
+ int ByteCnt = nDataBufBitCnt / 8;
+ //printk("%d\n",nDataBufBitCnt);
+- if ((nDataBufBitCnt % 8) != 0)
+- panic("HwThreeWire(): nDataBufBitCnt(%d) should be multiple of 8!!!\n",
+- nDataBufBitCnt);
+-
+- if (nDataBufBitCnt > 64)
+- panic("HwThreeWire(): nDataBufBitCnt(%d) should <= 64!!!\n",
+- nDataBufBitCnt);
++ if ((nDataBufBitCnt % 8) != 0) {
++ printk(KERN_ERR "rtl8187se: "
++ "HwThreeWire(): nDataBufBitCnt(%d)"
++ " should be multiple of 8!!!\n",
++ nDataBufBitCnt);
++ dump_stack();
++ nDataBufBitCnt += 8;
++ nDataBufBitCnt &= ~7;
++ }
++
++ if (nDataBufBitCnt > 64) {
++ printk(KERN_ERR "rtl8187se: HwThreeWire():"
++ " nDataBufBitCnt(%d) should <= 64!!!\n",
++ nDataBufBitCnt);
++ dump_stack();
++ nDataBufBitCnt = 64;
++ }
+
+ for(idx = 0; idx < ByteCnt; idx++)
+ {
--- /dev/null
+From 719f835853a92f6090258114a72ffe41f09155cd Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <eric.dumazet@gmail.com>
+Date: Wed, 8 Sep 2010 05:08:44 +0000
+Subject: udp: add rehash on connect()
+
+From: Eric Dumazet <eric.dumazet@gmail.com>
+
+commit 719f835853a92f6090258114a72ffe41f09155cd upstream.
+
+commit 30fff923 introduced in linux-2.6.33 (udp: bind() optimisation)
+added a secondary hash on UDP, hashed on (local addr, local port).
+
+Problem is that following sequence :
+
+fd = socket(...)
+connect(fd, &remote, ...)
+
+not only selects remote end point (address and port), but also sets
+local address, while UDP stack stored in secondary hash table the socket
+while its local address was INADDR_ANY (or ipv6 equivalent)
+
+Sequence is :
+ - autobind() : choose a random local port, insert socket in hash tables
+ [while local address is INADDR_ANY]
+ - connect() : set remote address and port, change local address to IP
+ given by a route lookup.
+
+When an incoming UDP frame comes, if more than 10 sockets are found in
+primary hash table, we switch to secondary table, and fail to find
+socket because its local address changed.
+
+One solution to this problem is to rehash datagram socket if needed.
+
+We add a new rehash(struct socket *) method in "struct proto", and
+implement this method for UDP v4 & v6, using a common helper.
+
+This rehashing only takes care of secondary hash table, since primary
+hash (based on local port only) is not changed.
+
+Reported-by: Krzysztof Piotr Oledzki <ole@ans.pl>
+Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
+Tested-by: Krzysztof Piotr Oledzki <ole@ans.pl>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/net/sock.h | 1 +
+ include/net/udp.h | 1 +
+ net/ipv4/datagram.c | 5 ++++-
+ net/ipv4/udp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
+ net/ipv6/datagram.c | 7 ++++++-
+ net/ipv6/udp.c | 10 ++++++++++
+ 6 files changed, 66 insertions(+), 2 deletions(-)
+
+--- a/include/net/sock.h
++++ b/include/net/sock.h
+@@ -681,6 +681,7 @@ struct proto {
+ /* Keeping track of sk's, looking them up, and port selection methods. */
+ void (*hash)(struct sock *sk);
+ void (*unhash)(struct sock *sk);
++ void (*rehash)(struct sock *sk);
+ int (*get_port)(struct sock *sk, unsigned short snum);
+
+ /* Keeping track of sockets in use */
+--- a/include/net/udp.h
++++ b/include/net/udp.h
+@@ -151,6 +151,7 @@ static inline void udp_lib_hash(struct s
+ }
+
+ extern void udp_lib_unhash(struct sock *sk);
++extern void udp_lib_rehash(struct sock *sk, u16 new_hash);
+
+ static inline void udp_lib_close(struct sock *sk, long timeout)
+ {
+--- a/net/ipv4/datagram.c
++++ b/net/ipv4/datagram.c
+@@ -62,8 +62,11 @@ int ip4_datagram_connect(struct sock *sk
+ }
+ if (!inet->inet_saddr)
+ inet->inet_saddr = rt->rt_src; /* Update source address */
+- if (!inet->inet_rcv_saddr)
++ if (!inet->inet_rcv_saddr) {
+ inet->inet_rcv_saddr = rt->rt_src;
++ if (sk->sk_prot->rehash)
++ sk->sk_prot->rehash(sk);
++ }
+ inet->inet_daddr = rt->rt_dst;
+ inet->inet_dport = usin->sin_port;
+ sk->sk_state = TCP_ESTABLISHED;
+--- a/net/ipv4/udp.c
++++ b/net/ipv4/udp.c
+@@ -1256,6 +1256,49 @@ void udp_lib_unhash(struct sock *sk)
+ }
+ EXPORT_SYMBOL(udp_lib_unhash);
+
++/*
++ * inet_rcv_saddr was changed, we must rehash secondary hash
++ */
++void udp_lib_rehash(struct sock *sk, u16 newhash)
++{
++ if (sk_hashed(sk)) {
++ struct udp_table *udptable = sk->sk_prot->h.udp_table;
++ struct udp_hslot *hslot, *hslot2, *nhslot2;
++
++ hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash);
++ nhslot2 = udp_hashslot2(udptable, newhash);
++ udp_sk(sk)->udp_portaddr_hash = newhash;
++ if (hslot2 != nhslot2) {
++ hslot = udp_hashslot(udptable, sock_net(sk),
++ udp_sk(sk)->udp_port_hash);
++ /* we must lock primary chain too */
++ spin_lock_bh(&hslot->lock);
++
++ spin_lock(&hslot2->lock);
++ hlist_nulls_del_init_rcu(&udp_sk(sk)->udp_portaddr_node);
++ hslot2->count--;
++ spin_unlock(&hslot2->lock);
++
++ spin_lock(&nhslot2->lock);
++ hlist_nulls_add_head_rcu(&udp_sk(sk)->udp_portaddr_node,
++ &nhslot2->head);
++ nhslot2->count++;
++ spin_unlock(&nhslot2->lock);
++
++ spin_unlock_bh(&hslot->lock);
++ }
++ }
++}
++EXPORT_SYMBOL(udp_lib_rehash);
++
++static void udp_v4_rehash(struct sock *sk)
++{
++ u16 new_hash = udp4_portaddr_hash(sock_net(sk),
++ inet_sk(sk)->inet_rcv_saddr,
++ inet_sk(sk)->inet_num);
++ udp_lib_rehash(sk, new_hash);
++}
++
+ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+ {
+ int rc = sock_queue_rcv_skb(sk, skb);
+@@ -1831,6 +1874,7 @@ struct proto udp_prot = {
+ .backlog_rcv = __udp_queue_rcv_skb,
+ .hash = udp_lib_hash,
+ .unhash = udp_lib_unhash,
++ .rehash = udp_v4_rehash,
+ .get_port = udp_v4_get_port,
+ .memory_allocated = &udp_memory_allocated,
+ .sysctl_mem = sysctl_udp_mem,
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -103,9 +103,12 @@ ipv4_connected:
+ if (ipv6_addr_any(&np->saddr))
+ ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);
+
+- if (ipv6_addr_any(&np->rcv_saddr))
++ if (ipv6_addr_any(&np->rcv_saddr)) {
+ ipv6_addr_set_v4mapped(inet->inet_rcv_saddr,
+ &np->rcv_saddr);
++ if (sk->sk_prot->rehash)
++ sk->sk_prot->rehash(sk);
++ }
+
+ goto out;
+ }
+@@ -190,6 +193,8 @@ ipv4_connected:
+ if (ipv6_addr_any(&np->rcv_saddr)) {
+ ipv6_addr_copy(&np->rcv_saddr, &fl.fl6_src);
+ inet->inet_rcv_saddr = LOOPBACK4_IPV6;
++ if (sk->sk_prot->rehash)
++ sk->sk_prot->rehash(sk);
+ }
+
+ ip6_dst_store(sk, dst,
+--- a/net/ipv6/udp.c
++++ b/net/ipv6/udp.c
+@@ -110,6 +110,15 @@ int udp_v6_get_port(struct sock *sk, uns
+ return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal, hash2_nulladdr);
+ }
+
++static void udp_v6_rehash(struct sock *sk)
++{
++ u16 new_hash = udp6_portaddr_hash(sock_net(sk),
++ &inet6_sk(sk)->rcv_saddr,
++ inet_sk(sk)->inet_num);
++
++ udp_lib_rehash(sk, new_hash);
++}
++
+ static inline int compute_score(struct sock *sk, struct net *net,
+ unsigned short hnum,
+ struct in6_addr *saddr, __be16 sport,
+@@ -1431,6 +1440,7 @@ struct proto udpv6_prot = {
+ .backlog_rcv = udpv6_queue_rcv_skb,
+ .hash = udp_lib_hash,
+ .unhash = udp_lib_unhash,
++ .rehash = udp_v6_rehash,
+ .get_port = udp_v6_get_port,
+ .memory_allocated = &udp_memory_allocated,
+ .sysctl_mem = sysctl_udp_mem,