* [patch net-2.6.25][IPV4][FIB] fix fib_proc compilation error
From: Daniel Lezcano @ 2008-01-25 13:30 UTC (permalink / raw)
To: David Miller, Linux Netdev List
[-- Attachment #1: Type: text/plain, Size: 1 bytes --]
[-- Attachment #2: fix-fib-frontend-compilation-error.patch --]
[-- Type: text/x-patch, Size: 848 bytes --]
Subject: fix fib_proc compilation error
From: Daniel Lezcano <dlezcano@fr.ibm.com>
Fix fib_proc_[init|exit] definition when CONFIG_PROCFS=no
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
---
include/net/ip_fib.h | 10 ++++++++++
1 file changed, 10 insertions(+)
Index: net-2.6.25-fix/include/net/ip_fib.h
===================================================================
--- net-2.6.25-fix.orig/include/net/ip_fib.h
+++ net-2.6.25-fix/include/net/ip_fib.h
@@ -264,6 +264,16 @@ static inline void fib_res_put(struct fi
#ifdef CONFIG_PROC_FS
extern int __net_init fib_proc_init(struct net *net);
extern void __net_exit fib_proc_exit(struct net *net);
+#else
+static inline int fib_proc_init(struct net *net)
+{
+ return 0;
+}
+
+static inline void fib_proc_exit(struct net *net)
+{
+ return ;
+}
#endif
#endif /* _NET_FIB_H */
^ permalink raw reply
* Re: Slow OOM in netif_RX function
From: Andi Kleen @ 2008-01-25 13:21 UTC (permalink / raw)
To: Ivan H. Dichev; +Cc: netdev
In-Reply-To: <20080124211810.3E24A46E9A@smtp.obs.bg>
"Ivan H. Dichev" <idichev@obs.bg> writes:
>
> What could happen if I put different Lan card in every slot?
> In ex. to-private -> 3com
> to-inet -> VIA
> to-dmz -> rtl8139
> And then to look which RX function is consuming the memory.
> (boomerang_rx, rtl8139_rx, ... etc)
The problem is unlikely to be in the driver (these are both
well tested ones) but more likely your complicated iptables setup somehow
triggers a skb leak.
There are unfortunately no shrink wrapped debug mechanisms in the kernel
for leaks like this (ok you could enable CONFIG_NETFILTER_DEBUG
and see if it prints something interesting, but that's a long shot).
If you wanted to write a custom debugging patch I would do something like this:
- Add two new integer fields to struct sk_buff: a time stamp and a integer field
- Fill the time stamp with jiffies in alloc_skb and clear the integer field
- In __kfree_skb clear the time stamp
- For all the ipt target modules in net/ipv4/netfilter/*.c you use change their
->target functions to put an unique value into the integer field you added.
- Do the same for the pkt_to_tuple functions for all conntrack modules
Then when you observe the leak take a crash dump using kdump on the router
and then use crash to dump all the slab objects for the sk_head_cache.
Then look for any that have an old time stamp and check what value they
have in the integer field. Then the netfilter function who set that unique value
likely triggered the leak somehow.
-Andi
^ permalink raw reply
* Re: [PATCH 00/14] RFC: Driver for Wireless RNDIS USB devices.
From: Jussi Kivilinna @ 2008-01-25 13:20 UTC (permalink / raw)
To: David Brownell; +Cc: linux-wireless, bjd, netdev
In-Reply-To: <200801241719.14941.david-b@pacbell.net>
On Thu, 2008-01-24 at 17:19 -0800, David Brownell wrote:
> > 13. [rndis_host] blacklist known wireless RNDIS devices
>
> That will be a headache over time though ... can't you just
> let the probe succeed enough to recogize it's wireless (using
> the media flag) and then bail, so the next driver can try?
Sure, that works too (but causes a little bit more message flood).
^ permalink raw reply
* Re: [Bugme-new] [Bug 9812] New: Kernel does not deliver packets going through the INPUT chain even if the app is listening on IN_ADDR_ANY
From: Patrick McHardy @ 2008-01-25 13:17 UTC (permalink / raw)
To: Andrew Morton; +Cc: netdev, bugme-daemon, pawel
In-Reply-To: <20080125051404.3bbefab3.akpm@linux-foundation.org>
Andrew Morton wrote:
>> On Fri, 25 Jan 2008 03:59:27 -0800 (PST) bugme-daemon@bugzilla.kernel.org wrote:
>> http://bugzilla.kernel.org/show_bug.cgi?id=9812
>>
>> Problem Description:
>>
>> I have a farm of web servers behind a load balancer in DSR mode.
>> I would like to be able to dump packets with any IP address on the web servers
>> through the load balancer and have web servers reply to these requests.
>> Currently for every IP web servers are supposed to reply to, I have to
>> configure the IP on all servers on their loopback interfaces. The web server
>> listens on IN_ADDR_ANY and I am forcing packets into the INPUT chain via
>> iptables/netfilter but the kernel never replies to any connection requests. I
>> only see the counter for OutNoRoutes increasing.
>>
>> Steps to reproduce:
>>
>> web server:
>>
>> #iptables -A PREROUTING -i eth0 -t mangle -p tcp --dport 80 -j MARK --set-mark
>> 1
>> #ip route add to local default dev lo protocol kernel table 1
>> #ip rule add fwmark 1 table 1 priority 1
>>
>> client:
>>
>> #ip route add 1.1.1.1/32 via <web server IP> dev eth0
>>
>> while making requests to 1.1.1.1:80 from the client you can see increasing
>> OutNoRoutes counter but no connection ever takes place.
I already commented in bugzilla, this is not a bug but an incorrect
setup. DNAT or REDIRECT must be used to make this work properly.
^ permalink raw reply
* Re: [PATCH 10/14] [rndis_host] Add rndis_early_init function pointer to 'struct rndis_data'.
From: Jussi Kivilinna @ 2008-01-25 13:14 UTC (permalink / raw)
To: David Brownell
Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, bjd-a1rhEgazXTw,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <200801241710.35528.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
On Thu, 2008-01-24 at 17:10 -0800, David Brownell wrote:
> Could this -- and #11/14 -- instead be generalized a bit,
> so they're not RNDIS-specific? At least in name; the
> only user for now would be the rndis_host code.
>
> The generalization would presumably be "early_init" and
> "link_change", paired with doc comments reflecting that
> they're usable by any driver stack built over the usbnet
> framework core.
>
> There's no point IMO to having generalizable hooks be
> restricted this way.
Sure.
^ permalink raw reply
* Re: [Bugme-new] [Bug 9812] New: Kernel does not deliver packets going through the INPUT chain even if the app is listening on IN_ADDR_ANY
From: Andrew Morton @ 2008-01-25 13:14 UTC (permalink / raw)
To: netdev; +Cc: bugme-daemon, pawel
In-Reply-To: <bug-9812-10286@http.bugzilla.kernel.org/>
> On Fri, 25 Jan 2008 03:59:27 -0800 (PST) bugme-daemon@bugzilla.kernel.org wrote:
> http://bugzilla.kernel.org/show_bug.cgi?id=9812
>
> Summary: Kernel does not deliver packets going through the INPUT
> chain even if the app is listening on IN_ADDR_ANY
> Product: Networking
> Version: 2.5
> KernelVersion: 2.6.22-14
> Platform: All
> OS/Version: Linux
> Tree: Mainline
> Status: NEW
> Severity: normal
> Priority: P1
> Component: Netfilter/Iptables
> AssignedTo: networking_netfilter-iptables@kernel-bugs.osdl.org
> ReportedBy: pawel@rogocz.com
>
>
> Latest working kernel version: never worked
> Earliest failing kernel version:
> Distribution: ubuntu 7.10
>
> Problem Description:
>
> I have a farm of web servers behind a load balancer in DSR mode.
> I would like to be able to dump packets with any IP address on the web servers
> through the load balancer and have web servers reply to these requests.
> Currently for every IP web servers are supposed to reply to, I have to
> configure the IP on all servers on their loopback interfaces. The web server
> listens on IN_ADDR_ANY and I am forcing packets into the INPUT chain via
> iptables/netfilter but the kernel never replies to any connection requests. I
> only see the counter for OutNoRoutes increasing.
>
> Steps to reproduce:
>
> web server:
>
> #iptables -A PREROUTING -i eth0 -t mangle -p tcp --dport 80 -j MARK --set-mark
> 1
> #ip route add to local default dev lo protocol kernel table 1
> #ip rule add fwmark 1 table 1 priority 1
>
> client:
>
> #ip route add 1.1.1.1/32 via <web server IP> dev eth0
>
> while making requests to 1.1.1.1:80 from the client you can see increasing
> OutNoRoutes counter but no connection ever takes place.
>
>
^ permalink raw reply
* Re: [Bugme-new] [Bug 9811] New: Loopback address to eth0 interface changes scope permanently
From: Andrew Morton @ 2008-01-25 10:50 UTC (permalink / raw)
To: netdev; +Cc: bugme-daemon, bjorn
In-Reply-To: <bug-9811-10286@http.bugzilla.kernel.org/>
> On Fri, 25 Jan 2008 02:04:04 -0800 (PST) bugme-daemon@bugzilla.kernel.org wrote:
> http://bugzilla.kernel.org/show_bug.cgi?id=9811
>
> Summary: Loopback address to eth0 interface changes scope
> permanently
> Product: Networking
> Version: 2.5
> KernelVersion: 2.6.24-rc8
> Platform: All
> OS/Version: Linux
> Tree: Mainline
> Status: NEW
> Severity: normal
> Priority: P1
> Component: IPV4
> AssignedTo: shemminger@linux-foundation.org
> ReportedBy: bjorn@mork.no
>
>
> Latest working kernel version: none
> Earliest failing kernel version: 2.6.18 (verified, but most likely "any")
> Distribution: Debian
> Hardware Environment:
> Software Environment:
> Problem Description:
>
> >From gary.manchon@gmail.com :
>
> After a bad network interface configuration (ifconfig eth0 127.0.0.1),
> I cannot recover the network without rebooting the kernel.
>
> This is my working configuration :
>
> # ifconfig
> eth0 Link encap:Ethernet HWaddr 00:90:3E:1F:1C:17
> inet addr:192.168.240.195 Bcast:192.168.247.255 Mask:255.255.248.0
> UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
> RX packets:26 errors:0 dropped:0 overruns:0 frame:0
> TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
> collisions:0 txqueuelen:1000
> RX bytes:2633 (2.5 KiB) TX bytes:0 (0.0 B)
>
> lo Link encap:Local Loopback
> inet addr:127.0.0.1 Mask:255.0.0.0
> UP LOOPBACK RUNNING MTU:16436 Metric:1
> RX packets:0 errors:0 dropped:0 overruns:0 frame:0
> TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
> collisions:0 txqueuelen:0
> RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
>
> # route
> Kernel IP routing table
> Destination Gateway Genmask Flags Metric Ref Use Iface
> 192.168.240.0 * 255.255.248.0 U 0 0 0 eth0
> default 192.168.240.1 0.0.0.0 UG 0 0 0 eth0
>
> # ping -c 1 66.102.11.99
> PING 66.102.11.99 (66.102.11.99): 56 data bytes
> 64 bytes from 66.102.11.99: icmp_seq=0 ttl=63 time=4.5 ms
>
> --- 66.102.11.99 ping statistics ---
> 1 packets transmitted, 1 packets received, 0% packet loss
> round-trip min/avg/max = 4.5/4.5/4.5 ms
>
> Steps to reproduce:
>
> # ifconfig eth0 127.0.0.1
> # ifconfig eth0 192.168.240.195 netmask 255.255.248.0
> # route add default gw 192.168.240.1
>
>
> >From Bjørn Mork <bjorn@mork.no> :
>
> I suspect that the problem might be this code in net/ipv4/devinet.c ,
> which sets ifa_scope to RT_SCOPE_HOST if you configure a loopback
> address (127/8) on any interface. I guess it's there to protect us from
> sending packets with a loopback source address, which woulnd't look too
> good:
>
> static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
> {
> struct in_device *in_dev = __in_dev_get_rtnl(dev);
>
> ASSERT_RTNL();
>
> if (!in_dev) {
> inet_free_ifa(ifa);
> return -ENOBUFS;
> }
> ipv4_devconf_setall(in_dev);
> if (ifa->ifa_dev != in_dev) {
> BUG_TRAP(!ifa->ifa_dev);
> in_dev_hold(in_dev);
> ifa->ifa_dev = in_dev;
> }
> if (LOOPBACK(ifa->ifa_local))
> ifa->ifa_scope = RT_SCOPE_HOST;
> return inet_insert_ifa(ifa);
> }
>
>
>
> The real problem is that there's never anything resetting this scope if
> you change the address later. The attached patch fixes this.
>
>
> dhcp232:~# ip addr show dev eth0
> 2: eth0: <BROADCAST,MULTICAST,UP,10000> mtu 1500 qdisc pfifo_fast qlen 1000
> link/ether 00:aa:00:ff:00:ff brd ff:ff:ff:ff:ff:ff
> inet 192.168.3.232/24 brd 192.168.3.255 scope global eth0
> inet6 2001:16d8:ffb4:0:2aa:ff:feff:ff/64 scope global dynamic
> valid_lft 2591971sec preferred_lft 604771sec
> inet6 fe80::2aa:ff:feff:ff/64 scope link
> valid_lft forever preferred_lft forever
> dhcp232:~# ifconfig eth0 127.0.0.1
> dhcp232:~# ip addr show dev eth0
> 2: eth0: <BROADCAST,MULTICAST,UP,10000> mtu 1500 qdisc pfifo_fast qlen 1000
> link/ether 00:aa:00:ff:00:ff brd ff:ff:ff:ff:ff:ff
> inet 127.0.0.1/8 brd 127.255.255.255 scope host eth0
> inet6 2001:16d8:ffb4:0:2aa:ff:feff:ff/64 scope global dynamic
> valid_lft 2591951sec preferred_lft 604751sec
> inet6 fe80::2aa:ff:feff:ff/64 scope link
> valid_lft forever preferred_lft forever
> dhcp232:~# ifconfig eth0 192.168.3.232
> dhcp232:~# ip addr show dev eth0
> 2: eth0: <BROADCAST,MULTICAST,UP,10000> mtu 1500 qdisc pfifo_fast qlen 1000
> link/ether 00:aa:00:ff:00:ff brd ff:ff:ff:ff:ff:ff
> inet 192.168.3.232/24 brd 192.168.3.255 scope host eth0
> inet6 2001:16d8:ffb4:0:2aa:ff:feff:ff/64 scope global dynamic
> valid_lft 2591933sec preferred_lft 604733sec
> inet6 fe80::2aa:ff:feff:ff/64 scope link
> valid_lft forever preferred_lft forever
>
>
>
> Notice how the scope changes from "global" to "host" when configuring
> 127.0.0.1, and just never changes back. It will stay that way forever,
> or until something changes the scope or deletes the address.
>
> Deleting the addresss and re-adding it will work around the problem:
>
> dhcp232:~# ip addr del 192.168.3.232/24 dev eth0
> dhcp232:~# ifconfig eth0 192.168.3.232
> dhcp232:~# ip addr show dev eth0
> 2: eth0: <BROADCAST,MULTICAST,UP,10000> mtu 1500 qdisc pfifo_fast qlen 1000
> link/ether 00:aa:00:ff:00:ff brd ff:ff:ff:ff:ff:ff
> inet 192.168.3.232/24 brd 192.168.3.255 scope global eth0
> inet6 2001:16d8:ffb4:0:2aa:ff:feff:ff/64 scope global dynamic
> valid_lft 2591963sec preferred_lft 604763sec
> inet6 fe80::2aa:ff:feff:ff/64 scope link
> valid_lft forever preferred_lft forever
>
>
> Bjørn
^ permalink raw reply
* Re: [Bugme-new] [Bug 9810] New: Bridge doesn't work with e1000e driver
From: Andrew Morton @ 2008-01-25 9:33 UTC (permalink / raw)
To: netdev; +Cc: bugme-daemon, Auke Kok, Jesse Brandeburg, cijoml,
Stephen Hemminger
In-Reply-To: <bug-9810-10286@http.bugzilla.kernel.org/>
> On Fri, 25 Jan 2008 01:13:19 -0800 (PST) bugme-daemon@bugzilla.kernel.org wrote:
> http://bugzilla.kernel.org/show_bug.cgi?id=9810
>
> Summary: Bridge doesn't work with e1000e driver
> Product: Networking
> Version: 2.5
> KernelVersion: 2.6.24-rc8
> Platform: All
> OS/Version: Linux
> Tree: Mainline
> Status: NEW
> Severity: normal
> Priority: P1
> Component: Other
> AssignedTo: acme@ghostprotocols.net
> ReportedBy: cijoml@volny.cz
>
>
> Latest working kernel version: unknown
> Earliest failing kernel version: unknown
> Distribution: Debian stable
> Hardware Environment: Dell Optiplex 755
> Software Environment: Debian stable, vanilla 2.6.24-rc8
> Problem Description:
>
> Bridge doesn't work with e1000e driver
>
> Steps to reproduce:
>
> optiplex:/home/cijoml# brctl addbr br0
> optiplex:/home/cijoml# brctl addif br0 eth0
> optiplex:/home/cijoml# brctl show
> bridge name bridge id STP enabled interfaces
> br0 8000.001e4f93dd74 no eth0
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> optiplex:/home/cijoml# killall dhclient
> dhclient: no process killed
> optiplex:/home/cijoml# dhclient br0
> Internet Systems Consortium DHCP Client V3.0.4
> Copyright 2004-2006 Internet Systems Consortium.
> All rights reserved.
> For info, please visit http://www.isc.org/sw/dhcp/
>
> Listening on LPF/br0/00:1e:4f:93:dd:74
> Sending on LPF/br0/00:1e:4f:93:dd:74
> Sending on Socket/fallback
> DHCPREQUEST on br0 to 255.255.255.255 port 67
> DHCPREQUEST on br0 to 255.255.255.255 port 67
> DHCPREQUEST on br0 to 255.255.255.255 port 67
> DHCPDISCOVER on br0 to 255.255.255.255 port 67 interval 6
> DHCPDISCOVER on br0 to 255.255.255.255 port 67 interval 8
> DHCPDISCOVER on br0 to 255.255.255.255 port 67 interval 12
> DHCPDISCOVER on br0 to 255.255.255.255 port 67 interval 18
> DHCPDISCOVER on br0 to 255.255.255.255 port 67 interval 17
> No DHCPOFFERS received.
> Trying recorded lease 10.136.212.12
> PING 10.136.212.1 (10.136.212.1) 56(84) bytes of data.
>
> --- 10.136.212.1 ping statistics ---
> 1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms
>
> No working leases in persistent database - sleeping.
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> optiplex:/home/cijoml# killall dhclient
> optiplex:/home/cijoml# ifconfig br0 down
> optiplex:/home/cijoml# brctl delbr br0
> optiplex:/home/cijoml# dhclient eth0
> Internet Systems Consortium DHCP Client V3.0.4
> Copyright 2004-2006 Internet Systems Consortium.
> All rights reserved.
> For info, please visit http://www.isc.org/sw/dhcp/
>
> Listening on LPF/eth0/00:1e:4f:93:dd:74
> Sending on LPF/eth0/00:1e:4f:93:dd:74
> Sending on Socket/fallback
> DHCPREQUEST on eth0 to 255.255.255.255 port 67
> DHCPREQUEST on eth0 to 255.255.255.255 port 67
> DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 6
> ip length 339 disagrees with bytes received 343.
> accepting packet with data after udp payload.
> DHCPOFFER from 10.136.212.2
> DHCPREQUEST on eth0 to 255.255.255.255 port 67
> ip length 339 disagrees with bytes received 343.
> accepting packet with data after udp payload.
> ip length 339 disagrees with bytes received 343.
> accepting packet with data after udp payload.
> DHCPACK from 10.136.212.2
> bound to 10.136.212.15 -- renewal in 1149646 seconds.
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
>
^ permalink raw reply
* Re: [PATCH] fib_trie: rescan if key is lost during dump
From: Jarek Poplawski @ 2008-01-25 8:23 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: David Miller, kaber, netdev
In-Reply-To: <20080124135112.32b5c1c7@deepthought>
On 24-01-2008 22:51, Stephen Hemminger wrote:
> Normally during a dump the key of the last dumped entry is used for
> continuation, but since lock is dropped it might be lost. In that case
> fallback to the old counter based N^2 behaviour. This means the dump will end up
> skipping some routes which matches what FIB_HASH does.
>
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
...
> @@ -1918,35 +1931,37 @@ static int fn_trie_dump(struct fib_table
> struct leaf *l;
> struct trie *t = (struct trie *) tb->tb_data;
> t_key key = cb->args[2];
> + int count = cb->args[3];
>
> rcu_read_lock();
Sorry, but I lost the point: is rtnl held or not held here at the moment?
If held, how this rcu_read_lock can help? Maybe some additional comment
in the code?
Thanks,
Jarek P.
^ permalink raw reply
* [PATCH] SMC91x: poll_controller(): check for interrupts before calling handler
From: Kevin Hilman @ 2008-01-25 5:38 UTC (permalink / raw)
To: netdev; +Cc: Nicolas Pitre, Kevin Hilman
When using polling, smc_poll_controller() can call smc_interrupt()
when there are likely to be no real interrups. This will trigger the
"spurious interrupt" printk whenever the driver is being polled.
Instead, check for actual interrupts before calling smc_interrupt()
Signed-off-by: Kevin Hilman <khilman@mvista.com>
Signed-off-by: Nicolas Pitre <nico@cam.org>
---
drivers/net/smc91x.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 7da7589..64ef6c1 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -1350,8 +1350,12 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id)
*/
static void smc_poll_controller(struct net_device *dev)
{
+ struct smc_local *lp = netdev_priv(dev);
+ void __iomem *ioaddr = lp->base;
+
disable_irq(dev->irq);
- smc_interrupt(dev->irq, dev);
+ if (SMC_GET_INT() & SMC_GET_INT_MASK())
+ smc_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
--
1.5.3.7
^ permalink raw reply related
* Re: bluetooth : lockdep warning on rfcomm
From: Dave Young @ 2008-01-25 5:37 UTC (permalink / raw)
To: LKML; +Cc: Netdev, Marcel Holtmann, David Miller, bluez-devel
In-Reply-To: <a8e1da0801240125x6c65a4bfva24ff50cef890eba@mail.gmail.com>
On Jan 24, 2008 5:25 PM, Dave Young <hidave.darkstar@gmail.com> wrote:
>
> On Jan 24, 2008 11:02 AM, Dave Young <hidave.darkstar@gmail.com> wrote:
> > =============================================
> > [ INFO: possible recursive locking detected ]
> > 2.6.24-rc8-mm1 #8
> > ---------------------------------------------
> > bluepush/3213 is trying to acquire lock:
> > (sk_lock-AF_BLUETOOTH){--..}, at: [<f8978c80>]
> > l2cap_sock_bind+0x40/0x100 [l2cap]
> >
> > but task is already holding lock:
> > (sk_lock-AF_BLUETOOTH){--..}, at: [<f894a31e>]
> > rfcomm_sock_connect+0x3e/0xe0 [rfcomm]
> >
> > other info that might help us debug this:
> > 2 locks held by bluepush/3213:
> > #0: (sk_lock-AF_BLUETOOTH){--..}, at: [<f894a31e>]
> > rfcomm_sock_connect+0x3e/0xe0 [rfcomm]
> > #1: (rfcomm_mutex){--..}, at: [<f8947556>] rfcomm_dlc_open+0x26/0x60 [rfcomm]
> >
> > stack backtrace:
> > Pid: 3213, comm: bluepush Not tainted 2.6.24-rc8-mm1 #8
> > [<c0132128>] ? printk+0x18/0x20
> > [<c0154437>] print_deadlock_bug+0xc7/0xe0
> > [<c01544bc>] check_deadlock+0x6c/0x80
> > [<c01548fc>] validate_chain+0x14c/0x320
> > [<c0156221>] __lock_acquire+0x1c1/0x730
> > [<c0156d89>] lock_acquire+0x79/0xb0
> > [<f8978c80>] ? l2cap_sock_bind+0x40/0x100 [l2cap]
> > [<c03c05f5>] lock_sock_nested+0x55/0x70
> > [<f8978c80>] ? l2cap_sock_bind+0x40/0x100 [l2cap]
> > [<f8978c80>] l2cap_sock_bind+0x40/0x100 [l2cap]
> > [<c03bdb4a>] kernel_bind+0xa/0x10
> > [<f8947afc>] rfcomm_session_create+0x4c/0x110 [rfcomm]
> > [<f8947509>] __rfcomm_dlc_open+0x129/0x150 [rfcomm]
> > [<f8947568>] rfcomm_dlc_open+0x38/0x60 [rfcomm]
> > [<f894a396>] rfcomm_sock_connect+0xb6/0xe0 [rfcomm]
> > [<c03bcd39>] sys_connect+0x99/0xd0
> > [<c010f509>] ? cache_add_dev+0x39/0x1a0
> > [<c015323d>] ? put_lock_stats+0xd/0x30
> > [<c01532c0>] ? lock_release_holdtime+0x60/0x80
> > [<c018e86c>] ? fget+0x7c/0x100
> > [<c0156b97>] ? __lock_release+0x47/0x70
> > [<c018e86c>] ? fget+0x7c/0x100
> > [<c02611b7>] ? copy_from_user+0x37/0x70
> > [<c03bd855>] sys_socketcall+0xa5/0x230
> > [<c0155659>] ? trace_hardirqs_on+0xb9/0x130
> > [<c010501b>] ? restore_nocheck+0x12/0x15
> >
>
> While fixing this issue, another locking dependency confused me. Are
> rfcomm_dev_lock and &d->lock in same lock class?
>
> The warnings as following:
>
> =======================================================
> [ INFO: possible circular locking dependency detected ]
> 2.6.24-rc8-mm1 #8
> -------------------------------------------------------
> krfcommd/2912 is trying to acquire lock:
> (rfcomm_dev_lock){-.--}, at: [<f89d5bf2>]
> rfcomm_dev_state_change+0x92/0x160 [rfcomm]
>
> but task is already holding lock:
> (&d->lock){--..}, at: [<f89d15d3>] __rfcomm_dlc_close+0x43/0xd0 [rfcomm]
>
> which lock already depends on the new lock.
Answer to myself, the reason is that lockdep think this as a lock order problem.
in rfcomm_device_add the lock order is :
rfcomm_dev_lock --> dlc lock
but in __rfcomm_dlc_close is :
dlc lock --> rfcomm_dev_lock (-> state_change->rfcomm_dev_get)
>
>
> the existing dependency chain (in reverse order) is:
>
> -> #1 (&d->lock){--..}:
> [<c0153b13>] add_lock_to_list+0x33/0x70
> [<c01545a3>] check_prev_add+0xd3/0x200
> [<f89d5311>] rfcomm_dev_add+0x191/0x300 [rfcomm]
> [<c0154765>] check_prevs_add+0x95/0xe0
> [<c01549ef>] validate_chain+0x23f/0x320
> [<c0156221>] __lock_acquire+0x1c1/0x730
> [<c0155539>] mark_held_locks+0x39/0x80
> [<c0156d89>] lock_acquire+0x79/0xb0
> [<f89d5311>] rfcomm_dev_add+0x191/0x300 [rfcomm]
> [<c0436749>] _spin_lock+0x39/0x80
> [<f89d5311>] rfcomm_dev_add+0x191/0x300 [rfcomm]
> [<f89d5b10>] rfcomm_dev_data_ready+0x0/0x50 [rfcomm]
> [<f89d5311>] rfcomm_dev_add+0x191/0x300 [rfcomm]
> [<f89d565e>] rfcomm_create_dev+0x6e/0x100 [rfcomm]
> [<c03c05fa>] lock_sock_nested+0x5a/0x70
> [<f89d5ae3>] rfcomm_dev_ioctl+0x33/0x60 [rfcomm]
> [<f89d4c8c>] rfcomm_sock_ioctl+0x2c/0x50 [rfcomm]
> [<c03bc001>] sock_ioctl+0xc1/0x220
> [<c03bbf40>] sock_ioctl+0x0/0x220
> [<c019a366>] vfs_ioctl+0x76/0x90
> [<c019a616>] do_vfs_ioctl+0x56/0x140
> [<c019a762>] sys_ioctl+0x62/0x70
> [<c0104fba>] syscall_call+0x7/0xb
> [<ffffffff>] 0xffffffff
>
> -> #0 (rfcomm_dev_lock){-.--}:
> [<c0154504>] check_prev_add+0x34/0x200
> [<c012a9ab>] default_wake_function+0xb/0x10
> [<c0154765>] check_prevs_add+0x95/0xe0
> [<c01549ef>] validate_chain+0x23f/0x320
> [<c0156221>] __lock_acquire+0x1c1/0x730
> [<c0156d89>] lock_acquire+0x79/0xb0
> [<f89d5bf2>] rfcomm_dev_state_change+0x92/0x160 [rfcomm]
> [<c04361e9>] _read_lock+0x39/0x80
> [<f89d5bf2>] rfcomm_dev_state_change+0x92/0x160 [rfcomm]
> [<f89d5bf2>] rfcomm_dev_state_change+0x92/0x160 [rfcomm]
> [<f89d15e8>] __rfcomm_dlc_close+0x58/0xd0 [rfcomm]
> [<f89d2523>] rfcomm_recv_ua+0x73/0x140 [rfcomm]
> [<f89d3151>] rfcomm_recv_frame+0x171/0x1e0 [rfcomm]
> [<c0155659>] trace_hardirqs_on+0xb9/0x130
> [<c0436a39>] _spin_unlock_irqrestore+0x39/0x70
> [<f89d3447>] rfcomm_run+0xe7/0x590 [rfcomm]
> [<c0120000>] hpet_legacy_next_event+0x20/0x50
> [<f89d3360>] rfcomm_run+0x0/0x590 [rfcomm]
> [<c0146e0c>] kthread+0x5c/0xa0
> [<c0146db0>] kthread+0x0/0xa0
> [<c0105c17>] kernel_thread_helper+0x7/0x10
> [<ffffffff>] 0xffffffff
>
> other info that might help us debug this:
>
> 2 locks held by krfcommd/2912:
> #0: (rfcomm_mutex){--..}, at: [<f89d33db>] rfcomm_run+0x7b/0x590 [rfcomm]
> #1: (&d->lock){--..}, at: [<f89d15d3>] __rfcomm_dlc_close+0x43/0xd0 [rfcomm]
>
> stack backtrace:
> Pid: 2912, comm: krfcommd Not tainted 2.6.24-rc8-mm1 #8
> [<c0132128>] ? printk+0x18/0x20
> [<c0153cff>] print_circular_bug_tail+0x6f/0x80
> [<c0154504>] check_prev_add+0x34/0x200
> [<c012a9ab>] ? default_wake_function+0xb/0x10
> [<c0154765>] check_prevs_add+0x95/0xe0
> [<c01549ef>] validate_chain+0x23f/0x320
> [<c0156221>] __lock_acquire+0x1c1/0x730
> [<c0156d89>] lock_acquire+0x79/0xb0
> [<f89d5bf2>] ? rfcomm_dev_state_change+0x92/0x160 [rfcomm]
> [<c04361e9>] _read_lock+0x39/0x80
> [<f89d5bf2>] ? rfcomm_dev_state_change+0x92/0x160 [rfcomm]
> [<f89d5bf2>] rfcomm_dev_state_change+0x92/0x160 [rfcomm]
> [<f89d15e8>] __rfcomm_dlc_close+0x58/0xd0 [rfcomm]
> [<f89d2523>] rfcomm_recv_ua+0x73/0x140 [rfcomm]
> [<f89d3151>] rfcomm_recv_frame+0x171/0x1e0 [rfcomm]
> [<c0155659>] ? trace_hardirqs_on+0xb9/0x130
> [<c0436a39>] ? _spin_unlock_irqrestore+0x39/0x70
> [<f89d3447>] rfcomm_run+0xe7/0x590 [rfcomm]
> [<c0120000>] ? hpet_legacy_next_event+0x20/0x50
> [<f89d3360>] ? rfcomm_run+0x0/0x590 [rfcomm]
> [<c0146e0c>] kthread+0x5c/0xa0
> [<c0146db0>] ? kthread+0x0/0xa0
> [<c0105c17>] kernel_thread_helper+0x7/0x10
> =======================
>
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
^ permalink raw reply
* Re: pull request: wireless-2.6 'upstream' 2008-01-24
From: David Miller @ 2008-01-25 5:26 UTC (permalink / raw)
To: linville; +Cc: netdev, linux-wireless
In-Reply-To: <20080125035751.GC3411@tuxdriver.com>
From: "John W. Linville" <linville@tuxdriver.com>
Date: Thu, 24 Jan 2008 22:57:51 -0500
> On Thu, Jan 24, 2008 at 02:53:43PM -0500, John W. Linville wrote:
>
> > The cfg80211 API change breaks ath5k, so I have listed it as "depends
> > on BROKEN". I am assured that the ath5k team has agreed to fix
> > this ASAP. Meanwhile we wanted to have it in place so that we can
> > start shaking-out problems with other drivers.
>
> Looks like this might have broken more than I expected, and there
> may be some refactoring of the wireless rndis bits too. So, let's
> hold off on this request. I'll post a new one in the next day or so.
Ok.
^ permalink raw reply
* RE: [PATCH UCC TDM 1/3 Updated] Platform changes for UCC TDM driver for MPC8323eRDB. Also includes related QE changes and dts entries.
From: Aggrwal Poonam @ 2008-01-25 4:09 UTC (permalink / raw)
To: avorontsov, Tabi Timur
Cc: Gala Kumar, akpm, linux-kernel, netdev, rubini, linuxppc-dev,
Barkowski Michael, Cutler Richard, Kalra Ashish
In-Reply-To: <20080124172327.GA6786@localhost.localdomain>
Hello Anton/Tabi
I am not sure which is the best place to configure the pins. Because
some drivers do it in one way and some in the other.
I actually tried to make the driver similar to ucc_geth because it is a
QE driver. The driver has no platform code in the platform files similar
to ucc_geth. It is probed along with all the QE devices thorugh
of_platform_bus_probe.
And the pins are configured for all the QE devices using par_io_init.
I thought this to be the most consistent way at that time.
How should we close this point?
Can we go ahead with the pio-map?
Infact the discussion in this thread was very good and I got to know a
lot of rationales behind this.
Please suggest.
Thanks and Regards
Poonam
From: Anton Vorontsov [mailto:avorontsov@ru.mvista.com]
Sent: Thursday, January 24, 2008 10:53 PM
To: Tabi Timur
Cc: Aggrwal Poonam; Gala Kumar; akpm@linux-foundation.org;
linux-kernel@vger.kernel.org; netdev@vger.kernel.org;
rubini@vision.unipv.it; linuxppc-dev@ozlabs.org; Barkowski Michael;
Cutler Richard; Kalra Ashish
Subject: Re: [PATCH UCC TDM 1/3 Updated] Platform changes for UCC TDM
driver for MPC8323eRDB. Also includes related QE changes and dts
entries.
On Thu, Jan 24, 2008 at 10:33:47AM -0600, Timur Tabi wrote:
> Anton Vorontsov wrote:
>
> >Are you saying that TDM is sharing same pins with the other QE
> >device, and we can choose to use/not use some device depending on
> >which driver is loaded?
>
> No. I'd have to closely examine the DTS, but I don't think that UCC
> devices share pins at all. But that isn't my point.
>
> >In that particular case UCC configuration is static, for every UCC.
> >So, we can set up all pins in the firmware/board file.
>
> Yes, but deciding what the UCC does might not be static. At what
> point do we declare, "UCC5 is for eth0 and eth0 only"?
>
> The advantage of putting the pin configurations in the device tree is
> that they now become configurable. I can envision a scenario where
> UCC5 could be either an Ethernet or a UART, depending on the setting
> of some jumpers on the board. That's what the QE was designed for: any
> UCC can do any task, and you can even have a UCC change its purpose
while the system is running.
> So I don't want the pin configurations hard-coded into the kernel.
> Having them in the device tree gives me some flexibility.
If hardware configuration is selected at the bootup time, by jumpers or
switches, it's even easier to do it right. Without pio-map.
> For instance, I have a plan (that I keep postponing) to introduce a
> new feature in U-Boot where U-Boot can determine the settings of some
> board jumpers and modify the device tree accordingly. The instructions
> on how to modify the device tree would be embedded in the tree itself.
Why you need to modify the device tree for that? Let the U-Boot simply
setup pins for the kernel. Regarding kernel overwriting pins
configuration...
> I can't
> support this feature if the kernel calls par_io_config_pin()
> regardless of what's in the device tree.
What I've understood from the previous debates, is that ideally kernel
should not touch pins' configuration. Today we're using pio-map solely
to fix up some old firmware misconfiguration. And we can do this in the
board file still. To determine if we need to fixup the firmware or not,
we can use some device tree property instead (firmware version?).
p.s.
I'm neither for pio-map nor against. I just want some consequence
regarding this. Last thread ended with consequence that pio-map is a bad
thing to use...
--
Anton Vorontsov
email: cbou@mail.ru
backup email: ya-cbou@yandex.ru
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: pull request: wireless-2.6 'upstream' 2008-01-24
From: John W. Linville @ 2008-01-25 3:57 UTC (permalink / raw)
To: davem; +Cc: netdev, linux-wireless
In-Reply-To: <20080124195343.GC3200@tuxdriver.com>
On Thu, Jan 24, 2008 at 02:53:43PM -0500, John W. Linville wrote:
> The cfg80211 API change breaks ath5k, so I have listed it as "depends
> on BROKEN". I am assured that the ath5k team has agreed to fix
> this ASAP. Meanwhile we wanted to have it in place so that we can
> start shaking-out problems with other drivers.
Looks like this might have broken more than I expected, and there
may be some refactoring of the wireless rndis bits too. So, let's
hold off on this request. I'll post a new one in the next day or so.
Thanks,
John
--
John W. Linville
linville@tuxdriver.com
^ permalink raw reply
* RE: [PATCH UCC TDM 3/3 ] Modified Documentation to explain dtsentries for TDM driver
From: Aggrwal Poonam @ 2008-01-25 3:58 UTC (permalink / raw)
To: Wood Scott
Cc: Barkowski Michael, netdev, Gala Kumar, linux-kernel, rubini,
linuxppc-dev, Kalra Ashish, Cutler Richard, akpm, Tabi Timur
In-Reply-To: <20080124201226.GA3926@loki.buserror.net>
Hi Scott
The device tree already has a brg-frequency property in qe node which
is the value of BRGCLK. The function get_brg_clk uses this property to
find the value of BRGCLK.
In case this value is 0(some older u-boots populate bus-frequency
property of qe and not the brg-frequency), get_brg_clk uses
bus-frequency/2 as BRGCLK.
With Regards
Poonam
-----Original Message-----
From: Wood Scott
Sent: Friday, January 25, 2008 1:42 AM
To: Aggrwal Poonam
Cc: Gala Kumar; akpm@linux-foundation.org; linux-kernel@vger.kernel.org;
netdev@vger.kernel.org; rubini@vision.unipv.it; linuxppc-dev@ozlabs.org;
Barkowski Michael; Cutler Richard; Tabi Timur; Kalra Ashish
Subject: Re: [PATCH UCC TDM 3/3 ] Modified Documentation to explain
dtsentries for TDM driver
On Thu, Jan 24, 2008 at 10:24:13AM +0530, Poonam_Aggrwal-b10812 wrote:
> + ix) Baud Rate Generator (BRG)
> +
> + Required properties:
> + - compatible : shpuld be "fsl,cpm-brg"
> + - fsl,brg-sources : define the input clock for all 16 BRGs. The
input
> + clock source could be 1 to 24 for CLK1 to CLK24. Zero means that
the
> + particular BRG will be driven by QE clock(BRGCLK).
Should also have a clock-frequency property to specify what BRGCLK is.
-Scott
^ permalink raw reply
* Re: [PATCH v2] PS3: gelic: Add wireless support for PS3
From: Masakazu Mokuno @ 2008-01-25 3:36 UTC (permalink / raw)
To: John W. Linville, Dan Williams
Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
geoffrey.levand-mEdOJwZ7QcZBDgjK7y7TUQ, Geert Uytterhoeven,
Paul Mackerras
In-Reply-To: <20080125024725.GB3411-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
On Thu, 24 Jan 2008 21:47:25 -0500
"John W. Linville" <linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org> wrote:
> On Thu, Jan 24, 2008 at 08:49:45PM -0500, Dan Williams wrote:
> > On Thu, 2008-01-24 at 14:51 +0900, Masakazu Mokuno wrote:
> > > Hi
> > >
> > > PS3: gelic: Add wireless support for PS3
> > >
> > > This is the version 2 of the re-worked (rewritten) version of the
> > > wireless support driver for PS3. The version 1 of the new driver was
> > > submitted on 13th Dec. 2007 (and the old one was submitted to net-dev ML
> > > in June 2007).
> > >
> > > Major differences with the old driver are:
> > > - The new driver has a separate ethX interface from ethernet.
> > > They share the same MAC address.
> > > - Thus we can use both ethernet and wireless simultaenously.
> > > - The new driver returns AP's cipher information by the common IE
> > > format in the scan information.
> > > - Cipher selection is done via the common wireless extension way
> >
> > Looks like all my issues have been addressed. Thanks! Lets get this in
> > 2.6.25 :)
> >
> > Acked-by: Dan Williams <dcbw-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>
> ACK -- please merge it with the other patches through the powerpc tree.
>
> Thanks,
>
> John
Thank you, John, Dan.
I'll ask Paul to merge this if the wired part of dependent gelic patches
gets acked from network people.
--
Masakazu MOKUNO
^ permalink raw reply
* RE: [PATCH 2.6.25 1/1]S2io: Multiqueue network device support implementation
From: Ramkrishna Vepa @ 2008-01-25 3:19 UTC (permalink / raw)
To: David Miller, andi; +Cc: Sreenivasa Honnur, netdev, jeff, support
In-Reply-To: <20080123.233006.124819204.davem@davemloft.net>
> From: netdev-owner@vger.kernel.org
[mailto:netdev-owner@vger.kernel.org]
> On Behalf Of David Miller
> Sent: Wednesday, January 23, 2008 11:30 PM
>
> From: Andi Kleen <andi@firstfloor.org>
> Date: Thu, 24 Jan 2008 08:25:49 +0100
>
> > > have done away with handling tx completion in the interrupt
handler,
> and
> > > are instead handling them in the context of the transmit. The slow
> path,
> > > straggling transmit completions will be handled in the timer
context.
> >
> > Ok -- hopefully you don't have bad corner cases from this when the
pipe
> > is not fully filled and then causing longer latencies on completion.
> > Old NAPI sometimes suffered from such problems.
>
> BTW, such a TX completion timer will stall TCP sockets when the TX
> queue of the device is partially filled and then sending stops.
>
> TX ring SKB liberation really must be done in a very small finite
> amount of time in order to avoid this problem properly.
>
> Deferring it to HZ granular timers doesn't give a quick enough
> response, especially at high packet rates.
[Ram] We could add a lower granular tx completion interrupt instead, to
handle all the transmit fifos. But this will be a fall back in the event
the completions do not happen in the context of the transmit.
Ram
^ permalink raw reply
* RE: [PATCH 2.6.25 1/1]S2io: Multiqueue network device support implementation
From: Ramkrishna Vepa @ 2008-01-25 3:19 UTC (permalink / raw)
To: Andi Kleen; +Cc: Sreenivasa Honnur, netdev, jeff, support
In-Reply-To: <20080124072549.GA6814@one.firstfloor.org>
> > [Ram] I am assuming that this is with regards to msi-x interrupts.
We
>
> Yes.
>
> And avoiding bouncing locks for device state between CPUs.
>
> > have done away with handling tx completion in the interrupt handler,
and
> > are instead handling them in the context of the transmit. The slow
path,
> > straggling transmit completions will be handled in the timer
context.
>
> Ok -- hopefully you don't have bad corner cases from this when the
pipe
> is not fully filled and then causing longer latencies on completion.
> Old NAPI sometimes suffered from such problems.
[Ram] We have hit the driver pretty hard during testing and have not
encountered any problems either on the network or host.
Ram
>
> -Andi
^ permalink raw reply
* Re: [PATCH 09/26] atl1: refactor tx processing
From: Jeff Garzik @ 2008-01-25 3:01 UTC (permalink / raw)
To: Jay Cliburn; +Cc: csnook, linux-kernel, atl1-devel, netdev
In-Reply-To: <20080124190024.1b81238e@osprey.hogchain.net>
Jay Cliburn wrote:
> On Tue, 22 Jan 2008 18:31:09 -0600
> Jay Cliburn <jacliburn@bellsouth.net> wrote:
>
>> On Tue, 22 Jan 2008 04:58:17 -0500
>> Jeff Garzik <jeff@garzik.org> wrote:
>>
> [...]
>>> for such a huge patch, this description is very tiny. [describe]
>>> what is refactored, and why.
>
> Is this one any better?
>
>
>
>>From df475e2eea401f9dc18ca23dab538b99fb9e710c Mon Sep 17 00:00:00 2001
> From: Jay Cliburn <jacliburn@bellsouth.net>
> Date: Wed, 23 Jan 2008 21:36:36 -0600
> Subject: [PATCH] atl1: simplify tx packet descriptor
>
> The transmit packet descriptor consists of four 32-bit words, with word 3
> upper bits overloaded depending upon the condition of its bits 3 and 4.
> The driver currently duplicates all word 2 and some word 3 register bit
> definitions unnecessarily and also uses a set of nested structures in its
> definition of the TPD without good cause. This patch adds a lengthy
> comment describing the TPD, eliminates duplicate TPD bit definitions,
> and simplifies the TPD structure itself. It also expands the TSO check
> to correctly handle custom checksum versus TSO processing using the revised
> TPD definitions. Finally, shorten some variable names in the transmit
> processing path to reduce line lengths, rename some variables to better
> describe their purpose (e.g., nseg versus m), and add a comment or two
> to better describe what the code is doing.
>
> Signed-off-by: Jay Cliburn <jacliburn@bellsouth.net>
> ---
> drivers/net/atlx/atl1.c | 265 +++++++++++++++++++++++++----------------------
> drivers/net/atlx/atl1.h | 201 +++++++++++++++++++-----------------
> 2 files changed, 246 insertions(+), 220 deletions(-)
Yep, better.
Jeff
^ permalink raw reply
* Re: [PATCH v2] PS3: gelic: Add wireless support for PS3
From: John W. Linville @ 2008-01-25 2:47 UTC (permalink / raw)
To: Dan Williams
Cc: Masakazu Mokuno, linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
geoffrey.levand-mEdOJwZ7QcZBDgjK7y7TUQ, Geert Uytterhoeven
In-Reply-To: <1201225785.15917.8.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
On Thu, Jan 24, 2008 at 08:49:45PM -0500, Dan Williams wrote:
> On Thu, 2008-01-24 at 14:51 +0900, Masakazu Mokuno wrote:
> > Hi
> >
> > PS3: gelic: Add wireless support for PS3
> >
> > This is the version 2 of the re-worked (rewritten) version of the
> > wireless support driver for PS3. The version 1 of the new driver was
> > submitted on 13th Dec. 2007 (and the old one was submitted to net-dev ML
> > in June 2007).
> >
> > Major differences with the old driver are:
> > - The new driver has a separate ethX interface from ethernet.
> > They share the same MAC address.
> > - Thus we can use both ethernet and wireless simultaenously.
> > - The new driver returns AP's cipher information by the common IE
> > format in the scan information.
> > - Cipher selection is done via the common wireless extension way
>
> Looks like all my issues have been addressed. Thanks! Lets get this in
> 2.6.25 :)
>
> Acked-by: Dan Williams <dcbw-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
ACK -- please merge it with the other patches through the powerpc tree.
Thanks,
John
--
John W. Linville
linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org
^ permalink raw reply
* [PATCH] phylib: Add Realtek 821x eth PHY support
From: Kim Phillips @ 2008-01-25 2:28 UTC (permalink / raw)
To: netdev, jgarzik; +Cc: Johnson Leung, Kevin Lam, Joe D'Abbraccio
this PHY present on the MPC8315E and MPC837xE RDB boards.
Signed-off-by: Johnson Leung <r58129@freescale.com>
Signed-off-by: Kevin Lam <r43770@freescale.com>
Signed-off-by: Joe D'Abbraccio <ljd015@freescale.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
---
drivers/net/phy/Kconfig | 5 +++
drivers/net/phy/Makefile | 1 +
drivers/net/phy/realtek.c | 80 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 86 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/phy/realtek.c
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 7fe03ce..f4ca059 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -60,6 +60,11 @@ config ICPLUS_PHY
---help---
Currently supports the IP175C PHY.
+config REALTEK_PHY
+ tristate "Drivers for Realtek PHYs"
+ ---help---
+ Supports the Realtek 821x PHY.
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 3d6cc7b..5997d6e 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -12,5 +12,6 @@ obj-$(CONFIG_SMSC_PHY) += smsc.o
obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
+obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_FIXED_PHY) += fixed.o
obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
new file mode 100644
index 0000000..a052a67
--- /dev/null
+++ b/drivers/net/phy/realtek.c
@@ -0,0 +1,80 @@
+/*
+ * drivers/net/phy/realtek.c
+ *
+ * Driver for Realtek PHYs
+ *
+ * Author: Johnson Leung <r58129@freescale.com>
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/phy.h>
+
+#define RTL821x_PHYSR 0x11
+#define RTL821x_PHYSR_DUPLEX 0x2000
+#define RTL821x_PHYSR_SPEED 0xc000
+#define RTL821x_INER 0x12
+#define RTL821x_INER_INIT 0x6400
+#define RTL821x_INSR 0x13
+
+MODULE_DESCRIPTION("Realtek PHY driver");
+MODULE_AUTHOR("Johnson Leung");
+MODULE_LICENSE("GPL");
+
+static int rtl821x_ack_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ err = phy_read(phydev, RTL821x_INSR);
+
+ return (err < 0) ? err : 0;
+}
+
+static int rtl821x_config_intr(struct phy_device *phydev)
+{
+ int err;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ err = phy_write(phydev, RTL821x_INER,
+ RTL821x_INER_INIT);
+ else
+ err = phy_write(phydev, RTL821x_INER, 0);
+
+ return err;
+}
+
+/* RTL8211B */
+static struct phy_driver rtl821x_driver = {
+ .phy_id = 0x001cc912,
+ .name = "RTL821x Gigabit Ethernet",
+ .phy_id_mask = 0x001fffff,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &rtl821x_ack_interrupt,
+ .config_intr = &rtl821x_config_intr,
+ .driver = { .owner = THIS_MODULE,},
+};
+
+static int __init realtek_init(void)
+{
+ int ret;
+
+ ret = phy_driver_register(&rtl821x_driver);
+
+ return ret;
+}
+
+static void __exit realtek_exit(void)
+{
+ phy_driver_unregister(&rtl821x_driver);
+}
+
+module_init(realtek_init);
+module_exit(realtek_exit);
--
1.5.2.2
^ permalink raw reply related
* Re: [PATCH] SMC91x: don't flag spurious interrupts when polling
From: Nicolas Pitre @ 2008-01-25 2:23 UTC (permalink / raw)
To: Kevin Hilman; +Cc: netdev
In-Reply-To: <1201227343-10853-1-git-send-email-khilman@mvista.com>
On Thu, 24 Jan 2008, Kevin Hilman wrote:
> When using polling, smc_poll_controller() can call smc_interrupt()
> when there are likely to be no real interrups. This will trigger the
> "spurious interrupt" printk whenever the driver is being polled.
>
> This adds an 'is_polling' flags, and doesn't trigger the spurious
> warning when in polling mode.
>
> Signed-off-by: Kevin Hilman <khilman@mvista.com>
> Signed-off-by: Nicolas Pitre <nico@cam.org>
NAK
Kevin: you sent the wrong patch !
Nicolas
^ permalink raw reply
* [PATCH] SMC91x: don't flag spurious interrupts when polling
From: Kevin Hilman @ 2008-01-25 2:15 UTC (permalink / raw)
To: netdev; +Cc: Nicolas Pitre, Kevin Hilman
When using polling, smc_poll_controller() can call smc_interrupt()
when there are likely to be no real interrups. This will trigger the
"spurious interrupt" printk whenever the driver is being polled.
This adds an 'is_polling' flags, and doesn't trigger the spurious
warning when in polling mode.
Signed-off-by: Kevin Hilman <khilman@mvista.com>
Signed-off-by: Nicolas Pitre <nico@cam.org>
---
drivers/net/smc91x.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 7da7589..64ef6c1 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -1350,8 +1350,12 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id)
*/
static void smc_poll_controller(struct net_device *dev)
{
+ struct smc_local *lp = netdev_priv(dev);
+ void __iomem *ioaddr = lp->base;
+
disable_irq(dev->irq);
- smc_interrupt(dev->irq, dev);
+ if (SMC_GET_INT() & SMC_GET_INT_MASK())
+ smc_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
--
1.5.3.7
^ permalink raw reply related
* Re: [PATCH v2] PS3: gelic: Add wireless support for PS3
From: Dan Williams @ 2008-01-25 1:49 UTC (permalink / raw)
To: Masakazu Mokuno
Cc: linux-wireless, netdev, geoffrey.levand, Geert Uytterhoeven
In-Reply-To: <20080124144253.6176.40F06B3A@sm.sony.co.jp>
On Thu, 2008-01-24 at 14:51 +0900, Masakazu Mokuno wrote:
> Hi
>
> PS3: gelic: Add wireless support for PS3
>
> This is the version 2 of the re-worked (rewritten) version of the
> wireless support driver for PS3. The version 1 of the new driver was
> submitted on 13th Dec. 2007 (and the old one was submitted to net-dev ML
> in June 2007).
>
> Major differences with the old driver are:
> - The new driver has a separate ethX interface from ethernet.
> They share the same MAC address.
> - Thus we can use both ethernet and wireless simultaenously.
> - The new driver returns AP's cipher information by the common IE
> format in the scan information.
> - Cipher selection is done via the common wireless extension way
Looks like all my issues have been addressed. Thanks! Lets get this in
2.6.25 :)
Acked-by: Dan Williams <dcbw@redhat.com>
> V2 changes:
> - Emit more null IWAP events at appropriate timings, as Dan Williams
> pointed out at the V1 submission.
> - Fix sparse warnings
> o make some functions as static
> o use NULL for pointer instead of 0
> - Remove extra space
>
> Signed-off-by: Masakazu Mokuno <mokuno@sm.sony.co.jp>
> ---
>
> drivers/net/Kconfig | 10
> drivers/net/Makefile | 3
> drivers/net/ps3_gelic_net.c | 18
> drivers/net/ps3_gelic_net.h | 6
> drivers/net/ps3_gelic_wireless.c | 2753 +++++++++++++++++++++++++++++++++++++++
> drivers/net/ps3_gelic_wireless.h | 329 ++++
> 6 files changed, 3117 insertions(+), 2 deletions(-)
>
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -2302,6 +2302,16 @@ config GELIC_NET
> To compile this driver as a module, choose M here: the
> module will be called ps3_gelic.
>
> +config GELIC_WIRELESS
> + bool "PS3 Wireless support"
> + depends on GELIC_NET
> + help
> + This option adds the support for the wireless feature of PS3.
> + If you have the wireless-less model of PS3 or have no plan to
> + use wireless feature, disabling this option saves memory. As
> + the driver automatically distinguishes the models, you can
> + safely enable this option even if you have a wireless-less model.
> +
> config GIANFAR
> tristate "Gianfar Ethernet"
> depends on 85xx || 83xx || PPC_86xx
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -66,7 +66,8 @@ obj-$(CONFIG_BNX2) += bnx2.o
> spidernet-y += spider_net.o spider_net_ethtool.o
> obj-$(CONFIG_SPIDER_NET) += spidernet.o sungem_phy.o
> obj-$(CONFIG_GELIC_NET) += ps3_gelic.o
> -ps3_gelic-objs += ps3_gelic_net.o
> +gelic_wireless-$(CONFIG_GELIC_WIRELESS) += ps3_gelic_wireless.o
> +ps3_gelic-objs += ps3_gelic_net.o $(gelic_wireless-y)
> obj-$(CONFIG_TC35815) += tc35815.o
> obj-$(CONFIG_SKGE) += skge.o
> obj-$(CONFIG_SKY2) += sky2.o
> --- a/drivers/net/ps3_gelic_net.c
> +++ b/drivers/net/ps3_gelic_net.c
> @@ -46,9 +46,10 @@
> #include <asm/lv1call.h>
>
> #include "ps3_gelic_net.h"
> +#include "ps3_gelic_wireless.h"
>
> #define DRV_NAME "Gelic Network Driver"
> -#define DRV_VERSION "1.1"
> +#define DRV_VERSION "2.0"
>
> MODULE_AUTHOR("SCE Inc.");
> MODULE_DESCRIPTION("Gelic Network driver");
> @@ -1154,6 +1155,12 @@ static irqreturn_t gelic_card_interrupt(
> if (status & GELIC_CARD_PORT_STATUS_CHANGED)
> gelic_card_get_ether_port_status(card, 1);
>
> +#ifdef CONFIG_GELIC_WIRELESS
> + if (status & (GELIC_CARD_WLAN_EVENT_RECEIVED |
> + GELIC_CARD_WLAN_COMMAND_COMPLETED))
> + gelic_wl_interrupt(card->netdev[GELIC_PORT_WIRELESS], status);
> +#endif
> +
> return IRQ_HANDLED;
> }
>
> @@ -1635,6 +1642,12 @@ static int ps3_gelic_driver_probe(struct
> goto fail_setup_netdev;
> }
>
> +#ifdef CONFIG_GELIC_WIRELESS
> + if (gelic_wl_driver_probe(card)) {
> + dev_dbg(&dev->core, "%s: WL init failed\n", __func__);
> + goto fail_setup_netdev;
> + }
> +#endif
> pr_debug("%s: done\n", __func__);
> return 0;
>
> @@ -1674,6 +1687,9 @@ static int ps3_gelic_driver_remove(struc
> struct net_device *netdev0;
> pr_debug("%s: called\n", __func__);
>
> +#ifdef CONFIG_GELIC_WIRELESS
> + gelic_wl_driver_remove(card);
> +#endif
> /* stop interrupt */
> gelic_card_set_irq_mask(card, 0);
>
> --- a/drivers/net/ps3_gelic_net.h
> +++ b/drivers/net/ps3_gelic_net.h
> @@ -57,6 +57,8 @@
> #define GELIC_CARD_RX_PROTECTION_ERR 0x0000000004000000L
> #define GELIC_CARD_TX_TCP_UDP_CHECKSUM_ERR 0x0000000008000000L
> #define GELIC_CARD_PORT_STATUS_CHANGED 0x0000000020000000L
> +#define GELIC_CARD_WLAN_EVENT_RECEIVED 0x0000000040000000L
> +#define GELIC_CARD_WLAN_COMMAND_COMPLETED 0x0000000080000000L
> /* INT 0 */
> #define GELIC_CARD_TX_FLAGGED_DESCR 0x0004000000000000L
> #define GELIC_CARD_RX_FLAGGED_DESCR 0x0040000000000000L
> @@ -180,6 +182,10 @@ enum gelic_lv1_net_control_code {
> GELIC_LV1_GET_ETH_PORT_STATUS = 2,
> GELIC_LV1_SET_NEGOTIATION_MODE = 3,
> GELIC_LV1_GET_VLAN_ID = 4,
> + GELIC_LV1_GET_CHANNEL = 6,
> + GELIC_LV1_POST_WLAN_CMD = 9,
> + GELIC_LV1_GET_WLAN_CMD_RESULT = 10,
> + GELIC_LV1_GET_WLAN_EVENT = 11
> };
>
> /* status returened from GET_ETH_PORT_STATUS */
> --- /dev/null
> +++ b/drivers/net/ps3_gelic_wireless.c
> @@ -0,0 +1,2753 @@
> +/*
> + * PS3 gelic network driver.
> + *
> + * Copyright (C) 2007 Sony Computer Entertainment Inc.
> + * Copyright 2007 Sony Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +#undef DEBUG
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +
> +#include <linux/etherdevice.h>
> +#include <linux/ethtool.h>
> +#include <linux/if_vlan.h>
> +
> +#include <linux/in.h>
> +#include <linux/ip.h>
> +#include <linux/tcp.h>
> +#include <linux/wireless.h>
> +#include <linux/ctype.h>
> +#include <linux/string.h>
> +#include <net/iw_handler.h>
> +#include <net/ieee80211.h>
> +
> +#include <linux/dma-mapping.h>
> +#include <net/checksum.h>
> +#include <asm/firmware.h>
> +#include <asm/ps3.h>
> +#include <asm/lv1call.h>
> +
> +#include "ps3_gelic_net.h"
> +#include "ps3_gelic_wireless.h"
> +
> +
> +static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan);
> +static int gelic_wl_try_associate(struct net_device *netdev);
> +
> +/*
> + * tables
> + */
> +
> +/* 802.11b/g channel to freq in MHz */
> +static const int channel_freq[] = {
> + 2412, 2417, 2422, 2427, 2432,
> + 2437, 2442, 2447, 2452, 2457,
> + 2462, 2467, 2472, 2484
> +};
> +#define NUM_CHANNELS ARRAY_SIZE(channel_freq)
> +
> +/* in bps */
> +static const int bitrate_list[] = {
> + 1000000,
> + 2000000,
> + 5500000,
> + 11000000,
> + 6000000,
> + 9000000,
> + 12000000,
> + 18000000,
> + 24000000,
> + 36000000,
> + 48000000,
> + 54000000
> +};
> +#define NUM_BITRATES ARRAY_SIZE(bitrate_list)
> +
> +/*
> + * wpa2 support requires the hypervisor version 2.0 or later
> + */
> +static inline int wpa2_capable(void)
> +{
> + return (0 <= ps3_compare_firmware_version(2, 0, 0));
> +}
> +
> +static inline int precise_ie(void)
> +{
> + return 0; /* FIXME */
> +}
> +/*
> + * post_eurus_cmd helpers
> + */
> +struct eurus_cmd_arg_info {
> + int pre_arg; /* command requres arg1, arg2 at POST COMMAND */
> + int post_arg; /* command requires arg1, arg2 at GET_RESULT */
> +};
> +
> +static const struct eurus_cmd_arg_info cmd_info[GELIC_EURUS_CMD_MAX_INDEX] = {
> + [GELIC_EURUS_CMD_SET_COMMON_CFG] = { .pre_arg = 1},
> + [GELIC_EURUS_CMD_SET_WEP_CFG] = { .pre_arg = 1},
> + [GELIC_EURUS_CMD_SET_WPA_CFG] = { .pre_arg = 1},
> + [GELIC_EURUS_CMD_GET_COMMON_CFG] = { .post_arg = 1},
> + [GELIC_EURUS_CMD_GET_WEP_CFG] = { .post_arg = 1},
> + [GELIC_EURUS_CMD_GET_WPA_CFG] = { .post_arg = 1},
> + [GELIC_EURUS_CMD_GET_RSSI_CFG] = { .post_arg = 1},
> + [GELIC_EURUS_CMD_GET_SCAN] = { .post_arg = 1},
> +};
> +
> +#ifdef DEBUG
> +static const char *cmdstr(enum gelic_eurus_command ix)
> +{
> + switch (ix) {
> + case GELIC_EURUS_CMD_ASSOC:
> + return "ASSOC";
> + case GELIC_EURUS_CMD_DISASSOC:
> + return "DISASSOC";
> + case GELIC_EURUS_CMD_START_SCAN:
> + return "SCAN";
> + case GELIC_EURUS_CMD_GET_SCAN:
> + return "GET SCAN";
> + case GELIC_EURUS_CMD_SET_COMMON_CFG:
> + return "SET_COMMON_CFG";
> + case GELIC_EURUS_CMD_GET_COMMON_CFG:
> + return "GET_COMMON_CFG";
> + case GELIC_EURUS_CMD_SET_WEP_CFG:
> + return "SET_WEP_CFG";
> + case GELIC_EURUS_CMD_GET_WEP_CFG:
> + return "GET_WEP_CFG";
> + case GELIC_EURUS_CMD_SET_WPA_CFG:
> + return "SET_WPA_CFG";
> + case GELIC_EURUS_CMD_GET_WPA_CFG:
> + return "GET_WPA_CFG";
> + case GELIC_EURUS_CMD_GET_RSSI_CFG:
> + return "GET_RSSI";
> + default:
> + break;
> + }
> + return "";
> +};
> +#else
> +static inline const char *cmdstr(enum gelic_eurus_command ix)
> +{
> + return "";
> +}
> +#endif
> +
> +/* synchronously do eurus commands */
> +static void gelic_eurus_sync_cmd_worker(struct work_struct *work)
> +{
> + struct gelic_eurus_cmd *cmd;
> + struct gelic_card *card;
> + struct gelic_wl_info *wl;
> +
> + u64 arg1, arg2;
> +
> + pr_debug("%s: <-\n", __func__);
> + cmd = container_of(work, struct gelic_eurus_cmd, work);
> + BUG_ON(cmd_info[cmd->cmd].pre_arg &&
> + cmd_info[cmd->cmd].post_arg);
> + wl = cmd->wl;
> + card = port_to_card(wl_port(wl));
> +
> + if (cmd_info[cmd->cmd].pre_arg) {
> + arg1 = ps3_mm_phys_to_lpar(__pa(cmd->buffer));
> + arg2 = cmd->buf_size;
> + } else {
> + arg1 = 0;
> + arg2 = 0;
> + }
> + init_completion(&wl->cmd_done_intr);
> + pr_debug("%s: cmd='%s' start\n", __func__, cmdstr(cmd->cmd));
> + cmd->status = lv1_net_control(bus_id(card), dev_id(card),
> + GELIC_LV1_POST_WLAN_CMD,
> + cmd->cmd, arg1, arg2,
> + &cmd->tag, &cmd->size);
> + if (cmd->status) {
> + complete(&cmd->done);
> + pr_info("%s: cmd issue failed\n", __func__);
> + return;
> + }
> +
> + wait_for_completion(&wl->cmd_done_intr);
> +
> + if (cmd_info[cmd->cmd].post_arg) {
> + arg1 = ps3_mm_phys_to_lpar(__pa(cmd->buffer));
> + arg2 = cmd->buf_size;
> + } else {
> + arg1 = 0;
> + arg2 = 0;
> + }
> +
> + cmd->status = lv1_net_control(bus_id(card), dev_id(card),
> + GELIC_LV1_GET_WLAN_CMD_RESULT,
> + cmd->tag, arg1, arg2,
> + &cmd->cmd_status, &cmd->size);
> +#ifdef DEBUG
> + if (cmd->status || cmd->cmd_status) {
> + pr_debug("%s: cmd done tag=%#lx arg1=%#lx, arg2=%#lx\n", __func__,
> + cmd->tag, arg1, arg2);
> + pr_debug("%s: cmd done status=%#x cmd_status=%#lx size=%#lx\n",
> + __func__, cmd->status, cmd->cmd_status, cmd->size);
> + }
> +#endif
> + complete(&cmd->done);
> + pr_debug("%s: cmd='%s' done\n", __func__, cmdstr(cmd->cmd));
> +}
> +
> +static struct gelic_eurus_cmd *gelic_eurus_sync_cmd(struct gelic_wl_info *wl,
> + unsigned int eurus_cmd,
> + void *buffer,
> + unsigned int buf_size)
> +{
> + struct gelic_eurus_cmd *cmd;
> +
> + /* allocate cmd */
> + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
> + if (!cmd)
> + return NULL;
> +
> + /* initialize members */
> + cmd->cmd = eurus_cmd;
> + cmd->buffer = buffer;
> + cmd->buf_size = buf_size;
> + cmd->wl = wl;
> + INIT_WORK(&cmd->work, gelic_eurus_sync_cmd_worker);
> + init_completion(&cmd->done);
> + queue_work(wl->eurus_cmd_queue, &cmd->work);
> +
> + /* wait for command completion */
> + wait_for_completion(&cmd->done);
> +
> + return cmd;
> +}
> +
> +static u32 gelic_wl_get_link(struct net_device *netdev)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
> + u32 ret;
> +
> + pr_debug("%s: <-\n", __func__);
> + down(&wl->assoc_stat_lock);
> + if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
> + ret = 1;
> + else
> + ret = 0;
> + up(&wl->assoc_stat_lock);
> + pr_debug("%s: ->\n", __func__);
> + return ret;
> +}
> +
> +static void gelic_wl_send_iwap_event(struct gelic_wl_info *wl, u8 *bssid)
> +{
> + union iwreq_data data;
> +
> + memset(&data, 0, sizeof(data));
> + if (bssid)
> + memcpy(data.ap_addr.sa_data, bssid, ETH_ALEN);
> + data.ap_addr.sa_family = ARPHRD_ETHER;
> + wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWAP,
> + &data, NULL);
> +}
> +
> +/*
> + * wireless extension handlers and helpers
> + */
> +
> +/* SIOGIWNAME */
> +static int gelic_wl_get_name(struct net_device *dev,
> + struct iw_request_info *info,
> + union iwreq_data *iwreq, char *extra)
> +{
> + strcpy(iwreq->name, "IEEE 802.11bg");
> + return 0;
> +}
> +
> +static void gelic_wl_get_ch_info(struct gelic_wl_info *wl)
> +{
> + struct gelic_card *card = port_to_card(wl_port(wl));
> + u64 ch_info_raw, tmp;
> + int status;
> +
> + if (!test_and_set_bit(GELIC_WL_STAT_CH_INFO, &wl->stat)) {
> + status = lv1_net_control(bus_id(card), dev_id(card),
> + GELIC_LV1_GET_CHANNEL, 0, 0, 0,
> + &ch_info_raw,
> + &tmp);
> + /* some fw versions may return error */
> + if (status) {
> + if (status != LV1_NO_ENTRY)
> + pr_info("%s: available ch unknown\n", __func__);
> + wl->ch_info = 0x07ff;/* 11 ch */
> + } else
> + /* 16 bits of MSB has available channels */
> + wl->ch_info = ch_info_raw >> 48;
> + }
> + return;
> +}
> +
> +/* SIOGIWRANGE */
> +static int gelic_wl_get_range(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *iwreq, char *extra)
> +{
> + struct iw_point *point = &iwreq->data;
> + struct iw_range *range = (struct iw_range *)extra;
> + struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
> + unsigned int i, chs;
> +
> + pr_debug("%s: <-\n", __func__);
> + point->length = sizeof(struct iw_range);
> + memset(range, 0, sizeof(struct iw_range));
> +
> + range->we_version_compiled = WIRELESS_EXT;
> + range->we_version_source = 22;
> +
> + /* available channels and frequencies */
> + gelic_wl_get_ch_info(wl);
> +
> + for (i = 0, chs = 0;
> + i < NUM_CHANNELS && chs < IW_MAX_FREQUENCIES; i++)
> + if (wl->ch_info & (1 << i)) {
> + range->freq[chs].i = i + 1;
> + range->freq[chs].m = channel_freq[i];
> + range->freq[chs].e = 6;
> + chs++;
> + }
> + range->num_frequency = chs;
> + range->old_num_frequency = chs;
> + range->num_channels = chs;
> + range->old_num_channels = chs;
> +
> + /* bitrates */
> + for (i = 0; i < NUM_BITRATES; i++)
> + range->bitrate[i] = bitrate_list[i];
> + range->num_bitrates = i;
> +
> + /* signal levels */
> + range->max_qual.qual = 100; /* relative value */
> + range->max_qual.level = 100;
> + range->avg_qual.qual = 50;
> + range->avg_qual.level = 50;
> + range->sensitivity = 0;
> +
> + /* Event capability */
> + IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
> + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
> + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
> +
> + /* encryption capability */
> + range->enc_capa = IW_ENC_CAPA_WPA |
> + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
> + if (wpa2_capable())
> + range->enc_capa |= IW_ENC_CAPA_WPA2;
> + range->encoding_size[0] = 5; /* 40bit WEP */
> + range->encoding_size[1] = 13; /* 104bit WEP */
> + range->encoding_size[2] = 32; /* WPA-PSK */
> + range->num_encoding_sizes = 3;
> + range->max_encoding_tokens = GELIC_WEP_KEYS;
> +
> + pr_debug("%s: ->\n", __func__);
> + return 0;
> +
> +}
> +
> +/* SIOC{G,S}IWSCAN */
> +static int gelic_wl_set_scan(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *wrqu, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> +
> + return gelic_wl_start_scan(wl, 1);
> +}
> +
> +#define OUI_LEN 3
> +static const u8 rsn_oui[OUI_LEN] = { 0x00, 0x0f, 0xac };
> +static const u8 wpa_oui[OUI_LEN] = { 0x00, 0x50, 0xf2 };
> +
> +/*
> + * synthesize WPA/RSN IE data
> + * See WiFi WPA specification and IEEE 802.11-2007 7.3.2.25
> + * for the format
> + */
> +static size_t gelic_wl_synthesize_ie(u8 *buf,
> + struct gelic_eurus_scan_info *scan)
> +{
> +
> + const u8 *oui_header;
> + u8 *start = buf;
> + int rsn;
> + int ccmp;
> +
> + pr_debug("%s: <- sec=%16x\n", __func__, scan->security);
> + switch (be16_to_cpu(scan->security) & GELIC_EURUS_SCAN_SEC_MASK) {
> + case GELIC_EURUS_SCAN_SEC_WPA:
> + rsn = 0;
> + break;
> + case GELIC_EURUS_SCAN_SEC_WPA2:
> + rsn = 1;
> + break;
> + default:
> + /* WEP or none. No IE returned */
> + return 0;
> + }
> +
> + switch (be16_to_cpu(scan->security) & GELIC_EURUS_SCAN_SEC_WPA_MASK) {
> + case GELIC_EURUS_SCAN_SEC_WPA_TKIP:
> + ccmp = 0;
> + break;
> + case GELIC_EURUS_SCAN_SEC_WPA_AES:
> + ccmp = 1;
> + break;
> + default:
> + if (rsn) {
> + ccmp = 1;
> + pr_info("%s: no cipher info. defaulted to CCMP\n",
> + __func__);
> + } else {
> + ccmp = 0;
> + pr_info("%s: no cipher info. defaulted to TKIP\n",
> + __func__);
> + }
> + }
> +
> + if (rsn)
> + oui_header = rsn_oui;
> + else
> + oui_header = wpa_oui;
> +
> + /* element id */
> + if (rsn)
> + *buf++ = MFIE_TYPE_RSN;
> + else
> + *buf++ = MFIE_TYPE_GENERIC;
> +
> + /* length filed; set later */
> + buf++;
> +
> + /* wpa special header */
> + if (!rsn) {
> + memcpy(buf, wpa_oui, OUI_LEN);
> + buf += OUI_LEN;
> + *buf++ = 0x01;
> + }
> +
> + /* version */
> + *buf++ = 0x01; /* version 1.0 */
> + *buf++ = 0x00;
> +
> + /* group cipher */
> + memcpy(buf, oui_header, OUI_LEN);
> + buf += OUI_LEN;
> +
> + if (ccmp)
> + *buf++ = 0x04; /* CCMP */
> + else
> + *buf++ = 0x02; /* TKIP */
> +
> + /* pairwise key count always 1 */
> + *buf++ = 0x01;
> + *buf++ = 0x00;
> +
> + /* pairwise key suit */
> + memcpy(buf, oui_header, OUI_LEN);
> + buf += OUI_LEN;
> + if (ccmp)
> + *buf++ = 0x04; /* CCMP */
> + else
> + *buf++ = 0x02; /* TKIP */
> +
> + /* AKM count is 1 */
> + *buf++ = 0x01;
> + *buf++ = 0x00;
> +
> + /* AKM suite is assumed as PSK*/
> + memcpy(buf, oui_header, OUI_LEN);
> + buf += OUI_LEN;
> + *buf++ = 0x02; /* PSK */
> +
> + /* RSN capabilities is 0 */
> + *buf++ = 0x00;
> + *buf++ = 0x00;
> +
> + /* set length field */
> + start[1] = (buf - start - 2);
> +
> + pr_debug("%s: ->\n", __func__);
> + return (buf - start);
> +}
> +
> +struct ie_item {
> + u8 *data;
> + u8 len;
> +};
> +
> +struct ie_info {
> + struct ie_item wpa;
> + struct ie_item rsn;
> +};
> +
> +static void gelic_wl_parse_ie(u8 *data, size_t len,
> + struct ie_info *ie_info)
> +{
> + size_t data_left = len;
> + u8 *pos = data;
> + u8 item_len;
> + u8 item_id;
> +
> + pr_debug("%s: data=%p len=%ld \n", __func__,
> + data, len);
> + memset(ie_info, 0, sizeof(struct ie_info));
> +
> + while (0 < data_left) {
> + item_id = *pos++;
> + item_len = *pos++;
> +
> + switch (item_id) {
> + case MFIE_TYPE_GENERIC:
> + if (!memcmp(pos, wpa_oui, OUI_LEN) &&
> + pos[OUI_LEN] == 0x01) {
> + ie_info->wpa.data = pos - 2;
> + ie_info->wpa.len = item_len + 2;
> + }
> + break;
> + case MFIE_TYPE_RSN:
> + ie_info->rsn.data = pos - 2;
> + /* length includes the header */
> + ie_info->rsn.len = item_len + 2;
> + break;
> + default:
> + pr_debug("%s: ignore %#x,%d\n", __func__,
> + item_id, item_len);
> + break;
> + }
> + pos += item_len;
> + data_left -= item_len + 2;
> + }
> + pr_debug("%s: wpa=%p,%d wpa2=%p,%d\n", __func__,
> + ie_info->wpa.data, ie_info->wpa.len,
> + ie_info->rsn.data, ie_info->rsn.len);
> +}
> +
> +
> +/*
> + * translate the scan informations from hypervisor to a
> + * independent format
> + */
> +static char *gelic_wl_translate_scan(struct net_device *netdev,
> + char *ev,
> + char *stop,
> + struct gelic_wl_scan_info *network)
> +{
> + struct iw_event iwe;
> + struct gelic_eurus_scan_info *scan = network->hwinfo;
> + char *tmp;
> + u8 rate;
> + unsigned int i, j, len;
> + u8 buf[MAX_WPA_IE_LEN];
> +
> + pr_debug("%s: <-\n", __func__);
> +
> + /* first entry should be AP's mac address */
> + iwe.cmd = SIOCGIWAP;
> + iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
> + memcpy(iwe.u.ap_addr.sa_data, &scan->bssid[2], ETH_ALEN);
> + ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_ADDR_LEN);
> +
> + /* ESSID */
> + iwe.cmd = SIOCGIWESSID;
> + iwe.u.data.flags = 1;
> + iwe.u.data.length = strnlen(scan->essid, 32);
> + ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid);
> +
> + /* FREQUENCY */
> + iwe.cmd = SIOCGIWFREQ;
> + iwe.u.freq.m = be16_to_cpu(scan->channel);
> + iwe.u.freq.e = 0; /* table value in MHz */
> + iwe.u.freq.i = 0;
> + ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_FREQ_LEN);
> +
> + /* RATES */
> + iwe.cmd = SIOCGIWRATE;
> + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
> + /* to stuff multiple values in one event */
> + tmp = ev + IW_EV_LCP_LEN;
> + /* put them in ascendant order (older is first) */
> + i = 0;
> + j = 0;
> + pr_debug("%s: rates=%d rate=%d\n", __func__,
> + network->rate_len, network->rate_ext_len);
> + while (i < network->rate_len) {
> + if (j < network->rate_ext_len &&
> + ((scan->ext_rate[j] & 0x7f) < (scan->rate[i] & 0x7f)))
> + rate = scan->ext_rate[j++] & 0x7f;
> + else
> + rate = scan->rate[i++] & 0x7f;
> + iwe.u.bitrate.value = rate * 500000; /* 500kbps unit */
> + tmp = iwe_stream_add_value(ev, tmp, stop, &iwe,
> + IW_EV_PARAM_LEN);
> + }
> + while (j < network->rate_ext_len) {
> + iwe.u.bitrate.value = (scan->ext_rate[j++] & 0x7f) * 500000;
> + tmp = iwe_stream_add_value(ev, tmp, stop, &iwe,
> + IW_EV_PARAM_LEN);
> + }
> + /* Check if we added any rate */
> + if (IW_EV_LCP_LEN < (tmp - ev))
> + ev = tmp;
> +
> + /* ENCODE */
> + iwe.cmd = SIOCGIWENCODE;
> + if (be16_to_cpu(scan->capability) & WLAN_CAPABILITY_PRIVACY)
> + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
> + else
> + iwe.u.data.flags = IW_ENCODE_DISABLED;
> + iwe.u.data.length = 0;
> + ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid);
> +
> + /* MODE */
> + iwe.cmd = SIOCGIWMODE;
> + if (be16_to_cpu(scan->capability) &
> + (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
> + if (be16_to_cpu(scan->capability) & WLAN_CAPABILITY_ESS)
> + iwe.u.mode = IW_MODE_MASTER;
> + else
> + iwe.u.mode = IW_MODE_ADHOC;
> + ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_UINT_LEN);
> + }
> +
> + /* QUAL */
> + iwe.cmd = IWEVQUAL;
> + iwe.u.qual.updated = IW_QUAL_ALL_UPDATED |
> + IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID;
> + iwe.u.qual.level = be16_to_cpu(scan->rssi);
> + iwe.u.qual.qual = be16_to_cpu(scan->rssi);
> + iwe.u.qual.noise = 0;
> + ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_QUAL_LEN);
> +
> + /* RSN */
> + memset(&iwe, 0, sizeof(iwe));
> + if (be16_to_cpu(scan->size) <= sizeof(*scan)) {
> + /* If wpa[2] capable station, synthesize IE and put it */
> + len = gelic_wl_synthesize_ie(buf, scan);
> + if (len) {
> + iwe.cmd = IWEVGENIE;
> + iwe.u.data.length = len;
> + ev = iwe_stream_add_point(ev, stop, &iwe, buf);
> + }
> + } else {
> + /* this scan info has IE data */
> + struct ie_info ie_info;
> + size_t data_len;
> +
> + data_len = be16_to_cpu(scan->size) - sizeof(*scan);
> +
> + gelic_wl_parse_ie(scan->elements, data_len, &ie_info);
> +
> + if (ie_info.wpa.len && (ie_info.wpa.len <= sizeof(buf))) {
> + memcpy(buf, ie_info.wpa.data, ie_info.wpa.len);
> + iwe.cmd = IWEVGENIE;
> + iwe.u.data.length = ie_info.wpa.len;
> + ev = iwe_stream_add_point(ev, stop, &iwe, buf);
> + }
> +
> + if (ie_info.rsn.len && (ie_info.rsn.len <= sizeof(buf))) {
> + memset(&iwe, 0, sizeof(iwe));
> + memcpy(buf, ie_info.rsn.data, ie_info.rsn.len);
> + iwe.cmd = IWEVGENIE;
> + iwe.u.data.length = ie_info.rsn.len;
> + ev = iwe_stream_add_point(ev, stop, &iwe, buf);
> + }
> + }
> +
> + pr_debug("%s: ->\n", __func__);
> + return ev;
> +}
> +
> +
> +static int gelic_wl_get_scan(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *wrqu, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + struct gelic_wl_scan_info *scan_info;
> + char *ev = extra;
> + char *stop = ev + wrqu->data.length;
> + int ret = 0;
> + unsigned long this_time = jiffies;
> +
> + pr_debug("%s: <-\n", __func__);
> + if (down_interruptible(&wl->scan_lock))
> + return -EAGAIN;
> +
> + switch (wl->scan_stat) {
> + case GELIC_WL_SCAN_STAT_SCANNING:
> + /* If a scan in progress, caller should call me again */
> + ret = -EAGAIN;
> + goto out;
> + break;
> +
> + case GELIC_WL_SCAN_STAT_INIT:
> + /* last scan request failed or never issued */
> + ret = -ENODEV;
> + goto out;
> + break;
> + case GELIC_WL_SCAN_STAT_GOT_LIST:
> + /* ok, use current list */
> + break;
> + }
> +
> + list_for_each_entry(scan_info, &wl->network_list, list) {
> + if (wl->scan_age == 0 ||
> + time_after(scan_info->last_scanned + wl->scan_age,
> + this_time))
> + ev = gelic_wl_translate_scan(netdev, ev, stop,
> + scan_info);
> + else
> + pr_debug("%s:entry too old\n", __func__);
> +
> + if (stop - ev <= IW_EV_ADDR_LEN) {
> + ret = -E2BIG;
> + goto out;
> + }
> + }
> +
> + wrqu->data.length = ev - extra;
> + wrqu->data.flags = 0;
> +out:
> + up(&wl->scan_lock);
> + pr_debug("%s: -> %d %d\n", __func__, ret, wrqu->data.length);
> + return ret;
> +}
> +
> +#ifdef DEBUG
> +static void scan_list_dump(struct gelic_wl_info *wl)
> +{
> + struct gelic_wl_scan_info *scan_info;
> + int i;
> + DECLARE_MAC_BUF(mac);
> +
> + i = 0;
> + list_for_each_entry(scan_info, &wl->network_list, list) {
> + pr_debug("%s: item %d\n", __func__, i++);
> + pr_debug("valid=%d eurusindex=%d last=%lx\n",
> + scan_info->valid, scan_info->eurus_index,
> + scan_info->last_scanned);
> + pr_debug("r_len=%d r_ext_len=%d essid_len=%d\n",
> + scan_info->rate_len, scan_info->rate_ext_len,
> + scan_info->essid_len);
> + /* -- */
> + pr_debug("bssid=%s\n",
> + print_mac(mac, &scan_info->hwinfo->bssid[2]));
> + pr_debug("essid=%s\n", scan_info->hwinfo->essid);
> + }
> +}
> +#endif
> +
> +static int gelic_wl_set_auth(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct iw_param *param = &data->param;
> + struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
> + unsigned long irqflag;
> + int ret = 0;
> +
> + pr_debug("%s: <- %d\n", __func__, param->flags & IW_AUTH_INDEX);
> + spin_lock_irqsave(&wl->lock, irqflag);
> + switch (param->flags & IW_AUTH_INDEX) {
> + case IW_AUTH_WPA_VERSION:
> + if (param->value & IW_AUTH_WPA_VERSION_DISABLED) {
> + pr_debug("%s: NO WPA selected\n", __func__);
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
> + wl->group_cipher_method = GELIC_WL_CIPHER_WEP;
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_WEP;
> + }
> + if (param->value & IW_AUTH_WPA_VERSION_WPA) {
> + pr_debug("%s: WPA version 1 selected\n", __func__);
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA;
> + wl->group_cipher_method = GELIC_WL_CIPHER_TKIP;
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP;
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN;
> + }
> + if (param->value & IW_AUTH_WPA_VERSION_WPA2) {
> + /*
> + * As the hypervisor may not tell the cipher
> + * information of the AP if it is WPA2,
> + * you will not decide suitable cipher from
> + * its beacon.
> + * You should have knowledge about the AP's
> + * cipher infomation in other method prior to
> + * the association.
> + */
> + if (!precise_ie())
> + pr_info("%s: WPA2 may not work\n", __func__);
> + if (wpa2_capable()) {
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA2;
> + wl->group_cipher_method = GELIC_WL_CIPHER_AES;
> + wl->pairwise_cipher_method =
> + GELIC_WL_CIPHER_AES;
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN;
> + } else
> + ret = -EINVAL;
> + }
> + break;
> +
> + case IW_AUTH_CIPHER_PAIRWISE:
> + if (param->value &
> + (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) {
> + pr_debug("%s: WEP selected\n", __func__);
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_WEP;
> + }
> + if (param->value & IW_AUTH_CIPHER_TKIP) {
> + pr_debug("%s: TKIP selected\n", __func__);
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP;
> + }
> + if (param->value & IW_AUTH_CIPHER_CCMP) {
> + pr_debug("%s: CCMP selected\n", __func__);
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_AES;
> + }
> + if (param->value & IW_AUTH_CIPHER_NONE) {
> + pr_debug("%s: no auth selected\n", __func__);
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_NONE;
> + }
> + break;
> + case IW_AUTH_CIPHER_GROUP:
> + if (param->value &
> + (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) {
> + pr_debug("%s: WEP selected\n", __func__);
> + wl->group_cipher_method = GELIC_WL_CIPHER_WEP;
> + }
> + if (param->value & IW_AUTH_CIPHER_TKIP) {
> + pr_debug("%s: TKIP selected\n", __func__);
> + wl->group_cipher_method = GELIC_WL_CIPHER_TKIP;
> + }
> + if (param->value & IW_AUTH_CIPHER_CCMP) {
> + pr_debug("%s: CCMP selected\n", __func__);
> + wl->group_cipher_method = GELIC_WL_CIPHER_AES;
> + }
> + if (param->value & IW_AUTH_CIPHER_NONE) {
> + pr_debug("%s: no auth selected\n", __func__);
> + wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
> + }
> + break;
> + case IW_AUTH_80211_AUTH_ALG:
> + if (param->value & IW_AUTH_ALG_SHARED_KEY) {
> + pr_debug("%s: shared key specified\n", __func__);
> + wl->auth_method = GELIC_EURUS_AUTH_SHARED;
> + } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
> + pr_debug("%s: open system specified\n", __func__);
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN;
> + } else
> + ret = -EINVAL;
> + break;
> +
> + case IW_AUTH_WPA_ENABLED:
> + if (param->value) {
> + pr_debug("%s: WPA enabled\n", __func__);
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA;
> + } else {
> + pr_debug("%s: WPA disabled\n", __func__);
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
> + }
> + break;
> +
> + case IW_AUTH_KEY_MGMT:
> + if (param->value & IW_AUTH_KEY_MGMT_PSK)
> + break;
> + /* intentionally fall through */
> + default:
> + ret = -EOPNOTSUPP;
> + break;
> + };
> +
> + if (!ret)
> + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
> +
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s: -> %d\n", __func__, ret);
> + return ret;
> +}
> +
> +static int gelic_wl_get_auth(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *iwreq, char *extra)
> +{
> + struct iw_param *param = &iwreq->param;
> + struct gelic_wl_info *wl = port_wl(netdev_port(netdev));
> + unsigned long irqflag;
> + int ret = 0;
> +
> + pr_debug("%s: <- %d\n", __func__, param->flags & IW_AUTH_INDEX);
> + spin_lock_irqsave(&wl->lock, irqflag);
> + switch (param->flags & IW_AUTH_INDEX) {
> + case IW_AUTH_WPA_VERSION:
> + switch (wl->wpa_level) {
> + case GELIC_WL_WPA_LEVEL_WPA:
> + param->value |= IW_AUTH_WPA_VERSION_WPA;
> + break;
> + case GELIC_WL_WPA_LEVEL_WPA2:
> + param->value |= IW_AUTH_WPA_VERSION_WPA2;
> + break;
> + default:
> + param->value |= IW_AUTH_WPA_VERSION_DISABLED;
> + }
> + break;
> +
> + case IW_AUTH_80211_AUTH_ALG:
> + if (wl->auth_method == GELIC_EURUS_AUTH_SHARED)
> + param->value = IW_AUTH_ALG_SHARED_KEY;
> + else if (wl->auth_method == GELIC_EURUS_AUTH_OPEN)
> + param->value = IW_AUTH_ALG_OPEN_SYSTEM;
> + break;
> +
> + case IW_AUTH_WPA_ENABLED:
> + switch (wl->wpa_level) {
> + case GELIC_WL_WPA_LEVEL_WPA:
> + case GELIC_WL_WPA_LEVEL_WPA2:
> + param->value = 1;
> + break;
> + default:
> + param->value = 0;
> + break;
> + }
> + break;
> + default:
> + ret = -EOPNOTSUPP;
> + }
> +
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s: -> %d\n", __func__, ret);
> + return ret;
> +}
> +
> +/* SIOC{S,G}IWESSID */
> +static int gelic_wl_set_essid(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + unsigned long irqflag;
> +
> + pr_debug("%s: <- l=%d f=%d\n", __func__,
> + data->essid.length, data->essid.flags);
> + if (IW_ESSID_MAX_SIZE < data->essid.length)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (data->essid.flags) {
> + wl->essid_len = data->essid.length;
> + memcpy(wl->essid, extra, wl->essid_len);
> + pr_debug("%s: essid = '%s'\n", __func__, extra);
> + set_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat);
> + } else {
> + pr_debug("%s: ESSID any \n", __func__);
> + clear_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat);
> + }
> + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> +
> +
> + gelic_wl_try_associate(netdev); /* FIXME */
> + pr_debug("%s: -> \n", __func__);
> + return 0;
> +}
> +
> +static int gelic_wl_get_essid(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + unsigned long irqflag;
> +
> + pr_debug("%s: <- \n", __func__);
> + down(&wl->assoc_stat_lock);
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat) ||
> + wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) {
> + memcpy(extra, wl->essid, wl->essid_len);
> + data->essid.length = wl->essid_len;
> + data->essid.flags = 1;
> + } else
> + data->essid.flags = 0;
> +
> + up(&wl->assoc_stat_lock);
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s: -> len=%d \n", __func__, data->essid.length);
> +
> + return 0;
> +}
> +
> +/* SIO{S,G}IWENCODE */
> +static int gelic_wl_set_encode(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + struct iw_point *enc = &data->encoding;
> + __u16 flags;
> + unsigned int irqflag;
> + int key_index, index_specified;
> + int ret = 0;
> +
> + pr_debug("%s: <- \n", __func__);
> + flags = enc->flags & IW_ENCODE_FLAGS;
> + key_index = enc->flags & IW_ENCODE_INDEX;
> +
> + pr_debug("%s: key_index = %d\n", __func__, key_index);
> + pr_debug("%s: key_len = %d\n", __func__, enc->length);
> + pr_debug("%s: flag=%x\n", __func__, enc->flags & IW_ENCODE_FLAGS);
> +
> + if (GELIC_WEP_KEYS < key_index)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (key_index) {
> + index_specified = 1;
> + key_index--;
> + } else {
> + index_specified = 0;
> + key_index = wl->current_key;
> + }
> +
> + if (flags & IW_ENCODE_NOKEY) {
> + /* if just IW_ENCODE_NOKEY, change current key index */
> + if (!flags && index_specified) {
> + wl->current_key = key_index;
> + goto done;
> + }
> +
> + if (flags & IW_ENCODE_DISABLED) {
> + if (!index_specified) {
> + /* disable encryption */
> + wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
> + wl->pairwise_cipher_method =
> + GELIC_WL_CIPHER_NONE;
> + /* invalidate all key */
> + wl->key_enabled = 0;
> + } else
> + clear_bit(key_index, &wl->key_enabled);
> + }
> +
> + if (flags & IW_ENCODE_OPEN)
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN;
> + if (flags & IW_ENCODE_RESTRICTED) {
> + pr_info("%s: shared key mode enabled\n", __func__);
> + wl->auth_method = GELIC_EURUS_AUTH_SHARED;
> + }
> + } else {
> + if (IW_ENCODING_TOKEN_MAX < enc->length) {
> + ret = -EINVAL;
> + goto done;
> + }
> + wl->key_len[key_index] = enc->length;
> + memcpy(wl->key[key_index], extra, enc->length);
> + set_bit(key_index, &wl->key_enabled);
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_WEP;
> + wl->group_cipher_method = GELIC_WL_CIPHER_WEP;
> + }
> + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
> +done:
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s: -> \n", __func__);
> + return ret;
> +}
> +
> +static int gelic_wl_get_encode(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + struct iw_point *enc = &data->encoding;
> + unsigned int irqflag;
> + unsigned int key_index, index_specified;
> + int ret = 0;
> +
> + pr_debug("%s: <- \n", __func__);
> + key_index = enc->flags & IW_ENCODE_INDEX;
> + pr_debug("%s: flag=%#x point=%p len=%d extra=%p\n", __func__,
> + enc->flags, enc->pointer, enc->length, extra);
> + if (GELIC_WEP_KEYS < key_index)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (key_index) {
> + index_specified = 1;
> + key_index--;
> + } else {
> + index_specified = 0;
> + key_index = wl->current_key;
> + }
> +
> + if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
> + switch (wl->auth_method) {
> + case GELIC_EURUS_AUTH_OPEN:
> + enc->flags = IW_ENCODE_OPEN;
> + break;
> + case GELIC_EURUS_AUTH_SHARED:
> + enc->flags = IW_ENCODE_RESTRICTED;
> + break;
> + }
> + } else
> + enc->flags = IW_ENCODE_DISABLED;
> +
> + if (test_bit(key_index, &wl->key_enabled)) {
> + if (enc->length < wl->key_len[key_index]) {
> + ret = -EINVAL;
> + goto done;
> + }
> + enc->length = wl->key_len[key_index];
> + memcpy(extra, wl->key[key_index], wl->key_len[key_index]);
> + } else {
> + enc->length = 0;
> + enc->flags |= IW_ENCODE_NOKEY;
> + }
> + enc->flags |= key_index + 1;
> + pr_debug("%s: -> flag=%x len=%d\n", __func__,
> + enc->flags, enc->length);
> +
> +done:
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + return ret;
> +}
> +
> +/* SIOC{S,G}IWAP */
> +static int gelic_wl_set_ap(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + unsigned long irqflag;
> +
> + pr_debug("%s: <-\n", __func__);
> + if (data->ap_addr.sa_family != ARPHRD_ETHER)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (is_valid_ether_addr(data->ap_addr.sa_data)) {
> + memcpy(wl->bssid, data->ap_addr.sa_data,
> + ETH_ALEN);
> + set_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat);
> + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
> + pr_debug("%s: bss=%02x:%02x:%02x:%02x:%02x:%02x\n",
> + __func__,
> + wl->bssid[0], wl->bssid[1],
> + wl->bssid[2], wl->bssid[3],
> + wl->bssid[4], wl->bssid[5]);
> + } else {
> + pr_debug("%s: clear bssid\n", __func__);
> + clear_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat);
> + memset(wl->bssid, 0, ETH_ALEN);
> + }
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s: ->\n", __func__);
> + return 0;
> +}
> +
> +static int gelic_wl_get_ap(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + unsigned long irqflag;
> +
> + pr_debug("%s: <-\n", __func__);
> + down(&wl->assoc_stat_lock);
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) {
> + data->ap_addr.sa_family = ARPHRD_ETHER;
> + memcpy(data->ap_addr.sa_data, wl->active_bssid,
> + ETH_ALEN);
> + } else
> + memset(data->ap_addr.sa_data, 0, ETH_ALEN);
> +
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + up(&wl->assoc_stat_lock);
> + pr_debug("%s: ->\n", __func__);
> + return 0;
> +}
> +
> +/* SIOC{S,G}IWENCODEEXT */
> +static int gelic_wl_set_encodeext(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + struct iw_point *enc = &data->encoding;
> + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
> + __u16 alg;
> + __u16 flags;
> + unsigned int irqflag;
> + int key_index;
> + int ret = 0;
> +
> + pr_debug("%s: <- \n", __func__);
> + flags = enc->flags & IW_ENCODE_FLAGS;
> + alg = ext->alg;
> + key_index = enc->flags & IW_ENCODE_INDEX;
> +
> + pr_debug("%s: key_index = %d\n", __func__, key_index);
> + pr_debug("%s: key_len = %d\n", __func__, enc->length);
> + pr_debug("%s: flag=%x\n", __func__, enc->flags & IW_ENCODE_FLAGS);
> + pr_debug("%s: ext_flag=%x\n", __func__, ext->ext_flags);
> + pr_debug("%s: ext_key_len=%x\n", __func__, ext->key_len);
> +
> + if (GELIC_WEP_KEYS < key_index)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (key_index)
> + key_index--;
> + else
> + key_index = wl->current_key;
> +
> + if (!enc->length && (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
> + /* reques to change default key index */
> + pr_debug("%s: request to change default key to %d\n",
> + __func__, key_index);
> + wl->current_key = key_index;
> + goto done;
> + }
> +
> + if (alg == IW_ENCODE_ALG_NONE || (flags & IW_ENCODE_DISABLED)) {
> + pr_debug("%s: alg disabled\n", __func__);
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
> + wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_NONE;
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN; /* should be open */
> + } else if (alg == IW_ENCODE_ALG_WEP) {
> + pr_debug("%s: WEP requested\n", __func__);
> + if (flags & IW_ENCODE_OPEN) {
> + pr_debug("%s: open key mode\n", __func__);
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN;
> + }
> + if (flags & IW_ENCODE_RESTRICTED) {
> + pr_debug("%s: shared key mode\n", __func__);
> + wl->auth_method = GELIC_EURUS_AUTH_SHARED;
> + }
> + if (IW_ENCODING_TOKEN_MAX < ext->key_len) {
> + pr_info("%s: key is too long %d\n", __func__,
> + ext->key_len);
> + ret = -EINVAL;
> + goto done;
> + }
> + /* OK, update the key */
> + wl->key_len[key_index] = ext->key_len;
> + memset(wl->key[key_index], 0, IW_ENCODING_TOKEN_MAX);
> + memcpy(wl->key[key_index], ext->key, ext->key_len);
> + set_bit(key_index, &wl->key_enabled);
> + /* remember wep info changed */
> + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
> + } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
> + pr_debug("%s: TKIP/CCMP requested alg=%d\n", __func__, alg);
> + /* check key length */
> + if (IW_ENCODING_TOKEN_MAX < ext->key_len) {
> + pr_info("%s: key is too long %d\n", __func__,
> + ext->key_len);
> + ret = -EINVAL;
> + goto done;
> + }
> + if (alg == IW_ENCODE_ALG_CCMP) {
> + pr_debug("%s: AES selected\n", __func__);
> + wl->group_cipher_method = GELIC_WL_CIPHER_AES;
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_AES;
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA2;
> + } else {
> + pr_debug("%s: TKIP selected, WPA forced\n", __func__);
> + wl->group_cipher_method = GELIC_WL_CIPHER_TKIP;
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP;
> + /* FIXME: how do we do if WPA2 + TKIP? */
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA;
> + }
> + if (flags & IW_ENCODE_RESTRICTED)
> + BUG();
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN;
> + /* We should use same key for both and unicast */
> + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
> + pr_debug("%s: group key \n", __func__);
> + else
> + pr_debug("%s: unicast key \n", __func__);
> + /* OK, update the key */
> + wl->key_len[key_index] = ext->key_len;
> + memset(wl->key[key_index], 0, IW_ENCODING_TOKEN_MAX);
> + memcpy(wl->key[key_index], ext->key, ext->key_len);
> + set_bit(key_index, &wl->key_enabled);
> + /* remember info changed */
> + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
> + }
> +done:
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s: -> \n", __func__);
> + return ret;
> +}
> +
> +static int gelic_wl_get_encodeext(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + struct iw_point *enc = &data->encoding;
> + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
> + unsigned int irqflag;
> + int key_index;
> + int ret = 0;
> + int max_key_len;
> +
> + pr_debug("%s: <- \n", __func__);
> +
> + max_key_len = enc->length - sizeof(struct iw_encode_ext);
> + if (max_key_len < 0)
> + return -EINVAL;
> + key_index = enc->flags & IW_ENCODE_INDEX;
> +
> + pr_debug("%s: key_index = %d\n", __func__, key_index);
> + pr_debug("%s: key_len = %d\n", __func__, enc->length);
> + pr_debug("%s: flag=%x\n", __func__, enc->flags & IW_ENCODE_FLAGS);
> +
> + if (GELIC_WEP_KEYS < key_index)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (key_index)
> + key_index--;
> + else
> + key_index = wl->current_key;
> +
> + memset(ext, 0, sizeof(struct iw_encode_ext));
> + switch (wl->group_cipher_method) {
> + case GELIC_WL_CIPHER_WEP:
> + ext->alg = IW_ENCODE_ALG_WEP;
> + enc->flags |= IW_ENCODE_ENABLED;
> + break;
> + case GELIC_WL_CIPHER_TKIP:
> + ext->alg = IW_ENCODE_ALG_TKIP;
> + enc->flags |= IW_ENCODE_ENABLED;
> + break;
> + case GELIC_WL_CIPHER_AES:
> + ext->alg = IW_ENCODE_ALG_CCMP;
> + enc->flags |= IW_ENCODE_ENABLED;
> + break;
> + case GELIC_WL_CIPHER_NONE:
> + default:
> + ext->alg = IW_ENCODE_ALG_NONE;
> + enc->flags |= IW_ENCODE_NOKEY;
> + break;
> + }
> +
> + if (!(enc->flags & IW_ENCODE_NOKEY)) {
> + if (max_key_len < wl->key_len[key_index]) {
> + ret = -E2BIG;
> + goto out;
> + }
> + if (test_bit(key_index, &wl->key_enabled))
> + memcpy(ext->key, wl->key[key_index],
> + wl->key_len[key_index]);
> + else
> + pr_debug("%s: disabled key requested ix=%d\n",
> + __func__, key_index);
> + }
> +out:
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s: -> \n", __func__);
> + return ret;
> +}
> +/* SIOC{S,G}IWMODE */
> +static int gelic_wl_set_mode(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + __u32 mode = data->mode;
> + int ret;
> +
> + pr_debug("%s: <- \n", __func__);
> + if (mode == IW_MODE_INFRA)
> + ret = 0;
> + else
> + ret = -EOPNOTSUPP;
> + pr_debug("%s: -> %d\n", __func__, ret);
> + return ret;
> +}
> +
> +static int gelic_wl_get_mode(struct net_device *netdev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + __u32 *mode = &data->mode;
> + pr_debug("%s: <- \n", __func__);
> + *mode = IW_MODE_INFRA;
> + pr_debug("%s: ->\n", __func__);
> + return 0;
> +}
> +
> +/* SIOCIWFIRSTPRIV */
> +static int hex2bin(u8 *str, u8 *bin, unsigned int len)
> +{
> + unsigned int i;
> + static unsigned char *hex = "0123456789ABCDEF";
> + unsigned char *p, *q;
> + u8 tmp;
> +
> + if (len != WPA_PSK_LEN * 2)
> + return -EINVAL;
> +
> + for (i = 0; i < WPA_PSK_LEN * 2; i += 2) {
> + p = strchr(hex, toupper(str[i]));
> + q = strchr(hex, toupper(str[i + 1]));
> + if (!p || !q) {
> + pr_info("%s: unconvertible PSK digit=%d\n",
> + __func__, i);
> + return -EINVAL;
> + }
> + tmp = ((p - hex) << 4) + (q - hex);
> + *bin++ = tmp;
> + }
> + return 0;
> +};
> +
> +static int gelic_wl_priv_set_psk(struct net_device *net_dev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev));
> + unsigned int len;
> + unsigned int irqflag;
> + int ret = 0;
> +
> + pr_debug("%s:<- len=%d\n", __func__, data->data.length);
> + len = data->data.length - 1;
> + if (len <= 2)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + if (extra[0] == '"' && extra[len - 1] == '"') {
> + pr_debug("%s: passphrase mode\n", __func__);
> + /* pass phrase */
> + if (GELIC_WL_EURUS_PSK_MAX_LEN < (len - 2)) {
> + pr_info("%s: passphrase too long\n", __func__);
> + ret = -E2BIG;
> + goto out;
> + }
> + memset(wl->psk, 0, sizeof(wl->psk));
> + wl->psk_len = len - 2;
> + memcpy(wl->psk, &(extra[1]), wl->psk_len);
> + wl->psk_type = GELIC_EURUS_WPA_PSK_PASSPHRASE;
> + } else {
> + ret = hex2bin(extra, wl->psk, len);
> + if (ret)
> + goto out;
> + wl->psk_len = WPA_PSK_LEN;
> + wl->psk_type = GELIC_EURUS_WPA_PSK_BIN;
> + }
> + set_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat);
> +out:
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s:->\n", __func__);
> + return ret;
> +}
> +
> +static int gelic_wl_priv_get_psk(struct net_device *net_dev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev));
> + char *p;
> + unsigned int irqflag;
> + unsigned int i;
> +
> + pr_debug("%s:<-\n", __func__);
> + if (!capable(CAP_NET_ADMIN))
> + return -EPERM;
> +
> + spin_lock_irqsave(&wl->lock, irqflag);
> + p = extra;
> + if (test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat)) {
> + if (wl->psk_type == GELIC_EURUS_WPA_PSK_BIN) {
> + for (i = 0; i < wl->psk_len; i++) {
> + sprintf(p, "%02xu", wl->psk[i]);
> + p += 2;
> + }
> + *p = '\0';
> + data->data.length = wl->psk_len * 2;
> + } else {
> + *p++ = '"';
> + memcpy(p, wl->psk, wl->psk_len);
> + p += wl->psk_len;
> + *p++ = '"';
> + *p = '\0';
> + data->data.length = wl->psk_len + 2;
> + }
> + } else
> + /* no psk set */
> + data->data.length = 0;
> + spin_unlock_irqrestore(&wl->lock, irqflag);
> + pr_debug("%s:-> %d\n", __func__, data->data.length);
> + return 0;
> +}
> +
> +/* SIOCGIWNICKN */
> +static int gelic_wl_get_nick(struct net_device *net_dev,
> + struct iw_request_info *info,
> + union iwreq_data *data, char *extra)
> +{
> + strcpy(extra, "gelic_wl");
> + data->data.length = strlen(extra);
> + data->data.flags = 1;
> + return 0;
> +}
> +
> +
> +/* --- */
> +
> +static struct iw_statistics *gelic_wl_get_wireless_stats(
> + struct net_device *netdev)
> +{
> +
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + struct gelic_eurus_cmd *cmd;
> + struct iw_statistics *is;
> + struct gelic_eurus_rssi_info *rssi;
> +
> + pr_debug("%s: <-\n", __func__);
> +
> + is = &wl->iwstat;
> + memset(is, 0, sizeof(*is));
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_RSSI_CFG,
> + wl->buf, sizeof(*rssi));
> + if (cmd && !cmd->status && !cmd->cmd_status) {
> + rssi = wl->buf;
> + is->qual.level = be16_to_cpu(rssi->rssi);
> + is->qual.updated = IW_QUAL_LEVEL_UPDATED |
> + IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID;
> + } else
> + /* not associated */
> + is->qual.updated = IW_QUAL_ALL_INVALID;
> +
> + kfree(cmd);
> + pr_debug("%s: ->\n", __func__);
> + return is;
> +}
> +
> +/*
> + * scanning helpers
> + */
> +static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan)
> +{
> + struct gelic_eurus_cmd *cmd;
> + int ret = 0;
> +
> + pr_debug("%s: <- always=%d\n", __func__, always_scan);
> + if (down_interruptible(&wl->scan_lock))
> + return -ERESTARTSYS;
> +
> + /*
> + * If already a scan in progress, do not trigger more
> + */
> + if (wl->scan_stat == GELIC_WL_SCAN_STAT_SCANNING) {
> + pr_debug("%s: scanning now\n", __func__);
> + goto out;
> + }
> +
> + init_completion(&wl->scan_done);
> + /*
> + * If we have already a bss list, don't try to get new
> + */
> + if (!always_scan && wl->scan_stat == GELIC_WL_SCAN_STAT_GOT_LIST) {
> + pr_debug("%s: already has the list\n", __func__);
> + complete(&wl->scan_done);
> + goto out;
> + }
> + /*
> + * issue start scan request
> + */
> + wl->scan_stat = GELIC_WL_SCAN_STAT_SCANNING;
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_START_SCAN,
> + NULL, 0);
> + if (!cmd || cmd->status || cmd->cmd_status) {
> + wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
> + complete(&wl->scan_done);
> + ret = -ENOMEM;
> + goto out;
> + }
> + kfree(cmd);
> +out:
> + up(&wl->scan_lock);
> + pr_debug("%s: ->\n", __func__);
> + return ret;
> +}
> +
> +/*
> + * retrieve scan result from the chip (hypervisor)
> + * this function is invoked by schedule work.
> + */
> +static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
> +{
> + struct gelic_eurus_cmd *cmd = NULL;
> + struct gelic_wl_scan_info *target, *tmp;
> + struct gelic_wl_scan_info *oldest = NULL;
> + struct gelic_eurus_scan_info *scan_info;
> + unsigned int scan_info_size;
> + union iwreq_data data;
> + unsigned long this_time = jiffies;
> + unsigned int data_len, i, found, r;
> + DECLARE_MAC_BUF(mac);
> +
> + pr_debug("%s:start\n", __func__);
> + down(&wl->scan_lock);
> +
> + if (wl->scan_stat != GELIC_WL_SCAN_STAT_SCANNING) {
> + /*
> + * stop() may be called while scanning, ignore result
> + */
> + pr_debug("%s: scan complete when stat != scanning(%d)\n",
> + __func__, wl->scan_stat);
> + goto out;
> + }
> +
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_SCAN,
> + wl->buf, PAGE_SIZE);
> + if (!cmd || cmd->status || cmd->cmd_status) {
> + wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
> + pr_info("%s:cmd failed\n", __func__);
> + kfree(cmd);
> + goto out;
> + }
> + data_len = cmd->size;
> + pr_debug("%s: data_len = %d\n", __func__, data_len);
> + kfree(cmd);
> +
> + /* OK, bss list retrieved */
> + wl->scan_stat = GELIC_WL_SCAN_STAT_GOT_LIST;
> +
> + /* mark all entries are old */
> + list_for_each_entry_safe(target, tmp, &wl->network_list, list) {
> + target->valid = 0;
> + /* expire too old entries */
> + if (time_before(target->last_scanned + wl->scan_age,
> + this_time)) {
> + kfree(target->hwinfo);
> + target->hwinfo = NULL;
> + list_move_tail(&target->list, &wl->network_free_list);
> + }
> + }
> +
> + /* put them in the newtork_list */
> + scan_info = wl->buf;
> + scan_info_size = 0;
> + i = 0;
> + while (scan_info_size < data_len) {
> + pr_debug("%s:size=%d bssid=%s scan_info=%p\n", __func__,
> + be16_to_cpu(scan_info->size),
> + print_mac(mac, &scan_info->bssid[2]), scan_info);
> + found = 0;
> + oldest = NULL;
> + list_for_each_entry(target, &wl->network_list, list) {
> + if (!compare_ether_addr(&target->hwinfo->bssid[2],
> + &scan_info->bssid[2])) {
> + found = 1;
> + pr_debug("%s: same BBS found scanned list\n",
> + __func__);
> + break;
> + }
> + if (!oldest ||
> + (target->last_scanned < oldest->last_scanned))
> + oldest = target;
> + }
> +
> + if (!found) {
> + /* not found in the list */
> + if (list_empty(&wl->network_free_list)) {
> + /* expire oldest */
> + target = oldest;
> + } else {
> + target = list_entry(wl->network_free_list.next,
> + struct gelic_wl_scan_info,
> + list);
> + }
> + }
> +
> + /* update the item */
> + target->last_scanned = this_time;
> + target->valid = 1;
> + target->eurus_index = i;
> + kfree(target->hwinfo);
> + target->hwinfo = kzalloc(be16_to_cpu(scan_info->size),
> + GFP_KERNEL);
> + if (!target->hwinfo) {
> + pr_info("%s: kzalloc failed\n", __func__);
> + i++;
> + scan_info_size += be16_to_cpu(scan_info->size);
> + scan_info = (void *)scan_info +
> + be16_to_cpu(scan_info->size);
> + continue;
> + }
> + /* copy hw scan info */
> + memcpy(target->hwinfo, scan_info, scan_info->size);
> + target->essid_len = strnlen(scan_info->essid,
> + sizeof(scan_info->essid));
> + target->rate_len = 0;
> + for (r = 0; r < MAX_RATES_LENGTH; r++)
> + if (scan_info->rate[r])
> + target->rate_len++;
> + if (8 < target->rate_len)
> + pr_info("%s: AP returns %d rates\n", __func__,
> + target->rate_len);
> + target->rate_ext_len = 0;
> + for (r = 0; r < MAX_RATES_EX_LENGTH; r++)
> + if (scan_info->ext_rate[r])
> + target->rate_ext_len++;
> + list_move_tail(&target->list, &wl->network_list);
> + /* bump pointer */
> + i++;
> + scan_info_size += be16_to_cpu(scan_info->size);
> + scan_info = (void *)scan_info + be16_to_cpu(scan_info->size);
> + }
> + memset(&data, 0, sizeof(data));
> + wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWSCAN, &data,
> + NULL);
> +out:
> + complete(&wl->scan_done);
> + up(&wl->scan_lock);
> + pr_debug("%s:end\n", __func__);
> +}
> +
> +/*
> + * Select an appropriate bss from current scan list regarding
> + * current settings from userspace.
> + * The caller must hold wl->scan_lock,
> + * and on the state of wl->scan_state == GELIC_WL_SCAN_GOT_LIST
> + */
> +static void update_best(struct gelic_wl_scan_info **best,
> + struct gelic_wl_scan_info *candid,
> + int *best_weight,
> + int *weight)
> +{
> + if (*best_weight < ++(*weight)) {
> + *best_weight = *weight;
> + *best = candid;
> + }
> +}
> +
> +static
> +struct gelic_wl_scan_info *gelic_wl_find_best_bss(struct gelic_wl_info *wl)
> +{
> + struct gelic_wl_scan_info *scan_info;
> + struct gelic_wl_scan_info *best_bss;
> + int weight, best_weight;
> + u16 security;
> + DECLARE_MAC_BUF(mac);
> +
> + pr_debug("%s: <-\n", __func__);
> +
> + best_bss = NULL;
> + best_weight = 0;
> +
> + list_for_each_entry(scan_info, &wl->network_list, list) {
> + pr_debug("%s: station %p\n", __func__, scan_info);
> +
> + if (!scan_info->valid) {
> + pr_debug("%s: station invalid\n", __func__);
> + continue;
> + }
> +
> + /* If bss specified, check it only */
> + if (test_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat)) {
> + if (!compare_ether_addr(&scan_info->hwinfo->bssid[2],
> + wl->bssid)) {
> + best_bss = scan_info;
> + pr_debug("%s: bssid matched\n", __func__);
> + break;
> + } else {
> + pr_debug("%s: bssid unmached\n", __func__);
> + continue;
> + }
> + }
> +
> + weight = 0;
> +
> + /* security */
> + security = be16_to_cpu(scan_info->hwinfo->security) &
> + GELIC_EURUS_SCAN_SEC_MASK;
> + if (wl->wpa_level == GELIC_WL_WPA_LEVEL_WPA2) {
> + if (security == GELIC_EURUS_SCAN_SEC_WPA2)
> + update_best(&best_bss, scan_info,
> + &best_weight, &weight);
> + else
> + continue;
> + } else if (wl->wpa_level == GELIC_WL_WPA_LEVEL_WPA) {
> + if (security == GELIC_EURUS_SCAN_SEC_WPA)
> + update_best(&best_bss, scan_info,
> + &best_weight, &weight);
> + else
> + continue;
> + } else if (wl->wpa_level == GELIC_WL_WPA_LEVEL_NONE &&
> + wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
> + if (security == GELIC_EURUS_SCAN_SEC_WEP)
> + update_best(&best_bss, scan_info,
> + &best_weight, &weight);
> + else
> + continue;
> + }
> +
> + /* If ESSID is set, check it */
> + if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat)) {
> + if ((scan_info->essid_len == wl->essid_len) &&
> + !strncmp(wl->essid,
> + scan_info->hwinfo->essid,
> + scan_info->essid_len))
> + update_best(&best_bss, scan_info,
> + &best_weight, &weight);
> + else
> + continue;
> + }
> + }
> +
> +#ifdef DEBUG
> + pr_debug("%s: -> bss=%p\n", __func__, best_bss);
> + if (best_bss) {
> + pr_debug("%s:addr=%s\n", __func__,
> + print_mac(mac, &best_bss->hwinfo->bssid[2]));
> + }
> +#endif
> + return best_bss;
> +}
> +
> +/*
> + * Setup WEP configuration to the chip
> + * The caller must hold wl->scan_lock,
> + * and on the state of wl->scan_state == GELIC_WL_SCAN_GOT_LIST
> + */
> +static int gelic_wl_do_wep_setup(struct gelic_wl_info *wl)
> +{
> + unsigned int i;
> + struct gelic_eurus_wep_cfg *wep;
> + struct gelic_eurus_cmd *cmd;
> + int wep104 = 0;
> + int have_key = 0;
> + int ret = 0;
> +
> + pr_debug("%s: <-\n", __func__);
> + /* we can assume no one should uses the buffer */
> + wep = wl->buf;
> + memset(wep, 0, sizeof(*wep));
> +
> + if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
> + pr_debug("%s: WEP mode\n", __func__);
> + for (i = 0; i < GELIC_WEP_KEYS; i++) {
> + if (!test_bit(i, &wl->key_enabled))
> + continue;
> +
> + pr_debug("%s: key#%d enabled\n", __func__, i);
> + have_key = 1;
> + if (wl->key_len[i] == 13)
> + wep104 = 1;
> + else if (wl->key_len[i] != 5) {
> + pr_info("%s: wrong wep key[%d]=%d\n",
> + __func__, i, wl->key_len[i]);
> + ret = -EINVAL;
> + goto out;
> + }
> + memcpy(wep->key[i], wl->key[i], wl->key_len[i]);
> + }
> +
> + if (!have_key) {
> + pr_info("%s: all wep key disabled\n", __func__);
> + ret = -EINVAL;
> + goto out;
> + }
> +
> + if (wep104) {
> + pr_debug("%s: 104bit key\n", __func__);
> + wep->security = cpu_to_be16(GELIC_EURUS_WEP_SEC_104BIT);
> + } else {
> + pr_debug("%s: 40bit key\n", __func__);
> + wep->security = cpu_to_be16(GELIC_EURUS_WEP_SEC_40BIT);
> + }
> + } else {
> + pr_debug("%s: NO encryption\n", __func__);
> + wep->security = cpu_to_be16(GELIC_EURUS_WEP_SEC_NONE);
> + }
> +
> + /* issue wep setup */
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_SET_WEP_CFG,
> + wep, sizeof(*wep));
> + if (!cmd)
> + ret = -ENOMEM;
> + else if (cmd->status || cmd->cmd_status)
> + ret = -ENXIO;
> +
> + kfree(cmd);
> +out:
> + pr_debug("%s: ->\n", __func__);
> + return ret;
> +}
> +
> +#ifdef DEBUG
> +static const char *wpasecstr(enum gelic_eurus_wpa_security sec)
> +{
> + switch (sec) {
> + case GELIC_EURUS_WPA_SEC_NONE:
> + return "NONE";
> + break;
> + case GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP:
> + return "WPA_TKIP_TKIP";
> + break;
> + case GELIC_EURUS_WPA_SEC_WPA_TKIP_AES:
> + return "WPA_TKIP_AES";
> + break;
> + case GELIC_EURUS_WPA_SEC_WPA_AES_AES:
> + return "WPA_AES_AES";
> + break;
> + case GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP:
> + return "WPA2_TKIP_TKIP";
> + break;
> + case GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES:
> + return "WPA2_TKIP_AES";
> + break;
> + case GELIC_EURUS_WPA_SEC_WPA2_AES_AES:
> + return "WPA2_AES_AES";
> + break;
> + }
> + return "";
> +};
> +#endif
> +
> +static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl)
> +{
> + struct gelic_eurus_wpa_cfg *wpa;
> + struct gelic_eurus_cmd *cmd;
> + u16 security;
> + int ret = 0;
> +
> + pr_debug("%s: <-\n", __func__);
> + /* we can assume no one should uses the buffer */
> + wpa = wl->buf;
> + memset(wpa, 0, sizeof(*wpa));
> +
> + if (!test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat))
> + pr_info("%s: PSK not configured yet\n", __func__);
> +
> + /* copy key */
> + memcpy(wpa->psk, wl->psk, wl->psk_len);
> +
> + /* set security level */
> + if (wl->wpa_level == GELIC_WL_WPA_LEVEL_WPA2) {
> + if (wl->group_cipher_method == GELIC_WL_CIPHER_AES) {
> + security = GELIC_EURUS_WPA_SEC_WPA2_AES_AES;
> + } else {
> + if (wl->pairwise_cipher_method == GELIC_WL_CIPHER_AES &&
> + precise_ie())
> + security = GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES;
> + else
> + security = GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP;
> + }
> + } else {
> + if (wl->group_cipher_method == GELIC_WL_CIPHER_AES) {
> + security = GELIC_EURUS_WPA_SEC_WPA_AES_AES;
> + } else {
> + if (wl->pairwise_cipher_method == GELIC_WL_CIPHER_AES &&
> + precise_ie())
> + security = GELIC_EURUS_WPA_SEC_WPA_TKIP_AES;
> + else
> + security = GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP;
> + }
> + }
> + wpa->security = cpu_to_be16(security);
> +
> + /* PSK type */
> + wpa->psk_type = cpu_to_be16(wl->psk_type);
> +#ifdef DEBUG
> + pr_debug("%s: sec=%s psktype=%s\nn", __func__,
> + wpasecstr(wpa->security),
> + (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ?
> + "BIN" : "passphrase");
> +#if 0
> + /*
> + * don't enable here if you plan to submit
> + * the debug log because this dumps your precious
> + * passphrase/key.
> + */
> + pr_debug("%s: psk=%s\n",
> + (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ?
> + (char *)"N/A" : (char *)wpa->psk);
> +#endif
> +#endif
> + /* issue wpa setup */
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_SET_WPA_CFG,
> + wpa, sizeof(*wpa));
> + if (!cmd)
> + ret = -ENOMEM;
> + else if (cmd->status || cmd->cmd_status)
> + ret = -ENXIO;
> + kfree(cmd);
> + pr_debug("%s: --> %d\n", __func__, ret);
> + return ret;
> +}
> +
> +/*
> + * Start association. caller must hold assoc_stat_lock
> + */
> +static int gelic_wl_associate_bss(struct gelic_wl_info *wl,
> + struct gelic_wl_scan_info *bss)
> +{
> + struct gelic_eurus_cmd *cmd;
> + struct gelic_eurus_common_cfg *common;
> + int ret = 0;
> + unsigned long rc;
> +
> + pr_debug("%s: <-\n", __func__);
> +
> + /* do common config */
> + common = wl->buf;
> + memset(common, 0, sizeof(*common));
> + common->bss_type = cpu_to_be16(GELIC_EURUS_BSS_INFRA);
> + common->op_mode = cpu_to_be16(GELIC_EURUS_OPMODE_11BG);
> +
> + common->scan_index = cpu_to_be16(bss->eurus_index);
> + switch (wl->auth_method) {
> + case GELIC_EURUS_AUTH_OPEN:
> + common->auth_method = cpu_to_be16(GELIC_EURUS_AUTH_OPEN);
> + break;
> + case GELIC_EURUS_AUTH_SHARED:
> + common->auth_method = cpu_to_be16(GELIC_EURUS_AUTH_SHARED);
> + break;
> + }
> +
> +#ifdef DEBUG
> + scan_list_dump(wl);
> +#endif
> + pr_debug("%s: common cfg index=%d bsstype=%d auth=%d\n", __func__,
> + be16_to_cpu(common->scan_index),
> + be16_to_cpu(common->bss_type),
> + be16_to_cpu(common->auth_method));
> +
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_SET_COMMON_CFG,
> + common, sizeof(*common));
> + if (!cmd || cmd->status || cmd->cmd_status) {
> + ret = -ENOMEM;
> + kfree(cmd);
> + goto out;
> + }
> + kfree(cmd);
> +
> + /* WEP/WPA */
> + switch (wl->wpa_level) {
> + case GELIC_WL_WPA_LEVEL_NONE:
> + /* If WEP or no security, setup WEP config */
> + ret = gelic_wl_do_wep_setup(wl);
> + break;
> + case GELIC_WL_WPA_LEVEL_WPA:
> + case GELIC_WL_WPA_LEVEL_WPA2:
> + ret = gelic_wl_do_wpa_setup(wl);
> + break;
> + };
> +
> + if (ret) {
> + pr_debug("%s: WEP/WPA setup failed %d\n", __func__,
> + ret);
> + }
> +
> + /* start association */
> + init_completion(&wl->assoc_done);
> + wl->assoc_stat = GELIC_WL_ASSOC_STAT_ASSOCIATING;
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_ASSOC,
> + NULL, 0);
> + if (!cmd || cmd->status || cmd->cmd_status) {
> + pr_debug("%s: assoc request failed\n", __func__);
> + wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
> + kfree(cmd);
> + ret = -ENOMEM;
> + gelic_wl_send_iwap_event(wl, NULL);
> + goto out;
> + }
> + kfree(cmd);
> +
> + /* wait for connected event */
> + rc = wait_for_completion_timeout(&wl->assoc_done, HZ * 4);/*FIXME*/
> +
> + if (!rc) {
> + /* timeouted. Maybe key or cyrpt mode is wrong */
> + pr_info("%s: connect timeout \n", __func__);
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC,
> + NULL, 0);
> + kfree(cmd);
> + wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
> + gelic_wl_send_iwap_event(wl, NULL);
> + ret = -ENXIO;
> + } else {
> + wl->assoc_stat = GELIC_WL_ASSOC_STAT_ASSOCIATED;
> + /* copy bssid */
> + memcpy(wl->active_bssid, &bss->hwinfo->bssid[2], ETH_ALEN);
> +
> + /* send connect event */
> + gelic_wl_send_iwap_event(wl, wl->active_bssid);
> + pr_info("%s: connected\n", __func__);
> + }
> +out:
> + pr_debug("%s: ->\n", __func__);
> + return ret;
> +}
> +
> +/*
> + * connected event
> + */
> +static void gelic_wl_connected_event(struct gelic_wl_info *wl,
> + u64 event)
> +{
> + u64 desired_event = 0;
> +
> + switch (wl->wpa_level) {
> + case GELIC_WL_WPA_LEVEL_NONE:
> + desired_event = GELIC_LV1_WL_EVENT_CONNECTED;
> + break;
> + case GELIC_WL_WPA_LEVEL_WPA:
> + case GELIC_WL_WPA_LEVEL_WPA2:
> + desired_event = GELIC_LV1_WL_EVENT_WPA_CONNECTED;
> + break;
> + }
> +
> + if (desired_event == event) {
> + pr_debug("%s: completed \n", __func__);
> + complete(&wl->assoc_done);
> + netif_carrier_on(port_to_netdev(wl_port(wl)));
> + } else
> + pr_debug("%s: event %#lx under wpa\n",
> + __func__, event);
> +}
> +
> +/*
> + * disconnect event
> + */
> +static void gelic_wl_disconnect_event(struct gelic_wl_info *wl,
> + u64 event)
> +{
> + struct gelic_eurus_cmd *cmd;
> + int lock;
> +
> + /*
> + * If we fall here in the middle of association,
> + * associate_bss() should be waiting for complation of
> + * wl->assoc_done.
> + * As it waits with timeout, just leave assoc_done
> + * uncompleted, then it terminates with timeout
> + */
> + if (down_trylock(&wl->assoc_stat_lock)) {
> + pr_debug("%s: already locked\n", __func__);
> + lock = 0;
> + } else {
> + pr_debug("%s: obtain lock\n", __func__);
> + lock = 1;
> + }
> +
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC, NULL, 0);
> + kfree(cmd);
> +
> + /* send disconnected event to the supplicant */
> + if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
> + gelic_wl_send_iwap_event(wl, NULL);
> +
> + wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
> + netif_carrier_off(port_to_netdev(wl_port(wl)));
> +
> + if (lock)
> + up(&wl->assoc_stat_lock);
> +}
> +/*
> + * event worker
> + */
> +#ifdef DEBUG
> +static const char *eventstr(enum gelic_lv1_wl_event event)
> +{
> + static char buf[32];
> + char *ret;
> + if (event & GELIC_LV1_WL_EVENT_DEVICE_READY)
> + ret = "EURUS_READY";
> + else if (event & GELIC_LV1_WL_EVENT_SCAN_COMPLETED)
> + ret = "SCAN_COMPLETED";
> + else if (event & GELIC_LV1_WL_EVENT_DEAUTH)
> + ret = "DEAUTH";
> + else if (event & GELIC_LV1_WL_EVENT_BEACON_LOST)
> + ret = "BEACON_LOST";
> + else if (event & GELIC_LV1_WL_EVENT_CONNECTED)
> + ret = "CONNECTED";
> + else if (event & GELIC_LV1_WL_EVENT_WPA_CONNECTED)
> + ret = "WPA_CONNECTED";
> + else if (event & GELIC_LV1_WL_EVENT_WPA_ERROR)
> + ret = "WPA_ERROR";
> + else {
> + sprintf(buf, "Unknown(%#x)", event);
> + ret = buf;
> + }
> + return ret;
> +}
> +#else
> +static const char *eventstr(enum gelic_lv1_wl_event event)
> +{
> + return NULL;
> +}
> +#endif
> +static void gelic_wl_event_worker(struct work_struct *work)
> +{
> + struct gelic_wl_info *wl;
> + struct gelic_port *port;
> + u64 event, tmp;
> + int status;
> +
> + pr_debug("%s:start\n", __func__);
> + wl = container_of(work, struct gelic_wl_info, event_work.work);
> + port = wl_port(wl);
> + while (1) {
> + status = lv1_net_control(bus_id(port->card), dev_id(port->card),
> + GELIC_LV1_GET_WLAN_EVENT, 0, 0, 0,
> + &event, &tmp);
> + if (status) {
> + if (status != LV1_NO_ENTRY)
> + pr_debug("%s:wlan event failed %d\n",
> + __func__, status);
> + /* got all events */
> + pr_debug("%s:end\n", __func__);
> + return;
> + }
> + pr_debug("%s: event=%s\n", __func__, eventstr(event));
> + switch (event) {
> + case GELIC_LV1_WL_EVENT_SCAN_COMPLETED:
> + gelic_wl_scan_complete_event(wl);
> + break;
> + case GELIC_LV1_WL_EVENT_BEACON_LOST:
> + case GELIC_LV1_WL_EVENT_DEAUTH:
> + gelic_wl_disconnect_event(wl, event);
> + break;
> + case GELIC_LV1_WL_EVENT_CONNECTED:
> + case GELIC_LV1_WL_EVENT_WPA_CONNECTED:
> + gelic_wl_connected_event(wl, event);
> + break;
> + default:
> + break;
> + }
> + } /* while */
> +}
> +/*
> + * association worker
> + */
> +static void gelic_wl_assoc_worker(struct work_struct *work)
> +{
> + struct gelic_wl_info *wl;
> +
> + struct gelic_wl_scan_info *best_bss;
> + int ret;
> +
> + wl = container_of(work, struct gelic_wl_info, assoc_work.work);
> +
> + down(&wl->assoc_stat_lock);
> +
> + if (wl->assoc_stat != GELIC_WL_ASSOC_STAT_DISCONN)
> + goto out;
> +
> + ret = gelic_wl_start_scan(wl, 0);
> + if (ret == -ERESTARTSYS) {
> + pr_debug("%s: scan start failed association\n", __func__);
> + schedule_delayed_work(&wl->assoc_work, HZ/10); /*FIXME*/
> + goto out;
> + } else if (ret) {
> + pr_info("%s: scan prerequisite failed\n", __func__);
> + goto out;
> + }
> +
> + /*
> + * Wait for bss scan completion
> + * If we have scan list already, gelic_wl_start_scan()
> + * returns OK and raises the complete. Thus,
> + * it's ok to wait unconditionally here
> + */
> + wait_for_completion(&wl->scan_done);
> +
> + pr_debug("%s: scan done\n", __func__);
> + down(&wl->scan_lock);
> + if (wl->scan_stat != GELIC_WL_SCAN_STAT_GOT_LIST) {
> + gelic_wl_send_iwap_event(wl, NULL);
> + pr_info("%s: no scan list. association failed\n", __func__);
> + goto scan_lock_out;
> + }
> +
> + /* find best matching bss */
> + best_bss = gelic_wl_find_best_bss(wl);
> + if (!best_bss) {
> + gelic_wl_send_iwap_event(wl, NULL);
> + pr_info("%s: no bss matched. association failed\n", __func__);
> + goto scan_lock_out;
> + }
> +
> + /* ok, do association */
> + ret = gelic_wl_associate_bss(wl, best_bss);
> + if (ret)
> + pr_info("%s: association failed %d\n", __func__, ret);
> +scan_lock_out:
> + up(&wl->scan_lock);
> +out:
> + up(&wl->assoc_stat_lock);
> +}
> +/*
> + * Interrupt handler
> + * Called from the ethernet interrupt handler
> + * Processes wireless specific virtual interrupts only
> + */
> +void gelic_wl_interrupt(struct net_device *netdev, u64 status)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> +
> + if (status & GELIC_CARD_WLAN_COMMAND_COMPLETED) {
> + pr_debug("%s:cmd complete\n", __func__);
> + complete(&wl->cmd_done_intr);
> + }
> +
> + if (status & GELIC_CARD_WLAN_EVENT_RECEIVED) {
> + pr_debug("%s:event received\n", __func__);
> + queue_delayed_work(wl->event_queue, &wl->event_work, 0);
> + }
> +}
> +
> +/*
> + * driver helpers
> + */
> +#define IW_IOCTL(n) [(n) - SIOCSIWCOMMIT]
> +static const iw_handler gelic_wl_wext_handler[] =
> +{
> + IW_IOCTL(SIOCGIWNAME) = gelic_wl_get_name,
> + IW_IOCTL(SIOCGIWRANGE) = gelic_wl_get_range,
> + IW_IOCTL(SIOCSIWSCAN) = gelic_wl_set_scan,
> + IW_IOCTL(SIOCGIWSCAN) = gelic_wl_get_scan,
> + IW_IOCTL(SIOCSIWAUTH) = gelic_wl_set_auth,
> + IW_IOCTL(SIOCGIWAUTH) = gelic_wl_get_auth,
> + IW_IOCTL(SIOCSIWESSID) = gelic_wl_set_essid,
> + IW_IOCTL(SIOCGIWESSID) = gelic_wl_get_essid,
> + IW_IOCTL(SIOCSIWENCODE) = gelic_wl_set_encode,
> + IW_IOCTL(SIOCGIWENCODE) = gelic_wl_get_encode,
> + IW_IOCTL(SIOCSIWAP) = gelic_wl_set_ap,
> + IW_IOCTL(SIOCGIWAP) = gelic_wl_get_ap,
> + IW_IOCTL(SIOCSIWENCODEEXT) = gelic_wl_set_encodeext,
> + IW_IOCTL(SIOCGIWENCODEEXT) = gelic_wl_get_encodeext,
> + IW_IOCTL(SIOCSIWMODE) = gelic_wl_set_mode,
> + IW_IOCTL(SIOCGIWMODE) = gelic_wl_get_mode,
> + IW_IOCTL(SIOCGIWNICKN) = gelic_wl_get_nick,
> +};
> +
> +static struct iw_priv_args gelic_wl_private_args[] =
> +{
> + {
> + .cmd = GELIC_WL_PRIV_SET_PSK,
> + .set_args = IW_PRIV_TYPE_CHAR |
> + (GELIC_WL_EURUS_PSK_MAX_LEN + 2),
> + .name = "set_psk"
> + },
> + {
> + .cmd = GELIC_WL_PRIV_GET_PSK,
> + .get_args = IW_PRIV_TYPE_CHAR |
> + (GELIC_WL_EURUS_PSK_MAX_LEN + 2),
> + .name = "get_psk"
> + }
> +};
> +
> +static const iw_handler gelic_wl_private_handler[] =
> +{
> + gelic_wl_priv_set_psk,
> + gelic_wl_priv_get_psk,
> +};
> +
> +static const struct iw_handler_def gelic_wl_wext_handler_def = {
> + .num_standard = ARRAY_SIZE(gelic_wl_wext_handler),
> + .standard = gelic_wl_wext_handler,
> + .get_wireless_stats = gelic_wl_get_wireless_stats,
> + .num_private = ARRAY_SIZE(gelic_wl_private_handler),
> + .num_private_args = ARRAY_SIZE(gelic_wl_private_args),
> + .private = gelic_wl_private_handler,
> + .private_args = gelic_wl_private_args,
> +};
> +
> +static struct net_device *gelic_wl_alloc(struct gelic_card *card)
> +{
> + struct net_device *netdev;
> + struct gelic_port *port;
> + struct gelic_wl_info *wl;
> + unsigned int i;
> +
> + pr_debug("%s:start\n", __func__);
> + netdev = alloc_etherdev(sizeof(struct gelic_port) +
> + sizeof(struct gelic_wl_info));
> + pr_debug("%s: netdev =%p card=%p \np", __func__, netdev, card);
> + if (!netdev)
> + return NULL;
> +
> + port = netdev_priv(netdev);
> + port->netdev = netdev;
> + port->card = card;
> + port->type = GELIC_PORT_WIRELESS;
> +
> + wl = port_wl(port);
> + pr_debug("%s: wl=%p port=%p\n", __func__, wl, port);
> +
> + /* allocate scan list */
> + wl->networks = kzalloc(sizeof(struct gelic_wl_scan_info) *
> + GELIC_WL_BSS_MAX_ENT, GFP_KERNEL);
> +
> + if (!wl->networks)
> + goto fail_bss;
> +
> + wl->eurus_cmd_queue = create_singlethread_workqueue("gelic_cmd");
> + if (!wl->eurus_cmd_queue)
> + goto fail_cmd_workqueue;
> +
> + wl->event_queue = create_singlethread_workqueue("gelic_event");
> + if (!wl->event_queue)
> + goto fail_event_workqueue;
> +
> + INIT_LIST_HEAD(&wl->network_free_list);
> + INIT_LIST_HEAD(&wl->network_list);
> + for (i = 0; i < GELIC_WL_BSS_MAX_ENT; i++)
> + list_add_tail(&wl->networks[i].list,
> + &wl->network_free_list);
> + init_completion(&wl->cmd_done_intr);
> +
> + INIT_DELAYED_WORK(&wl->event_work, gelic_wl_event_worker);
> + INIT_DELAYED_WORK(&wl->assoc_work, gelic_wl_assoc_worker);
> + init_MUTEX(&wl->scan_lock);
> + init_MUTEX(&wl->assoc_stat_lock);
> +
> + init_completion(&wl->scan_done);
> + /* for the case that no scan request is issued and stop() is called */
> + complete(&wl->scan_done);
> +
> + spin_lock_init(&wl->lock);
> +
> + wl->scan_age = 5*HZ; /* FIXME */
> +
> + /* buffer for receiving scanned list etc */
> + BUILD_BUG_ON(PAGE_SIZE <
> + sizeof(struct gelic_eurus_scan_info) *
> + GELIC_EURUS_MAX_SCAN);
> + wl->buf = (void *)get_zeroed_page(GFP_KERNEL);
> + if (!wl->buf) {
> + pr_info("%s:buffer allocation failed\n", __func__);
> + goto fail_getpage;
> + }
> + pr_debug("%s:end\n", __func__);
> + return netdev;
> +
> +fail_getpage:
> + destroy_workqueue(wl->event_queue);
> +fail_event_workqueue:
> + destroy_workqueue(wl->eurus_cmd_queue);
> +fail_cmd_workqueue:
> + kfree(wl->networks);
> +fail_bss:
> + free_netdev(netdev);
> + pr_debug("%s:end error\n", __func__);
> + return NULL;
> +
> +}
> +
> +static void gelic_wl_free(struct gelic_wl_info *wl)
> +{
> + struct gelic_wl_scan_info *scan_info;
> + unsigned int i;
> +
> + pr_debug("%s: <-\n", __func__);
> +
> + pr_debug("%s: destroy queues\n", __func__);
> + destroy_workqueue(wl->eurus_cmd_queue);
> + destroy_workqueue(wl->event_queue);
> +
> + scan_info = wl->networks;
> + for (i = 0; i < GELIC_WL_BSS_MAX_ENT; i++, scan_info++)
> + kfree(scan_info->hwinfo);
> + kfree(wl->networks);
> +
> + free_netdev(port_to_netdev(wl_port(wl)));
> +
> + pr_debug("%s: ->\n", __func__);
> +}
> +
> +static int gelic_wl_try_associate(struct net_device *netdev)
> +{
> + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
> + int ret = -1;
> + unsigned int i;
> +
> + pr_debug("%s: <-\n", __func__);
> +
> + /* check constraits for start association */
> + /* for no access restriction AP */
> + if (wl->group_cipher_method == GELIC_WL_CIPHER_NONE) {
> + if (test_bit(GELIC_WL_STAT_CONFIGURED,
> + &wl->stat))
> + goto do_associate;
> + else {
> + pr_debug("%s: no wep, not configured\n", __func__);
> + return ret;
> + }
> + }
> +
> + /* for WEP, one of four keys should be set */
> + if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
> + /* one of keys set */
> + for (i = 0; i < GELIC_WEP_KEYS; i++) {
> + if (test_bit(i, &wl->key_enabled))
> + goto do_associate;
> + }
> + pr_debug("%s: WEP, but no key specified\n", __func__);
> + return ret;
> + }
> +
> + /* for WPA[2], psk should be set */
> + if ((wl->group_cipher_method == GELIC_WL_CIPHER_TKIP) ||
> + (wl->group_cipher_method == GELIC_WL_CIPHER_AES)) {
> + if (test_bit(GELIC_WL_STAT_WPA_PSK_SET,
> + &wl->stat))
> + goto do_associate;
> + else {
> + pr_debug("%s: AES/TKIP, but PSK not configured\n",
> + __func__);
> + return ret;
> + }
> + }
> +
> +do_associate:
> + ret = schedule_delayed_work(&wl->assoc_work, 0);
> + pr_debug("%s: start association work %d\n", __func__, ret);
> + return ret;
> +}
> +
> +/*
> + * netdev handlers
> + */
> +static int gelic_wl_open(struct net_device *netdev)
> +{
> + struct gelic_card *card = netdev_card(netdev);
> +
> + pr_debug("%s:->%p\n", __func__, netdev);
> +
> + gelic_card_up(card);
> +
> + /* try to associate */
> + gelic_wl_try_associate(netdev);
> +
> + netif_start_queue(netdev);
> +
> + pr_debug("%s:<-\n", __func__);
> + return 0;
> +}
> +
> +/*
> + * reset state machine
> + */
> +static int gelic_wl_reset_state(struct gelic_wl_info *wl)
> +{
> + struct gelic_wl_scan_info *target;
> + struct gelic_wl_scan_info *tmp;
> +
> + /* empty scan list */
> + list_for_each_entry_safe(target, tmp, &wl->network_list, list) {
> + list_move_tail(&target->list, &wl->network_free_list);
> + }
> + wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
> +
> + /* clear configuration */
> + wl->auth_method = GELIC_EURUS_AUTH_OPEN;
> + wl->group_cipher_method = GELIC_WL_CIPHER_NONE;
> + wl->pairwise_cipher_method = GELIC_WL_CIPHER_NONE;
> + wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE;
> +
> + wl->key_enabled = 0;
> + wl->current_key = 0;
> +
> + wl->psk_type = GELIC_EURUS_WPA_PSK_PASSPHRASE;
> + wl->psk_len = 0;
> +
> + wl->essid_len = 0;
> + memset(wl->essid, 0, sizeof(wl->essid));
> + memset(wl->bssid, 0, sizeof(wl->bssid));
> + memset(wl->active_bssid, 0, sizeof(wl->active_bssid));
> +
> + wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN;
> +
> + memset(&wl->iwstat, 0, sizeof(wl->iwstat));
> + /* all status bit clear */
> + wl->stat = 0;
> + return 0;
> +}
> +
> +/*
> + * Tell eurus to terminate association
> + */
> +static void gelic_wl_disconnect(struct net_device *netdev)
> +{
> + struct gelic_port *port = netdev_priv(netdev);
> + struct gelic_wl_info *wl = port_wl(port);
> + struct gelic_eurus_cmd *cmd;
> +
> + /*
> + * If scann process is running on chip,
> + * further requests will be rejected
> + */
> + if (wl->scan_stat == GELIC_WL_SCAN_STAT_SCANNING)
> + wait_for_completion_timeout(&wl->scan_done, HZ);
> +
> + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC, NULL, 0);
> + kfree(cmd);
> + gelic_wl_send_iwap_event(wl, NULL);
> +};
> +
> +static int gelic_wl_stop(struct net_device *netdev)
> +{
> + struct gelic_port *port = netdev_priv(netdev);
> + struct gelic_wl_info *wl = port_wl(port);
> + struct gelic_card *card = netdev_card(netdev);
> +
> + pr_debug("%s:<-\n", __func__);
> +
> + /*
> + * Cancel pending association work.
> + * event work can run after netdev down
> + */
> + cancel_delayed_work(&wl->assoc_work);
> +
> + if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
> + gelic_wl_disconnect(netdev);
> +
> + /* reset our state machine */
> + gelic_wl_reset_state(wl);
> +
> + netif_stop_queue(netdev);
> +
> + gelic_card_down(card);
> +
> + pr_debug("%s:->\n", __func__);
> + return 0;
> +}
> +
> +/* -- */
> +
> +static struct ethtool_ops gelic_wl_ethtool_ops = {
> + .get_drvinfo = gelic_net_get_drvinfo,
> + .get_link = gelic_wl_get_link,
> + .get_tx_csum = ethtool_op_get_tx_csum,
> + .set_tx_csum = ethtool_op_set_tx_csum,
> + .get_rx_csum = gelic_net_get_rx_csum,
> + .set_rx_csum = gelic_net_set_rx_csum,
> +};
> +
> +static void gelic_wl_setup_netdev_ops(struct net_device *netdev)
> +{
> + struct gelic_wl_info *wl;
> + wl = port_wl(netdev_priv(netdev));
> + BUG_ON(!wl);
> + netdev->open = &gelic_wl_open;
> + netdev->stop = &gelic_wl_stop;
> + netdev->hard_start_xmit = &gelic_net_xmit;
> + netdev->set_multicast_list = &gelic_net_set_multi;
> + netdev->change_mtu = &gelic_net_change_mtu;
> + netdev->wireless_data = &wl->wireless_data;
> + netdev->wireless_handlers = &gelic_wl_wext_handler_def;
> + /* tx watchdog */
> + netdev->tx_timeout = &gelic_net_tx_timeout;
> + netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT;
> +
> + netdev->ethtool_ops = &gelic_wl_ethtool_ops;
> +#ifdef CONFIG_NET_POLL_CONTROLLER
> + netdev->poll_controller = gelic_net_poll_controller;
> +#endif
> +}
> +
> +/*
> + * driver probe/remove
> + */
> +int gelic_wl_driver_probe(struct gelic_card *card)
> +{
> + int ret;
> + struct net_device *netdev;
> +
> + pr_debug("%s:start\n", __func__);
> +
> + if (ps3_compare_firmware_version(1, 6, 0) < 0)
> + return 0;
> + if (!card->vlan[GELIC_PORT_WIRELESS].tx)
> + return 0;
> +
> + /* alloc netdevice for wireless */
> + netdev = gelic_wl_alloc(card);
> + if (!netdev)
> + return -ENOMEM;
> +
> + /* setup net_device structure */
> + gelic_wl_setup_netdev_ops(netdev);
> +
> + /* setup some of net_device and register it */
> + ret = gelic_net_setup_netdev(netdev, card);
> + if (ret)
> + goto fail_setup;
> + card->netdev[GELIC_PORT_WIRELESS] = netdev;
> +
> + /* add enable wireless interrupt */
> + card->irq_mask |= GELIC_CARD_WLAN_EVENT_RECEIVED |
> + GELIC_CARD_WLAN_COMMAND_COMPLETED;
> + /* to allow wireless commands while both interfaces are down */
> + gelic_card_set_irq_mask(card, GELIC_CARD_WLAN_EVENT_RECEIVED |
> + GELIC_CARD_WLAN_COMMAND_COMPLETED);
> + pr_debug("%s:end\n", __func__);
> + return 0;
> +
> +fail_setup:
> + gelic_wl_free(port_wl(netdev_port(netdev)));
> +
> + return ret;
> +}
> +
> +int gelic_wl_driver_remove(struct gelic_card *card)
> +{
> + struct gelic_wl_info *wl;
> + struct net_device *netdev;
> +
> + pr_debug("%s:start\n", __func__);
> +
> + if (ps3_compare_firmware_version(1, 6, 0) < 0)
> + return 0;
> + if (!card->vlan[GELIC_PORT_WIRELESS].tx)
> + return 0;
> +
> + netdev = card->netdev[GELIC_PORT_WIRELESS];
> + wl = port_wl(netdev_priv(netdev));
> +
> + /* if the interface was not up, but associated */
> + if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
> + gelic_wl_disconnect(netdev);
> +
> + complete(&wl->cmd_done_intr);
> +
> + /* cancel all work queue */
> + cancel_delayed_work(&wl->assoc_work);
> + cancel_delayed_work(&wl->event_work);
> + flush_workqueue(wl->eurus_cmd_queue);
> + flush_workqueue(wl->event_queue);
> +
> + unregister_netdev(netdev);
> +
> + /* disable wireless interrupt */
> + pr_debug("%s: disable intr\n", __func__);
> + card->irq_mask &= ~(GELIC_CARD_WLAN_EVENT_RECEIVED |
> + GELIC_CARD_WLAN_COMMAND_COMPLETED);
> + /* free bss list, netdev*/
> + gelic_wl_free(wl);
> + pr_debug("%s:end\n", __func__);
> + return 0;
> +}
> --- /dev/null
> +++ b/drivers/net/ps3_gelic_wireless.h
> @@ -0,0 +1,329 @@
> +/*
> + * PS3 gelic network driver.
> + *
> + * Copyright (C) 2007 Sony Computer Entertainment Inc.
> + * Copyright 2007 Sony Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation version 2.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +#ifndef _GELIC_WIRELESS_H
> +#define _GELIC_WIRELESS_H
> +
> +#include <linux/wireless.h>
> +#include <net/iw_handler.h>
> +
> +
> +/* return value from GELIC_LV1_GET_WLAN_EVENT netcontrol */
> +enum gelic_lv1_wl_event {
> + GELIC_LV1_WL_EVENT_DEVICE_READY = 0x01, /* Eurus ready */
> + GELIC_LV1_WL_EVENT_SCAN_COMPLETED = 0x02, /* Scan has completed */
> + GELIC_LV1_WL_EVENT_DEAUTH = 0x04, /* Deauthed by the AP */
> + GELIC_LV1_WL_EVENT_BEACON_LOST = 0x08, /* Beacon lost detected */
> + GELIC_LV1_WL_EVENT_CONNECTED = 0x10, /* Connected to AP */
> + GELIC_LV1_WL_EVENT_WPA_CONNECTED = 0x20, /* WPA connection */
> + GELIC_LV1_WL_EVENT_WPA_ERROR = 0x40, /* MIC error */
> +};
> +
> +/* arguments for GELIC_LV1_POST_WLAN_COMMAND netcontrol */
> +enum gelic_eurus_command {
> + GELIC_EURUS_CMD_ASSOC = 1, /* association start */
> + GELIC_EURUS_CMD_DISASSOC = 2, /* disassociate */
> + GELIC_EURUS_CMD_START_SCAN = 3, /* scan start */
> + GELIC_EURUS_CMD_GET_SCAN = 4, /* get scan result */
> + GELIC_EURUS_CMD_SET_COMMON_CFG = 5, /* set common config */
> + GELIC_EURUS_CMD_GET_COMMON_CFG = 6, /* set common config */
> + GELIC_EURUS_CMD_SET_WEP_CFG = 7, /* set WEP config */
> + GELIC_EURUS_CMD_GET_WEP_CFG = 8, /* get WEP config */
> + GELIC_EURUS_CMD_SET_WPA_CFG = 9, /* set WPA config */
> + GELIC_EURUS_CMD_GET_WPA_CFG = 10, /* get WPA config */
> + GELIC_EURUS_CMD_GET_RSSI_CFG = 11, /* get RSSI info. */
> + GELIC_EURUS_CMD_MAX_INDEX
> +};
> +
> +/* for GELIC_EURUS_CMD_COMMON_CFG */
> +enum gelic_eurus_bss_type {
> + GELIC_EURUS_BSS_INFRA = 0,
> + GELIC_EURUS_BSS_ADHOC = 1, /* not supported */
> +};
> +
> +enum gelic_eurus_auth_method {
> + GELIC_EURUS_AUTH_OPEN = 0, /* FIXME: WLAN_AUTH_OPEN */
> + GELIC_EURUS_AUTH_SHARED = 1, /* not supported */
> +};
> +
> +enum gelic_eurus_opmode {
> + GELIC_EURUS_OPMODE_11BG = 0, /* 802.11b/g */
> + GELIC_EURUS_OPMODE_11B = 1, /* 802.11b only */
> + GELIC_EURUS_OPMODE_11G = 2, /* 802.11g only */
> +};
> +
> +struct gelic_eurus_common_cfg {
> + /* all fields are big endian */
> + u16 scan_index;
> + u16 bss_type; /* infra or adhoc */
> + u16 auth_method; /* shared key or open */
> + u16 op_mode; /* B/G */
> +} __attribute__((packed));
> +
> +
> +/* for GELIC_EURUS_CMD_WEP_CFG */
> +enum gelic_eurus_wep_security {
> + GELIC_EURUS_WEP_SEC_NONE = 0,
> + GELIC_EURUS_WEP_SEC_40BIT = 1,
> + GELIC_EURUS_WEP_SEC_104BIT = 2,
> +};
> +
> +struct gelic_eurus_wep_cfg {
> + /* all fields are big endian */
> + u16 security;
> + u8 key[4][16];
> +} __attribute__((packed));
> +
> +/* for GELIC_EURUS_CMD_WPA_CFG */
> +enum gelic_eurus_wpa_security {
> + GELIC_EURUS_WPA_SEC_NONE = 0x0000,
> + /* group=TKIP, pairwise=TKIP */
> + GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP = 0x0001,
> + /* group=AES, pairwise=AES */
> + GELIC_EURUS_WPA_SEC_WPA_AES_AES = 0x0002,
> + /* group=TKIP, pairwise=TKIP */
> + GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP = 0x0004,
> + /* group=AES, pairwise=AES */
> + GELIC_EURUS_WPA_SEC_WPA2_AES_AES = 0x0008,
> + /* group=TKIP, pairwise=AES */
> + GELIC_EURUS_WPA_SEC_WPA_TKIP_AES = 0x0010,
> + /* group=TKIP, pairwise=AES */
> + GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES = 0x0020,
> +};
> +
> +enum gelic_eurus_wpa_psk_type {
> + GELIC_EURUS_WPA_PSK_PASSPHRASE = 0, /* passphrase string */
> + GELIC_EURUS_WPA_PSK_BIN = 1, /* 32 bytes binary key */
> +};
> +
> +#define GELIC_WL_EURUS_PSK_MAX_LEN 64
> +#define WPA_PSK_LEN 32 /* WPA spec says 256bit */
> +
> +struct gelic_eurus_wpa_cfg {
> + /* all fields are big endian */
> + u16 security;
> + u16 psk_type; /* psk key encoding type */
> + u8 psk[GELIC_WL_EURUS_PSK_MAX_LEN]; /* psk key; hex or passphrase */
> +} __attribute__((packed));
> +
> +/* for GELIC_EURUS_CMD_{START,GET}_SCAN */
> +enum gelic_eurus_scan_capability {
> + GELIC_EURUS_SCAN_CAP_ADHOC = 0x0000,
> + GELIC_EURUS_SCAN_CAP_INFRA = 0x0001,
> + GELIC_EURUS_SCAN_CAP_MASK = 0x0001,
> +};
> +
> +enum gelic_eurus_scan_sec_type {
> + GELIC_EURUS_SCAN_SEC_NONE = 0x0000,
> + GELIC_EURUS_SCAN_SEC_WEP = 0x0100,
> + GELIC_EURUS_SCAN_SEC_WPA = 0x0200,
> + GELIC_EURUS_SCAN_SEC_WPA2 = 0x0400,
> + GELIC_EURUS_SCAN_SEC_MASK = 0x0f00,
> +};
> +
> +enum gelic_eurus_scan_sec_wep_type {
> + GELIC_EURUS_SCAN_SEC_WEP_UNKNOWN = 0x0000,
> + GELIC_EURUS_SCAN_SEC_WEP_40 = 0x0001,
> + GELIC_EURUS_SCAN_SEC_WEP_104 = 0x0002,
> + GELIC_EURUS_SCAN_SEC_WEP_MASK = 0x0003,
> +};
> +
> +enum gelic_eurus_scan_sec_wpa_type {
> + GELIC_EURUS_SCAN_SEC_WPA_UNKNOWN = 0x0000,
> + GELIC_EURUS_SCAN_SEC_WPA_TKIP = 0x0001,
> + GELIC_EURUS_SCAN_SEC_WPA_AES = 0x0002,
> + GELIC_EURUS_SCAN_SEC_WPA_MASK = 0x0003,
> +};
> +
> +/*
> + * hw BSS information structure returned from GELIC_EURUS_CMD_GET_SCAN
> + */
> +struct gelic_eurus_scan_info {
> + /* all fields are big endian */
> + __be16 size;
> + __be16 rssi; /* percentage */
> + __be16 channel; /* channel number */
> + __be16 beacon_period; /* FIXME: in msec unit */
> + __be16 capability;
> + __be16 security;
> + u8 bssid[8]; /* last ETH_ALEN are valid. bssid[0],[1] are unused */
> + u8 essid[32]; /* IW_ESSID_MAX_SIZE */
> + u8 rate[16]; /* first MAX_RATES_LENGTH(12) are valid */
> + u8 ext_rate[16]; /* first MAX_RATES_EX_LENGTH(16) are valid */
> + __be32 reserved1;
> + __be32 reserved2;
> + __be32 reserved3;
> + __be32 reserved4;
> + u8 elements[0]; /* ie */
> +} __attribute__ ((packed));
> +
> +/* the hypervisor returns bbs up to 16 */
> +#define GELIC_EURUS_MAX_SCAN (16)
> +struct gelic_wl_scan_info {
> + struct list_head list;
> + struct gelic_eurus_scan_info *hwinfo;
> +
> + int valid; /* set 1 if this entry was in latest scanned list
> + * from Eurus */
> + unsigned int eurus_index; /* index in the Eurus list */
> + unsigned long last_scanned; /* acquired time */
> +
> + unsigned int rate_len;
> + unsigned int rate_ext_len;
> + unsigned int essid_len;
> +};
> +
> +/* for GELIC_EURUS_CMD_GET_RSSI */
> +struct gelic_eurus_rssi_info {
> + /* big endian */
> + __be16 rssi;
> +} __attribute__ ((packed));
> +
> +
> +/* for 'stat' member of gelic_wl_info */
> +enum gelic_wl_info_status_bit {
> + GELIC_WL_STAT_CONFIGURED,
> + GELIC_WL_STAT_CH_INFO, /* ch info aquired */
> + GELIC_WL_STAT_ESSID_SET, /* ESSID specified by userspace */
> + GELIC_WL_STAT_BSSID_SET, /* BSSID specified by userspace */
> + GELIC_WL_STAT_WPA_PSK_SET, /* PMK specified by userspace */
> + GELIC_WL_STAT_WPA_LEVEL_SET, /* WEP or WPA[2] selected */
> +};
> +
> +/* for 'scan_stat' member of gelic_wl_info */
> +enum gelic_wl_scan_state {
> + /* just initialized or get last scan result failed */
> + GELIC_WL_SCAN_STAT_INIT,
> + /* scan request issued, accepted or chip is scanning */
> + GELIC_WL_SCAN_STAT_SCANNING,
> + /* scan results retrieved */
> + GELIC_WL_SCAN_STAT_GOT_LIST,
> +};
> +
> +/* for 'cipher_method' */
> +enum gelic_wl_cipher_method {
> + GELIC_WL_CIPHER_NONE,
> + GELIC_WL_CIPHER_WEP,
> + GELIC_WL_CIPHER_TKIP,
> + GELIC_WL_CIPHER_AES,
> +};
> +
> +/* for 'wpa_level' */
> +enum gelic_wl_wpa_level {
> + GELIC_WL_WPA_LEVEL_NONE,
> + GELIC_WL_WPA_LEVEL_WPA,
> + GELIC_WL_WPA_LEVEL_WPA2,
> +};
> +
> +/* for 'assoc_stat' */
> +enum gelic_wl_assoc_state {
> + GELIC_WL_ASSOC_STAT_DISCONN,
> + GELIC_WL_ASSOC_STAT_ASSOCIATING,
> + GELIC_WL_ASSOC_STAT_ASSOCIATED,
> +};
> +/* part of private data alloc_etherdev() allocated */
> +#define GELIC_WEP_KEYS 4
> +struct gelic_wl_info {
> + /* bss list */
> + struct semaphore scan_lock;
> + struct list_head network_list;
> + struct list_head network_free_list;
> + struct gelic_wl_scan_info *networks;
> +
> + unsigned long scan_age; /* last scanned time */
> + enum gelic_wl_scan_state scan_stat;
> + struct completion scan_done;
> +
> + /* eurus command queue */
> + struct workqueue_struct *eurus_cmd_queue;
> + struct completion cmd_done_intr;
> +
> + /* eurus event handling */
> + struct workqueue_struct *event_queue;
> + struct delayed_work event_work;
> +
> + /* wl status bits */
> + unsigned long stat;
> + enum gelic_eurus_auth_method auth_method; /* open/shared */
> + enum gelic_wl_cipher_method group_cipher_method;
> + enum gelic_wl_cipher_method pairwise_cipher_method;
> + enum gelic_wl_wpa_level wpa_level; /* wpa/wpa2 */
> +
> + /* association handling */
> + struct semaphore assoc_stat_lock;
> + struct delayed_work assoc_work;
> + enum gelic_wl_assoc_state assoc_stat;
> + struct completion assoc_done;
> +
> + spinlock_t lock;
> + u16 ch_info; /* available channels. bit0 = ch1 */
> + /* WEP keys */
> + u8 key[GELIC_WEP_KEYS][IW_ENCODING_TOKEN_MAX];
> + unsigned long key_enabled;
> + unsigned int key_len[GELIC_WEP_KEYS];
> + unsigned int current_key;
> + /* WWPA PSK */
> + u8 psk[GELIC_WL_EURUS_PSK_MAX_LEN];
> + enum gelic_eurus_wpa_psk_type psk_type;
> + unsigned int psk_len;
> +
> + u8 essid[IW_ESSID_MAX_SIZE];
> + u8 bssid[ETH_ALEN]; /* userland requested */
> + u8 active_bssid[ETH_ALEN]; /* associated bssid */
> + unsigned int essid_len;
> +
> + /* buffer for hypervisor IO */
> + void *buf;
> +
> + struct iw_public_data wireless_data;
> + struct iw_statistics iwstat;
> +};
> +
> +#define GELIC_WL_BSS_MAX_ENT 32
> +#define GELIC_WL_ASSOC_RETRY 50
> +static inline struct gelic_port *wl_port(struct gelic_wl_info *wl)
> +{
> + return container_of((void *)wl, struct gelic_port, priv);
> +}
> +static inline struct gelic_wl_info *port_wl(struct gelic_port *port)
> +{
> + return port_priv(port);
> +}
> +
> +struct gelic_eurus_cmd {
> + struct work_struct work;
> + struct gelic_wl_info *wl;
> + unsigned int cmd; /* command code */
> + u64 tag;
> + u64 size;
> + void *buffer;
> + unsigned int buf_size;
> + struct completion done;
> + int status;
> + u64 cmd_status;
> +};
> +
> +/* private ioctls to pass PSK */
> +#define GELIC_WL_PRIV_SET_PSK (SIOCIWFIRSTPRIV + 0)
> +#define GELIC_WL_PRIV_GET_PSK (SIOCIWFIRSTPRIV + 1)
> +
> +extern int gelic_wl_driver_probe(struct gelic_card *card);
> +extern int gelic_wl_driver_remove(struct gelic_card *card);
> +extern void gelic_wl_interrupt(struct net_device *netdev, u64 status);
> +#endif /* _GELIC_WIRELESS_H */
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: 2.6.24-rc8-mm1 : net tcp_input.c warnings
From: Dave Young @ 2008-01-25 1:30 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: Kamalesh Babulal, Krishna Kumar2, Denys Fedoryshchenko,
David Miller, LKML, Netdev, Andrew Morton
In-Reply-To: <Pine.LNX.4.64.0801241108400.31652@kivilampi-30.cs.helsinki.fi>
On Jan 24, 2008 5:54 PM, Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> wrote:
> On Thu, 24 Jan 2008, Dave Young wrote:
>
> Hi Dave (& others),
>
> > Thanks.
>
> Thanks a lot, I was first to ignore all these because they occurred
> with newreno, but looked again... :-/
>
> > New warning trigged with your debug patch:
>
> This was probably with the earlier one I sent to you because there's still
> this case remaining which itself is valid:
>
> > P: 5 L: 0 vs 0 S: 0 vs 1 w: 2044790889-2044796616 (0)
>
> ...snip... this is still ok state (S+L <= P):
>
>
> > P: 5 L: 0 vs 0 S: 0 vs 3 w: 2044790889-2044796616 (0)
> > TCP wq(s) <
> > TCP wq(h) +++h+<
> > l0 s3 f0 p5 seq: su2044790889 hs2044795029 sn2044796616
> > ------------[ cut here ]------------
> > WARNING: at net/ipv4/tcp_input.c:2169 tcp_mark_head_lost+0x122/0x150()
> > Modules linked in: snd_seq_dummy snd_seq_oss snd_seq_midi_event
> > snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss eeprom e100 psmouse
> > snd_hda_intel snd_pcm snd_timer btusb bluetooth serio_raw snd 3c59x sg
> > evdev thermal soundcore rtc_cmos snd_page_alloc rtc_core rtc_lib
> > i2c_i801 processor button intel_agp dcdbas pcspkr agpgart
> > Pid: 0, comm: swapper Not tainted 2.6.24-rc8-mm1 #8
> > [<c0132100>] ? have_callable_console+0x20/0x30
> > [<c0131844>] warn_on_slowpath+0x54/0x80
> > [<c03ffe54>] ? tcp_print_queue+0x1a4/0x230
> > [<c0132438>] ? vprintk+0x308/0x320
> > [<c0132438>] ? vprintk+0x308/0x320
> > [<c0132438>] ? vprintk+0x308/0x320
> > [<c03ffff6>] ? tcp_verify_wq+0x116/0x1c0
> > [<c03f6052>] tcp_mark_head_lost+0x122/0x150
> > [<c03f60ca>] tcp_update_scoreboard+0x4a/0x190
> > [<c03f6e7a>] tcp_fastretrans_alert+0x4da/0x700
> > [<c03f7e63>] tcp_ack+0x1b3/0x3a0
> > [<c03fa21b>] tcp_rcv_established+0x3eb/0x710
> > [<c0401c05>] tcp_v4_do_rcv+0xe5/0x100
> > [<c04021fb>] tcp_v4_rcv+0x5db/0x660
> > [<c0401fa7>] ? tcp_v4_rcv+0x387/0x660
> > [<c03e5eed>] ? ip_local_deliver_finish+0x2d/0x1d0
> > [<c03e5f44>] ip_local_deliver_finish+0x84/0x1d0
> > [<c03e5eed>] ? ip_local_deliver_finish+0x2d/0x1d0
> > [<c0156b97>] ? __lock_release+0x47/0x70
> > [<c03e6147>] ip_local_deliver+0xb7/0xc0
> > [<c03e6202>] ip_rcv_finish+0xb2/0x3c0
> > [<c03c01d8>] ? sock_def_readable+0x48/0xa0
> > [<c03be061>] ? sock_queue_rcv_skb+0xb1/0x1a0
> > [<c03be0a7>] ? sock_queue_rcv_skb+0xf7/0x1a0
> > [<c03e669f>] ip_rcv+0x18f/0x290
> > [<c042fb10>] ? packet_rcv_spkt+0xd0/0x130
> > [<c03c8da6>] netif_receive_skb+0x2b6/0x330
> > [<c03c8c17>] ? netif_receive_skb+0x127/0x330
> > [<c03c8ea3>] ? process_backlog+0x83/0x100
> > [<c03c8eae>] process_backlog+0x8e/0x100
> > [<c03c90bc>] net_rx_action+0x13c/0x230
> > [<c03c8fd9>] ? net_rx_action+0x59/0x230
> > [<c0136f63>] __do_softirq+0x93/0x120
> > [<c013706a>] do_softirq+0x7a/0x80
> > [<c0137135>] irq_exit+0x65/0x90
> > [<c01078b1>] do_IRQ+0x41/0x80
> > [<c0155659>] ? trace_hardirqs_on+0xb9/0x130
> > [<c01059ca>] common_interrupt+0x2e/0x34
> > [<c0103390>] ? mwait_idle_with_hints+0x40/0x50
> > [<c01033a0>] ? mwait_idle+0x0/0x20
> > [<c01033b2>] mwait_idle+0x12/0x20
> > [<c0103141>] cpu_idle+0x61/0x110
> > [<c04339fd>] rest_init+0x5d/0x60
> > [<c05a47fa>] start_kernel+0x1fa/0x260
> > [<c05a4190>] ? unknown_bootoption+0x0/0x130
> > =======================
> > ---[ end trace 14b601818e6903ac ]---
> > ------------[ cut here ]------------
> > WARNING: at net/ipv4/tcp_ipv4.c:197 tcp_verify_wq+0x1b6/0x1c0()
> > Modules linked in: snd_seq_dummy snd_seq_oss snd_seq_midi_event
> > snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss eeprom e100 psmouse
> > snd_hda_intel snd_pcm snd_timer btusb bluetooth serio_raw snd 3c59x sg
> > evdev thermal soundcore rtc_cmos snd_page_alloc rtc_core rtc_lib
> > i2c_i801 processor button intel_agp dcdbas pcspkr agpgart
> > Pid: 0, comm: swapper Not tainted 2.6.24-rc8-mm1 #8
> > [<c0132100>] ? have_callable_console+0x20/0x30
> > [<c0131844>] warn_on_slowpath+0x54/0x80
> > [<c01317da>] ? print_oops_end_marker+0x2a/0x30
> > [<c0131849>] ? warn_on_slowpath+0x59/0x80
> > [<c03ffe54>] ? tcp_print_queue+0x1a4/0x230
> > [<c0132438>] ? vprintk+0x308/0x320
> > [<c0132438>] ? vprintk+0x308/0x320
> > [<c0400096>] tcp_verify_wq+0x1b6/0x1c0
> > [<c03ffff6>] ? tcp_verify_wq+0x116/0x1c0
> > [<c03f5ffc>] tcp_mark_head_lost+0xcc/0x150
> > [<c03f60ca>] tcp_update_scoreboard+0x4a/0x190
> > [<c03f6e7a>] tcp_fastretrans_alert+0x4da/0x700
> > [<c03f7e63>] tcp_ack+0x1b3/0x3a0
> > [<c03fa21b>] tcp_rcv_established+0x3eb/0x710
> > [<c0401c05>] tcp_v4_do_rcv+0xe5/0x100
> > [<c04021fb>] tcp_v4_rcv+0x5db/0x660
> > [<c0401fa7>] ? tcp_v4_rcv+0x387/0x660
> > [<c03e5eed>] ? ip_local_deliver_finish+0x2d/0x1d0
> > [<c03e5f44>] ip_local_deliver_finish+0x84/0x1d0
> > [<c03e5eed>] ? ip_local_deliver_finish+0x2d/0x1d0
> > [<c0156b97>] ? __lock_release+0x47/0x70
> > [<c03e6147>] ip_local_deliver+0xb7/0xc0
> > [<c03e6202>] ip_rcv_finish+0xb2/0x3c0
> > [<c03c01d8>] ? sock_def_readable+0x48/0xa0
> > [<c03be061>] ? sock_queue_rcv_skb+0xb1/0x1a0
> > [<c03be0a7>] ? sock_queue_rcv_skb+0xf7/0x1a0
> > [<c03e669f>] ip_rcv+0x18f/0x290
> > [<c042fb10>] ? packet_rcv_spkt+0xd0/0x130
> > [<c03c8da6>] netif_receive_skb+0x2b6/0x330
> > [<c03c8c17>] ? netif_receive_skb+0x127/0x330
> > [<c03c8ea3>] ? process_backlog+0x83/0x100
> > [<c03c8eae>] process_backlog+0x8e/0x100
> > [<c03c90bc>] net_rx_action+0x13c/0x230
> > [<c03c8fd9>] ? net_rx_action+0x59/0x230
> > [<c0136f63>] __do_softirq+0x93/0x120
> > [<c013706a>] do_softirq+0x7a/0x80
> > [<c0137135>] irq_exit+0x65/0x90
> > [<c01078b1>] do_IRQ+0x41/0x80
> > [<c0155659>] ? trace_hardirqs_on+0xb9/0x130
> > [<c01059ca>] common_interrupt+0x2e/0x34
> > [<c0103390>] ? mwait_idle_with_hints+0x40/0x50
> > [<c01033a0>] ? mwait_idle+0x0/0x20
> > [<c01033b2>] mwait_idle+0x12/0x20
> > [<c0103141>] cpu_idle+0x61/0x110
> > [<c04339fd>] rest_init+0x5d/0x60
> > [<c05a47fa>] start_kernel+0x1fa/0x260
> > [<c05a4190>] ? unknown_bootoption+0x0/0x130
> > =======================
> > ---[ end trace 14b601818e6903ac ]---
>
> ...But this no longer is, and even more, L: 5 is not valid state at this
> point all (should only happen if we went to RTO but it would reset S to
> zero with newreno):
>
> > P: 5 L: 5 vs 5 S: 0 vs 3 w: 2044790889-2044796616 (0)
> > TCP wq(s) LLLLl<
> > TCP wq(h) +++h+<
> > l5 s3 f0 p5 seq: su2044790889 hs2044795029 sn2044796616
>
> Surprisingly, it was the first time the WARN_ON for left_out returned
> correct location. This also explains why the patch I sent to Krishna
> didn't print anything (it didn't end up into printing because I forgot
> to add L+S>P check into to the state checking if).
>
> ...so please, could you (others than Denys) try this patch, it should
> solve the issue. And Denys, could you confirm (and if necessary double
> check) that the kernel you saw this similar problem with is the pure
> Linus' mainline, i.e., without any net-2.6.25 or mm bits please, if so,
> that problem persists. And anyway, there were some fackets_out related
> problems reported as well and this doesn't help for that but I think I've
> lost track of who was seeing it due to large number of reports :-), could
> somebody refresh my memory because I currently don't have time to dig it
> up from archives (at least on this week).
Thanks, applied on my test kernel, if there's no warnings I will just mute.
>
>
> --
> i.
>
> --
> [PATCH] [TCP]: NewReno must count every skb while marking losses
>
> NewReno should add cnt per skb (as with FACK) instead of depending
> on SACKED_ACKED bits which won't be set with it at all.
> Effectively, NewReno should always exists after the first
> iteration anyway (or immediately if there's already head in
> lost_out.
>
> This was fixed earlier in net-2.6.25 but got reverted among other
> stuff and I didn't notice that this is still necessary (actually
> wasn't even considering this case while trying to figure out the
> reports because I lived with different kind of code than it in
> reality was).
>
> This should solve the WARN_ONs in TCP code that as a result of
> this triggered multiple times in every place we check for this
> invariant.
>
> Special thanks to Dave Young <hidave.darkstar@gmail.com> and
> Krishna Kumar2 <krkumar2@in.ibm.com> for trying with my debug
> patches.
>
> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
> ---
> net/ipv4/tcp_input.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
> index 295490e..aa409a5 100644
> --- a/net/ipv4/tcp_input.c
> +++ b/net/ipv4/tcp_input.c
> @@ -2156,7 +2156,7 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int fast_rexmit)
> tp->lost_skb_hint = skb;
> tp->lost_cnt_hint = cnt;
>
> - if (tcp_is_fack(tp) ||
> + if (tcp_is_fack(tp) || tcp_is_reno(tp) ||
> (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))
> cnt += tcp_skb_pcount(skb);
>
> --
> 1.5.2.2
>
^ 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